|
|
Subscribe / Log in / New account

Contiguous memory allocation for drivers

By Jonathan Corbet
July 21, 2010
Allocation of physically-contiguous memory buffers is required by many device drivers, but it cannot always be reliably done on long-running Linux systems. That leads to all kinds of unsatisfying workarounds in driver code. The contiguous memory allocator patches recently posted by Michal Nazarewicz are an attempt to solve this problem in a consistent way for all drivers.

A few years ago, when your editor was writing the camera driver for the original OLPC XO system, a problem turned up. The video acquisition hardware on the system was capable of copying video frames into memory via DMA operations, but only to physically contiguous buffers. There was, in other words, no scatter/gather DMA capability built into this (cheap) DMA engine. A choice was thus forced: either allocate memory for video acquisition at boot time, or attempt to allocate it on the fly when the camera is actually used. The former choice is reliable, but it has the disadvantage of leaving a significant chunk of memory idle (on a memory-constrained system) whenever the camera is not in use - most of the time on most systems. The latter choice does not waste memory, but is unreliable - large, contiguous allocations are increasingly hard to do as memory gets fragmented. In the OLPC case, the decision was to sacrifice the memory to ensure that the camera would always work.

This particular problem has been faced many times by many developers over the years; each driver author has tended to go with whatever ad hoc solution seems to make sense at the time. For some years, the "bigphysarea" patch was available to help, but that patch was never put into the mainline and has not seen any maintenance for some time. So the problem remains unsolved in any sort of general sense.

The contiguous memory allocation (CMA) patches are an attempt to put together a flexible solution which can be used in all drivers. The basic technique will be familiar: CMA grabs a chunk of contiguous physical memory at boot time (when it's plentiful), then doles it out to drivers in response to allocation requests. Where it differs is mainly in an elaborate mechanism for defining the memory region(s) to reserve and the policies for handing them out.

A system using CMA will always need to have at least one boot-time parameter describing the memory region(s) to use and the policy for allocating from those regions. The syntax used is rather complex, to the point that a large portion of the patch is made up of parsing code; see the included Documentation/cma.txt file for the full details. A simple example of a CMA command-line option would be something like:

    cma=c=10M cma_map=camera=c

This defines a 10MB region (called "c") and states that allocation requests from the camera device should be satisfied from this region. Multiple regions can be defined, each with its own size, alignment constraints, and allocation algorithm, and memory regions can be split into different "kinds" as well. The "kinds" feature might be used to separate large and small allocations, or to put different buffers into different DMA zones or NUMA nodes. The more complex command lines are reminiscent of regular expressions, but with less readability. The purpose behind this complexity is to enable a great deal of flexibility in how memory is handled without the need to change the drivers which are working with that memory. Whether that flexibility is worth the cost is not (to your editor, at least) entirely clear.

A driver can actually allocate a memory chunk with:

    #include <linux/cma.h>

    unsigned long cma_alloc(const struct device *dev, const char *kind,
	     		    unsigned long size, unsigned long alignment);

If all goes well, the return value will be the physical address of the allocated memory region.

For reasons which are not entirely clear, buffers allocated with CMA have a reference count associated with them. So two functions are provided to manipulate that count:

    int cma_get(unsigned long addr);
    int cma_put(unsigned long addr);

Since reference counting is used, there is no cma_free() function; instead, the memory chunk is passed to cma_put() and freed internally when the reference count goes to zero.

CMA comes with a best-fit allocator, but it is designed to work with multiple internal allocators. So, should there be a need to use a different allocation algorithm, it's a really straightforward matter to add it to the system. Naturally enough, the command-line syntax offers a way to specify which allocator should be used for each region.

In summary: CMA offers a solution to a problem which driver authors have been dealing with for some years. Your editor suspects, though, that it will require some changes before a mainline merge can be contemplated. The complexity of the solution is probably more than is really called for in this situation, and the whole thing might benefit from some integration with the DMA mapping infrastructure. But, someday, it would be nice to incorporate a solution to the large-buffer problem that all drivers can use.

Index entries for this article
KernelContiguous memory allocator
KernelDevice drivers/Support APIs
KernelMemory management/Large allocations


to post comments

best fit?

Posted Jul 22, 2010 8:46 UTC (Thu) by ncm (guest, #165) [Link] (1 responses)

It's sad to see such an archaic allocation scheme as "best-fit" in this day and age. Does it wear spats?

best fit?

Posted Jul 25, 2010 10:38 UTC (Sun) by mina86 (guest, #68442) [Link]

CMA has been designed with flexibility in mind. Adding allocators is a straight-forward matter. Best fit was provided as an example and something to fill the void (without the allocator one wouldn't be able to use CMA after all).

Moreover, while testing we have discovered that best-fit works “just fine” for us. Having said that, I'm not saying that in the future I, or someone else, won't work on a better allocator.

Contiguous memory allocation for drivers

Posted Jul 22, 2010 9:16 UTC (Thu) by mjthayer (guest, #39183) [Link] (5 responses)

Since most memory allocations don't care about where they are in physical memory, wouldn't it be possible to have contiguous memory reclaiming code which would move bits of don't-have-to-be-contiguous memory about until it could defragment enough for a contiguous allocation? Of course, that would be expensive, but I could see it having its place as an emergency or guarantee measure alongside attempts to ensure that there is enough contiguous memory for "normal" use. It might also be more effective if it were done gradually in the background when it looked like contiguous memory might become tight in the forseeable future, not to mention if the rest of the memory subsystem were adjusted to take it into account.

Contiguous memory allocation for drivers

Posted Jul 22, 2010 11:09 UTC (Thu) by SimonO (guest, #56318) [Link]

Exactly, what's the point of memory management if it doesn't manage all possible needs? ;-)

I'd imagine a configuration parameter telling the memory management to start de-fragmenting memory as soon as a certain threshold is crossed, so that at any time when a camera-app or some other driver requests a chunk of contiguous memory, the request can quickly be satisfied. If the total amount of memory is insufficient for the normal workload and the newly started program with a need for contiguous memory isn't feasible, something can be done about it at that time.

I think that insufficient memory is a concept that users can understand, while insufficient contiguous memory is a lot harder to grasp. It's the job of the kernel to solve it for the user.

Cheers

Simon

Shifting memory around

Posted Jul 22, 2010 13:25 UTC (Thu) by corbet (editor, #1) [Link]

Indeed, that's just what the lumpy reclaim and memory compaction features do. They've helped, but it's still hard to reliably provide physically contiguous buffers in the megabyte size range, especially on smaller systems which don't have a whole lot of memory in the first place.

Contiguous memory allocation for drivers

Posted Jul 22, 2010 13:34 UTC (Thu) by tsr2 (subscriber, #4293) [Link] (2 responses)

I was thinking about something like this, but more along the lines of a "soft reserved area". If we assume that there are classes of memory that can always be discarded then an area can be reserved for contiguous memory allocation, but it will also allow memory to be allocated for pages that can definitely be safely discarded. When a contiguous memory allocation is required, then there is a block of memory available that can be freed quickly at low cost.

The difficulty for me, as someone unfamiliar with the kernel, is whether sufficient such pages would be available and identifiable? I wondered about I/O buffers, but clearly if the file is writeable then the pages could not always be discarded. If the kernel "knows" whether a file has been opened read only or read/write, that might simplify the question. Also there is a risk of a performance hit from having to dump a large number of buffers.

I'm guessing that such a scheme has already been considered by people that know more than I do about the issues and has been deemed impractical?

Contiguous memory allocation for drivers

Posted Jul 22, 2010 13:53 UTC (Thu) by nix (subscriber, #2304) [Link]

Well, the defragmentation code obviously knows which regions can be defragmented: so there could be a memory zone that contains only allocations that defragmentation could move out of the way, plus regions that could be freed without writeout. I don't think this exists yet, though, and memory zones are single contiguous lumps, not a bunch of individually-contiguous regions like CMA produces. So I suppose 'is in a CMA region' would have to be another page flag or something. But we're perennially short of those...

Contiguous memory allocation for drivers

Posted Jul 25, 2010 11:16 UTC (Sun) by mina86 (guest, #68442) [Link]

What you are describing is exactly what I've put as a “future work”. I believe that centralising contiguous-memory allocation will help implement a scheme where a free area of the CMA regions can be used for buffers, page cache, etc. Obviously, read-only pages would be preferred as they are trivial to discard but even dirty pages could stay in CMA managed regions of memory.

As I've said, this is, however, a future work. Hopefully, we'll get there some day. :)

Contiguous memory allocation for passing buffers between app & drivers?

Posted Jul 23, 2010 12:56 UTC (Fri) by gnu (guest, #65) [Link] (1 responses)

Are there some facilities for passing contiguous buffers between applications and drivers? For instance, many video SoCs have applications which do for eg, JPEG encode/decode etc and this buffer needs to be passed to another kernel driver which controls some hardware which acts on these buffers, or say, to a USB driver.

Contiguous memory allocation for passing buffers between app & drivers?

Posted Jul 25, 2010 11:10 UTC (Sun) by mina86 (guest, #68442) [Link]

No. We consider this to be a problem for another framework. In particular, CMA may be used with V4L drivers which do not need co worry about interaction with user space as V4L handles that. I am aware though that some devices may need such facilities and for those a separate solution should be developed (possibly working with CMA but not necessarily).

As a matter of fact, some time ago we have provided a solution for mapping physically-contiguous memory blocks to user space (including using such a buffer as SysV shared memory which is handy for X11) and then passing them back to devices (that was PMM and UPBuffer). It has also been completely agnostic to the way memory block is allocated as well as provided a “shadow buffer” if user provided buffer was not contiguous and a cache coherency control. If it'll became apparent that such features are needed part of the old solution can be incorporated in a new framework.

Contiguous memory allocation for drivers

Posted Jul 23, 2010 22:55 UTC (Fri) by giraffedata (guest, #1954) [Link] (2 responses)

I don't get it. How is this better than the driver allocating the memory at boot time? In the example, it looks like there is 10 MB reserved for the camera for the life of the kernel instance. What am I missing?

Contiguous memory allocation for drivers

Posted Jul 25, 2010 10:52 UTC (Sun) by mina86 (guest, #68442) [Link] (1 responses)

The driver don't need to allocate memory. It is my experience that allocating memory at boot time is not that trivial, i.e. you don't have a one “allocate that amount of memory at boot time” function call. With CMA driver don't have to worry where to get the memory region from -- driver merely uses it.

This is a rather minor point though. More importantly, drivers can easily share the same region of memory without even knowing about it. The example I keep giving is a system with a camera and a video decoder which never run at the same time. If each driver were to allocate space for themselves twice the amount of memory would be reserved then really needed. It's of course only a simple example and one could show many more.

Also, as a freebie, drivers get allocators that are implemented in CMA. This may not always be an advantage since not all drivers will need it but nonetheless some may benefit.

So to sum things up, all the complexity of reserving and allocating memory is moved from the drivers to the framework plus centralised management gives greater flexibility for platform architects.

Contiguous memory allocation for drivers

Posted Jul 25, 2010 14:31 UTC (Sun) by giraffedata (guest, #1954) [Link]

Those are good reasons for CMA, but don't seem to be what the article is about. In the example in the article, it appears that a region is dedicated to the camera -- there's no opportunity to share with another driver. And the article starts off by saying the problem to be solved is that if you allocate the memory at boot time, you waste the memory when you aren't using the camera, but if you allocate it later, you might not be able to get it because of fragmentation.

I have now read the linked CMA documentation as well, and I think the article just missed the point of CMA.

Movable block allocator

Posted Aug 3, 2010 2:59 UTC (Tue) by mebourne (guest, #50785) [Link]

A long time ago I implemented a sliding block memory allocator for a text editor in C. When allocating a block you could provide a relocation handler which would be called when the block got moved. That way the memory allocator could move blocks around at will to ensure minimum fragmentation. It worked very well and something similar would seem to be a good solution here. eg. If a DMA area had to be moved to make a larger continuous block for another user then the relocation handler could reprogram the hardware for the new address.

Contiguous memory allocation for drivers

Posted May 8, 2012 18:11 UTC (Tue) by thespirited (guest, #84526) [Link]

I am working on Camera Driver and whenever I try to allocate the memory around 10M, it fails but 4-5M memory is created. Is there a limit to memory allocation using cma_alloc, if yes, how do I increase it.


Copyright © 2010, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds