Happy shrimp http://blog.csdn.net/lights_joy/lights@hb165.com this article applies to ADI bf561 DSPuclinux-2008r1-rc8 (transplanted to vdsp5) Visual DSP ++ 5.0 welcome reprint, but please keep the author information
1.1 buddy algorithmThe buddy algorithm is a classic algorithm used for memory management. It aims to solve external memory fragments. There are two ways to avoid external fragmentation: 1. A set of non-consecutive idle page boxes are mapped to non-consecutive linear address ranges using paging units. 2. Develop appropriate technologies to record the existing idle consecutive page box blocks, so as to avoid splitting large blocks of idle blocks to meet requests for small blocks. The second method to avoid kernel selection. The buddy algorithm groups all idle page boxes into 11 linked lists. Each block element of each linked list contains 1, 2, 4, 8, 16, 32, and 64,128,256,512,102 consecutive page boxes, the physical address of the first page of each block is an integer multiple of the block size. For example, the starting address of a block with a size of 16 page boxes is 16*2 ^ 12 (the size of a page box is 4 K, the size of the 16 page boxes is a multiple of 16*4 K, 1 k = 1024 = 10 power of 2, 4 k = 12 power of 2. For example, if you want to request a block of 128 page frames, the algorithm first checks whether the linked list of the 128 page boxes has idle blocks. If not, query the linked list of the 256 page frames, if yes, split the blocks of the 256 page boxes into two parts, one for use, and one for insert into the linked list of the 128 page boxes. If not, check the linked list of the 512 page boxes. If yes, split it into 128,128,256. One 128 is used, and the other two are inserted into the corresponding linked list. If no error is found at 512, an error signal is returned. Opposite to the recycling process, the kernel tries to merge the idle partners with the size of B into a separately fast one with the size of 2B. The two blocks meeting the following conditions are called partners: 1, two blocks have the same size and are recorded as B; 2. Their physical addresses are continuous. 3, the physical address of the first page of the first block is a multiple of 2 * B * 2 ^ 12. This algorithm iterates. If the released block is merged successfully, it will try to merge 2B blocks to form larger blocks.
1.1.1 memory recoveryThe memory collection of the buddy algorithm is completed by two macros, _ free_page and free_page, and two collection functions. It is defined as: # DEFINE _ free_page (PAGE) _ free_pages (PAGE), 0) # define free_page (ADDR) free_pages (ADDR), 0) extern void fastcall (_ free_pages (struct page * Page, unsigned int order); extern void fastcall (free_pages (unsigned long ADDR, unsigned int order ));
1.1.1.1 _ free_pages and free_pagesThe implementation of these two functions is: fastcall void _ free_pages (struct page * Page, unsigned int order) {If (put_page_testzero (page) {If (Order = 0) free_hot_page (PAGE); else _ free_pages_ OK (page, order) ;}} fastcall void free_pages (unsigned long ADDR, unsigned int order) {If (ADDR! = 0) {vm_bug_on (! Virt_addr_valid (void *) ADDR); _ free_pages (pai_to_page (void *) ADDR), order);} from the implementation of these two functions, we can see that, they only receive different parameters, and the final processing method is the same. The free_pages function receives an absolute address as a parameter, while the _ free_pages function directly receives the pointer of the Structure of page as a parameter. In this example, the put_page_testzero function is used to subtract page-> _ count and determine whether it is 0. If it is 0, this page is no longer used by users, and this page is released. It can be seen from this that when order is 0, this function tries to put the memory page in the so-called hot cache first, otherwise it will be recycled to the linked list of the specified order.
1.1.1.2 _ free_pages_ OKThis function is located at mm/page_alloc.c: static void _ free_pages_ OK (struct page * Page, unsigned int order) {unsigned long flags; int I; int reserved = 0; // determine whether these consecutive pages should be released. Normally, the reserved value is 0 for (I = 0; I <(1 <order); ++ I) reserved + = free_pages_check (page + I); If (Reserved) return; If (! Pagehighmem (page) // The constant value is true debug_check_no_locks_freed (page_address (PAGE), page_size <order); // The empty statement arch_free_page (page, order ); // empty statement kernel_map_pages (page, 1 <order, 0); // empty statement local_irq_save (flags); _ count_vm_events (pgfree, 1 <order ); // The empty statement free_one_page (page_zone (PAGE), page, order); local_irq_restore (flags);} is very simple, that is, calling the free_one_page function for release.
1.1.1.3 free_one_pageStatic void free_one_page (struct zone * zone, struct page * Page, int order) {spin_lock (& zone-> lock); zone-> all_unreclaimable = 0; zone-> pages_scanned = 0; _ free_one_page (page, zone, order); spin_unlock (& zone-> lock);} call the _ free_one_page function to continue tracking.
1.1.1.4 _ free_one_page/** Freeing function for a buddy system allocator. ** the concept of a buddy system is to maintain direct-mapped table * (containing bit values) for memory blocks of various "orders ". * The bottom level table contains the map for the smallest allocatable * units of memory (here, pages), and each level above it describes * pairs of units from the levels below, hence, "buddies ". * at a high level, All that happens here is marking the table entry * at the bottom level available, and propagating the changes upward * as necessary, plus some accounting needed to play nicely with other * parts of the VM system. * at each level, we keep a list of pages, which are heads of continuous * free pages of length of (1 <order) and marked with pg_buddy. page's * Order is recorded in page_private (PAGE) f Ield. * So when we are allocating or freeing one, we can derive the state of the * Other. that is, if we allocate a small block, and both were * free, the remainder of the region must be split into blocks. * If a block is freed, and its buddy is also free, then this * triggers coalescing into a block of larger size. ** -- WLI */static inline void _ free_one_page (struct page * Page, struct zone * z One, unsigned int order) {unsigned long page_idx; int order_size = 1 <order; If (unlikely (pagecompound (page) destroy_compound_page (page, order ); page_idx = page_to_pfn (PAGE) & (1 <max_order)-1); vm_bug_on (page_idx & (order_size-1); vm_bug_on (bad_range (zone, page )); _ mod_zone_page_state (zone, nr_free_pages, order_size); While (Order <MAX_ORDER-1) {unsigned long combined_idx; struct F Ree_area * area; struct page * Buddy; buddy = _ page_find_buddy (page, page_idx, order); If (! Page_is_buddy (page, buddy, order) break;/* move the buddy up one level. */list_del (& buddy-> LRU); Area = Zone-> free_area + order; area-> nr_free --; rmv_page_order (Buddy); combined_idx = _ find_combined_index (page_idx, order); page = page + (combined_idx-page_idx); page_idx = combined_idx; Order ++;} set_page_order (page, order); list_add (& page-> LRU, & zone-> free_area [order]. free_list); zone-> free _ Area [order]. nr_free ++;} the core of the buddy algorithm has been clearly stated in this comment. It divides the memory into blocks of different sizes, each of which consists of pages of varying numbers. The smallest block has only one page, followed by two pages, four pages, eight pages... Block. It consists of up to 1024 pages. In the preceding functions, the while loop places the page in a larger block as much as possible. After finding the largest block, the memory block is placed in the corresponding block linked list.
1.1.2 search for the buddy pageIn the buddy algorithm, each page corresponds to a buddy page. You can use the _ page_find_buddy function to find the buddy page corresponding to the specified page: /** locate the struct page for both the matching buddy in our * pair (buddy1) and the combined O (n + 1) page they form (page ). ** 1) Any buddy B1 will have an order o twin B2 which satisfies * the following equation: * b2 = b1 ^ (1 <O) * For example, if the starting buddy (buddy2) is #8 its Order * 1 buddy is #10: * b2 = 8 ^ (1 <1) = 8 ^ 2 = 10 ** 2) Any buddy B will have an order O + 1 parent P which * satisfies the following equation: * P = B &~ (1 <O) ** assumption: * _ mem_map is contiguous at least up to max_order */static inline struct page * _ page_find_buddy (struct page * Page, unsigned long page_idx, unsigned int order) {unsigned long buddy_idx = page_idx ^ (1 <order); Return page + (buddy_idx-page_idx );}
1.1.3 check whether the two pages are mutual buddyYou can use the page_is_buddy function to check whether two specified pages are buddy: /** this function checks whether a page is free & is the buddy * We Can Do coalesce a page and Its buddy if * () the buddy is not in a hole & * (B) The Buddy is in the buddy system & * (c) A page and Its buddy have the same Order & * (d) a page and Its buddy are in the same zone. ** for recording whether a page is in the buddy system, we use pg_buddy. * Setting, clearing, and testing pg_buddy is serialized by zone-> lock. ** for recording Page's order, we use page_private (page ). */static inline int page_is_buddy (struct page * Page, struct page * Buddy, int order) {If (! Pfn_valid_within (page_to_pfn (Buddy) // The constant is false return 0; If (page_zone_id (PAGE )! = Page_zone_id (Buddy) return 0; If (pagebuddy (Buddy) & page_order (Buddy) = order) {bug_on (page_count (Buddy )! = 0); return 1;} return 0;} Here pagebuddy is used to determine whether a page is marked with pg_buddy. Note: during initialization, all pages are marked with only pg_reserved. # Define pagebuddy (PAGE) test_bit (pg_buddy, & (PAGE)-> flags)