2014-12-17 22:10:32

by Gregory Fong

[permalink] [raw]
Subject: [RFC PATCH] mm: cma: add functions for getting allocation info

These functions allow for retrieval of information on what is allocated from
within a given CMA region. It can be useful to know the number of distinct
contiguous allocations and where in the region those allocations are located.

Based on an initial version by Marc Carino <[email protected]> in a driver
that used the CMA bitmap directly; this instead moves the logic into the core
CMA API.

Signed-off-by: Gregory Fong <[email protected]>
---
This has been really useful for us to determine allocation information for a
CMA region. We have had a separate driver that might not be appropriate for
upstream, but allowed using a user program to run CMA unit tests to verify that
allocations end up where they we would expect. This addition would allow for
that without needing to expose the CMA bitmap. Wanted to put this out there to
see if anyone else would be interested, comments and suggestions welcome.

include/linux/cma.h | 3 ++
mm/cma.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 94 insertions(+)

diff --git a/include/linux/cma.h b/include/linux/cma.h
index a93438b..bc676e5 100644
--- a/include/linux/cma.h
+++ b/include/linux/cma.h
@@ -25,6 +25,9 @@ extern int __init cma_declare_contiguous(phys_addr_t base,
extern int cma_init_reserved_mem(phys_addr_t base,
phys_addr_t size, int order_per_bit,
struct cma **res_cma);
+extern int cma_get_alloc_info(struct cma *cma, int index, phys_addr_t *base,
+ phys_addr_t *size);
extern struct page *cma_alloc(struct cma *cma, int count, unsigned int align);
+extern int cma_get_alloc_count(struct cma *cma);
extern bool cma_release(struct cma *cma, struct page *pages, int count);
#endif
diff --git a/mm/cma.c b/mm/cma.c
index f891762..fc9a04a 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -447,3 +447,94 @@ bool cma_release(struct cma *cma, struct page *pages, int count)

return true;
}
+
+enum cma_scan_type {
+ GET_NUM_ALLOCS,
+ GET_ALLOC_INFO,
+};
+
+struct cma_scan_bitmap_res {
+ int index; /* index of allocation (input) */
+ unsigned long offset; /* offset into bitmap */
+ unsigned long size; /* size in bits */
+ int num_allocs; /* number of allocations */
+};
+
+static int cma_scan_bitmap(struct cma *cma, enum cma_scan_type op,
+ struct cma_scan_bitmap_res *res)
+{
+ unsigned long i = 0, pos_head = 0, pos_tail;
+ int count = 0, head_found = 0;
+
+ if (!cma)
+ return -EFAULT;
+
+ /* Count the number of contiguous chunks */
+ do {
+ if (head_found) {
+ pos_tail = find_next_zero_bit(cma->bitmap, cma->count,
+ i);
+
+ if (op == GET_ALLOC_INFO && count == res->index) {
+ res->offset = pos_head;
+ res->size = pos_tail - pos_head;
+ return 0;
+ }
+ count++;
+
+ head_found = 0;
+ i = pos_tail + 1;
+
+ } else {
+ pos_head = find_next_bit(cma->bitmap, cma->count, i);
+ i = pos_head + 1;
+ head_found = 1;
+ }
+ } while (i < cma->count);
+
+ if (op == GET_NUM_ALLOCS) {
+ res->num_allocs = count;
+ return 0;
+ } else {
+ return -EINVAL;
+ }
+}
+
+/**
+ * cma_get_alloc_info() - Get info on the requested allocation
+ * @cma: Contiguous memory region for which the allocation is performed.
+ * @index: Index of the allocation to get info for
+ * @base: Base address of the allocation
+ * @size: Size of the allocation in bytes
+ *
+ * Return: 0 on success, negative on failure
+ */
+int cma_get_alloc_info(struct cma *cma, int index, phys_addr_t *base,
+ phys_addr_t *size)
+{
+ struct cma_scan_bitmap_res res;
+ int ret;
+
+ res.index = index;
+ ret = cma_scan_bitmap(cma, GET_ALLOC_INFO, &res);
+ if (ret)
+ return ret;
+
+ *base = cma_get_base(cma) + PFN_PHYS(res.offset << cma->order_per_bit);
+ *size = PFN_PHYS(res.size << cma->order_per_bit);
+ return 0;
+}
+
+/**
+ * cma_get_alloc_count() - Get number of allocations
+ * @cma: Contiguous memory region for which the allocation is performed.
+ *
+ * Return: number of allocations on success, negative on failure
+ */
+int cma_get_alloc_count(struct cma *cma)
+{
+ struct cma_scan_bitmap_res res;
+ int ret = cma_scan_bitmap(cma, GET_NUM_ALLOCS, &res);
+
+ return (ret < 0) ? ret : res.num_allocs;
+}
--
1.9.1


2014-12-18 17:00:43

by Laura Abbott

[permalink] [raw]
Subject: Re: [RFC PATCH] mm: cma: add functions for getting allocation info

On 12/17/2014 2:10 PM, Gregory Fong wrote:
> These functions allow for retrieval of information on what is allocated from
> within a given CMA region. It can be useful to know the number of distinct
> contiguous allocations and where in the region those allocations are located.
>
> Based on an initial version by Marc Carino <[email protected]> in a driver
> that used the CMA bitmap directly; this instead moves the logic into the core
> CMA API.
>
> Signed-off-by: Gregory Fong <[email protected]>
> ---
> This has been really useful for us to determine allocation information for a
> CMA region. We have had a separate driver that might not be appropriate for
> upstream, but allowed using a user program to run CMA unit tests to verify that
> allocations end up where they we would expect. This addition would allow for
> that without needing to expose the CMA bitmap. Wanted to put this out there to
> see if anyone else would be interested, comments and suggestions welcome.
>

Information is definitely useful but I'm not sure how it's intended to
be used. Do you have a sample usage of these APIs? Another option might
be to just add regular debugfs support for each of the regions instead
of just calling out to a separate driver.

Thanks,
Laura

--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

2014-12-18 19:20:22

by Michal Nazarewicz

[permalink] [raw]
Subject: Re: [RFC PATCH] mm: cma: add functions for getting allocation info

On Wed, Dec 17 2014, Gregory Fong <[email protected]> wrote:
> These functions allow for retrieval of information on what is allocated from
> within a given CMA region. It can be useful to know the number of distinct
> contiguous allocations and where in the region those allocations are located.
>
> Based on an initial version by Marc Carino <[email protected]> in a driver
> that used the CMA bitmap directly; this instead moves the logic into the core
> CMA API.
>
> Signed-off-by: Gregory Fong <[email protected]>
> ---
> This has been really useful for us to determine allocation information for a
> CMA region. We have had a separate driver that might not be appropriate for
> upstream, but allowed using a user program to run CMA unit tests to verify that
> allocations end up where they we would expect. This addition would allow for
> that without needing to expose the CMA bitmap. Wanted to put this out there to
> see if anyone else would be interested, comments and suggestions welcome.

I don't like it at all. For example, cma_get_alloc_info has O(n^2)
complexity if one wishes to get information about all allocation.
Furthermore, it's prone to race conditions. If all you need this for is
debugging and testing, why not have user space parse output of dmesg?
With debug messages enabled, CMA prints ranges it allocated and testing
tool can figure out CMA's behaviour based on that.

> include/linux/cma.h | 3 ++
> mm/cma.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 94 insertions(+)
>
> diff --git a/include/linux/cma.h b/include/linux/cma.h
> index a93438b..bc676e5 100644
> --- a/include/linux/cma.h
> +++ b/include/linux/cma.h
> @@ -25,6 +25,9 @@ extern int __init cma_declare_contiguous(phys_addr_t base,
> extern int cma_init_reserved_mem(phys_addr_t base,
> phys_addr_t size, int order_per_bit,
> struct cma **res_cma);
> +extern int cma_get_alloc_info(struct cma *cma, int index, phys_addr_t *base,
> + phys_addr_t *size);
> extern struct page *cma_alloc(struct cma *cma, int count, unsigned int align);
> +extern int cma_get_alloc_count(struct cma *cma);
> extern bool cma_release(struct cma *cma, struct page *pages, int count);
> #endif
> diff --git a/mm/cma.c b/mm/cma.c
> index f891762..fc9a04a 100644
> --- a/mm/cma.c
> +++ b/mm/cma.c
> @@ -447,3 +447,94 @@ bool cma_release(struct cma *cma, struct page *pages, int count)
>
> return true;
> }
> +
> +enum cma_scan_type {
> + GET_NUM_ALLOCS,
> + GET_ALLOC_INFO,
> +};
> +
> +struct cma_scan_bitmap_res {
> + int index; /* index of allocation (input) */
> + unsigned long offset; /* offset into bitmap */
> + unsigned long size; /* size in bits */
> + int num_allocs; /* number of allocations */
> +};
> +
> +static int cma_scan_bitmap(struct cma *cma, enum cma_scan_type op,
> + struct cma_scan_bitmap_res *res)
> +{
> + unsigned long i = 0, pos_head = 0, pos_tail;
> + int count = 0, head_found = 0;
> +
> + if (!cma)
> + return -EFAULT;
> +
> + /* Count the number of contiguous chunks */
> + do {
> + if (head_found) {
> + pos_tail = find_next_zero_bit(cma->bitmap, cma->count,
> + i);
> +
> + if (op == GET_ALLOC_INFO && count == res->index) {
> + res->offset = pos_head;
> + res->size = pos_tail - pos_head;
> + return 0;
> + }
> + count++;
> +
> + head_found = 0;
> + i = pos_tail + 1;
> +
> + } else {
> + pos_head = find_next_bit(cma->bitmap, cma->count, i);
> + i = pos_head + 1;
> + head_found = 1;
> + }
> + } while (i < cma->count);
> +
> + if (op == GET_NUM_ALLOCS) {
> + res->num_allocs = count;
> + return 0;
> + } else {
> + return -EINVAL;
> + }
> +}
> +
> +/**
> + * cma_get_alloc_info() - Get info on the requested allocation
> + * @cma: Contiguous memory region for which the allocation is performed.
> + * @index: Index of the allocation to get info for
> + * @base: Base address of the allocation
> + * @size: Size of the allocation in bytes
> + *
> + * Return: 0 on success, negative on failure
> + */
> +int cma_get_alloc_info(struct cma *cma, int index, phys_addr_t *base,
> + phys_addr_t *size)
> +{
> + struct cma_scan_bitmap_res res;
> + int ret;
> +
> + res.index = index;
> + ret = cma_scan_bitmap(cma, GET_ALLOC_INFO, &res);
> + if (ret)
> + return ret;
> +
> + *base = cma_get_base(cma) + PFN_PHYS(res.offset << cma->order_per_bit);
> + *size = PFN_PHYS(res.size << cma->order_per_bit);
> + return 0;
> +}
> +
> +/**
> + * cma_get_alloc_count() - Get number of allocations
> + * @cma: Contiguous memory region for which the allocation is performed.
> + *
> + * Return: number of allocations on success, negative on failure
> + */
> +int cma_get_alloc_count(struct cma *cma)
> +{
> + struct cma_scan_bitmap_res res;
> + int ret = cma_scan_bitmap(cma, GET_NUM_ALLOCS, &res);
> +
> + return (ret < 0) ? ret : res.num_allocs;
> +}
> --
> 1.9.1
>

--
Best regards, _ _
.o. | Liege of Serenely Enlightened Majesty of o' \,=./ `o
..o | Computer Science, Michał “mina86” Nazarewicz (o o)
ooo +--<[email protected]>--<xmpp:[email protected]>--ooO--(_)--Ooo--

2015-02-04 23:14:44

by Gregory Fong

[permalink] [raw]
Subject: Re: [RFC PATCH] mm: cma: add functions for getting allocation info

On Thu, Dec 18, 2014 at 9:00 AM, Laura Abbott <[email protected]> wrote:
> On 12/17/2014 2:10 PM, Gregory Fong wrote:
>>
>> These functions allow for retrieval of information on what is allocated from
>> within a given CMA region. It can be useful to know the number of distinct
>> contiguous allocations and where in the region those allocations are
>> located.
>>
>> Based on an initial version by Marc Carino <[email protected]> in a driver
>> that used the CMA bitmap directly; this instead moves the logic into the core
>> CMA API.
>>
>> Signed-off-by: Gregory Fong <[email protected]>
>> ---
>> This has been really useful for us to determine allocation information for a
>> CMA region. We have had a separate driver that might not be appropriate for
>> upstream, but allowed using a user program to run CMA unit tests to verify that
>> allocations end up where they we would expect. This addition would allow for
>> that without needing to expose the CMA bitmap. Wanted to put this out there to
>> see if anyone else would be interested, comments and suggestions welcome.
>>
>
> Information is definitely useful but I'm not sure how it's intended to
> be used. Do you have a sample usage of these APIs? Another option might
> be to just add regular debugfs support for each of the regions instead
> of just calling out to a separate driver.

Sorry for the late reply, got way behind on emails.

Some background is probably good to start here: we use CMA to provide
very large (hundreds of MiB) contiguous regions for an out-of-kernel
allocator to divvy up according to varying platform requirements.
It's an unusual configuration but one that we're stuck with for now.

After having some time to think about this more and taking into
consideration yours and Michał's reply, this definitely does not seem
like the proper approach. Something better would probably be like
what Stefan is working on[1], so I'll wait to see his v2 that uses
debugfs instead.

[1] https://lkml.org/lkml/2014/12/26/95

Thanks,
Gregory