Skip to contentSkip to conversation

GFP_ZONEMASK vs. MAX_NR_ZONES

RFC PATCH In review Matthew Dobson 2 participants 2 messages Jan 31, 2003

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 GFP_ZONEMASK vs. MAX_NR_ZONES

Whilst reading through some code for an unrelated patch the other day, I stumbled across the build_zonelist* functions. It seemed to me that the bounds on the loop seemed too large.

There are only 3 memory zones: DMA (__GFP_DMA = 0x01), NORMAL, & HIGHMEM (__GFP_DMA = 0x02). Thus, GFP_ZONEMASK doesn't need to be 0x0f, but only 0x03. My guess this was to leave room for future zones? In any case, the loop in build_zonelists should almost certainly not go from i=0..GFP_ZONEMASK. This instantiates 13 zones that are never used, because there is no case that I could find where any zonemask above 0x02 is used. A zonemask of 0x03 would be DMA | HIGHMEM, but I could not find an instance of that either, probably because it wouldn't make much sense to request a chunk of memory from DMA & HIGHMEM.

By changing the value of GFP_ZONEMASK to accurately represent the number of zones, and changing the size of the node_zonelists array to MAX_NR_ZONES, we save ((156 * MAX_NUMNODES) + 42) bytes per pglist_data structure (basically per node). This translates to 198 bytes on UP/SMP, and 1290 bytes per node (MAX_NUMNODES=8) on NUMAQ. Not a stagerring savings, but why waste it?

Can anyone point out why this patch would be wrong (other arch's using it differently, fundamental misunderstanding on my part, etc)? BTW, this patch boots for me on NUMAQ, and really should affect UP (except for the slight size savings).

Cheers!

-Matt

include/linux/gfp.h +1 -1
diff -Nur --exclude-from=/usr/src/.dontdiff linux-2.5.59-vanilla/include/linux/gfp.h linux-2.5.59-zonelist_fix/include/linux/gfp.h
@@ -7,7 +7,7 @@
 /*
  * GFP bitmasks..
  */
-/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low four bits) */
+/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low two bits) */
 #define __GFP_DMA	0x01
 #define __GFP_HIGHMEM	0x02
 
include/linux/mmzone.h +2 -2
diff -Nur --exclude-from=/usr/src/.dontdiff linux-2.5.59-vanilla/include/linux/mmzone.h linux-2.5.59-zonelist_fix/include/linux/mmzone.h
@@ -162,7 +162,7 @@
 	struct zone *zones[MAX_NUMNODES * MAX_NR_ZONES + 1]; // NULL delimited
 };
 
-#define GFP_ZONEMASK	0x0f
+#define GFP_ZONEMASK	0x03
 
 /*
  * The pg_data_t structure is used in machines with CONFIG_DISCONTIGMEM
@@ -178,7 +178,7 @@
 struct bootmem_data;
 typedef struct pglist_data {
 	struct zone node_zones[MAX_NR_ZONES];
-	struct zonelist node_zonelists[GFP_ZONEMASK+1];
+	struct zonelist node_zonelists[MAX_NR_ZONES];
 	int nr_zones;
 	struct page *node_mem_map;
 	unsigned long *valid_addr_bitmap;
mm/page_alloc.c +1 -1
diff -Nur --exclude-from=/usr/src/.dontdiff linux-2.5.59-vanilla/mm/page_alloc.c linux-2.5.59-zonelist_fix/mm/page_alloc.c
@@ -962,7 +962,7 @@
 
 	local_node = pgdat->node_id;
 	printk("Building zonelist for node : %d\n", local_node);
-	for (i = 0; i <= GFP_ZONEMASK; i++) {
+	for (i = 0; i < MAX_NR_ZONES; i++) {
 		struct zonelist *zonelist;
 
 		zonelist = pgdat->node_zonelists + i;
#1 lore raw
Quoted 4 lines · Matthew Dobson

Whilst reading through some code for an unrelated patch the other day, I stumbled across the build_zonelist* functions. It seemed to me that the bounds on the loop seemed too large.

Quoted 9 lines

There are only 3 memory zones: DMA (__GFP_DMA = 0x01), NORMAL, & HIGHMEM (__GFP_DMA = 0x02). Thus, GFP_ZONEMASK doesn't need to be 0x0f, but only 0x03. My guess this was to leave room for future zones? In any case, the loop in build_zonelists should almost certainly not go from i=0..GFP_ZONEMASK. This instantiates 13 zones that are never used, because there is no case that I could find where any zonemask above 0x02 is used. A zonemask of 0x03 would be DMA | HIGHMEM, but I could not find an instance of that either, probably because it wouldn't make much sense to request a chunk of memory from DMA & HIGHMEM.

Erich Focht added a hack to NEC's tree so he can represent different nodes on their IA64 machines as memory zones and most 64it architectures really only needs a single zone (ZONE_NORMAL), so it might be an interesting option to make all this stuff per-arch..

Quoted 1 line