Add populated_map to account for memoryless nodes
Subsystems (8)
PATCH 1/1 Add populated_map to account for memoryless nodes
Split up Lee and Anton's original patch
(http://marc.info/?l=linux-mm&m=118133042025995&w=2), to allow for the populated_map changes to go in on their own.
Add a populated_map nodemask to indicate a node has memory or not. We have run into a number of issues (in practice and in code) with assumptions about every node having memory. Having this nodemask allows us to fix these issues; in particular, THISNODE allocations will come from the node specified, only, and the INTERLEAVE policy will be able to do the right thing with memoryless nodes.
---
Andrew, sorry, typo'd your address in the previous series. Will be sending them out again, anyways...
include/linux/nodemask.h +10 -0
@@ -64,12 +64,16 @@* * int node_online(node) Is some node online? * int node_possible(node) Is some node possible? +* int node_populated(node) Is some node populated [at policy_zone] * * int any_online_node(mask) First online node in mask * * node_set_online(node) set bit 'node' in node_online_map * node_set_offline(node) clear bit 'node' in node_online_map * +* node_set_populated(node) set bit 'node' in node_populated_map +* node_not_populated(node) clear bit 'node' in node_populated_map +* * for_each_node(node) for-loop node over node_possible_map * for_each_online_node(node) for-loop node over node_online_map *
@@ -344,12 +348,14 @@ static inline void __nodes_remap(nodemask_t *dstp, const nodemask_t *srcp,extern nodemask_t node_online_map;extern nodemask_t node_possible_map; +extern nodemask_t node_populated_map;#if MAX_NUMNODES >1 #define num_online_nodes () nodes_weight(node_online_map)#define num_possible_nodes () nodes_weight(node_possible_map)#define node_online (node) node_isset((node), node_online_map)#define node_possible (node) node_isset((node), node_possible_map) +#define node_populated (node) node_isset((node), node_populated_map)#define first_online_node first_node(node_online_map)#define next_online_node (nid) next_node((nid), node_online_map)extern int nr_node_ids;
@@ -358,6 +364,7 @@ extern int nr_node_ids;#define num_possible_nodes () 1#define node_online (node) ((node) == 0)#define node_possible (node) ((node) == 0) +#define node_populated (node) ((node) == 0)#define first_online_node 0#define next_online_node (nid) (MAX_NUMNODES)#define nr_node_ids 1
@@ -375,6 +382,9 @@ extern int nr_node_ids;#define node_set_online (node) set_bit((node), node_online_map.bits)#define node_set_offline (node) clear_bit((node), node_online_map.bits) +#define node_set_populated (node) set_bit((node), node_populated_map.bits) +#define node_not_populated (node) clear_bit((node), node_populated_map.bits) +#define for_each_node (node) for_each_node_mask((node), node_possible_map)#define for_each_online_node (node) for_each_node_mask((node), node_online_map)
mm/page_alloc.c +31 -2
@@ -54,6 +54,9 @@ nodemask_t node_online_map __read_mostly = { { [0] = 1UL } };EXPORT_SYMBOL (node_online_map);nodemask_t node_possible_map__read_mostly =NODE_MASK_ALL ;EXPORT_SYMBOL (node_possible_map); +nodemask_t node_populated_map__read_mostly =NODE_MASK_NONE ; +EXPORT_SYMBOL (node_populated_map); +unsigned long totalram_pages__read_mostly ;unsigned long totalreserve_pages__read_mostly ;long nr_swap_pages;
@@ -2161,7 +2164,7 @@ static int node_order[MAX_NUMNODES];static void build_zonelists_in_zone_order (pg_data_t *pgdat,int nr_nodes) {enum zone_type i; -int pos, j, node; +int pos, j;int zone_type;/* needs to be signed */ struct zone *z;struct zonelist *zonelist;
@@ -2171,7 +2174,7 @@ static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes) pos =0 ;for (zone_type = i; zone_type >=0 ; zone_type--) {for (j =0 ; j < nr_nodes; j++) { - node = node_order[j]; +int node = node_order[j]; z = &NODE_DATA (node)->node_zones[zone_type];if (populated_zone (z)) { zonelist->zones[pos++] = z;
@@ -2244,6 +2247,22 @@ static void set_zonelist_order(void) current_zonelist_order = user_zonelist_order; } +/* +* setup_populate_map() - record nodes whose "policy_zone" is "on-node". +*/ +static void setup_populated_map (int nid) +{ +pg_data_t *pgdat =NODE_DATA (nid); +struct zonelist *zl = pgdat->node_zonelists + policy_zone; +struct zone *z = zl->zones[0 ]; + +VM_BUG_ON (!z); +if (z->zone_pgdat == pgdat) +node_set_populated (nid); +else +node_not_populated (nid); +} +static void build_zonelists (pg_data_t *pgdat) {int j, node, load;
@@ -2327,6 +2346,15 @@ static void set_zonelist_order(void) current_zonelist_order =ZONELIST_ORDER_ZONE ; } +/* +* setup_populated_map - non-NUMA case +* Only node 0 should be on-line, and it MUST be populated! +*/ +static void setup_populated_map (int nid) +{ +node_set_populated (nid); +} +static void build_zonelists (pg_data_t *pgdat) {int node, local_node;
@@ -2381,6 +2409,7 @@ static int __build_all_zonelists(void *dummy)for_each_online_node (nid) {build_zonelists (NODE_DATA (nid));build_zonelist_cache (NODE_DATA (nid)); +setup_populated_map (nid); }return 0 ; }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 10 lines · Nishanth Aravamudan
mm/page_alloc.c +1
-1@@ -2161,7 +2164,7 @@ static int node_order[MAX_NUMNODES];static void build_zonelists_in_zone_order (pg_data_t *pgdat,int nr_nodes) {enum zone_type i; -int pos, j, node; +int pos, j;int zone_type;/* needs to be signed */ struct zone *z;struct zonelist *zonelist;
mm/page_alloc.c static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes) · line 2180
Quoted 8 lines
mm/page_alloc.c +1
-1@@ -2171,7 +2174,7 @@ static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes) pos =0 ;for (zone_type = i; zone_type >=0 ; zone_type--) {for (j =0 ; j < nr_nodes; j++) { - node = node_order[j]; +int node = node_order[j]; z = &NODE_DATA (node)->node_zones[zone_type];if (populated_zone (z)) { zonelist->zones[pos++] = z;
Unrelated modifications.
Quoted 9 lines
mm/page_alloc.c +5
-0@@ -2244,6 +2247,22 @@ static void set_zonelist_order(void) current_zonelist_order = user_zonelist_order; } +/* +* setup_populate_map() - record nodes whose "policy_zone" is "on-node". +*/ +static void setup_populated_map (int nid) +{
mm/page_alloc.c static void set_zonelist_order(void) · line 2264
Quoted 10 lines
mm/page_alloc.c +10
-0+pg_data_t *pgdat =NODE_DATA (nid); +struct zonelist *zl = pgdat->node_zonelists + policy_zone; +struct zone *z = zl->zones[0 ]; + +VM_BUG_ON (!z); +if (z->zone_pgdat == pgdat) +node_set_populated (nid); +else +node_not_populated (nid); +}
A node is only populated if it has memory in the policy zone? I would say a node is populated if it has any memory in any zone.
The above check may fail on x86_64 where only some nodes may have ZONE_NORMAL. Others only have ZONE_DMA32. Policy zone will be set to ZONE_NORMAL.
Quoted 6 lines
mm/page_alloc.c +1
-0+static void build_zonelists (pg_data_t *pgdat) {int j, node, load;@@ -2327,6 +2346,15 @@ static void set_zonelist_order(void) current_zonelist_order =ZONELIST_ORDER_ZONE ;
mm/page_alloc.c static void set_zonelist_order(void) · line 2356
Quoted 10 lines
mm/page_alloc.c +8
-0} +/* +* setup_populated_map - non-NUMA case +* Only node 0 should be on-line, and it MUST be populated! +*/ +static void setup_populated_map (int nid) +{ +node_set_populated (nid); +}
I'd say provide fallback functions so that node_populated() always returns true for !NUMA. That way it can be optimized out at compile time.
mm/page_alloc.c static int __build_all_zonelists(void *dummy) · line 2413
Quoted 9 lines
mm/page_alloc.c +1
-0static void build_zonelists (pg_data_t *pgdat) {int node, local_node;@@ -2381,6 +2409,7 @@ static int __build_all_zonelists(void *dummy)for_each_online_node (nid) {build_zonelists (NODE_DATA (nid));build_zonelist_cache (NODE_DATA (nid)); +setup_populated_map (nid); }
Is it possible to move the set_populated_node into build_zonelists somehow?
F.e. In build_zonelists_node you can check if nr_zones > 0 and then set it up?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v2 1/1 Add populated_map to account for memoryless nodes
Quoted 14 lines · Christoph Lameter
Quoted 12 lines · Nishanth Aravamudan
(quoted diff) +1
-1@@ -2161,7 +2164,7 @@ static int node_order[MAX_NUMNODES]; static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes) { enum zone_type i; - int pos, j, node; + int pos, j; int zone_type; /* needs to be signed */ struct zone *z; struct zonelist *zonelist;@@ -2171,7 +2174,7 @@ static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes) pos = 0; for (zone_type = i; zone_type >= 0; zone_type--) {
Quoted 8 lines
Review static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes) · line 2180
Quoted 6 lines
(quoted diff) +1
-1for (j = 0; j < nr_nodes; j++) { - node = node_order[j]; + int node = node_order[j]; z = &NODE_DATA(node)->node_zones[zone_type]; if (populated_zone(z)) { zonelist->zones[pos++] = z;Unrelated modifications.
Agreed -- sorry, I have just been refreshing/testing Lee and Anton's original fixes.
Quoted 24 lines
Quoted 9 lines
(quoted diff) +5
-0@@ -2244,6 +2247,22 @@ static void set_zonelist_order(void) current_zonelist_order = user_zonelist_order; } +/* + * setup_populate_map() - record nodes whose "policy_zone" is "on-node". + */ +static void setup_populated_map(int nid) +{Review static void set_zonelist_order(void) · line 2264
Quoted 10 lines
(quoted diff) +10
-0+ pg_data_t *pgdat = NODE_DATA(nid); + struct zonelist *zl = pgdat->node_zonelists + policy_zone; + struct zone *z = zl->zones[0]; + + VM_BUG_ON(!z); + if (z->zone_pgdat == pgdat) + node_set_populated(nid); + else + node_not_populated(nid); +}A node is only populated if it has memory in the policy zone? I would say a node is populated if it has any memory in any zone.
Quoted 3 lines
The above check may fail on
x86_64where only some nodes may haveZONE_NORMAL. Others only haveZONE_DMA32. Policy zone will be set toZONE_NORMAL.
I agree here as well, updated below.
Quoted 7 lines
Quoted 7 lines
(quoted diff) +0
-0static void build_zonelists(pg_data_t *pgdat) { int j, node, load;@@ -2327,6 +2346,15 @@ static void set_zonelist_order(void) current_zonelist_order = ZONELIST_ORDER_ZONE; }
Quoted 12 lines
Review static void set_zonelist_order(void) · line 2356
Quoted 8 lines
(quoted diff) +8
-0+/* + * setup_populated_map - non-NUMA case + * Only node 0 should be on-line, and it MUST be populated! + */ +static void setup_populated_map(int nid) +{ + node_set_populated(nid); +}I'd say provide fallback functions so that
node_populated()always returns true for !NUMA. That way it can be optimized out at compile time.
Already done in the original patch (node_populated() returns (node == 0) if MAX_NUMODES <= 1), I think.
Quoted 13 lines
Review static int __build_all_zonelists(void *dummy) · line 2413
Quoted 9 lines
(quoted diff) +1
-0static void build_zonelists(pg_data_t *pgdat) { int node, local_node;@@ -2381,6 +2409,7 @@ static int __build_all_zonelists(void *dummy) for_each_online_node(nid) { build_zonelists(NODE_DATA(nid)); build_zonelist_cache(NODE_DATA(nid)); + setup_populated_map(nid); }Is it possible to move the
set_populated_nodeintobuild_zonelistssomehow?
Quoted 2 lines
F.e. In
build_zonelists_nodeyou can check ifnr_zones> 0 and then set it up?
I've tried to do this as well, please see below.
Split up Lee and Anton's original patch
(http://marc.info/?l=linux-mm&m=118133042025995&w=2), to allow for the populated_map changes to go in on their own.
Add a populated_map nodemask to indicate a node has memory or not. We have run into a number of issues (in practice and in code) with assumptions about every node having memory. Having this nodemask allows us to fix these issues; in particular, THISNODE allocations will come from the node specified, only, and the INTERLEAVE policy will be able to do the right thing with memoryless nodes.
include/linux/nodemask.h +10 -0
@@ -64,12 +64,16 @@* * int node_online(node) Is some node online? * int node_possible(node) Is some node possible? +* int node_populated(node) Is some node populated [at policy_zone] * * int any_online_node(mask) First online node in mask * * node_set_online(node) set bit 'node' in node_online_map * node_set_offline(node) clear bit 'node' in node_online_map * +* node_set_populated(node) set bit 'node' in node_populated_map +* node_not_populated(node) clear bit 'node' in node_populated_map +* * for_each_node(node) for-loop node over node_possible_map * for_each_online_node(node) for-loop node over node_online_map *
@@ -344,12 +348,14 @@ static inline void __nodes_remap(nodemask_t *dstp, const nodemask_t *srcp,extern nodemask_t node_online_map;extern nodemask_t node_possible_map; +extern nodemask_t node_populated_map;#if MAX_NUMNODES >1 #define num_online_nodes () nodes_weight(node_online_map)#define num_possible_nodes () nodes_weight(node_possible_map)#define node_online (node) node_isset((node), node_online_map)#define node_possible (node) node_isset((node), node_possible_map) +#define node_populated (node) node_isset((node), node_populated_map)#define first_online_node first_node(node_online_map)#define next_online_node (nid) next_node((nid), node_online_map)extern int nr_node_ids;
@@ -358,6 +364,7 @@ extern int nr_node_ids;#define num_possible_nodes () 1#define node_online (node) ((node) == 0)#define node_possible (node) ((node) == 0) +#define node_populated (node) ((node) == 0)#define first_online_node 0#define next_online_node (nid) (MAX_NUMNODES)#define nr_node_ids 1
@@ -375,6 +382,9 @@ extern int nr_node_ids;#define node_set_online (node) set_bit((node), node_online_map.bits)#define node_set_offline (node) clear_bit((node), node_online_map.bits) +#define node_set_populated (node) set_bit((node), node_populated_map.bits) +#define node_not_populated (node) clear_bit((node), node_populated_map.bits) +#define for_each_node (node) for_each_node_mask((node), node_possible_map)#define for_each_online_node (node) for_each_node_mask((node), node_online_map)
mm/page_alloc.c +16 -0
@@ -54,6 +54,9 @@ nodemask_t node_online_map __read_mostly = { { [0] = 1UL } };EXPORT_SYMBOL (node_online_map);nodemask_t node_possible_map__read_mostly =NODE_MASK_ALL ;EXPORT_SYMBOL (node_possible_map); +nodemask_t node_populated_map__read_mostly =NODE_MASK_NONE ; +EXPORT_SYMBOL (node_populated_map); +unsigned long totalram_pages__read_mostly ;unsigned long totalreserve_pages__read_mostly ;long nr_swap_pages;
@@ -2251,6 +2254,7 @@ static void build_zonelists(pg_data_t *pgdat)nodemask_t used_mask;int local_node, prev_node;struct zonelist *zonelist; +struct zone *z;int order = current_zonelist_order;/* initialize zonelists */
@@ -2299,6 +2303,18 @@ static void build_zonelists(pg_data_t *pgdat)/* calculate node order -- i.e., DMA last! */ build_zonelists_in_zone_order (pgdat, j); } + +/* +* record nodes whose first fallback zone is "on-node" as +* populated +*/ + z = pgdat->node_zonelists->zones[0 ]; + +VM_BUG_ON (!z); +if (z->zone_pgdat == pgdat) +node_set_populated (local_node); +else +node_not_populated (local_node); }/* Construct the zonelist performance cache - see further mmzone.h */
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 2 lines · Nishanth Aravamudan
Already done in the original patch (
node_populated()returns (node == 0) ifMAX_NUMODES<= 1), I think.
Ah good.
Quoted 10 lines
mm/page_alloc.c +5
-0@@ -2299,6 +2303,18 @@ static void build_zonelists(pg_data_t *pgdat)/* calculate node order -- i.e., DMA last! */ build_zonelists_in_zone_order (pgdat, j); } + +/* +* record nodes whose first fallback zone is "on-node" as +* populated +*/
mm/page_alloc.c static void build_zonelists(pg_data_t *pgdat) · line 2320
Quoted 10 lines
mm/page_alloc.c +7
-0+ z = pgdat->node_zonelists->zones[0 ]; + +VM_BUG_ON (!z); +if (z->zone_pgdat == pgdat) +node_set_populated (local_node); +else +node_not_populated (local_node); }/* Construct the zonelist performance cache - see further mmzone.h */
Could be much simpler:
if (pgdat->node_present_pages)
node_set_populated(local_node);
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v3 1/1 Add populated_map to account for memoryless nodes
Quoted 25 lines · Christoph Lameter
Quoted 2 lines · Nishanth Aravamudan
Already done in the original patch (
node_populated()returns (node == 0) ifMAX_NUMODES<= 1), I think.Ah good.
Quoted 18 lines
(quoted diff) +12
-0@@ -2299,6 +2303,18 @@ static void build_zonelists(pg_data_t *pgdat) /* calculate node order -- i.e., DMA last! */ build_zonelists_in_zone_order(pgdat, j); } + + /* + * record nodes whose first fallback zone is "on-node" as + * populated + */ + z = pgdat->node_zonelists->zones[0]; + + VM_BUG_ON(!z); + if (z->zone_pgdat == pgdat) + node_set_populated(local_node); + else + node_not_populated(local_node); }
Quoted 7 lines
Review static void build_zonelists(pg_data_t *pgdat) · line 2320
Quoted 2 lines
(quoted diff) +0
-0/* Construct the zonelist performance cache - see further mmzone.h */Could be much simpler:
if (
pgdat->node_present_pages)node_set_populated(local_node);
Err, duh -- I was thinking of making this change, but then forgot.
Thanks for the reviews, Christoph!
Split up Lee and Anton's original patch
(http://marc.info/?l=linux-mm&m=118133042025995&w=2), to allow for the populated_map changes to go in on their own.
Add a populated_map nodemask to indicate a node has memory or not. We have run into a number of issues (in practice and in code) with assumptions about every node having memory. Having this nodemask allows us to fix these issues; in particular, THISNODE allocations will come from the node specified, only, and the INTERLEAVE policy will be able to do the right thing with memoryless nodes.
include/linux/nodemask.h +10 -0
@@ -64,12 +64,16 @@* * int node_online(node) Is some node online? * int node_possible(node) Is some node possible? +* int node_populated(node) Is some node populated? * * int any_online_node(mask) First online node in mask * * node_set_online(node) set bit 'node' in node_online_map * node_set_offline(node) clear bit 'node' in node_online_map * +* node_set_populated(node) set bit 'node' in node_populated_map +* node_not_populated(node) clear bit 'node' in node_populated_map +* * for_each_node(node) for-loop node over node_possible_map * for_each_online_node(node) for-loop node over node_online_map *
@@ -344,12 +348,14 @@ static inline void __nodes_remap(nodemask_t *dstp, const nodemask_t *srcp,extern nodemask_t node_online_map;extern nodemask_t node_possible_map; +extern nodemask_t node_populated_map;#if MAX_NUMNODES >1 #define num_online_nodes () nodes_weight(node_online_map)#define num_possible_nodes () nodes_weight(node_possible_map)#define node_online (node) node_isset((node), node_online_map)#define node_possible (node) node_isset((node), node_possible_map) +#define node_populated (node) node_isset((node), node_populated_map)#define first_online_node first_node(node_online_map)#define next_online_node (nid) next_node((nid), node_online_map)extern int nr_node_ids;
@@ -358,6 +364,7 @@ extern int nr_node_ids;#define num_possible_nodes () 1#define node_online (node) ((node) == 0)#define node_possible (node) ((node) == 0) +#define node_populated (node) ((node) == 0)#define first_online_node 0#define next_online_node (nid) (MAX_NUMNODES)#define nr_node_ids 1
@@ -375,6 +382,9 @@ extern int nr_node_ids;#define node_set_online (node) set_bit((node), node_online_map.bits)#define node_set_offline (node) clear_bit((node), node_online_map.bits) +#define node_set_populated (node) set_bit((node), node_populated_map.bits) +#define node_not_populated (node) clear_bit((node), node_populated_map.bits) +#define for_each_node (node) for_each_node_mask((node), node_possible_map)#define for_each_online_node (node) for_each_node_mask((node), node_online_map)
mm/page_alloc.c +10 -0
@@ -54,6 +54,9 @@ nodemask_t node_online_map __read_mostly = { { [0] = 1UL } };EXPORT_SYMBOL (node_online_map);nodemask_t node_possible_map__read_mostly =NODE_MASK_ALL ;EXPORT_SYMBOL (node_possible_map); +nodemask_t node_populated_map__read_mostly =NODE_MASK_NONE ; +EXPORT_SYMBOL (node_populated_map); +unsigned long totalram_pages__read_mostly ;unsigned long totalreserve_pages__read_mostly ;long nr_swap_pages;
@@ -2299,6 +2302,13 @@ static void build_zonelists(pg_data_t *pgdat)/* calculate node order -- i.e., DMA last! */ build_zonelists_in_zone_order (pgdat, j); } + +/* +* record populated zones for use when INTERLEAVE'ing or using +* GFP_THISNODE +*/ +if (pgdat->node_present_pages) +node_set_populated (local_node); }/* Construct the zonelist performance cache - see further mmzone.h */
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH 1/1 Fix INTERLEAVE with memoryless nodes
Applies to 2.6.22-rc4-mm2 with
add-populated_map-to-account-for-memoryless-nodes
applied.
Based on ideas from Christoph Lameter, add checks in the INTERLEAVE paths for memoryless nodes. We do not want to try interleaving onto those nodes.
Christoph said:
"This does not work for the address based interleaving for anonymous vmas. I am not sure what to do there. We could change the calculation of the node to be based only on nodes with memory and then skip the memoryless ones. I have only added a comment to describe its brokennes for now."
I have copied his draft comment.
Change alloc_pages_node() to fail __GFP_THISNODE allocations if the node is not populated.
Again, Christoph said:
"This will fix the alloc_pages_node case but not the alloc_pages() case. In the alloc_pages() case we do not specify a node. Implicitly it is understood that we (in the case of no memory policy / cpuset options) allocate from the nearest node. So it may be argued there that the GFP_THISNODE behavior of taking the first node from the zonelist is okay."
Christoph was also worried about the performance impact on these paths, so, as he suggested, uninline alloc_pages_node() and move it to mempolicy.c.
include/linux/gfp.h +1 -13
@@ -165,19 +165,7 @@ static inline void arch_alloc_page(struct page *page, int order) { }extern struct page *FASTCALL (__alloc_pages (gfp_t ,unsigned int ,struct zonelist *)); -static inline struct page *alloc_pages_node (int nid,gfp_t gfp_mask, -unsigned int order) -{ -if (unlikely (order >=MAX_ORDER )) -return NULL ; - -/* Unknown node is current node */ -if (nid <0 ) - nid =numa_node_id (); - -return __alloc_pages (gfp_mask, order, -NODE_DATA (nid)->node_zonelists +gfp_zone (gfp_mask)); -} +extern struct page *alloc_pages_node (int ,gfp_t ,unsigned int );#ifdef CONFIG_NUMA extern struct page *alloc_pages_current (gfp_t gfp_mask,unsigned order);
mm/mempolicy.c +37 -3
@@ -174,6 +174,7 @@ static struct zonelist *bind_zonelist(nodemask_t *nodes)static struct mempolicy *mpol_new (int mode,nodemask_t *nodes) {struct mempolicy *policy; +unsigned nid;PDprintk ("setting mode %d nodes[0] %lx\n" , mode,nodes_addr (*nodes)[0 ]);if (mode ==MPOL_DEFAULT )
@@ -184,6 +185,16 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes)atomic_set (&policy->refcnt,1 );switch (mode) {case MPOL_INTERLEAVE : +/* +* Clear any memoryless nodes here so that v.nodes can be used +* without extra checks +*/ + nid =first_node (*nodes); +while (nid <MAX_NUMNODES ) { +if (!node_populated (nid)) +node_clear (nid, *nodes); + nid =next_node (nid, *nodes); + } policy->v.nodes = *nodes;if (nodes_weight (*nodes) ==0 ) {kmem_cache_free (policy_cache, policy);
@@ -578,6 +589,22 @@ long do_get_mempolicy(int *policy, nodemask_t *nmask,return err; } +struct page *alloc_pages_node (int nid,gfp_t gfp_mask,unsigned int order) +{ +if (unlikely (order >=MAX_ORDER )) +return NULL ; + +/* Unknown node is current node */ +if (nid <0 ) + nid =numa_node_id (); + +if ((gfp_mask & __GFP_THISNODE) && !node_populated (nid)) +return NULL ; + +return __alloc_pages (gfp_mask, order, +NODE_DATA (nid)->node_zonelists +gfp_zone (gfp_mask)); +} +#ifdef CONFIG_MIGRATION /* * page migration
@@ -1126,9 +1153,11 @@ static unsigned interleave_nodes(struct mempolicy *policy)struct task_struct *me = current; nid = me->il_next; - next =next_node (nid, policy->v.nodes); -if (next >=MAX_NUMNODES ) - next =first_node (policy->v.nodes); +do { + next =next_node (nid, policy->v.nodes); +if (next >=MAX_NUMNODES ) + next =first_node (policy->v.nodes); + }while (!node_populated (next)); me->il_next = next;return nid; }
@@ -1192,6 +1221,11 @@ static inline unsigned interleave_nid(struct mempolicy *pol,* for huge pages, since vm_pgoff is in units of small * pages, we need to shift off the always 0 bits to get * a useful offset. +* +* NOTE: For configurations with memoryless nodes this +* is broken since the allocation attempts on that node +* will fall back to other nodes and thus one +* neighboring node will be overallocated from. */ BUG_ON (shift <PAGE_SHIFT ); off = vma->vm_pgoff >> (shift -PAGE_SHIFT );
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v6 1/1 Fix hugetlb pool allocation with empty nodes
Applies to 2.6.22-rc4-mm2 with
add-populated_map-to-account-for-memoryless-nodes
fix-interleave-with-memoryless-nodes
applied.
Split Lee and Anton's patch
(http://marc.info/?l=linux-mm&m=118133042025995&w=2) into two parts.
Only attempt to allocate huge pages on nodes that contain memory, as specified by node_populated_map.
mm/hugetlb.c +15 -6
@@ -105,13 +105,22 @@ static void free_huge_page(struct page *page)static int alloc_fresh_huge_page (void ) { -static int nid =0 ; +static int nid =-1 ;struct page *page; - page =alloc_pages_node (nid, htlb_alloc_mask|__GFP_COMP|__GFP_NOWARN, -HUGETLB_PAGE_ORDER ); - nid =next_node (nid, node_online_map); -if (nid ==MAX_NUMNODES ) - nid =first_node (node_online_map); +int start_nid; + +if (nid <0 ) + nid =first_node (node_populated_map); + start_nid = nid; + +do { + page =alloc_pages_node (nid, +GFP_HIGHUSER |__GFP_COMP|GFP_THISNODE , +HUGETLB_PAGE_ORDER ); + nid =next_node (nid, node_populated_map); +if (nid >= nr_node_ids) + nid =first_node (node_populated_map); + }while (!page && nid != start_nid);if (page) {set_compound_page_dtor (page, free_huge_page);spin_lock (&hugetlb_lock);
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH 1/1 hugetlb: numafy several functions
Applies to 2.6.22-rc4-mm2 with
add-populated_map-to-account-for-memoryless-nodes
fix-interleave-with-memoryless-nodes
fix-hugetlb-pool-allocation-with-empty-nodes
applied.
Add node-parameterized helpers for dequeue_huge_page, alloc_fresh_huge_page and try_to_free_low. Also have update_and_free_page() take a nid parameter. This is necessary to add a per-node sysfs attribute to specify the number of hugepages on that node.
mm/hugetlb.c +63 -34
@@ -66,11 +66,22 @@ static void enqueue_huge_page(struct page *page) free_huge_pages_node[nid]++; } +static struct page *dequeue_huge_page_node (int nid) +{ +struct page *page; + + page =list_entry (hugepage_freelists[nid].next, + struct page, lru); +list_del (&page->lru); + free_huge_pages--; + free_huge_pages_node[nid]--; +return page; +} +static struct page *dequeue_huge_page (struct vm_area_struct *vma,unsigned long address) {int nid; -struct page *page =NULL ;struct zonelist *zonelist =huge_zonelist (vma, address, htlb_alloc_mask);struct zone **z;
@@ -82,14 +93,9 @@ static struct page *dequeue_huge_page(struct vm_area_struct *vma,break ; } -if (*z) { - page =list_entry (hugepage_freelists[nid].next, - struct page, lru); -list_del (&page->lru); - free_huge_pages--; - free_huge_pages_node[nid]--; - } -return page; +if (*z) +return dequeue_huge_page_node (nid); +return NULL ; }static void free_huge_page (struct page *page)
@@ -103,6 +109,25 @@ static void free_huge_page(struct page *page)spin_unlock (&hugetlb_lock); } +static struct page *alloc_fresh_huge_page_node (int nid) +{ +struct page *page; + + page =alloc_pages_node (nid, +GFP_HIGHUSER |__GFP_COMP|GFP_THISNODE , +HUGETLB_PAGE_ORDER ); +if (page) { +set_compound_page_dtor (page, free_huge_page); +spin_lock (&hugetlb_lock); + nr_huge_pages++; + nr_huge_pages_node[nid]++; +spin_unlock (&hugetlb_lock); +put_page (page);/* free it into the hugepage allocator */ + } + +return page; +} +static int alloc_fresh_huge_page (void ) {static int nid =-1 ;
@@ -114,22 +139,14 @@ static int alloc_fresh_huge_page(void) start_nid = nid;do { - page =alloc_pages_node (nid, -GFP_HIGHUSER |__GFP_COMP|GFP_THISNODE , -HUGETLB_PAGE_ORDER ); + page =alloc_fresh_huge_page_node (nid); nid =next_node (nid, node_populated_map);if (nid >= nr_node_ids) nid =first_node (node_populated_map); }while (!page && nid != start_nid); -if (page) { -set_compound_page_dtor (page, free_huge_page); -spin_lock (&hugetlb_lock); - nr_huge_pages++; - nr_huge_pages_node[page_to_nid (page)]++; -spin_unlock (&hugetlb_lock); -put_page (page);/* free it into the hugepage allocator */ + +if (page)return 1 ; - }return 0 ; }
@@ -199,11 +216,11 @@ static unsigned int cpuset_mems_nr(unsigned int *array) }#ifdef CONFIG_SYSCTL -static void update_and_free_page (struct page *page) +static void update_and_free_page (int nid,struct page *page) {int i; nr_huge_pages--; - nr_huge_pages_node[page_to_nid (page)]--; + nr_huge_pages_node[nid]--;for (i =0 ; i < (HPAGE_SIZE /PAGE_SIZE ); i++) { page[i].flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced | 1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |
@@ -215,25 +232,37 @@ static void update_and_free_page(struct page *page) }#ifdef CONFIG_HIGHMEM +static void try_to_free_low_node (int nid,unsigned long count) +{ +struct page *page, *next; + +list_for_each_entry_safe (page, next, + &hugepage_freelists[nid], lru) { +if (PageHighMem (page)) +continue ; +list_del (&page->lru); +update_and_free_page (nid, page); + free_huge_pages--; + free_huge_pages_node[nid]--; +if (count >= nr_huge_pages_node[nid]) +return ; + } +} +static void try_to_free_low (unsigned long count) {int i;for (i =0 ; i <MAX_NUMNODES ; ++i) { -struct page *page, *next; -list_for_each_entry_safe (page, next, &hugepage_freelists[i], lru) { -if (PageHighMem (page)) -continue ; -list_del (&page->lru); -update_and_free_page (page); - free_huge_pages--; - free_huge_pages_node[page_to_nid (page)]--; -if (count >= nr_huge_pages) -return ; - } +try_to_free_low_node (i, count); +if (count >= nr_huge_pages) +break ; } }#else +static inline void try_to_free_low_node (int nid,unsigned long count) +{ +}static inline void try_to_free_low (unsigned long count) { }
@@ -255,7 +284,7 @@ static unsigned long set_max_huge_pages(unsigned long count)struct page *page =dequeue_huge_page (NULL ,0 );if (!page)break ; -update_and_free_page (page); +update_and_free_page (page_to_nid (page), page); }spin_unlock (&hugetlb_lock);return nr_huge_pages;
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH 1/1 hugetlb: add per-node nr_hugepages sysfs attribute
Applies to 2.6.22-rc4-mm2 with
add-populated_map-to-account-for-memoryless-nodes
fix-interleave-with-memoryless-nodes
fix-hugetlb-pool-allocation-with-empty-nodes
hugetlb-numafy-several-functions
applied.
Allow specifying the number of hugepages to allocate on a particular node. Our current global sysctl will try its best to put hugepages equally on each node, but htat may not always be desired. This allows the admin to control the layout of hugepage allocation at a finer level (while not breaking the existing interface).
---
I would have liked to have avoided the #ifdef's in node.c, but I couldn't figure out a simple way to conditionalize the create_file/remove_file calls.
drivers/base/node.c +11 -0
@@ -131,6 +131,11 @@ static ssize_t node_read_distance(struct sys_device * dev, char * buf) } static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL); +#ifdef CONFIG_HUGETLB_PAGE +static SYSDEV_ATTR(nr_hugepages, S_IRUGO | S_IWUSR, + hugetlb_read_nr_hugepages_node, + hugetlb_write_nr_hugepages_node); +#endif /* * register_node - Setup a sysfs device for a node.
@@ -151,6 +156,9 @@ int register_node(struct node *node, int num, struct node *parent)sysdev_create_file (&node->sysdev, &attr_meminfo);sysdev_create_file (&node->sysdev, &attr_numastat);sysdev_create_file (&node->sysdev, &attr_distance); +#ifdef CONFIG_HUGETLB_PAGE +sysdev_create_file (&node->sysdev, &attr_nr_hugepages); +#endif }return error; }
@@ -168,6 +176,9 @@ void unregister_node(struct node *node)sysdev_remove_file (&node->sysdev, &attr_meminfo);sysdev_remove_file (&node->sysdev, &attr_numastat);sysdev_remove_file (&node->sysdev, &attr_distance); +#ifdef CONFIG_HUGETLB_PAGE +sysdev_remove_file (&node->sysdev, &attr_nr_hugepages); +#endif sysdev_unregister (&node->sysdev); }
include/linux/hugetlb.h +4 -0
@@ -5,6 +5,7 @@#include <linux/mempolicy.h> #include <linux/shm.h> +#include <linux/sysdev.h> #include <asm/tlbflush.h> struct ctl_table ;
@@ -23,6 +24,9 @@ void __unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned lonint hugetlb_prefault (struct address_space *,struct vm_area_struct *);int hugetlb_report_meminfo (char *);int hugetlb_report_node_meminfo (int ,char *); +ssize_t hugetlb_read_nr_hugepages_node (struct sys_device *,char *); +ssize_t hugetlb_write_nr_hugepages_node (struct sys_device *,const char *, +size_t );unsigned long hugetlb_total_pages (void );int hugetlb_fault (struct mm_struct *mm,struct vm_area_struct *vma,unsigned long address,int write_access);
mm/hugetlb.c +53 -1
72 lines not on this page · raw message
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH][RFC] hugetlb: add per-node nr_hugepages sysfs attribute
mm/hugetlb.c int hugetlb_report_node_meminfo(int nid, char *buf) · line 358
Quoted 7 lines · Nishanth Aravamudan
mm/hugetlb.c +7
-0+/* +* unpopulated nodes can return pages from other nodes for +* THISNODE requests, so do a populated check and avoid +* double-checking in the sysctl path +*/ +if (!node_populated (nid)) +return count;
THISNODE fixes address this issue right?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH][RFC] hugetlb: add per-node nr_hugepages sysfs attribute
In reply to Nishanth Aravamudandrivers/base/node.c static ssize_t node_read_distance(struct sys_device * dev, char * buf) · line 138
Quoted 8 lines · Nishanth Aravamudan
}
staticSYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL);drivers/base/node.c +5
-0+#ifdef CONFIG_HUGETLB_PAGE +static SYSDEV_ATTR(nr_hugepages, S_IRUGO | S_IWUSR, + hugetlb_read_nr_hugepages_node, + hugetlb_write_nr_hugepages_node); +#endif
Move the above to hugetlb.c?
Also so far there is nothing in the nodes directories that can be modified. This is the first one. Is that really the right location?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH][RFC] hugetlb: add per-node nr_hugepages sysfs attribute
Quoted 13 lines · Christoph Lameter
drivers/base/node.c static ssize_t node_read_distance(struct sys_device * dev, char * buf) · line 138
Quoted 8 lines · Nishanth Aravamudan
}
staticSYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL);drivers/base/node.c +5
-0+#ifdef CONFIG_HUGETLB_PAGE +static SYSDEV_ATTR(nr_hugepages, S_IRUGO | S_IWUSR, + hugetlb_read_nr_hugepages_node, + hugetlb_write_nr_hugepages_node); +#endif Move the above to
hugetlb.c?
Quoted 2 lines
Also so far there is nothing in the nodes directories that can be modified. This is the first one. Is that really the right location?
I will rework this taking into account this comment and the other (sorry, forgot to refresh the patch and the commentary after the other changes).
As far as moving it, that might be the best option, but I'm not sure how to make sure that everything builds. Will ponder.
Also, I don't really see where else a per-node attribute should go other than /sys/devices/system/node/nodeX... Did you have a better location in mind?
Thanks,
Nish
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH][RFC] hugetlb: add per-node nr_hugepages sysfs attribute
Quoted 3 lines · Nishanth Aravamudan
Also, I don't really see where else a per-node attribute should go other than
/sys/devices/system/node/nodeX... Did you have a better location in mind?
No I think this is okay but doing so sets a precedent. If you do this then others will add more config stuff to that directory. So we need the feedback from others.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH][RFC] hugetlb: add per-node nr_hugepages sysfs attribute
In reply to Christoph LameterQuoted 5 lines · Christoph Lameter
Quoted 3 lines · Nishanth Aravamudan
}
staticSYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL);
Quoted 7 lines
drivers/base/node.c static ssize_t node_read_distance(struct sys_device * dev, char * buf) · line 138
Quoted 5 lines
drivers/base/node.c +5
-0+#ifdef CONFIG_HUGETLB_PAGE +static SYSDEV_ATTR(nr_hugepages, S_IRUGO | S_IWUSR, + hugetlb_read_nr_hugepages_node, + hugetlb_write_nr_hugepages_node); +#endif Move the above to
hugetlb.c?
Ok, if I do that, would you prefer I just add callbacks into hugetlb code for register_node() and unregister_node() that are no-ops if !CONFIG_HUGETLB_PAGE? That is, rather than
sysdev_remove_file(&node->sysdev, &attr_nr_hugepages);
just call something like
hugetlb_unregister_node()
? And similar for register? Otherwise, there are still going to be ifdefs for the remove and add calls.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH][RFC] hugetlb: add per-node nr_hugepages sysfs attribute
Quoted 4 lines · Nishanth Aravamudan
Ok, if I do that, would you prefer I just add callbacks into hugetlb code for
register_node()andunregister_node()that are no-ops if !CONFIG_HUGETLB_PAGE? That is, rather than
Quoted 8 lines
sysdev_remove_file(&node->sysdev, &attr_nr_hugepages);just call something like
hugetlb_unregister_node()? And similar for register? Otherwise, there are still going to be ifdefs for the remove and add calls.
Sounds good. Lets see the patch.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH][RFC] hugetlb: add per-node nr_hugepages sysfs attribute
Quoted 8 lines · Christoph Lameter
Quoted 6 lines · Nishanth Aravamudan
Ok, if I do that, would you prefer I just add callbacks into hugetlb code for
register_node()andunregister_node()that are no-ops if !CONFIG_HUGETLB_PAGE? That is, rather thansysdev_remove_file(&node->sysdev, &attr_nr_hugepages);
Quoted 8 lines
Quoted 6 lines
just call something like
hugetlb_unregister_node()? And similar for register? Otherwise, there are still going to be ifdefs for the remove and add calls.
Sounds good. Lets see the patch.
Of course, just wanted to make sure were on the same page.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH][RFC] hugetlb: numafy several functions
In reply to Nishanth AravamudanQuoted 5 lines
Add node-parameterized helpers for
dequeue_huge_page,alloc_fresh_huge_pageandtry_to_free_low. Also haveupdate_and_free_page()take a nid parameter. This is necessary to add a per-node sysfs attribute to specify the number of hugepages on that node.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
In reply to Nishanth AravamudanReview
Quoted 2 lines · Nishanth Aravamudan
(quoted diff) +2
-0+ if (nid < 0) + nid = first_node(node_populated_map);
nid == 1 means local node? Or why do we check for nid < 0?
if (nid == 1) nid = numa_node_id();
?
mm/hugetlb.c static void free_huge_page(struct page *page) · line 123
Quoted 8 lines
mm/hugetlb.c +8
-0+do { + page =alloc_pages_node (nid, +GFP_HIGHUSER |__GFP_COMP|GFP_THISNODE , +HUGETLB_PAGE_ORDER ); + nid =next_node (nid, node_populated_map); +if (nid >= nr_node_ids) + nid =first_node (node_populated_map); + }while (!page && nid != start_nid);
Looks good.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 11 lines · Christoph Lameter
Review
Quoted 2 lines · Nishanth Aravamudan
(quoted diff) +2
-0+ if (nid < 0) + nid = first_node(node_populated_map);nid == 1 means local node? Or why do we check for nid < 0?
if (nid == 1) nid = numa_node_id();?
No, nid is a static variable. So we initialize it to -1 to catch the first time we go through the loop.
IIRC, we can't just set it to first_node(node_populated_map), because it's a non-constant or something?
Quoted 10 lines
mm/hugetlb.c static void free_huge_page(struct page *page) · line 123
Quoted 8 lines
mm/hugetlb.c +8
-0+do { + page =alloc_pages_node (nid, +GFP_HIGHUSER |__GFP_COMP|GFP_THISNODE , +HUGETLB_PAGE_ORDER ); + nid =next_node (nid, node_populated_map); +if (nid >= nr_node_ids) + nid =first_node (node_populated_map); + }while (!page && nid != start_nid);Looks good.
Thanks,
Nish
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 11 lines · Nishanth Aravamudan
Quoted 10 lines · Christoph Lameter
Review
Quoted 2 lines · Nishanth Aravamudan
(quoted diff) +2
-0+ if (nid < 0) + nid = first_node(node_populated_map);nid == 1 means local node? Or why do we check for nid < 0?
if (nid == 1) nid = numa_node_id();
Quoted 7 lines
Quoted 1 line
?
No, nid is a static variable. So we initialize it to -1 to catch the first time we go through the loop.
IIRC, we can't just set it to
first_node(node_populated_map), because it's a non-constant or something?
Sure, you can initialize a c variable from another. So drop the -1.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 15 lines · Christoph Lameter
Quoted 13 lines · Nishanth Aravamudan
Quoted 11 lines · Christoph Lameter
Review
Quoted 2 lines · Nishanth Aravamudan
(quoted diff) +2
-0+ if (nid < 0) + nid = first_node(node_populated_map);nid == 1 means local node? Or why do we check for nid < 0?
if (nid == 1) nid = numa_node_id();?
Quoted 7 lines
Quoted 5 lines
No, nid is a static variable. So we initialize it to -1 to catch the first time we go through the loop.
IIRC, we can't just set it to
first_node(node_populated_map), because it's a non-constant or something?Sure, you can initialize a c variable from another. So drop the -1.
If I do:
static int nid = first_node(node_populated_map), I get:
mm/hugetlb.c:108: error: initializer element is not constant
??
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 3 lines · Nishanth Aravamudan
static int nid =
first_node(node_populated_map), I get:
mm/hugetlb.c:108: error: initializer element is not constant
Remove the static.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 7 lines · Christoph Lameter
Quoted 3 lines · Nishanth Aravamudan
static int nid =
first_node(node_populated_map), I get:
mm/hugetlb.c:108: error: initializer element is not constantRemove the static.
Cutting down the CCs.
Removing static wont help if the variable is still global. You need to define a local variable. Then it can be initialized with a variable expression.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 8 lines · Christoph Lameter
Quoted 6 lines · Christoph Lameter
Quoted 3 lines · Nishanth Aravamudan
static int nid =
first_node(node_populated_map), I get:
mm/hugetlb.c:108: error: initializer element is not constant
Quoted 7 lines
Quoted 1 line
Remove the static.
Cutting down the CCs.
Removing static wont help if the variable is still global. You need to define a local variable. Then it can be initialized with a variable expression.
What global?
nid is static to alloc_fresh_huge_page().
gcc says that the static variable (which *must* be static for the current round-robin allocation method) cannot be initialized with a non-constant (which first_node is).
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 1 line · Nishanth Aravamudan
nid is static to
alloc_fresh_huge_page().
Ahh did not see that. Can you not call simply into interleave() from mempolicy.c? It will get you the counter that you need.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 6 lines · Christoph Lameter
Quoted 1 line · Nishanth Aravamudan
nid is static to
alloc_fresh_huge_page().Ahh did not see that. Can you not call simply into
interleave()frommempolicy.c? It will get you the counter that you need.
You just told me that mempolicy.c is built conditionally on NUMA. alloc_fresh_huge_page() is not, it only depeonds on CONFIG_HUGETLB_PAGE!
The only interleave functions I see in mempolicy.c are:
interleave_nodes(), which takes a mempolicy, which I don't have in hugetlb.c
interleave_nid(), which also takes a mempolicy
I guess I could try and use huge_zonelist(), but I don't see the point?
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 5 lines · Nishanth Aravamudan
Quoted 2 lines
Ahh did not see that. Can you not call simply into
interleave()frommempolicy.c? It will get you the counter that you need.You just told me that
mempolicy.cis built conditionally on NUMA.alloc_fresh_huge_page()is not, it only depeonds onCONFIG_HUGETLB_PAGE!
Well you just need to have the appropriate fallbacks defined in mempolicy.h
Quoted 8 lines
The only interleave functions I see in
mempolicy.care:
interleave_nodes(), which takes a mempolicy, which I don't have inhugetlb.c
interleave_nid(), which also takes a mempolicyI guess I could try and use
huge_zonelist(), but I don't see the point?
Export a function for the interleave functionality so that we do not have to replicate the same thing in various locations in the kernel.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 10 lines · Christoph Lameter
Quoted 5 lines · Nishanth Aravamudan
Quoted 2 lines
Ahh did not see that. Can you not call simply into
interleave()frommempolicy.c? It will get you the counter that you need.You just told me that
mempolicy.cis built conditionally on NUMA.alloc_fresh_huge_page()is not, it only depeonds onCONFIG_HUGETLB_PAGE!Well you just need to have the appropriate fallbacks defined in
mempolicy.h
Ok, I understand that.
Quoted 11 lines
Quoted 8 lines
The only interleave functions I see in
mempolicy.care:
interleave_nodes(), which takes a mempolicy, which I don't have inhugetlb.c
interleave_nid(), which also takes a mempolicyI guess I could try and use
huge_zonelist(), but I don't see the point?Export a function for the interleave functionality so that we do not have to replicate the same thing in various locations in the kernel.
But I don't understand this at all.
This is *not* generically available, unless every caller has its own private static variable. I don't know how to do that in C.
You're asking me to complicate patches that work just fine right now. Well, excluding a hasty patch that I didn't compile-test. All I'm trying to do is ask for some guidance.
What we have here is:
alloc_fresh_huge_page() should return 1 after a successful allocation of a huge page on a different node, in a round-robin fashion, on every invocation; or 0, if no huge page could be allocated.
I don't see how to make that generic in a simple way. It relies on an interator that is private to the function, not to any structure. And this is really a one-time allocation right now (hugepages).
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 7 lines · Nishanth Aravamudan
Quoted 2 lines
Export a function for the interleave functionality so that we do not have to replicate the same thing in various locations in the kernel.
But I don't understand this at all.
This is *not* generically available, unless every caller has its own private static variable. I don't know how to do that in C.
It is already there. Each task has a il_next field in its task struct for that purpose.
Quoted 1 line
You're asking me to complicate patches that work just fine right now.
I am trying to simplify your work.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 5 lines · Christoph Lameter
Quoted 3 lines · Nishanth Aravamudan
Quoted 2 lines
Export a function for the interleave functionality so that we do not have to replicate the same thing in various locations in the kernel.
Quoted 7 lines
Quoted 4 lines
But I don't understand this at all.
This is *not* generically available, unless every caller has its own private static variable. I don't know how to do that in C.
It is already there. Each task has a
il_nextfield in its task struct for that purpose.
Hrm, maybe that will work -- but then it means that if one is interleaving huge pages, it will interfere with the interleaving of small pages. Given that right now, huge pages are a rather precious commodity, do we want this?
Quoted 3 lines
Quoted 1 line
You're asking me to complicate patches that work just fine right now.
I am trying to simplify your work.
Sorry, I wasn't trying to sound unappreciative. Your suggestions are very valuable!
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 4 lines · Nishanth Aravamudan
Hrm, maybe that will work -- but then it means that if one is interleaving huge pages, it will interfere with the interleaving of small pages. Given that right now, huge pages are a rather precious commodity, do we want this?
The number of pages interleaved for small pages is quite high. So there will not be a significant effect. If we use this counter then we can fall back on existing functionality in the memory policy subsystem.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
In reply to Christoph LameterQuoted 5 lines · Christoph Lameter
Quoted 3 lines · Nishanth Aravamudan
Quoted 2 lines
Export a function for the interleave functionality so that we do not have to replicate the same thing in various locations in the kernel.
Quoted 7 lines
Quoted 4 lines
But I don't understand this at all.
This is *not* generically available, unless every caller has its own private static variable. I don't know how to do that in C.
It is already there. Each task has a
il_nextfield in its task struct for that purpose.
Ok, I see that. And it represent the next node to use for an interleaved allocation. Makes sense to me, and I see how it's used in mempolicy.c to achieve that. But we're running at system boot time, or whenever some invokes the sysctl /proc/sys/vm/nr_hugepages. Do we really want to muck with some arbitray bash shell's il_next field to achieve interleaving? What if it's a C process that is trying to achieve actual interleaving for other purposes and also allocates some hugepages on the system? It seems like il_next is very much a process-related field.
When I wrote "caller", I meant calling function, sorry, not calling process.
I'm not entirely sure how il_next is useful here, sorry.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 3 lines · Nishanth Aravamudan
Ok, I see that. And it represent the next node to use for an interleaved allocation. Makes sense to me, and I see how it's used in
mempolicy.cto achieve that. But we're running at system boot time, or whenever some
At boot time the init_task is running and you can effectively use a global variable like you have now.
Quoted 5 lines
invokes the sysctl
/proc/sys/vm/nr_hugepages. Do we really want to muck with some arbitray bash shell'sil_nextfield to achieve interleaving? What if it's a C process that is trying to achieve actual interleaving for other purposes and also allocates some hugepages on the system? It seems likeil_nextis very much a process-related field.
il_next is process related. Mucking around is what is was put there for. The bash process wont be hurt by changing its il_next field.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
In reply to Christoph LameterQuoted 7 lines · Christoph Lameter
Quoted 3 lines · Nishanth Aravamudan
static int nid =
first_node(node_populated_map), I get:
mm/hugetlb.c:108: error: initializer element is not constantRemove the static.
Then every hugepage will be allocated on the first populated node!
The whole point of alloc_fresh_huge_page is that it round-robins hugepages allocations among all populated nodes. Or it will once we fix it :)
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
In reply to Nishanth AravamudanQuoted 4 lines · Christoph Lameter
Quoted 4 lines
nid == 1 means local node? Or why do we check for nid < 0?
if (nid == 1) nid = numa_node_id();?
Quoted 4 lines · Nishanth Aravamudan
No, nid is a static variable. So we initialize it to -1 to catch the first time we go through the loop.
IIRC, we can't just set it tofirst_node(node_populated_map), because it's a non-constant or something?
I wrote that, so I figure I should chime in. The static variable can be killed off outright.
Initially filling the pool doesn't need the static affair. Refilling the pool from the page allocator can refill the node with the least memory first, and choose randomly otherwise. Using default mpolicies or defaulting to node-local memory instead of round-robin allocation will likely do for callers into the allocator.
It depends a bit on what SGI's app that originally wanted striping of hugetlb does.
Also, if one has such a large number of nodes that exhaustive search for the node with the least memory would be prohibitive, esp. when in a loop, it's always possible to keep node ID's in an array heap-ordered by the number of pages in the node's segment of the pool. In such a manner the inner loop's search is limited to O(lg(nr_online_nodes())).
-- wli
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 2 lines · William Lee Irwin III
I wrote that, so I figure I should chime in. The static variable can be killed off outright.
I agree.
Quoted 5 lines
Initially filling the pool doesn't need the static affair. Refilling the pool from the page allocator can refill the node with the least memory first, and choose randomly otherwise. Using default mpolicies or defaulting to node-local memory instead of round-robin allocation will likely do for callers into the allocator.
Each task already has a next node field. Just use that.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 5 lines · William Lee Irwin III
Quoted 5 lines
Initially filling the pool doesn't need the static affair. Refilling the pool from the page allocator can refill the node with the least memory first, and choose randomly otherwise. Using default mpolicies or defaulting to node-local memory instead of round-robin allocation will likely do for callers into the allocator.
Quoted 1 line · Christoph Lameter
Each task already has a next node field. Just use that.
That's new. It sounds convenient.
-- wli
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 4 lines · William Lee Irwin III
Quoted 1 line · Christoph Lameter
Each task already has a next node field. Just use that.
That's new. It sounds convenient.
No its ancient.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 1 line · Christoph Lameter
Quoted 1 line
Quoted 1 line
Each task already has a next node field. Just use that.
Quoted 1 line · William Lee Irwin III
Quoted 1 line
That's new. It sounds convenient.
Quoted 1 line · Christoph Lameter
No its ancient.
Heh. It all depends on your view of time. One's point of view tends toward geologic when 2.4.9 (not a typo) is still current for a number of one's customers. Not to mention when one maintains code (or attempts to, however poorly) with open bugs where the last known working versions are in the 2.0.x and 2.2.x version spaces.
Shiny new code from 2005 can indeed be a breath of fresh air to some.
-- wli
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
In reply to William Lee Irwin IIIQuoted 24 lines · William Lee Irwin III
Quoted 4 lines · Christoph Lameter
Quoted 4 lines
nid == 1 means local node? Or why do we check for nid < 0?
if (nid == 1) nid = numa_node_id();?
Quoted 4 lines · Nishanth Aravamudan
No, nid is a static variable. So we initialize it to -1 to catch the first time we go through the loop.
IIRC, we can't just set it tofirst_node(node_populated_map), because it's a non-constant or something?I wrote that, so I figure I should chime in. The static variable can be killed off outright.
Initially filling the pool doesn't need the static affair. Refilling the pool from the page allocator can refill the node with the least memory first, and choose randomly otherwise. Using default mpolicies or defaulting to node-local memory instead of round-robin allocation will likely do for callers into the allocator.
It depends a bit on what SGI's app that originally wanted striping of hugetlb does.
Quoted 6 lines
Also, if one has such a large number of nodes that exhaustive search for the node with the least memory would be prohibitive, esp. when in a loop, it's always possible to keep node ID's in an array heap-ordered by the number of pages in the node's segment of the pool. In such a manner the inner loop's search is limited to O(lg(nr_online_nodes())).
Well, (presuming I understood everything you wrote :), don't we need the static 'affair' to guarantee the initial allocations are approximately round-robin? Or, if we aren't going to make that guarantee, than we should only change that once my sysfs allocator (or its equivalent) is available?
Just trying to get a handle on what you're suggesting without any historical context.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 7 lines · Nishanth Aravamudan
Well, (presuming I understood everything you wrote :), don't we need the static 'affair' to guarantee the initial allocations are approximately round-robin? Or, if we aren't going to make that guarantee, than we should only change that once my sysfs allocator (or its equivalent) is available?
Just trying to get a handle on what you're suggesting without any historical context.
For initially filling the pool one can just loop over nid's modulo the number of populated nodes and pass down a stack-allocated variable.
-- wli
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 11 lines · William Lee Irwin III
Quoted 7 lines · Nishanth Aravamudan
Well, (presuming I understood everything you wrote :), don't we need the static 'affair' to guarantee the initial allocations are approximately round-robin? Or, if we aren't going to make that guarantee, than we should only change that once my sysfs allocator (or its equivalent) is available?
Just trying to get a handle on what you're suggesting without any historical context.For initially filling the pool one can just loop over nid's modulo the number of populated nodes and pass down a stack-allocated variable.
Ok, I'll play with that a bit.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 4 lines · Nishanth Aravamudan
Quoted 2 lines
For initially filling the pool one can just loop over nid's modulo the number of populated nodes and pass down a stack-allocated variable.
Ok, I'll play with that a bit.
That would work too but then you need to write your own interleave function.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
In reply to William Lee Irwin IIIQuoted 11 lines · William Lee Irwin III
Quoted 7 lines · Nishanth Aravamudan
Well, (presuming I understood everything you wrote :), don't we need the static 'affair' to guarantee the initial allocations are approximately round-robin? Or, if we aren't going to make that guarantee, than we should only change that once my sysfs allocator (or its equivalent) is available?
Just trying to get a handle on what you're suggesting without any historical context.For initially filling the pool one can just loop over nid's modulo the number of populated nodes and pass down a stack-allocated variable.
But how does one differentiate between "initally filling" the pool and a later attempt to add to the pool (or even just marginally later).
I guess I don't see why folks are so against this static variable :) It does the job and removing it seems like it could be an independent cleanup?
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 2 lines · William Lee Irwin III
Quoted 2 lines
For initially filling the pool one can just loop over nid's modulo the number of populated nodes and pass down a stack-allocated variable.
Quoted 5 lines · Nishanth Aravamudan
But how does one differentiate between "initally filling" the pool and a later attempt to add to the pool (or even just marginally later). I guess I don't see why folks are so against this static variable :) It does the job and removing it seems like it could be an independent cleanup?
Well, another approach is to just statically initialize it to something and then always check to make sure the node for the nid has memory, and if not, find the next nid with a node with memory from the populated map.
-- wli
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v7 1/1 Fix hugetlb pool allocation with empty nodes
Quoted 11 lines · William Lee Irwin III
Quoted 2 lines · William Lee Irwin III
Quoted 2 lines
For initially filling the pool one can just loop over nid's modulo the number of populated nodes and pass down a stack-allocated variable.
Quoted 5 lines · Nishanth Aravamudan
But how does one differentiate between "initally filling" the pool and a later attempt to add to the pool (or even just marginally later). I guess I don't see why folks are so against this static variable :) It does the job and removing it seems like it could be an independent cleanup?
Quoted 3 lines
Well, another approach is to just statically initialize it to something and then always check to make sure the node for the nid has memory, and if not, find the next nid with a node with memory from the populated map.
How does something like this look? Or is it overkill?
[PATCH 2.6.22-rc4-mm2] Fix hugetlb pool allocation with empty nodes V7
Anton found a problem with the hugetlb pool allocation when some nodes have no memory (http://marc.info/?l=linux-mm&m=118133042025995&w=2). Lee worked on versions that tried to fix it, but none were accepted. Christoph has created a set of patches which allow for GFP_THISNODE allocations to fail if the node has no memory and for exporting a node_memory_map indicating which nodes have memory. Since mempolicy.c already has a number of functions which support interleaving, create a mempolicy when we invoke alloc_fresh_huge_page() that specifies interleaving across all the nodes in node_memory_map, rather than custom interleaving code in hugetlb.c. This requires adding some dummy functions, and some declarations, in mempolicy.h to compile with NUMA or !NUMA.
include/linux/mempolicy.h +14 -0
@@ -76,6 +76,8 @@ struct mempolicy {* The default fast path of a NULL MPOL_DEFAULT policy is always inlined. */ +extern struct mempolicy *mpol_new (int mode,nodemask_t *nodes); +extern void __mpol_free (struct mempolicy *pol);static inline void mpol_free (struct mempolicy *pol) {
@@ -164,6 +166,8 @@ static inline void check_highest_zone(enum zone_type k) policy_zone = k; } +extern unsigned interleave_nodes (struct mempolicy *policy); +int do_migrate_pages (struct mm_struct *mm,const nodemask_t *from_nodes,const nodemask_t *to_nodes,int flags);
@@ -179,6 +183,11 @@ static inline int mpol_equal(struct mempolicy *a, struct mempolicy *b)#define mpol_set_vma_default (vma) do {} while(0) +static inline struct mempolicy *mpol_new (int mode,nodemask_t *nodes) +{ +return NULL ; +} +static inline void mpol_free (struct mempolicy *p) { }
@@ -267,6 +276,11 @@ static inline int do_migrate_pages(struct mm_struct *mm,static inline void check_highest_zone (int k) { } + +static inline unsigned interleave_nodes (struct mempolicy *policy) +{ +return 0 ; +}#endif /* CONFIG_NUMA */ #endif /* __KERNEL__ */
mm/hugetlb.c +27 -10
@@ -103,15 +103,20 @@ static void free_huge_page(struct page *page)spin_unlock (&hugetlb_lock); } -static int alloc_fresh_huge_page (void ) +static int alloc_fresh_huge_page (struct mempolicy *policy) { -static int nid =0 ; +int nid;struct page *page; - page =alloc_pages_node (nid, htlb_alloc_mask|__GFP_COMP|__GFP_NOWARN, -HUGETLB_PAGE_ORDER ); - nid =next_node (nid, node_online_map); -if (nid ==MAX_NUMNODES ) - nid =first_node (node_online_map); +int start_nid =interleave_nodes (policy); + + nid = start_nid; + +do { + page =alloc_pages_node (nid, + htlb_alloc_mask|__GFP_COMP|GFP_THISNODE , +HUGETLB_PAGE_ORDER ); + nid =interleave_nodes (policy); + }while (!page && nid != start_nid);if (page) {set_compound_page_dtor (page, free_huge_page);spin_lock (&hugetlb_lock);
@@ -153,6 +158,7 @@ fail:static int __init hugetlb_init (void ) {unsigned long i; +struct mempolicy *pol;if (HPAGE_SHIFT ==0 )return 0 ;
@@ -160,11 +166,16 @@ static int __init hugetlb_init(void)for (i =0 ; i <MAX_NUMNODES ; ++i)INIT_LIST_HEAD (&hugepage_freelists[i]); + pol =mpol_new (MPOL_INTERLEAVE , &node_memory_map); +if (IS_ERR (pol)) + goto quit;for (i =0 ; i < max_huge_pages; ++i) { -if (!alloc_fresh_huge_page ()) +if (!alloc_fresh_huge_page (pol))break ; } +mpol_free (pol); max_huge_pages = free_huge_pages = nr_huge_pages = i; +quit:printk ("Total HugeTLB memory allocated, %ld\n" , free_huge_pages);return 0 ; }
@@ -232,10 +243,16 @@ static inline void try_to_free_low(unsigned long count)static unsigned long set_max_huge_pages (unsigned long count) { +struct mempolicy *pol; + + pol =mpol_new (MPOL_INTERLEAVE , &node_memory_map); +if (IS_ERR (pol)) +return nr_huge_pages;while (count > nr_huge_pages) { -if (!alloc_fresh_huge_page ()) -return nr_huge_pages; +if (!alloc_fresh_huge_page (pol)) +break ; } +mpol_free (pol);if (count >= nr_huge_pages)return nr_huge_pages;
mm/mempolicy.c +2 -2
@@ -171,7 +171,7 @@ static struct zonelist *bind_zonelist(nodemask_t *nodes) }/* Create a new policy */ -static struct mempolicy *mpol_new (int mode,nodemask_t *nodes) +struct mempolicy *mpol_new (int mode,nodemask_t *nodes) {struct mempolicy *policy;
@@ -1121,7 +1121,7 @@ static struct zonelist *zonelist_policy(gfp_t gfp, struct mempolicy *policy) }/* Do dynamic interleaving for a process */ -static unsigned interleave_nodes (struct mempolicy *policy) +unsigned interleave_nodes (struct mempolicy *policy) {unsigned nid, next;struct task_struct *me = current;
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v3 1/1 hugetlb: numafy several functions
Quoted 12 lines · Nishanth Aravamudan
Quoted 11 lines · William Lee Irwin III
Quoted 2 lines · William Lee Irwin III
Quoted 2 lines
For initially filling the pool one can just loop over nid's modulo the number of populated nodes and pass down a stack-allocated variable.
Quoted 5 lines · Nishanth Aravamudan
But how does one differentiate between "initally filling" the pool and a later attempt to add to the pool (or even just marginally later). I guess I don't see why folks are so against this static variable :) It does the job and removing it seems like it could be an independent cleanup?
Quoted 5 lines
Quoted 3 lines
Well, another approach is to just statically initialize it to something and then always check to make sure the node for the nid has memory, and if not, find the next nid with a node with memory from the populated map.
How does something like this look? Or is it overkill?
If that patch looks ok, then the other patches (numafy and sysfs) are relatively unchanged.
commit 041cb3d3c2fd3640aff50e2f701b8b5a670193de
Author: Nishanth Aravamudan <[email protected]> Date: Tue Jun 12 17:10:21 2007 -0700
hugetlb: numafy several functions
Add node-parameterized helpers for dequeue_huge_page, alloc_fresh_huge_page and try_to_free_low. Also have update_and_free_page() take a nid parameter. This is necessary to add a per-node sysfs attribute to specify the number of hugepages on that node.
mm/hugetlb.c +63 -34
@@ -66,11 +66,22 @@ static void enqueue_huge_page(struct page *page) free_huge_pages_node[nid]++; } +static struct page *dequeue_huge_page_node (int nid) +{ +struct page *page; + + page =list_entry (hugepage_freelists[nid].next, + struct page, lru); +list_del (&page->lru); + free_huge_pages--; + free_huge_pages_node[nid]--; +return page; +} +static struct page *dequeue_huge_page (struct vm_area_struct *vma,unsigned long address) {int nid; -struct page *page =NULL ;struct zonelist *zonelist =huge_zonelist (vma, address, htlb_alloc_mask);struct zone **z;
@@ -82,14 +93,9 @@ static struct page *dequeue_huge_page(struct vm_area_struct *vma,break ; } -if (*z) { - page =list_entry (hugepage_freelists[nid].next, - struct page, lru); -list_del (&page->lru); - free_huge_pages--; - free_huge_pages_node[nid]--; - } -return page; +if (*z) +return dequeue_huge_page_node (nid); +return NULL ; }static void free_huge_page (struct page *page)
@@ -103,6 +109,25 @@ static void free_huge_page(struct page *page)spin_unlock (&hugetlb_lock); } +static struct page *alloc_fresh_huge_page_node (int nid) +{ +struct page *page; + + page =alloc_pages_node (nid, +GFP_HIGHUSER |__GFP_COMP|GFP_THISNODE , +HUGETLB_PAGE_ORDER ); +if (page) { +set_compound_page_dtor (page, free_huge_page); +spin_lock (&hugetlb_lock); + nr_huge_pages++; + nr_huge_pages_node[nid]++; +spin_unlock (&hugetlb_lock); +put_page (page);/* free it into the hugepage allocator */ + } + +return page; +} +static int alloc_fresh_huge_page (struct mempolicy *policy) {int nid;
@@ -112,20 +137,12 @@ static int alloc_fresh_huge_page(struct mempolicy *policy) nid = start_nid;do { - page =alloc_pages_node (nid, - htlb_alloc_mask|__GFP_COMP|GFP_THISNODE , -HUGETLB_PAGE_ORDER ); + page =alloc_fresh_huge_page_node (nid); nid =interleave_nodes (policy); }while (!page && nid != start_nid); -if (page) { -set_compound_page_dtor (page, free_huge_page); -spin_lock (&hugetlb_lock); - nr_huge_pages++; - nr_huge_pages_node[page_to_nid (page)]++; -spin_unlock (&hugetlb_lock); -put_page (page);/* free it into the hugepage allocator */ + +if (page)return 1 ; - }return 0 ; }
@@ -201,11 +218,11 @@ static unsigned int cpuset_mems_nr(unsigned int *array) }#ifdef CONFIG_SYSCTL -static void update_and_free_page (struct page *page) +static void update_and_free_page (int nid,struct page *page) {int i; nr_huge_pages--; - nr_huge_pages_node[page_to_nid (page)]--; + nr_huge_pages_node[nid]--;for (i =0 ; i < (HPAGE_SIZE /PAGE_SIZE ); i++) { page[i].flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced | 1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |
@@ -217,25 +234,37 @@ static void update_and_free_page(struct page *page) }#ifdef CONFIG_HIGHMEM +static void try_to_free_low_node (int nid,unsigned long count) +{ +struct page *page, *next; + +list_for_each_entry_safe (page, next, + &hugepage_freelists[nid], lru) { +if (PageHighMem (page)) +continue ; +list_del (&page->lru); +update_and_free_page (nid, page); + free_huge_pages--; + free_huge_pages_node[nid]--; +if (count >= nr_huge_pages_node[nid]) +return ; + } +} +static void try_to_free_low (unsigned long count) {int i;for (i =0 ; i <MAX_NUMNODES ; ++i) { -struct page *page, *next; -list_for_each_entry_safe (page, next, &hugepage_freelists[i], lru) { -if (PageHighMem (page)) -continue ; -list_del (&page->lru); -update_and_free_page (page); - free_huge_pages--; - free_huge_pages_node[page_to_nid (page)]--; -if (count >= nr_huge_pages) -return ; - } +try_to_free_low_node (i, count); +if (count >= nr_huge_pages) +break ; } }#else +static inline void try_to_free_low_node (int nid,unsigned long count) +{ +}static inline void try_to_free_low (unsigned long count) { }
@@ -263,7 +292,7 @@ static unsigned long set_max_huge_pages(unsigned long count)struct page *page =dequeue_huge_page (NULL ,0 );if (!page)break ; -update_and_free_page (page); +update_and_free_page (page_to_nid (page), page); }spin_unlock (&hugetlb_lock);return nr_huge_pages;
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v3 1/1 hugetlb: add per-node nr_hugepages sysfs attribute
Quoted 13 lines · Nishanth Aravamudan
Quoted 12 lines · Nishanth Aravamudan
Quoted 11 lines · William Lee Irwin III
Quoted 2 lines · William Lee Irwin III
Quoted 2 lines
For initially filling the pool one can just loop over nid's modulo the number of populated nodes and pass down a stack-allocated variable.
Quoted 5 lines · Nishanth Aravamudan
But how does one differentiate between "initally filling" the pool and a later attempt to add to the pool (or even just marginally later). I guess I don't see why folks are so against this static variable :) It does the job and removing it seems like it could be an independent cleanup?
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
Well, another approach is to just statically initialize it to something and then always check to make sure the node for the nid has memory, and if not, find the next nid with a node with memory from the populated map.
How does something like this look? Or is it overkill?
If that patch looks ok, then the other patches (numafy and sysfs) are relatively unchanged.
commit 05a7edb8c909c674cdefb0323348825cf3e2d1d0
Author: Nishanth Aravamudan <[email protected]> Date: Thu Jun 7 08:54:48 2007 -0700
hugetlb: add per-node nr_hugepages sysfs attribute
Allow specifying the number of hugepages to allocate on a particular node. Our current global sysctl will try its best to put hugepages equally on each node, but htat may not always be desired. This allows the admin to control the layout of hugepage allocation at a finer level (while not breaking the existing interface). Add callbacks in the sysfs node registration and unregistration functions into hugetlb to add the nr_hugepages attribute, which is a no-op if !NUMA or !HUGETLB.
---
Do the dummy function definitions need to be (void)0?
drivers/base/node.c +4 -0
@@ -131,6 +131,8 @@ static ssize_t node_read_distance(struct sys_device * dev, char * buf) } static SYSDEV_ATTR(distance, S_IRUGO, node_read_distance, NULL); +#ifdef CONFIG_HUGETLB_PAGE +#endif /* * register_node - Setup a sysfs device for a node.
@@ -151,6 +153,7 @@ int register_node(struct node *node, int num, struct node *parent)sysdev_create_file (&node->sysdev, &attr_meminfo);sysdev_create_file (&node->sysdev, &attr_numastat);sysdev_create_file (&node->sysdev, &attr_distance); +hugetlb_register_node (node); }return error; }
@@ -168,6 +171,7 @@ void unregister_node(struct node *node)sysdev_remove_file (&node->sysdev, &attr_meminfo);sysdev_remove_file (&node->sysdev, &attr_numastat);sysdev_remove_file (&node->sysdev, &attr_distance); +hugetlb_unregister_node (node);sysdev_unregister (&node->sysdev); }
include/linux/hugetlb.h +8 -0
@@ -5,6 +5,7 @@#include <linux/mempolicy.h> #include <linux/shm.h> +#include <linux/sysdev.h> #include <asm/tlbflush.h> struct ctl_table ;
@@ -23,6 +24,11 @@ void __unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned lonint hugetlb_prefault (struct address_space *,struct vm_area_struct *);int hugetlb_report_meminfo (char *);int hugetlb_report_node_meminfo (int ,char *); +int hugetlb_register_node (struct sys_device *); +void hugetlb_unregister_node (struct sys_device *); +ssize_t hugetlb_read_nr_hugepages_node (struct sys_device *,char *); +ssize_t hugetlb_write_nr_hugepages_node (struct sys_device *,const char *, +size_t );unsigned long hugetlb_total_pages (void );int hugetlb_fault (struct mm_struct *mm,struct vm_area_struct *vma,unsigned long address,int write_access);
@@ -114,6 +120,8 @@ static inline unsigned long hugetlb_total_pages(void)#define unmap_hugepage_range (vma, start, end) BUG()#define hugetlb_report_meminfo (buf) 0#define hugetlb_report_node_meminfo (n, buf) 0 +#define hugetlb_register_node (node) 0 +#define hugetlb_unregister_node (node) 0#define follow_huge_pmd (mm, addr, pmd, write) NULL#define prepare_hugepage_range (addr,len,pgoff) (-EINVAL)#define pmd_huge (x) 0
mm/hugetlb.c +62 -1
87 lines not on this page · raw message
Quoted 192 lines
commit
041cb3d3c2fd3640aff50e2f701b8b5a670193deAuthor: Nishanth Aravamudan <[email protected]> Date: Tue Jun 12 17:10:21 2007 -0700hugetlb: numafy several functions
Add node-parameterized helpers for
dequeue_huge_page,alloc_fresh_huge_pageandtry_to_free_low. Also haveupdate_and_free_page()take a nid parameter. This is necessary to add a per-node sysfs attribute to specify the number of hugepages on that node.Signed-off-by Nishanth Aravamudan <[email protected]>Cc William Lee Irwin III <[email protected]>Cc Christoph Lameter <[email protected]>Cc Lee Schermerhorn <[email protected]>Cc Anton Blanchard <[email protected]>Cc Andrew Morton <[email protected]>mm/hugetlb.c +63
-34@@ -66,11 +66,22 @@ static void enqueue_huge_page(struct page *page) free_huge_pages_node[nid]++; } +static struct page *dequeue_huge_page_node (int nid) +{ +struct page *page; + + page =list_entry (hugepage_freelists[nid].next, + struct page, lru); +list_del (&page->lru); + free_huge_pages--; + free_huge_pages_node[nid]--; +return page; +} +static struct page *dequeue_huge_page (struct vm_area_struct *vma,unsigned long address) {int nid; -struct page *page =NULL ;struct zonelist *zonelist =huge_zonelist (vma, address, htlb_alloc_mask);struct zone **z;@@ -82,14 +93,9 @@ static struct page *dequeue_huge_page(struct vm_area_struct *vma,break ; } -if (*z) { - page =list_entry (hugepage_freelists[nid].next, - struct page, lru); -list_del (&page->lru); - free_huge_pages--; - free_huge_pages_node[nid]--; - } -return page; +if (*z) +return dequeue_huge_page_node (nid); +return NULL ; }static void free_huge_page (struct page *page)@@ -103,6 +109,25 @@ static void free_huge_page(struct page *page)spin_unlock (&hugetlb_lock); } +static struct page *alloc_fresh_huge_page_node (int nid) +{ +struct page *page; + + page =alloc_pages_node (nid, +GFP_HIGHUSER |__GFP_COMP|GFP_THISNODE , +HUGETLB_PAGE_ORDER ); +if (page) { +set_compound_page_dtor (page, free_huge_page); +spin_lock (&hugetlb_lock); + nr_huge_pages++; + nr_huge_pages_node[nid]++; +spin_unlock (&hugetlb_lock); +put_page (page);/* free it into the hugepage allocator */ + } + +return page; +} +static int alloc_fresh_huge_page (struct mempolicy *policy) {int nid;@@ -112,20 +137,12 @@ static int alloc_fresh_huge_page(struct mempolicy *policy) nid = start_nid;do { - page =alloc_pages_node (nid, - htlb_alloc_mask|__GFP_COMP|GFP_THISNODE , -HUGETLB_PAGE_ORDER ); + page =alloc_fresh_huge_page_node (nid); nid =interleave_nodes (policy); }while (!page && nid != start_nid); -if (page) { -set_compound_page_dtor (page, free_huge_page); -spin_lock (&hugetlb_lock); - nr_huge_pages++; - nr_huge_pages_node[page_to_nid (page)]++; -spin_unlock (&hugetlb_lock); -put_page (page);/* free it into the hugepage allocator */ + +if (page)return 1 ; - }return 0 ; }@@ -201,11 +218,11 @@ static unsigned int cpuset_mems_nr(unsigned int *array) }#ifdef CONFIG_SYSCTL -static void update_and_free_page (struct page *page) +static void update_and_free_page (int nid,struct page *page) {int i; nr_huge_pages--; - nr_huge_pages_node[page_to_nid (page)]--; + nr_huge_pages_node[nid]--;for (i =0 ; i < (HPAGE_SIZE /PAGE_SIZE ); i++) { page[i].flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced | 1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |@@ -217,25 +234,37 @@ static void update_and_free_page(struct page *page) }#ifdef CONFIG_HIGHMEM +static void try_to_free_low_node (int nid,unsigned long count) +{ +struct page *page, *next; + +list_for_each_entry_safe (page, next, + &hugepage_freelists[nid], lru) { +if (PageHighMem (page)) +continue ; +list_del (&page->lru); +update_and_free_page (nid, page); + free_huge_pages--; + free_huge_pages_node[nid]--; +if (count >= nr_huge_pages_node[nid]) +return ; + } +} +static void try_to_free_low (unsigned long count) {int i;for (i =0 ; i <MAX_NUMNODES ; ++i) { -struct page *page, *next; -list_for_each_entry_safe (page, next, &hugepage_freelists[i], lru) { -if (PageHighMem (page)) -continue ; -list_del (&page->lru); -update_and_free_page (page); - free_huge_pages--; - free_huge_pages_node[page_to_nid (page)]--; -if (count >= nr_huge_pages) -return ; - } +try_to_free_low_node (i, count); +if (count >= nr_huge_pages) +break ; } }#else +static inline void try_to_free_low_node (int nid,unsigned long count) +{ +}static inline void try_to_free_low (unsigned long count) { }@@ -263,7 +292,7 @@ static unsigned long set_max_huge_pages(unsigned long count)struct page *page =dequeue_huge_page (NULL ,0 );if (!page)break ; -update_and_free_page (page); +update_and_free_page (page_to_nid (page), page); }spin_unlock (&hugetlb_lock);return nr_huge_pages;Signature · 3 lines
-- Nishanth Aravamudan <[email protected]> IBM Linux Technology Center
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v3][RFC] hugetlb: add per-node nr_hugepages sysfs attribute
On Wed, 2007-06-13 at 08:28 -0700, Nishanth Aravamudan wrote:
<snip>
Quoted 25 lines
commit
05a7edb8c909c674cdefb0323348825cf3e2d1d0Author: Nishanth Aravamudan <[email protected]> Date: Thu Jun 7 08:54:48 2007 -0700hugetlb: add per-node
nr_hugepagessysfs attributeAllow specifying the number of hugepages to allocate on a particular node. Our current global sysctl will try its best to put hugepages equally on each node, but htat may not always be desired. This allows the admin to control the layout of hugepage allocation at a finer level (while not breaking the existing interface). Add callbacks in the sysfs node registration and unregistration functions into hugetlb to add the
nr_hugepagesattribute, which is a no-op if !NUMA or !HUGETLB.Signed-off-by Nishanth Aravamudan <[email protected]>Cc William Lee Irwin III <[email protected]>Cc Christoph Lameter <[email protected]>Cc Lee Schermerhorn <[email protected]>Cc Anton Blanchard <[email protected]>Cc Andrew Morton <[email protected]>---
Do the dummy function definitions need to be (void)0?
<snip>
Quoted 13 lines
include/linux/hugetlb.h +1
-0@@ -5,6 +5,7 @@#include <linux/mempolicy.h> #include <linux/shm.h> +#include <linux/sysdev.h> #include <asm/tlbflush.h> struct ctl_table ;
include/linux/hugetlb.h void __unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned lon · line 28
Quoted 5 lines
include/linux/hugetlb.h +2
-0@@ -23,6 +24,11 @@ void __unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned lonint hugetlb_prefault (struct address_space *,struct vm_area_struct *);int hugetlb_report_meminfo (char *);int hugetlb_report_node_meminfo (int ,char *); +int hugetlb_register_node (struct sys_device *); +void hugetlb_unregister_node (struct sys_device *);
The parameter type for the two functions above need to be "struct node". You'll need to include <linux/node.h> after <linux/sysdev.h>, as well. Otherwise, doesn't build.
<snip>
Still testing...
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v4 1/1 hugetlb: add per-node nr_hugepages sysfs attribute
Quoted 41 lines · Lee Schermerhorn
On Wed, 2007-06-13 at 08:28 -0700, Nishanth Aravamudan wrote:
<snip>Quoted 25 lines
commit
05a7edb8c909c674cdefb0323348825cf3e2d1d0Author: Nishanth Aravamudan <[email protected]> Date: Thu Jun 7 08:54:48 2007 -0700hugetlb: add per-node
nr_hugepagessysfs attributeAllow specifying the number of hugepages to allocate on a particular node. Our current global sysctl will try its best to put hugepages equally on each node, but htat may not always be desired. This allows the admin to control the layout of hugepage allocation at a finer level (while not breaking the existing interface). Add callbacks in the sysfs node registration and unregistration functions into hugetlb to add the
nr_hugepagesattribute, which is a no-op if !NUMA or !HUGETLB.Signed-off-by Nishanth Aravamudan <[email protected]>Cc William Lee Irwin III <[email protected]>Cc Christoph Lameter <[email protected]>Cc Lee Schermerhorn <[email protected]>Cc Anton Blanchard <[email protected]>Cc Andrew Morton <[email protected]>---
Do the dummy function definitions need to be (void)0?<snip>
Quoted 11 lines
include/linux/hugetlb.h +1
-0@@ -5,6 +5,7 @@#include <linux/mempolicy.h> #include <linux/shm.h> +#include <linux/sysdev.h> #include <asm/tlbflush.h>
Quoted 11 lines
include/linux/hugetlb.h void __unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned lon · line 28
Quoted 7 lines
include/linux/hugetlb.h +2
-0struct ctl_table ;@@ -23,6 +24,11 @@ void __unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned lonint hugetlb_prefault (struct address_space *,struct vm_area_struct *);int hugetlb_report_meminfo (char *);int hugetlb_report_node_meminfo (int ,char *); +int hugetlb_register_node (struct sys_device *); +void hugetlb_unregister_node (struct sys_device *);The parameter type for the two functions above need to be "struct node". You'll need to include <
linux/node.h> after <linux/sysdev.h>, as well. Otherwise, doesn't build.
Sigh... Actually a few fixes worth doing. Make stuff static, since it's now all in hugetlb.c and only compile if NUMA. And don't export the nr_hugepages functions any more via hugetlb.h, as they are now private.
Compile-tested with HUGETLB && NUMA, HUGETLB && !NUMA, !HUGETLB && NUMA, !HUGETLB && !NUMA.
Will throw it at the machines I ran the previous set on, to verify everything runs as expected, but for review:
hugetlb: add per-node nr_hugepages sysfs attribute
Allow specifying the number of hugepages to allocate on a particular node. Our current global sysctl will try its best to put hugepages equally on each node, but htat may not always be desired. This allows the admin to control the layout of hugepage allocation at a finer level (while not breaking the existing interface). Add callbacks in the sysfs node registration and unregistration functions into hugetlb to add the nr_hugepages attribute, which is a no-op if !NUMA or !HUGETLB.
drivers/base/node.c +2 -0
@@ -151,6 +151,7 @@ int register_node(struct node *node, int num, struct node *parent)sysdev_create_file (&node->sysdev, &attr_meminfo);sysdev_create_file (&node->sysdev, &attr_numastat);sysdev_create_file (&node->sysdev, &attr_distance); +hugetlb_register_node (node); }return error; }
@@ -168,6 +169,7 @@ void unregister_node(struct node *node)sysdev_remove_file (&node->sysdev, &attr_meminfo);sysdev_remove_file (&node->sysdev, &attr_numastat);sysdev_remove_file (&node->sysdev, &attr_distance); +hugetlb_unregister_node (node);sysdev_unregister (&node->sysdev); }
include/linux/hugetlb.h +11 -0
@@ -4,7 +4,9 @@#ifdef CONFIG_HUGETLB_PAGE #include <linux/mempolicy.h> +#include <linux/node.h> #include <linux/shm.h> +#include <linux/sysdev.h> #include <asm/tlbflush.h> struct ctl_table ;
@@ -23,6 +25,13 @@ void __unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned lonint hugetlb_prefault (struct address_space *,struct vm_area_struct *);int hugetlb_report_meminfo (char *);int hugetlb_report_node_meminfo (int ,char *); +#ifdef CONFIG_NUMA +int hugetlb_register_node (struct node *); +void hugetlb_unregister_node (struct node *); +#else +#define hugetlb_register_node (node) 0 +#define hugetlb_unregister_node (node) 0 +#endif unsigned long hugetlb_total_pages (void );int hugetlb_fault (struct mm_struct *mm,struct vm_area_struct *vma,unsigned long address,int write_access);
@@ -114,6 +123,8 @@ static inline unsigned long hugetlb_total_pages(void)#define unmap_hugepage_range (vma, start, end) BUG()#define hugetlb_report_meminfo (buf) 0#define hugetlb_report_node_meminfo (n, buf) 0 +#define hugetlb_register_node (node) 0 +#define hugetlb_unregister_node (node) 0#define follow_huge_pmd (mm, addr, pmd, write) NULL#define prepare_hugepage_range (addr,len,pgoff) (-EINVAL)#define pmd_huge (x) 0
mm/hugetlb.c +65 -1
90 lines not on this page · raw message
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v4][RFC] hugetlb: add per-node nr_hugepages sysfs attribute
Quoted 25 lines · Nishanth Aravamudan
Quoted 24 lines · Lee Schermerhorn
On Wed, 2007-06-13 at 08:28 -0700, Nishanth Aravamudan wrote:
<snip>Quoted 22 lines
commit
05a7edb8c909c674cdefb0323348825cf3e2d1d0Author: Nishanth Aravamudan <[email protected]> Date: Thu Jun 7 08:54:48 2007 -0700hugetlb: add per-node
nr_hugepagessysfs attributeAllow specifying the number of hugepages to allocate on a particular node. Our current global sysctl will try its best to put hugepages equally on each node, but htat may not always be desired. This allows the admin to control the layout of hugepage allocation at a finer level (while not breaking the existing interface). Add callbacks in the sysfs node registration and unregistration functions into hugetlb to add the
nr_hugepagesattribute, which is a no-op if !NUMA or !HUGETLB.Signed-off-by Nishanth Aravamudan <[email protected]>Cc William Lee Irwin III <[email protected]>Cc Christoph Lameter <[email protected]>Cc Lee Schermerhorn <[email protected]>Cc Anton Blanchard <[email protected]>Cc Andrew Morton <[email protected]>
Quoted 5 lines
Quoted 5 lines
Quoted 3 lines
---
Do the dummy function definitions need to be (void)0?<snip>
I tested hugepage allocation on my HP rx8620 platform [16 cpu ia64, 32GB in 4 "real" nodes and one pseudo-node containing only DMA memory]. As expected, I don't get a balanced distribution across the real nodes. Here's what I see:
# before allocating huge pages: root@gwydyr(root):cat /sys/devices/system/node/node*/meminfo | grep HugeP Node 0 HugePages_Total: 0 Node 0 HugePages_Free: 0 Node 1 HugePages_Total: 0 Node 1 HugePages_Free: 0 Node 2 HugePages_Total: 0 Node 2 HugePages_Free: 0 Node 3 HugePages_Total: 0 Node 3 HugePages_Free: 0 Node 4 HugePages_Total: 0 Node 4 HugePages_Free: 0
# Now allocate 64 256MB pages. Only nodes 0-3 have NORMAL memory. # Zone 4 contains ~512MB of DMA memory. Some has already been # used, so I doubt that even 1 256MB [aligned] huge page is available.
root@gwydyr(root):echo 64 >/proc/sys/vm/nr_hugepages root@gwydyr(root):cat /sys/devices/system/node/node*/meminfo | grep HugeP
Node 0 HugePages_Total: 13 <---??? Node 0 HugePages_Free: 26 <---??? Node 1 HugePages_Total: 12 Node 1 HugePages_Free: 12 Node 2 HugePages_Total: 13 Node 2 HugePages_Free: 13 Node 3 HugePages_Total: 13 Node 3 HugePages_Free: 13 Node 4 HugePages_Total: 13 <---??? Node 4 HugePages_Free: 0
# 13 of the pages say they're from Node 4, but I know that has only ~512MB or memory, of which some is already used. Unlikely that I can allocate even 1 256MB huge page because of alignment. Note that the free pages are accounted on Node 0, where they actually reside.
Here's some zoneinfo after the allocation above [forgot to snap it before].
# zoneinfo shell function contains:
# cat /proc/zoneinfo | egrep '^Node|^ pages |^ *present|^ *spanned'
# results after allocating huge pages
root@gwydyr(root):zoneinfo
Node 0, zone Normal
pages free 36157
spanned 486400
present 484738
Node 1, zone Normal
pages free 318034
spanned 520192
present 518413
Node 2, zone Normal
pages free 301526
spanned 520192
present 518414
Node 3, zone Normal
pages free 301932
spanned 520182
present 518362
Node 4, zone DMA
pages free 31706
spanned 32767
present 32656
^^^^^^^^^^^^^^^^^^^^^^ Nope! no huge pages allocated from here!# now try to free the huge pages.
root@gwydyr(root):echo 0 >/proc/sys/vm/nr_hugepages root@gwydyr(root):cat /sys/devices/system/node/node*/meminfo | grep HugeP
Node 0 HugePages_Total: 4294967283 <--- ??? Node 0 HugePages_Free: 0 Node 1 HugePages_Total: 0 Node 1 HugePages_Free: 0 Node 2 HugePages_Total: 0 Node 2 HugePages_Free: 0 Node 3 HugePages_Total: 0 Node 3 HugePages_Free: 0 Node 4 HugePages_Total: 13 <---??? they weren't really there to begin with! Node 4 HugePages_Free: 0
# Apparently on remove, the pages were decremented from node 0 instead of node 4 where they were accounted for on allocation, resulting in a negative count on node 0 and the original 13 count still on node 4.
------------------
I tried to "tighten up" alloc_pages_node() to check the location of the first zone in the selected zonelist, as discussed in previous exchange. When I do this, I hit a BUG() in slub.c in early_kmem_cache_node_alloc(), as it apparently can't handle new_slab() returning a NULL page, even tho' it calls it with GFP_THISNODE. Slub should be able to handle memoryless nodes, right? I'm looking for a work around to this now.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v4][RFC] hugetlb: add per-node nr_hugepages sysfs attribute
Quoted 30 lines · Lee Schermerhorn
Quoted 29 lines · Nishanth Aravamudan
Quoted 28 lines · Lee Schermerhorn
On Wed, 2007-06-13 at 08:28 -0700, Nishanth Aravamudan wrote:
<snip>Quoted 25 lines
commit
05a7edb8c909c674cdefb0323348825cf3e2d1d0Author: Nishanth Aravamudan <[email protected]> Date: Thu Jun 7 08:54:48 2007 -0700hugetlb: add per-node
nr_hugepagessysfs attributeAllow specifying the number of hugepages to allocate on a particular node. Our current global sysctl will try its best to put hugepages equally on each node, but htat may not always be desired. This allows the admin to control the layout of hugepage allocation at a finer level (while not breaking the existing interface). Add callbacks in the sysfs node registration and unregistration functions into hugetlb to add the
nr_hugepagesattribute, which is a no-op if !NUMA or !HUGETLB.Signed-off-by Nishanth Aravamudan <[email protected]>Cc William Lee Irwin III <[email protected]>Cc Christoph Lameter <[email protected]>Cc Lee Schermerhorn <[email protected]>Cc Anton Blanchard <[email protected]>Cc Andrew Morton <[email protected]>---
Do the dummy function definitions need to be (void)0?
Quoted 6 lines
Quoted 1 line
Quoted 1 line
<snip>
I tested hugepage allocation on my HP rx8620 platform [16 cpu ia64, 32GB in 4 "real" nodes and one pseudo-node containing only DMA memory]. As expected, I don't get a balanced distribution across the real nodes. Here's what I see:
Hrm, not good.
Can you try without any of my add-on patches, but just the original set from Christoph?
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v4][RFC] hugetlb: add per-node nr_hugepages sysfs attribute
Quoted 38 lines · Nishanth Aravamudan
Quoted 30 lines · Lee Schermerhorn
Quoted 29 lines · Nishanth Aravamudan
Quoted 28 lines · Lee Schermerhorn
On Wed, 2007-06-13 at 08:28 -0700, Nishanth Aravamudan wrote:
<snip>Quoted 25 lines
commit
05a7edb8c909c674cdefb0323348825cf3e2d1d0Author: Nishanth Aravamudan <[email protected]> Date: Thu Jun 7 08:54:48 2007 -0700hugetlb: add per-node
nr_hugepagessysfs attributeAllow specifying the number of hugepages to allocate on a particular node. Our current global sysctl will try its best to put hugepages equally on each node, but htat may not always be desired. This allows the admin to control the layout of hugepage allocation at a finer level (while not breaking the existing interface). Add callbacks in the sysfs node registration and unregistration functions into hugetlb to add the
nr_hugepagesattribute, which is a no-op if !NUMA or !HUGETLB.Signed-off-by Nishanth Aravamudan <[email protected]>Cc William Lee Irwin III <[email protected]>Cc Christoph Lameter <[email protected]>Cc Lee Schermerhorn <[email protected]>Cc Anton Blanchard <[email protected]>Cc Andrew Morton <[email protected]>---
Do the dummy function definitions need to be (void)0?Quoted 6 lines
Quoted 1 line
Quoted 1 line
<snip>
I tested hugepage allocation on my HP rx8620 platform [16 cpu ia64, 32GB in 4 "real" nodes and one pseudo-node containing only DMA memory]. As expected, I don't get a balanced distribution across the real nodes. Here's what I see:
Quoted 4 lines
Hrm, not good.
Can you try without any of my add-on patches, but just the original set from Christoph?
I can do that. However, I've tested with two patches: one to the "GFP_THISNODE" behavior in alloc_pages_node(), and one for interleaving in your "fix hugetlb pool allocation..." patch. With these 2 patches, hugetlb allocation appears to work on my platform, at least via the vm.nr_hugepages sysctl. Haven't tried your per node attribute yet, and I'm just rebooting to try the command line. I'll try out the x86_64 platform tomorrow.
I'll post the fixes in response to the respective patches from you and Christoph.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v4][RFC] hugetlb: add per-node nr_hugepages sysfs attribute
In reply to Lee SchermerhornQuoted 7 lines · On Wed, 13 Jun 2007 16:05:10 -0400 Lee Schermerhorn <[email protected]>…
I tried to "tighten up"
alloc_pages_node()to check the location of the first zone in the selected zonelist, as discussed in previous exchange. When I do this, I hit aBUG()inslub.cinearly_kmem_cache_node_alloc(), as it apparently can't handlenew_slab()returning a NULL page, even tho' it calls it withGFP_THISNODE. Slub should be able to handle memoryless nodes, right? I'm looking for a work around to this now.
The memoryless node patchset results in SLUB not attempting to allocate on memoryless nodes during bootstrap.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v4][RFC] hugetlb: add per-node nr_hugepages sysfs attribute
Quoted 11 lines · Christoph Lameter
Quoted 7 lines · On Wed, 13 Jun 2007 16:05:10 -0400 Lee Schermerhorn <[email protected]>…
I tried to "tighten up"
alloc_pages_node()to check the location of the first zone in the selected zonelist, as discussed in previous exchange. When I do this, I hit aBUG()inslub.cinearly_kmem_cache_node_alloc(), as it apparently can't handlenew_slab()returning a NULL page, even tho' it calls it withGFP_THISNODE. Slub should be able to handle memoryless nodes, right? I'm looking for a work around to this now.
Quoted 3 lines
The memoryless node patchset results in SLUB not attempting to allocate on memoryless nodes during bootstrap.
Christoph:
The message that you're responding to is from 13jun, before your memoryless nodes patch. We discussed it and have more or less resolved it. I was trying to ensure that GFP_THISNODE would fail on my funky interleaved node with just DMA memory, when you ask for a higher zone. I.e., no fallback. You disagreed with this, so I'm waiting for the memoryless nodes patches to get into -mm, so I can address the issue of hugepages [and regular interleaved pages] being allocated from a node where they shouldn't on my platform.
This has been discussed in the past week by Nish, Paul Mundt, and others in the -mm thread:
[hugetlb] Try to grow pool for MAP_SHARED mappings
I think we can handle the fundamental issue [even nodes with memory are not necessarily candidates for interleave, hugepages, ...] by adding another node_state[]. See the mentioned thread.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v7][RFC] Fix hugetlb pool allocation with empty nodes
In reply to Nishanth AravamudanQuoted 104 lines · Nishanth Aravamudan
Quoted 11 lines · William Lee Irwin III
Quoted 2 lines · William Lee Irwin III
Quoted 2 lines
For initially filling the pool one can just loop over nid's modulo the number of populated nodes and pass down a stack-allocated variable.
Quoted 5 lines · Nishanth Aravamudan
But how does one differentiate between "initally filling" the pool and a later attempt to add to the pool (or even just marginally later). I guess I don't see why folks are so against this static variable :) It does the job and removing it seems like it could be an independent cleanup?
Quoted 3 lines
Well, another approach is to just statically initialize it to something and then always check to make sure the node for the nid has memory, and if not, find the next nid with a node with memory from the populated map.
How does something like this look? Or is it overkill?
[PATCH 2.6.22-rc4-mm2] Fix hugetlb pool allocation with empty nodes V7
Anton found a problem with the hugetlb pool allocation when some nodes have no memory (http://marc.info/?l=linux-mm&m=118133042025995&w=2). Lee worked on versions that tried to fix it, but none were accepted. Christoph has created a set of patches which allow for
GFP_THISNODEallocations to fail if the node has no memory and for exporting anode_memory_mapindicating which nodes have memory. Sincemempolicy.calready has a number of functions which support interleaving, create a mempolicy when we invokealloc_fresh_huge_page()that specifies interleaving across all the nodes innode_memory_map, rather than custom interleaving code inhugetlb.c. This requires adding some dummy functions, and some declarations, inmempolicy.hto compile with NUMA or !NUMA.Signed-off-by Nishanth Aravamudan <[email protected]>Cc Anton Blanchard <[email protected]>Cc Lee Schermerhorn <[email protected]>Cc Christoph Lameter <[email protected]>Cc William Lee Irwin III <[email protected]>Cc Andrew Morton <[email protected]>include/linux/mempolicy.h +14
-0@@ -76,6 +76,8 @@ struct mempolicy {* The default fast path of a NULL MPOL_DEFAULT policy is always inlined. */ +extern struct mempolicy *mpol_new (int mode,nodemask_t *nodes); +extern void __mpol_free (struct mempolicy *pol);static inline void mpol_free (struct mempolicy *pol) {@@ -164,6 +166,8 @@ static inline void check_highest_zone(enum zone_type k) policy_zone = k; } +extern unsigned interleave_nodes (struct mempolicy *policy); +int do_migrate_pages (struct mm_struct *mm,const nodemask_t *from_nodes,const nodemask_t *to_nodes,int flags);@@ -179,6 +183,11 @@ static inline int mpol_equal(struct mempolicy *a, struct mempolicy *b)#define mpol_set_vma_default (vma) do {} while(0) +static inline struct mempolicy *mpol_new (int mode,nodemask_t *nodes) +{ +return NULL ; +} +static inline void mpol_free (struct mempolicy *p) { }@@ -267,6 +276,11 @@ static inline int do_migrate_pages(struct mm_struct *mm,static inline void check_highest_zone (int k) { } + +static inline unsigned interleave_nodes (struct mempolicy *policy) +{ +return 0 ; +}#endif /* CONFIG_NUMA */ #endif /* __KERNEL__ */ mm/hugetlb.c +2
-6@@ -103,15 +103,20 @@ static void free_huge_page(struct page *page)spin_unlock (&hugetlb_lock); } -static int alloc_fresh_huge_page (void ) +static int alloc_fresh_huge_page (struct mempolicy *policy) { -static int nid =0 ; +int nid;struct page *page; - page =alloc_pages_node (nid, htlb_alloc_mask|__GFP_COMP|__GFP_NOWARN, -HUGETLB_PAGE_ORDER ); - nid =next_node (nid, node_online_map); -if (nid ==MAX_NUMNODES )
mm/hugetlb.c static void free_huge_page(struct page *page) · line 118
Quoted 10 lines
mm/hugetlb.c +9
-1- nid =first_node (node_online_map); +int start_nid =interleave_nodes (policy); + + nid = start_nid; + + do { + page = alloc_pages_node(nid, + htlb_alloc_mask|__GFP_COMP|GFP_THISNODE, + HUGETLB_PAGE_ORDER); + nid = interleave_nodes(policy);
This needs to be:
if (!page) nid = interleave_nodes(policy);
Otherwise, you skip every other populated node, because you call interleave_nodes() at the top when you initialize start_nid. You only want to advance to the next node here if the allocation failed.
<snip>
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v7 1/1 Fix hugetlb pool allocation with empty nodes
Quoted 20 lines · Lee Schermerhorn
Quoted 19 lines · Nishanth Aravamudan
Quoted 11 lines · William Lee Irwin III
Quoted 2 lines · William Lee Irwin III
Quoted 2 lines
For initially filling the pool one can just loop over nid's modulo the number of populated nodes and pass down a stack-allocated variable.
Quoted 5 lines · Nishanth Aravamudan
But how does one differentiate between "initally filling" the pool and a later attempt to add to the pool (or even just marginally later). I guess I don't see why folks are so against this static variable :) It does the job and removing it seems like it could be an independent cleanup?
Quoted 3 lines
Well, another approach is to just statically initialize it to something and then always check to make sure the node for the nid has memory, and if not, find the next nid with a node with memory from the populated map.
How does something like this look? Or is it overkill?
[PATCH 2.6.22-rc4-mm2] Fix hugetlb pool allocation with empty nodes V7
<snip>
Quoted 8 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ do { + page = alloc_pages_node(nid, + htlb_alloc_mask|__GFP_COMP|GFP_THISNODE, + HUGETLB_PAGE_ORDER); + nid = interleave_nodes(policy);This needs to be:
Quoted 6 lines
if (!page) nid = interleave_nodes(policy);Otherwise, you skip every other populated node, because you call
interleave_nodes()at the top when you initializestart_nid. You only want to advance to the next node here if the allocation failed.
Nice catch, although I inverted it in my fix, so we're not checking page twice for NULL-ness. Updated patch follows.
[PATCH 2.6.22-rc4-mm2] Fix hugetlb pool allocation with empty nodes V7
Anton found a problem with the hugetlb pool allocation when some nodes have no memory (http://marc.info/?l=linux-mm&m=118133042025995&w=2). Lee worked on versions that tried to fix it, but none were accepted. Christoph has created a set of patches which allow for GFP_THISNODE allocations to fail if the node has no memory and for exporting a node_memory_map indicating which nodes have memory. Since mempolicy.c already has a number of functions which support interleaving, create a mempolicy when we invoke alloc_fresh_huge_page() that specifies interleaving across all the nodes in node_memory_map, rather than custom interleaving code in hugetlb.c. This requires adding some dummy functions, and some declarations, in mempolicy.h to compile with NUMA or !NUMA.
include/linux/mempolicy.h +14 -0
@@ -76,6 +76,8 @@ struct mempolicy {* The default fast path of a NULL MPOL_DEFAULT policy is always inlined. */ +extern struct mempolicy *mpol_new (int mode,nodemask_t *nodes); +extern void __mpol_free (struct mempolicy *pol);static inline void mpol_free (struct mempolicy *pol) {
@@ -164,6 +166,8 @@ static inline void check_highest_zone(enum zone_type k) policy_zone = k; } +extern unsigned interleave_nodes (struct mempolicy *policy); +int do_migrate_pages (struct mm_struct *mm,const nodemask_t *from_nodes,const nodemask_t *to_nodes,int flags);
@@ -179,6 +183,11 @@ static inline int mpol_equal(struct mempolicy *a, struct mempolicy *b)#define mpol_set_vma_default (vma) do {} while(0) +static inline struct mempolicy *mpol_new (int mode,nodemask_t *nodes) +{ +return NULL ; +} +static inline void mpol_free (struct mempolicy *p) { }
@@ -267,6 +276,11 @@ static inline int do_migrate_pages(struct mm_struct *mm,static inline void check_highest_zone (int k) { } + +static inline unsigned interleave_nodes (struct mempolicy *policy) +{ +return 0 ; +}#endif /* CONFIG_NUMA */ #endif /* __KERNEL__ */
mm/hugetlb.c +29 -10
@@ -103,15 +103,22 @@ static void free_huge_page(struct page *page)spin_unlock (&hugetlb_lock); } -static int alloc_fresh_huge_page (void ) +static int alloc_fresh_huge_page (struct mempolicy *policy) { -static int nid =0 ; +int nid;struct page *page; - page =alloc_pages_node (nid, htlb_alloc_mask|__GFP_COMP|__GFP_NOWARN, -HUGETLB_PAGE_ORDER ); - nid =next_node (nid, node_online_map); -if (nid ==MAX_NUMNODES ) - nid =first_node (node_online_map); +int start_nid =interleave_nodes (policy); + + nid = start_nid; + +do { + page =alloc_pages_node (nid, + htlb_alloc_mask|__GFP_COMP|GFP_THISNODE , +HUGETLB_PAGE_ORDER ); +if (page) +break ; + nid =interleave_nodes (policy); + }while (nid != start_nid);if (page) {set_compound_page_dtor (page, free_huge_page);spin_lock (&hugetlb_lock);
@@ -153,6 +160,7 @@ fail:static int __init hugetlb_init (void ) {unsigned long i; +struct mempolicy *pol;if (HPAGE_SHIFT ==0 )return 0 ;
@@ -160,11 +168,16 @@ static int __init hugetlb_init(void)for (i =0 ; i <MAX_NUMNODES ; ++i)INIT_LIST_HEAD (&hugepage_freelists[i]); + pol =mpol_new (MPOL_INTERLEAVE , &node_memory_map); +if (IS_ERR (pol)) + goto quit;for (i =0 ; i < max_huge_pages; ++i) { -if (!alloc_fresh_huge_page ()) +if (!alloc_fresh_huge_page (pol))break ; } +mpol_free (pol); max_huge_pages = free_huge_pages = nr_huge_pages = i; +quit:printk ("Total HugeTLB memory allocated, %ld\n" , free_huge_pages);return 0 ; }
@@ -232,10 +245,16 @@ static inline void try_to_free_low(unsigned long count)static unsigned long set_max_huge_pages (unsigned long count) { +struct mempolicy *pol; + + pol =mpol_new (MPOL_INTERLEAVE , &node_memory_map); +if (IS_ERR (pol)) +return nr_huge_pages;while (count > nr_huge_pages) { -if (!alloc_fresh_huge_page ()) -return nr_huge_pages; +if (!alloc_fresh_huge_page (pol)) +break ; } +mpol_free (pol);if (count >= nr_huge_pages)return nr_huge_pages;
mm/mempolicy.c +2 -2
@@ -171,7 +171,7 @@ static struct zonelist *bind_zonelist(nodemask_t *nodes) }/* Create a new policy */ -static struct mempolicy *mpol_new (int mode,nodemask_t *nodes) +struct mempolicy *mpol_new (int mode,nodemask_t *nodes) {struct mempolicy *policy;
@@ -1121,7 +1121,7 @@ static struct zonelist *zonelist_policy(gfp_t gfp, struct mempolicy *policy) }/* Do dynamic interleaving for a process */ -static unsigned interleave_nodes (struct mempolicy *policy) +unsigned interleave_nodes (struct mempolicy *policy) {unsigned nid, next;struct task_struct *me = current;
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
In reply to Christoph LameterQuoted 9 lines · Christoph Lameter
Review
Quoted 2 lines · Nishanth Aravamudan
(quoted diff) +2
-0+ if (nid < 0) + nid = first_node(node_populated_map);nid == 1 means local node? Or why do we check for nid < 0?
if (nid == 1) nid = numa_node_id();
That's not what it's doing. alloc_fresh_huge_page() is an incremental allocator. Keeps track of where it left off using a static variable. Because I changed it to scan a node map [the populated map], I needed to fetch the "first_node()" the first time it's called. Thus the initial value of -1. Thereafter, alloc_fresh_huge_page() just cycles around the populated map.
Quoted 13 lines
?
mm/hugetlb.c static void free_huge_page(struct page *page) · line 123
Quoted 8 lines
mm/hugetlb.c +8
-0+do { + page =alloc_pages_node (nid, +GFP_HIGHUSER |__GFP_COMP|GFP_THISNODE , +HUGETLB_PAGE_ORDER ); + nid =next_node (nid, node_populated_map); +if (nid >= nr_node_ids) + nid =first_node (node_populated_map); + }while (!page && nid != start_nid);Looks good.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH][RFC] Fix INTERLEAVE with memoryless nodes
In reply to Nishanth AravamudanQuoted 3 lines · Nishanth Aravamudan
Christoph was also worried about the performance impact on these paths, so, as he suggested, uninline
alloc_pages_node()and move it tomempolicy.c.
uninlining does not address performance issues.
Quoted 4 lines
mm/mempolicy.c +0
-0@@ -184,6 +185,16 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes)atomic_set (&policy->refcnt,1 );switch (mode) {case MPOL_INTERLEAVE :
mm/mempolicy.c static struct mempolicy *mpol_new(int mode, nodemask_t *nodes) · line 197
Quoted 10 lines
mm/mempolicy.c +10
-0+/* +* Clear any memoryless nodes here so that v.nodes can be used +* without extra checks +*/ + nid =first_node (*nodes); +while (nid <MAX_NUMNODES ) { +if (!node_populated (nid)) +node_clear (nid, *nodes); + nid =next_node (nid, *nodes); + }
There is a "nodes_and" function for this.
mm/mempolicy.c static unsigned interleave_nodes(struct mempolicy *policy) · line 1160
Quoted 12 lines
mm/mempolicy.c +5
-3@@ -1126,9 +1153,11 @@ static unsigned interleave_nodes(struct mempolicy *policy)struct task_struct *me = current; nid = me->il_next; - next =next_node (nid, policy->v.nodes); -if (next >=MAX_NUMNODES ) - next =first_node (policy->v.nodes); +do { + next =next_node (nid, policy->v.nodes); +if (next >=MAX_NUMNODES ) + next =first_node (policy->v.nodes); + }while (!node_populated (next));
Is there a case where nodes has no node set?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC PATCH v2 1/1 Fix INTERLEAVE with memoryless nodes
Quoted 8 lines · Christoph Lameter
Quoted 3 lines · Nishanth Aravamudan
Christoph was also worried about the performance impact on these paths, so, as he suggested, uninline
alloc_pages_node()and move it tomempolicy.c.uninlining does not address performance issues.
Quoted 16 lines
Quoted 4 lines
(quoted diff) +0
-0@@ -184,6 +185,16 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes) atomic_set(&policy->refcnt, 1); switch (mode) { case MPOL_INTERLEAVE:Review static struct mempolicy *mpol_new(int mode, nodemask_t *nodes) · line 197
Quoted 10 lines
(quoted diff) +10
-0+ /* + * Clear any memoryless nodes here so that v.nodes can be used + * without extra checks + */ + nid = first_node(*nodes); + while (nid < MAX_NUMNODES) { + if (!node_populated(nid)) + node_clear(nid, *nodes); + nid = next_node(nid, *nodes); + }There is a "
nodes_and" function for this.
Right, fixed.
Quoted 14 lines
Review static unsigned interleave_nodes(struct mempolicy *policy) · line 1160
Quoted 12 lines
(quoted diff) +5
-3@@ -1126,9 +1153,11 @@ static unsigned interleave_nodes(struct mempolicy *policy) struct task_struct *me = current; nid = me->il_next; - next = next_node(nid, policy->v.nodes); - if (next >= MAX_NUMNODES) - next = first_node(policy->v.nodes); + do { + next = next_node(nid, policy->v.nodes); + if (next >= MAX_NUMNODES) + next = first_node(policy->v.nodes); + } while (!node_populated(next));Is there a case where nodes has no node set?
Well, if the only place to get a "new" policy is mpol_new(), no, as just after the above nodes_and(), we check the weight of the nodemask. Is that sufficient?
Based on ideas from Christoph Lameter, add checks in the INTERLEAVE paths for memoryless nodes. We do not want to try interleaving onto those nodes.
Christoph said:
"This does not work for the address based interleaving for anonymous vmas. I am not sure what to do there. We could change the calculation of the node to be based only on nodes with memory and then skip the memoryless ones. I have only added a comment to describe its brokennes for now."
I have copied his draft's comment.
Change alloc_pages_node() to fail __GFP_THISNODE allocations if the node is not populated.
Again, Christoph said:
"This will fix the alloc_pages_node case but not the alloc_pages() case. In the alloc_pages() case we do not specify a node. Implicitly it is understood that we (in the case of no memory policy / cpuset options) allocate from the nearest node. So it may be argued there that the GFP_THISNODE behavior of taking the first node from the zonelist is okay."
Christoph was also worried about the performance impact on these paths, as am I.
Finally, as he suggested, uninline alloc_pages_node() and move it to mempolicy.c.
include/linux/gfp.h +1 -13
@@ -165,19 +165,7 @@ static inline void arch_alloc_page(struct page *page, int order) { }extern struct page *FASTCALL (__alloc_pages (gfp_t ,unsigned int ,struct zonelist *)); -static inline struct page *alloc_pages_node (int nid,gfp_t gfp_mask, -unsigned int order) -{ -if (unlikely (order >=MAX_ORDER )) -return NULL ; - -/* Unknown node is current node */ -if (nid <0 ) - nid =numa_node_id (); - -return __alloc_pages (gfp_mask, order, -NODE_DATA (nid)->node_zonelists +gfp_zone (gfp_mask)); -} +extern struct page *alloc_pages_node (int ,gfp_t ,unsigned int );#ifdef CONFIG_NUMA extern struct page *alloc_pages_current (gfp_t gfp_mask,unsigned order);
mm/mempolicy.c +33 -5
@@ -174,6 +174,7 @@ static struct zonelist *bind_zonelist(nodemask_t *nodes)static struct mempolicy *mpol_new (int mode,nodemask_t *nodes) {struct mempolicy *policy; +unsigned nid;PDprintk ("setting mode %d nodes[0] %lx\n" , mode,nodes_addr (*nodes)[0 ]);if (mode ==MPOL_DEFAULT )
@@ -184,8 +185,12 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes)atomic_set (&policy->refcnt,1 );switch (mode) {case MPOL_INTERLEAVE : - policy->v.nodes = *nodes; -if (nodes_weight (*nodes) ==0 ) { +/* +* Clear any memoryless nodes here so that v.nodes can be used +* without extra checks +*/ +nodes_and (policy->v.nodes, *nodes, node_populated_mask); +if (nodes_weight (policy->v.nodes) ==0 ) {kmem_cache_free (policy_cache, policy);return ERR_PTR (-EINVAL ); }
@@ -578,6 +583,22 @@ long do_get_mempolicy(int *policy, nodemask_t *nmask,return err; } +struct page *alloc_pages_node (int nid,gfp_t gfp_mask,unsigned int order) +{ +if (unlikely (order >=MAX_ORDER )) +return NULL ; + +/* Unknown node is current node */ +if (nid <0 ) + nid =numa_node_id (); + +if ((gfp_mask & __GFP_THISNODE) && !node_populated (nid)) +return NULL ; + +return __alloc_pages (gfp_mask, order, +NODE_DATA (nid)->node_zonelists +gfp_zone (gfp_mask)); +} +#ifdef CONFIG_MIGRATION /* * page migration
@@ -1126,9 +1147,11 @@ static unsigned interleave_nodes(struct mempolicy *policy)struct task_struct *me = current; nid = me->il_next; - next =next_node (nid, policy->v.nodes); -if (next >=MAX_NUMNODES ) - next =first_node (policy->v.nodes); +do { + next =next_node (nid, policy->v.nodes); +if (next >=MAX_NUMNODES ) + next =first_node (policy->v.nodes); + }while (!node_populated (next)); me->il_next = next;return nid; }
@@ -1192,6 +1215,11 @@ static inline unsigned interleave_nid(struct mempolicy *pol,* for huge pages, since vm_pgoff is in units of small * pages, we need to shift off the always 0 bits to get * a useful offset. +* +* NOTE: For configurations with memoryless nodes this +* is broken since the allocation attempts on that node +* will fall back to other nodes and thus one +* neighboring node will be overallocated from. */ BUG_ON (shift <PAGE_SHIFT ); off = vma->vm_pgoff >> (shift -PAGE_SHIFT );
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v2][RFC] Fix INTERLEAVE with memoryless nodes
Quoted 3 lines · Nishanth Aravamudan
Well, if the only place to get a "new" policy is
mpol_new(), no, as just after the abovenodes_and(), we check the weight of the nodemask. Is that sufficient?
Yes. That is good.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerRe: [PATCH v2][RFC] Fix INTERLEAVE with memoryless nodes
In reply to Nishanth AravamudanQuoted 21 lines · On Mon, 11 Jun 2007 17:14:36 -0700 Nishanth Aravamudan <[email protected]> wrote:
Christoph said:
"This does not work for the address based interleaving for anonymous vmas. I am not sure what to do there. We could change the calculation of the node to be based only on nodes with memory and then skip the memoryless ones. I have only added a comment to describe its brokennes for now."I have copied his draft's comment.
Change
alloc_pages_node()to fail__GFP_THISNODEallocations if the node is not populated.Again, Christoph said:
"This will fix thealloc_pages_nodecase but not thealloc_pages()case. In thealloc_pages()case we do not specify a node. Implicitly it is understood that we (in the case of no memory policy / cpuset options) allocate from the nearest node. So it may be argued there that theGFP_THISNODEbehavior of taking the first node from the zonelist is okay."
Quoted 6 lines
Christoph was also worried about the performance impact on these paths, as am I.
Finally, as he suggested, uninline
alloc_pages_node()and move it tomempolicy.c.
All confused.
Quoted 31 lines
include/linux/gfp.h +1
-13@@ -165,19 +165,7 @@ static inline void arch_alloc_page(struct page *page, int order) { }extern struct page *FASTCALL (__alloc_pages (gfp_t ,unsigned int ,struct zonelist *)); -static inline struct page *alloc_pages_node (int nid,gfp_t gfp_mask, -unsigned int order) -{ -if (unlikely (order >=MAX_ORDER )) -return NULL ; - -/* Unknown node is current node */ -if (nid <0 ) - nid =numa_node_id (); - -return __alloc_pages (gfp_mask, order, -NODE_DATA (nid)->node_zonelists +gfp_zone (gfp_mask)); -} +extern struct page *alloc_pages_node (int ,gfp_t ,unsigned int );#ifdef CONFIG_NUMA extern struct page *alloc_pages_current (gfp_t gfp_mask,unsigned order);mm/mempolicy.c +0
-0
mm/mempolicy.c static struct zonelist *bind_zonelist(nodemask_t *nodes) · line 177
Quoted 4 lines
mm/mempolicy.c +1
-0@@ -174,6 +174,7 @@ static struct zonelist *bind_zonelist(nodemask_t *nodes)static struct mempolicy *mpol_new (int mode,nodemask_t *nodes) {struct mempolicy *policy; +unsigned nid;
This variable appears to be unneeded.
Quoted 7 lines
mm/mempolicy.c +0
-1PDprintk ("setting mode %d nodes[0] %lx\n" , mode,nodes_addr (*nodes)[0 ]);if (mode ==MPOL_DEFAULT )@@ -184,8 +185,12 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes)atomic_set (&policy->refcnt,1 );switch (mode) {case MPOL_INTERLEAVE : - policy->v.nodes = *nodes;
mm/mempolicy.c static struct mempolicy *mpol_new(int mode, nodemask_t *nodes) · line 196
Quoted 10 lines
mm/mempolicy.c +6
-1-if (nodes_weight (*nodes) ==0 ) { +/* +* Clear any memoryless nodes here so that v.nodes can be used +* without extra checks +*/ +nodes_and (policy->v.nodes, *nodes, node_populated_mask); +if (nodes_weight (policy->v.nodes) ==0 ) {kmem_cache_free (policy_cache, policy);return ERR_PTR (-EINVAL ); }
I have no node_populated_mask.
The below improves the situation, but I wonder about, ahem, the maturity of this code.
From: Andrew Morton <[email protected]>
- Fix checkpatch.pl warning
- Fix build
- Fix unused var warning
---
include/linux/gfp.h | 2 +- mm/mempolicy.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-)
include/linux/gfp.h renamed from include/linux/gfp.h~fix-interleave-with-memoryless-nodes-fix +1 -1
@@ -130,7 +130,7 @@ static inline void arch_alloc_page(strucextern struct page *FASTCALL (__alloc_pages (gfp_t ,unsigned int ,struct zonelist *)); -extern struct page *alloc_pages_node (int ,gfp_t ,unsigned int ); +extern struct page *alloc_pages_node (int ,gfp_t ,unsigned int );#ifdef CONFIG_NUMA extern struct page *alloc_pages_current (gfp_t gfp_mask,unsigned order);
mm/mempolicy.c renamed from mm/mempolicy.c~fix-interleave-with-memoryless-nodes-fix +1 -2
@@ -172,7 +172,6 @@ static struct zonelist *bind_zonelist(nostatic struct mempolicy *mpol_new (int mode,nodemask_t *nodes) {struct mempolicy *policy; -unsigned nid;pr_debug ("setting mode %d nodes[0] %lx\n" , mode, nodes ?nodes_addr (*nodes)[0 ] :-1 );
@@ -189,7 +188,7 @@ static struct mempolicy *mpol_new(int mo* Clear any memoryless nodes here so that v.nodes can be used * without extra checks */ -nodes_and (policy->v.nodes, *nodes, node_populated_mask); +nodes_and (policy->v.nodes, *nodes, node_populated_map);if (nodes_weight (policy->v.nodes) ==0 ) {kmem_cache_free (policy_cache, policy);return ERR_PTR (-EINVAL );
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v2][RFC] Fix INTERLEAVE with memoryless nodes
Quoted 24 lines · Andrew Morton
Review
Quoted 1 line
(quoted diff) +1
-0+ unsigned nid;This variable appears to be unneeded.
Quoted 7 lines
(quoted diff) +0
-1PDprintk("setting mode %d nodes[0] %lx\n", mode, nodes_addr(*nodes)[0]); if (mode == MPOL_DEFAULT)@@ -184,8 +185,12 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes) atomic_set(&policy->refcnt, 1); switch (mode) { case MPOL_INTERLEAVE: - policy->v.nodes = *nodes;Review static struct mempolicy *mpol_new(int mode, nodemask_t *nodes) · line 196
Quoted 10 lines
(quoted diff) +6
-1- if (nodes_weight(*nodes) == 0) { + /* + * Clear any memoryless nodes here so that v.nodes can be used + * without extra checks + */ + nodes_and(policy->v.nodes, *nodes, node_populated_mask); + if (nodes_weight(policy->v.nodes) == 0) { kmem_cache_free(policy_cache, policy); return ERR_PTR(-EINVAL); }I have no
node_populated_mask.
Quoted 2 lines
The below improves the situation, but I wonder about, ahem, the maturity of this code.
Yeah. No one compiled it. But I think we have the general outline how this could be done.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v2][RFC] Fix INTERLEAVE with memoryless nodes
In reply to Andrew MortonQuoted 31 lines · Andrew Morton
Quoted 21 lines · On Mon, 11 Jun 2007 17:14:36 -0700 Nishanth Aravamudan <[email protected]> wrote:
Christoph said:
"This does not work for the address based interleaving for anonymous vmas. I am not sure what to do there. We could change the calculation of the node to be based only on nodes with memory and then skip the memoryless ones. I have only added a comment to describe its brokennes for now."I have copied his draft's comment.
Change
alloc_pages_node()to fail__GFP_THISNODEallocations if the node is not populated.Again, Christoph said:
"This will fix thealloc_pages_nodecase but not thealloc_pages()case. In thealloc_pages()case we do not specify a node. Implicitly it is understood that we (in the case of no memory policy / cpuset options) allocate from the nearest node. So it may be argued there that theGFP_THISNODEbehavior of taking the first node from the zonelist is okay."Quoted 6 lines
Christoph was also worried about the performance impact on these paths, as am I.
Finally, as he suggested, uninline
alloc_pages_node()and move it tomempolicy.c.All confused.
<snip>
Quoted 4 lines
I have no
node_populated_mask.The below improves the situation, but I wonder about, ahem, the maturity of this code.
Sorry, Andrew :(
I didn't expect you to pull all these patche so quickly. No one gave me much feedback the last few times I posted the series, so I wasn't expecting any this time either...that's what I get for pique-ing Christoph's interest :) We went through several revisions today alone...
If you would prefer dropping the series, I will clean them up and get them ready for you tomorrow.
The previous series were well-tested, but this one was more of a RFD/RFC with an emphasis on the D/C. Sorry for that and not making it more explicit.
How would you like me to proceed?
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerRe: [PATCH v2][RFC] Fix INTERLEAVE with memoryless nodes
Quoted 1 line · On Mon, 11 Jun 2007 18:41:42 -0700 Nishanth Aravamudan <[email protected]> wrote:
How would you like me to proceed?
I shall now go into hiding. Send 'em when they're ready, OK?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH v2][RFC] Fix INTERLEAVE with memoryless nodes
Quoted 5 lines · Andrew Morton
Quoted 1 line · On Mon, 11 Jun 2007 18:41:42 -0700 Nishanth Aravamudan <[email protected]> wrote:
How would you like me to proceed?
I shall now go into hiding. Send 'em when they're ready, OK?
Thanks, will do. Sorry again.
-Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 1 line · Nishanth Aravamudan
Err, duh -- I was thinking of making this change, but then forgot.
Now its fine.
Andrew please apply.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v4 1/1 Add populated_map to account for memoryless nodes
Quoted 5 lines · Christoph Lameter
Quoted 1 line · Nishanth Aravamudan
Err, duh -- I was thinking of making this change, but then forgot.
Now its fine.
Eep, except that we don't initialize node_populated_mask unless we're NUMA. Also, do you think it's worth adding the comment in mmzone.h that now now NUMA policies depend on present_pages?
Split up Lee and Anton's original patch
(http://marc.info/?l=linux-mm&m=118133042025995&w=2), to allow for the populated_map changes to go in on their own.
Add a populated_map nodemask to indicate a node has memory or not. We have run into a number of issues (in practice and in code) with assumptions about every node having memory. Having this nodemask allows us to fix these issues; in particular, THISNODE allocations will come from the node specified, only, and the INTERLEAVE policy will be able to do the right thing with memoryless nodes.
In the !NUMA case, we assume the pgdat represents a populated node. This is needed for follow-on patches which assume the mask works in NUMA and !NUMA.
include/linux/mmzone.h +4 -0
@@ -337,6 +337,10 @@ struct zone {* give them a chance of being in the same cacheline. */ unsigned long spanned_pages;/* total size, including holes */ +/* +* present_pages is assumed to indicate if a NUMA node is +* populated or not +*/ unsigned long present_pages;/* amount of memory (excluding holes) */ /*
include/linux/nodemask.h +10 -0
@@ -64,12 +64,16 @@* * int node_online(node) Is some node online? * int node_possible(node) Is some node possible? +* int node_populated(node) Is some node populated? * * int any_online_node(mask) First online node in mask * * node_set_online(node) set bit 'node' in node_online_map * node_set_offline(node) clear bit 'node' in node_online_map * +* node_set_populated(node) set bit 'node' in node_populated_map +* node_not_populated(node) clear bit 'node' in node_populated_map +* * for_each_node(node) for-loop node over node_possible_map * for_each_online_node(node) for-loop node over node_online_map *
@@ -344,12 +348,14 @@ static inline void __nodes_remap(nodemask_t *dstp, const nodemask_t *srcp,extern nodemask_t node_online_map;extern nodemask_t node_possible_map; +extern nodemask_t node_populated_map;#if MAX_NUMNODES >1 #define num_online_nodes () nodes_weight(node_online_map)#define num_possible_nodes () nodes_weight(node_possible_map)#define node_online (node) node_isset((node), node_online_map)#define node_possible (node) node_isset((node), node_possible_map) +#define node_populated (node) node_isset((node), node_populated_map)#define first_online_node first_node(node_online_map)#define next_online_node (nid) next_node((nid), node_online_map)extern int nr_node_ids;
@@ -358,6 +364,7 @@ extern int nr_node_ids;#define num_possible_nodes () 1#define node_online (node) ((node) == 0)#define node_possible (node) ((node) == 0) +#define node_populated (node) ((node) == 0)#define first_online_node 0#define next_online_node (nid) (MAX_NUMNODES)#define nr_node_ids 1
@@ -375,6 +382,9 @@ extern int nr_node_ids;#define node_set_online (node) set_bit((node), node_online_map.bits)#define node_set_offline (node) clear_bit((node), node_online_map.bits) +#define node_set_populated (node) set_bit((node), node_populated_map.bits) +#define node_not_populated (node) clear_bit((node), node_populated_map.bits) +#define for_each_node (node) for_each_node_mask((node), node_possible_map)#define for_each_online_node (node) for_each_node_mask((node), node_online_map)
mm/page_alloc.c +12 -0
@@ -54,6 +54,9 @@ nodemask_t node_online_map __read_mostly = { { [0] = 1UL } };EXPORT_SYMBOL (node_online_map);nodemask_t node_possible_map__read_mostly =NODE_MASK_ALL ;EXPORT_SYMBOL (node_possible_map); +nodemask_t node_populated_map__read_mostly =NODE_MASK_NONE ; +EXPORT_SYMBOL (node_populated_map); +unsigned long totalram_pages__read_mostly ;unsigned long totalreserve_pages__read_mostly ;long nr_swap_pages;
@@ -2299,6 +2302,13 @@ static void build_zonelists(pg_data_t *pgdat)/* calculate node order -- i.e., DMA last! */ build_zonelists_in_zone_order (pgdat, j); } + +/* +* record populated zones for use when INTERLEAVE'ing or using +* GFP_THISNODE +*/ +if (pgdat->node_present_pages) +node_set_populated (local_node); }/* Construct the zonelist performance cache - see further mmzone.h */
@@ -2360,6 +2370,8 @@ static void build_zonelists(pg_data_t *pgdat) zonelist->zones[j] =NULL ; } + +node_set_populated (local_node); }/* non-NUMA variant of zonelist performance cache - just NULL zlcache_ptr */
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 3 lines · Nishanth Aravamudan
Eep, except that we don't initialize
node_populated_maskunless we're NUMA. Also, do you think it's worth adding the comment inmmzone.hthat now now NUMA policies depend onpresent_pages?
No need to initialize if we do not use it. You may to #ifdef it out by moving the definition. Please sent a diff against the earlier patch since Andrew already merged it.
present_pages just indicates that there is memory on the node. So I am not sure that this will help.
mm/page_alloc.c static void build_zonelists(pg_data_t *pgdat) · line 2309
Quoted 5 lines
mm/page_alloc.c +5
-0+ +/* +* record populated zones for use when INTERLEAVE'ing or using +* GFP_THISNODE +*/
There may be other purposes as well. No need to enumerate those here.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/1 populated_map: fix !NUMA case, remove comment
Quoted 9 lines · Christoph Lameter
Quoted 3 lines · Nishanth Aravamudan
Eep, except that we don't initialize
node_populated_maskunless we're NUMA. Also, do you think it's worth adding the comment inmmzone.hthat now now NUMA policies depend onpresent_pages?No need to initialize if we do not use it. You may to #ifdef it out by moving the definition. Please sent a diff against the earlier patch since Andrew already merged it.
We will be using it (it == node_populated_mask) later in my sysfs patch and in the fix hugepage allocation patch.
Sorry, sent the updated patch before I got Andrew's mail.
Quoted 2 lines
present_pagesjust indicates that there is memory on the node. So I am not sure that this will help.
Ok.
Quoted 7 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ + /* + * record populated zones for use when INTERLEAVE'ing or using + * GFP_THISNODE + */There may be other purposes as well. No need to enumerate those here.
Ok.
Applies on top of add-populated_map-to-account-for-memoryless-nodes.patch.
populated_map needs to be consistent in both the NUMA and !NUMA cases to fix hugepage allocation with empty nodes. Assume the one node in the !NUMA case is populated.
Remove a comment that would only increase the maintenance burden.
mm/page_alloc.c +2 -4
@@ -2303,10 +2303,6 @@ static void build_zonelists(pg_data_t *pgdat)build_zonelists_in_zone_order (pgdat, j); } -/* -* record populated zones for use when INTERLEAVE'ing or using -* GFP_THISNODE -*/ if (pgdat->node_present_pages)node_set_populated (local_node); }
@@ -2370,6 +2366,8 @@ static void build_zonelists(pg_data_t *pgdat) zonelist->zones[j] =NULL ; } + +node_set_populated (local_node); }/* non-NUMA variant of zonelist performance cache - just NULL zlcache_ptr */
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 6 lines · Nishanth Aravamudan
Quoted 3 lines
No need to initialize if we do not use it. You may to #ifdef it out by moving the definition. Please sent a diff against the earlier patch since Andrew already merged it.
We will be using it (it ==
node_populated_mask) later in my sysfs patch and in the fix hugepage allocation patch.
But not in the !NUMA case. So the definition of the node_populated_mask can be moved into an #ifdef CONFIG_NUMA chunk in page_alloc.c and we can have fallback functions.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 6 lines · Christoph Lameter
Quoted 4 lines · Nishanth Aravamudan
Quoted 3 lines
No need to initialize if we do not use it. You may to #ifdef it out by moving the definition. Please sent a diff against the earlier patch since Andrew already merged it.
Quoted 6 lines
Quoted 2 lines
We will be using it (it ==
node_populated_mask) later in my sysfs patch and in the fix hugepage allocation patch.But not in the !NUMA case. So the definition of the
node_populated_maskcan be moved into an #ifdefCONFIG_NUMAchunk inpage_alloc.cand we can have fallback functions.
Ah, but we'll use it in mpol_new via nodes_and() regardless of NUMA/!NUMA, right?
I see no reason not make sure the node_populated_mask is sensible whenever it can be.
If you really feel that only CONFIG_NUMA code should use node_populated_mask, then I'll make that change and use node_populated() in the callers.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 2 lines · Nishanth Aravamudan
Ah, but we'll use it in
mpol_newvianodes_and()regardless of NUMA/!NUMA, right?
mempolicy.c will only be compiled for the NUMA case.
Quoted 3 lines
If you really feel that only
CONFIG_NUMAcode should usenode_populated_mask, then I'll make that change and usenode_populated()in the callers.
What point would there be of !NUMA configurations using node_populated_mask()?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 6 lines · Christoph Lameter
Quoted 2 lines · Nishanth Aravamudan
Ah, but we'll use it in
mpol_newvianodes_and()regardless of NUMA/!NUMA, right?
mempolicy.cwill only be compiled for the NUMA case.
Ah, I did not realize that, sorry.
Quoted 6 lines
Quoted 3 lines
If you really feel that only
CONFIG_NUMAcode should usenode_populated_mask, then I'll make that change and usenode_populated()in the callers.What point would there be of !NUMA configurations using
node_populated_mask()?
Well, I'm just trying to cover all my bases. I will rework the stack to be better and closer to what you'd like.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
In reply to Christoph LameterQuoted 5 lines · Christoph Lameter
Quoted 2 lines · Nishanth Aravamudan
Ah, but we'll use it in
mpol_newvianodes_and()regardless of NUMA/!NUMA, right?
Quoted 8 lines
mempolicy.cwill only be compiled for the NUMA case.Quoted 3 lines
If you really feel that only
CONFIG_NUMAcode should usenode_populated_mask, then I'll make that change and usenode_populated()in the callers.What point would there be of !NUMA configurations using
node_populated_mask()?
I really don't get this inconsistency...why do we export node_online_map and node_possible_map in !NUMA configurations, then?
Note, node_online_mask is used currently in hugetlb.c to achieve "interleaving" of fresh hugepages. And has no dependency on NUMA to be compiled or not.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
In reply to Christoph LameterQuoted 6 lines · Christoph Lameter
Quoted 4 lines · Nishanth Aravamudan
Quoted 3 lines
No need to initialize if we do not use it. You may to #ifdef it out by moving the definition. Please sent a diff against the earlier patch since Andrew already merged it.
Quoted 6 lines
Quoted 2 lines
We will be using it (it ==
node_populated_mask) later in my sysfs patch and in the fix hugepage allocation patch.But not in the !NUMA case. So the definition of the
node_populated_maskcan be moved into an #ifdefCONFIG_NUMAchunk inpage_alloc.cand we can have fallback functions.
No, see:
[PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
mm/hugetlb.c +15 -6
@@ -105,13 +105,22 @@ static void free_huge_page(struct page *page)static int alloc_fresh_huge_page (void ) { -static int nid =0 ; +static int nid =-1 ;struct page *page; - page =alloc_pages_node (nid, htlb_alloc_mask|__GFP_COMP|__GFP_NOWARN, -HUGETLB_PAGE_ORDER ); - nid =next_node (nid, node_online_map); -if (nid ==MAX_NUMNODES ) - nid =first_node (node_online_map); +int start_nid; + +if (nid <0 ) + nid =first_node (node_populated_map); + start_nid = nid; + +do { + page =alloc_pages_node (nid, +GFP_HIGHUSER |__GFP_COMP|GFP_THISNODE , +HUGETLB_PAGE_ORDER ); + nid =next_node (nid, node_populated_map); +if (nid >= nr_node_ids) + nid =first_node (node_populated_map); + }while (!page && nid != start_nid);if (page) {set_compound_page_dtor (page, free_huge_page);spin_lock (&hugetlb_lock);
wherein alloc_huge_page() checks node_populated_map for each invocation of alloc_huge_page_node(). And alloc_huge_page() does not depend on CONFIG_NUMA in any way.
If you would prefer, I could make it use node_online_map like before and check if the node is populated every time, but that seems silly if it's one line to make the node_populated_map sensible in both NUMA and !NUMA cases, similar to node_online_map.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 1 line · Nishanth Aravamudan
[PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
There is no point in compiling the interleave logic for !NUMA. There needs to be some sort of !NUMA fallback in hugetlb. It would be better to call a interleave function in mempolicy.c that provides an appropriate shim for !NUMA.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 8 lines · Christoph Lameter
Quoted 1 line · Nishanth Aravamudan
[PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
There is no point in compiling the interleave logic for !NUMA. There needs to be some sort of !NUMA fallback in hugetlb. It would be better to call a interleave function in
mempolicy.cthat provides an appropriate shim for !NUMA.
Hrm, if !NUMA, is the nid of the only node guaranteed to be 0? If so, I can just
Make alloc_fresh_huge_page() and other generic variants call into the _node() versions with nid=0, if !NUMA.
Would that be ok?
I'm not sure what kind of interleave function you're thinking of that could be in mempolicy.c? Note, this code used node_online_map before, which was also overkill in !NUMA.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 5 lines · Nishanth Aravamudan
Quoted 4 lines · Christoph Lameter
Quoted 1 line · Nishanth Aravamudan
[PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 7 lines
Quoted 4 lines
There is no point in compiling the interleave logic for !NUMA. There needs to be some sort of !NUMA fallback in hugetlb. It would be better to call a interleave function in
mempolicy.cthat provides an appropriate shim for !NUMA.Hrm, if !NUMA, is the nid of the only node guaranteed to be 0? If so, I can just
Yes.
Quoted 4 lines
Make
alloc_fresh_huge_page()and other generic variants call into the_node()versions with nid=0, if !NUMA.Would that be ok?
I am not sure what you are up to. Just make sure that the changes are minimal. Look in the source code for other examples on how !NUMA situations were handled.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 17 lines · Christoph Lameter
Quoted 5 lines · Nishanth Aravamudan
Quoted 4 lines · Christoph Lameter
Quoted 1 line · Nishanth Aravamudan
[PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 7 lines
Quoted 4 lines
There is no point in compiling the interleave logic for !NUMA. There needs to be some sort of !NUMA fallback in hugetlb. It would be better to call a interleave function in
mempolicy.cthat provides an appropriate shim for !NUMA.Hrm, if !NUMA, is the nid of the only node guaranteed to be 0? If so, I can just
Yes.
Quoted 8 lines
Quoted 4 lines
Make
alloc_fresh_huge_page()and other generic variants call into the_node()versions with nid=0, if !NUMA.Would that be ok?
I am not sure what you are up to. Just make sure that the changes are minimal. Look in the source code for other examples on how !NUMA situations were handled.
I swear I'm trying to make the code do the right thing, and understand the NUMA intricacies better. Sorry for the flood of e-mails and such. I asked about specific other cases because they are used in !NUMA situations too and I wasn't sure why node_populated_map should be different.
But ok, I will rely on the source to be correct and make my changelog indicate where I got the ideas from.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 4 lines · Nishanth Aravamudan
Quoted 3 lines
I am not sure what you are up to. Just make sure that the changes are minimal. Look in the source code for other examples on how !NUMA situations were handled.
Quoted 8 lines
I swear I'm trying to make the code do the right thing, and understand the NUMA intricacies better. Sorry for the flood of e-mails and such. I asked about specific other cases because they are used in !NUMA situations too and I wasn't sure why
node_populated_mapshould be different.But ok, I will rely on the source to be correct and make my changelog indicate where I got the ideas from.
Ok. I just hope this crash course in Linux NUMA is useful and you keep on working on NUMA....
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 12 lines · Christoph Lameter
Quoted 10 lines · Nishanth Aravamudan
Quoted 3 lines
I am not sure what you are up to. Just make sure that the changes are minimal. Look in the source code for other examples on how !NUMA situations were handled.
I swear I'm trying to make the code do the right thing, and understand the NUMA intricacies better. Sorry for the flood of e-mails and such. I asked about specific other cases because they are used in !NUMA situations too and I wasn't sure why
node_populated_mapshould be different.
Quoted 5 lines
Quoted 2 lines
But ok, I will rely on the source to be correct and make my changelog indicate where I got the ideas from.
Ok. I just hope this crash course in Linux NUMA is useful and you keep on working on NUMA....
I'll try, at least.
Thanks for the patience!
-Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
In reply to Nishanth AravamudanQuoted 27 lines · Nishanth Aravamudan
Quoted 17 lines · Christoph Lameter
Quoted 5 lines · Nishanth Aravamudan
Quoted 4 lines · Christoph Lameter
Quoted 1 line · Nishanth Aravamudan
[PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 7 lines
Quoted 4 lines
There is no point in compiling the interleave logic for !NUMA. There needs to be some sort of !NUMA fallback in hugetlb. It would be better to call a interleave function in
mempolicy.cthat provides an appropriate shim for !NUMA.Hrm, if !NUMA, is the nid of the only node guaranteed to be 0? If so, I can just
Yes.
Quoted 8 lines
Quoted 4 lines
Make
alloc_fresh_huge_page()and other generic variants call into the_node()versions with nid=0, if !NUMA.Would that be ok?
I am not sure what you are up to. Just make sure that the changes are minimal. Look in the source code for other examples on how !NUMA situations were handled.
Quoted 8 lines
I swear I'm trying to make the code do the right thing, and understand the NUMA intricacies better. Sorry for the flood of e-mails and such. I asked about specific other cases because they are used in !NUMA situations too and I wasn't sure why
node_populated_mapshould be different.But ok, I will rely on the source to be correct and make my changelog indicate where I got the ideas from.
Nish: when this all settles down, I still need to make sure it works on our platforms with the funny DMA-only node. What that comes down to is that when alloc_fresh_huge_page() calls:
page = alloc_pages_node(nid,
GFP_HIGHUSER|__GFP_COMP|GFP_THISNODE,
HUGETLB_PAGE_ORDER);I need to get a page that is on nid. On our platform, GFP_HIGHUSER is going to specify the zonelist for ZONE_NORMAL. The first zone on this list needs to be on-node for nid. With the changes you've made to the definition of populated map, I think this won't be the case. I need to test your latest patches and fix that, if it's broken.
I still think using policy zone is the "right way" to go, here. After all, only pages in the policy zone are controlled by policy, and that's the goal of spreading out the huge pages across nodes--to make them available to satisfy memory policy at allocation time. But that would need some adjustments for x86_64 systems that have some nodes that are all/mostly DMA32 and other nodes that are populated in zones > DMA32, if we want to allocate huge pages out of the DMA32 zone.
As far as the static variable, and round-robin allocation: the current method "works" both for huge pages allocated at boot time and for huge pages allocated at run-time vi the vm.nr_hugepages sysctl. By "works", I mean that it continues to spread the pages evenly across the "populated" nodes. If, however, you use the task local counter to interleave fresh huge pages, each write to the nr_hugepages from a different task ["echo NN >.../nr_hugepages"] will start at node zero or the first populated node--assuming you're interleaving across populated nodes and not on-line nodes. That's probably OK if you always change nr_hugepages by a multiple of the number of populated nodes. And, if things get out of balance, we'll have your per node attribute, I hope, to adjust any individual node.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 34 lines · Lee Schermerhorn
Quoted 33 lines · Nishanth Aravamudan
Quoted 17 lines · Christoph Lameter
Quoted 5 lines · Nishanth Aravamudan
Quoted 4 lines · Christoph Lameter
Quoted 1 line · Nishanth Aravamudan
[PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes
Quoted 7 lines
Quoted 4 lines
There is no point in compiling the interleave logic for !NUMA. There needs to be some sort of !NUMA fallback in hugetlb. It would be better to call a interleave function in
mempolicy.cthat provides an appropriate shim for !NUMA.Hrm, if !NUMA, is the nid of the only node guaranteed to be 0? If so, I can just
Yes.
Quoted 8 lines
Quoted 4 lines
Make
alloc_fresh_huge_page()and other generic variants call into the_node()versions with nid=0, if !NUMA.Would that be ok?
I am not sure what you are up to. Just make sure that the changes are minimal. Look in the source code for other examples on how !NUMA situations were handled.
I swear I'm trying to make the code do the right thing, and understand the NUMA intricacies better. Sorry for the flood of e-mails and such. I asked about specific other cases because they are used in !NUMA situations too and I wasn't sure why
node_populated_mapshould be different.
Quoted 6 lines
Quoted 2 lines
But ok, I will rely on the source to be correct and make my changelog indicate where I got the ideas from.
Nish: when this all settles down, I still need to make sure it works on our platforms with the funny DMA-only node. What that comes down to is that when
alloc_fresh_huge_page()calls:
Ok, thanks for these details.
Would you be ok with stabilizing the generic definition of node_populated_map as is (any present pages, regardless of location), and then trying to figure out how to get your platform to work with that?
Quoted 9 lines
page = alloc_pages_node(nid, GFP_HIGHUSER|__GFP_COMP|GFP_THISNODE, HUGETLB_PAGE_ORDER);I need to get a page that is on nid. On our platform,
GFP_HIGHUSERis going to specify the zonelist forZONE_NORMAL. The first zone on this list needs to be on-node for nid. With the changes you've made to the definition of populated map, I think this won't be the case. I need to test your latest patches and fix that, if it's broken.
Ok. But that means your platform is broken now too, right? As in, it's not a regression, per se?
I'm much more concerned in the short term about the whole memoryless-node issue, which I think is more straight-forward, and generic to fix.
Quoted 7 lines
I still think using policy zone is the "right way" to go, here. After all, only pages in the policy zone are controlled by policy, and that's the goal of spreading out the huge pages across nodes--to make them available to satisfy memory policy at allocation time. But that would need some adjustments for
x86_64systems that have some nodes that are all/mostly DMA32 and other nodes that are populated in zonesQuoted 1 line
DMA32, if we want to allocate huge pages out of the DMA32 zone.
Well, as of right now, I'm *only* trying to deal with memoryless nodes. So then this whole notion of policy_zone is relatively moot. It matters for your platform, I understand, but I think the fix there is more complex and probably should be stacked on the current set, once it is stabilized.
Quoted 4 lines
As far as the static variable, and round-robin allocation: the current method "works" both for huge pages allocated at boot time and for huge pages allocated at run-time vi the vm.nr_hugepages sysctl. By "works", I mean that it continues to spread the pages evenly across the
Quoted 8 lines
"populated" nodes. If, however, you use the task local counter to interleave fresh huge pages, each write to the
nr_hugepagesfrom a different task ["echo NN >.../nr_hugepages"] will start at node zero or the first populated node--assuming you're interleaving across populated nodes and not on-line nodes. That's probably OK if you always changenr_hugepagesby a multiple of the number of populated nodes. And, if things get out of balance, we'll have your per node attribute, I hope, to adjust any individual node.
Yes, I will reply about the il_next thing in a sec. Maybe Christoph has some cleverness.
And yes, I think the per-node attribute will fix most of the interface problems for 'odd' NUMA systems.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 2 lines · Nishanth Aravamudan
And yes, I think the per-node attribute will fix most of the interface problems for 'odd' NUMA systems.
Right. The definition of populate_node needs to be clear. We agreed that it is a node with memory. If we want to add further restrictions on the type of memory being used on the node then we can add further maps if necessary or have the subsystem manage a nodelist of allowed nodes.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
In reply to Nishanth AravamudanQuoted 1 line · Nishanth Aravamudan
On 12.06.2007 [11:06:22 -0400], Lee Schermerhorn wrote:
<snip>
Quoted 11 lines
Quoted 4 lines
Nish: when this all settles down, I still need to make sure it works on our platforms with the funny DMA-only node. What that comes down to is that when
alloc_fresh_huge_page()calls:Ok, thanks for these details.
Would you be ok with stabilizing the generic definition of
node_populated_mapas is (any present pages, regardless of location), and then trying to figure out how to get your platform to work with that?
Yeah, I think that's my only option now that node_populated_map is being used for other things than huge page setup.
Quoted 5 lines
Quoted 5 lines
page = alloc_pages_node(nid, GFP_HIGHUSER|__GFP_COMP|GFP_THISNODE, HUGETLB_PAGE_ORDER);
Quoted 8 lines
Quoted 5 lines
I need to get a page that is on nid. On our platform,
GFP_HIGHUSERis going to specify the zonelist forZONE_NORMAL. The first zone on this list needs to be on-node for nid. With the changes you've made to the definition of populated map, I think this won't be the case. I need to test your latest patches and fix that, if it's broken.Ok. But that means your platform is broken now too, right? As in, it's not a regression, per se?
Well, my patch [v4] fixed it on my platform. So this is a regression relative to my patch. But, then, my patch had an issue with an x86_64 system where one node is all/mostly DMA32 and other nodes have memory in higher zones. Maybe that's OK [or not] for hugepage allocation, but almost certainly not for regular page interleaving, ...
Quoted 4 lines
I'm much more concerned in the short term about the whole memoryless-node issue, which I think is more straight-forward, and generic to fix.
Perhaps, but I think we're still going to get off node allocations with the revised definition of the populated map and the new zonelist ordering. I think we'll need to check for and reject off-node allocations when '_THISNODE is specified. We can't assume that the first zone in a node's zonelist for a given gfp_zone is on-node.
[more in response to other mail...]
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 5 lines · Lee Schermerhorn
Well, my patch [v4] fixed it on my platform. So this is a regression relative to my patch. But, then, my patch had an issue with an
x86_64system where one node is all/mostly DMA32 and other nodes have memory in higher zones. Maybe that's OK [or not] for hugepage allocation, but almost certainly not for regular page interleaving, ...
Well this means your patch was arch specific.
Quoted 9 lines
Quoted 3 lines
I'm much more concerned in the short term about the whole memoryless-node issue, which I think is more straight-forward, and generic to fix.
Perhaps, but I think we're still going to get off node allocations with the revised definition of the populated map and the new zonelist ordering. I think we'll need to check for and reject off-node allocations when '
_THISNODEis specified. We can't assume that the first zone in a node's zonelist for a givengfp_zoneis on-node.
We do not do that anymore. GFP_THISNODE guarantees the allocation on the node with alloc_pages_node. Read on.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 9 lines · Christoph Lameter
Quoted 5 lines · Lee Schermerhorn
Well, my patch [v4] fixed it on my platform. So this is a regression relative to my patch. But, then, my patch had an issue with an
x86_64system where one node is all/mostly DMA32 and other nodes have memory in higher zones. Maybe that's OK [or not] for hugepage allocation, but almost certainly not for regular page interleaving, ...Well this means your patch was arch specific.
Worse than that--the problem is platform specific. I thought the patch was generic--that's what I was striving for. I just hadn't thought through the implications for x86_64 platforms with just the right amount of memory to cause a problem.
I tested on a 2 socket, 4GB blade. All memory, both nodes, was DMA32 or lower, so policy_zone == ZONE_DMA32 and it worked fine. I tested on a 4 socket, 32GB server--8GB per node. Policy_zone was ZONE_NORMAL, but all nodes had at least 4G of normal memory. For the nr_hugepages that I tried, I saw the pages allocated evenly across the nodes. Guess I didn't ask for enough pages to consume all of the normal memory on node 0 to see any imbalance thereafter.
Quoted 5 lines
Quoted 5 lines
Quoted 4 lines
I'm much more concerned in the short term about the whole memoryless-node issue, which I think is more straight-forward, and generic to fix.
Quoted 8 lines
Quoted 5 lines
Perhaps, but I think we're still going to get off node allocations with the revised definition of the populated map and the new zonelist ordering. I think we'll need to check for and reject off-node allocations when '
_THISNODEis specified. We can't assume that the first zone in a node's zonelist for a givengfp_zoneis on-node.We do not do that anymore.
GFP_THISNODEguarantees the allocation on the node withalloc_pages_node. Read on.
I have been reading. Might work as you say. Not because you're testing the populated map in alloc_pages_node(). That can still pass an off-node zonelist to __alloc_pages(). However, I'm hoping that the test of the zone_pgdat in get_page_from_freelist() will do the right thing. I'm referring to:
if (unlikely(NUMA_BUILD && (gfp_mask & __GFP_THISNODE) && zone->zone_pgdat != zonelist->zones[0]->zone_pgdat)) break;
But, I'm not convinced that zonelist->zones[0]->zone_pgdat always refers to the node specified the 'nid' argument of alloc_pages_node(). It was with my definition of the populated map, but I don't think so, now.
We'll see.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 7 lines · Lee Schermerhorn
I have been reading. Might work as you say. Not because you're testing the populated map in
alloc_pages_node(). That can still pass an off-node zonelist to__alloc_pages(). However, I'm hoping that the test of thezone_pgdatinget_page_from_freelist()will do the right thing. I'm referring to:
Quoted 7 lines
if (unlikely(NUMA_BUILD && (gfp_mask & __GFP_THISNODE) && zone->zone_pgdat != zonelist->zones[0]->zone_pgdat)) break;But, I'm not convinced that zonelist->zones[0]->zone_pgdat always refers to the node specified the 'nid' argument of
alloc_pages_node(). It was with my definition of the populated map, but I don't think so, now.
It does refer to the current node if the node has memory on its own. alloc_pages_node pickup the zonelist of the node. If the node has memory then the first zone will be the nodes zones.
Uhhh... Right there is another special case. The recently introduces zonelist swizzle makes the DMA zone come last and if a node had only a DMA zone then it may become swizzled to the end of the zonelist.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 4 lines · Christoph Lameter
Uhhh... Right there is another special case. The recently introduces zonelist swizzle makes the DMA zone come last and if a node had only a DMA zone then it may become swizzled to the end of the zonelist.
Maybe we can ignore that case for now:
Fix GFP_THISNODE behavior for memoryless nodes
GFP_THISNODE checks that the zone selected is within the pgdat (node) of the first zone of a nodelist. That only works if the node has memory. A memoryless node will have its first node on another pgdat (node).
GFP_THISNODE currently will return simply memory on the first pgdat. Thus it is returning memory on other nodes. GFP_THISNODE should fail if there is no local memory on a node.
So we add a check to verify that the node specified has memory in alloc_pages_node(). If the node has no memory then return NULL.
The case of alloc_pages(GFP_THISNODE) is not changed. alloc_pages() (with no memory policies in effect)
include/linux/gfp.h +7 -0
@@ -175,6 +175,13 @@ static inline struct page *alloc_pages_nif (nid <0 ) nid =numa_node_id (); +/* +* Check for the special case that GFP_THISNODE is used on a +* memoryless node +*/ +if ((gfp_mask & __GFP_THISNODE) && !node_memory (nid)) +return NULL ; +return __alloc_pages (gfp_mask, order,NODE_DATA (nid)->node_zonelists +gfp_zone (gfp_mask)); }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 34 lines · Christoph Lameter
Quoted 4 lines · Christoph Lameter
Uhhh... Right there is another special case. The recently introduces zonelist swizzle makes the DMA zone come last and if a node had only a DMA zone then it may become swizzled to the end of the zonelist.
Maybe we can ignore that case for now:
Fix
GFP_THISNODEbehavior for memoryless nodes
GFP_THISNODEchecks that the zone selected is within the pgdat (node) of the first zone of a nodelist. That only works if the node has memory. A memoryless node will have its first node on another pgdat (node).
GFP_THISNODEcurrently will return simply memory on the first pgdat. Thus it is returning memory on other nodes.GFP_THISNODEshould fail if there is no local memory on a node.So we add a check to verify that the node specified has memory in
alloc_pages_node(). If the node has no memory then return NULL.The case of
alloc_pages(GFP_THISNODE)is not changed.alloc_pages()(with no memory policies in effect)Signed-off-by Christoph Lameter <[email protected]>Signed-off-by Nishanth Aravamudan <[email protected]>Index:
linux-2.6.22-rc4-mm2/include/linux/gfp.h
===================================================================
include/linux/gfp.h static inline struct page *alloc_pages_n · line 184
Quoted 10 lines
include/linux/gfp.h +7
-0@@ -175,6 +175,13 @@ static inline struct page *alloc_pages_nif (nid <0 ) nid =numa_node_id (); +/* +* Check for the special case that GFP_THISNODE is used on a +* memoryless node +*/ +if ((gfp_mask & __GFP_THISNODE) && !node_memory (nid)) +return NULL ; +
Yep, this seems to be the right thing to do, and was in my rolled-up patch.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 10 lines · Nishanth Aravamudan
Quoted 9 lines · Christoph Lameter
Quoted 4 lines · Christoph Lameter
Uhhh... Right there is another special case. The recently introduces zonelist swizzle makes the DMA zone come last and if a node had only a DMA zone then it may become swizzled to the end of the zonelist.
Maybe we can ignore that case for now:
I wish we wouldn't. We need the "DMA zone comes last" for both HP and Fujitsu platforms. That's why Kame and I worked on that patch together.
Quoted 28 lines
Quoted 28 lines
Fix
GFP_THISNODEbehavior for memoryless nodes
GFP_THISNODEchecks that the zone selected is within the pgdat (node) of the first zone of a nodelist. That only works if the node has memory. A memoryless node will have its first node on another pgdat (node).
GFP_THISNODEcurrently will return simply memory on the first pgdat. Thus it is returning memory on other nodes.GFP_THISNODEshould fail if there is no local memory on a node.So we add a check to verify that the node specified has memory in
alloc_pages_node(). If the node has no memory then return NULL.The case of
alloc_pages(GFP_THISNODE)is not changed.alloc_pages()(with no memory policies in effect)Signed-off-by Christoph Lameter <[email protected]>Signed-off-by Nishanth Aravamudan <[email protected]>Index:
linux-2.6.22-rc4-mm2/include/linux/gfp.h
===================================================================include/linux/gfp.h +0
-0@@ -175,6 +175,13 @@ static inline struct page *alloc_pages_nif (nid <0 ) nid =numa_node_id ();
Quoted 10 lines
include/linux/gfp.h static inline struct page *alloc_pages_n · line 184
Quoted 7 lines
include/linux/gfp.h +7
-0+/* +* Check for the special case that GFP_THISNODE is used on a +* memoryless node +*/ +if ((gfp_mask & __GFP_THISNODE) && !node_memory (nid)) +return NULL ; +Yep, this seems to be the right thing to do, and was in my rolled-up patch.
I think that the "node has memory" mask is fine for scanning nodes that might have memory in the zone of interest--including in the hugetlb alloc_fresh_huge_page() loop. However, I think that to support all platforms in a generic way, alloc_pages_node() and alloc_page_interleave() [both take a node id arg] should be more strict when the gfp mask includes 'THISNODE and not assume that a populated node always has on-node memory in the zone of interest. E.g., something like:
pgdat_t *pgdat; struct zonelist *zonelist; ... /* * after validating nid, ... * Note that we need to fetch these values anyway for the * [likely?] call to __alloc_pages(). */ pgdat = NODE_DATA(nid); zonelist = pgdat->node_zonelists + gfp_zone(gfp_mask); if ((gfp_mask & __GFP_THISNODE) && zonelist->zones[0]->zone_pgdat != pgdat) return NULL; return __alloc_pages(gfp_mask, order, zonelist);
I see you've submitted a new patch set. I grab it [when Nish reposts] and test it as is and modified to look something like the above, if needed.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 9 lines · Lee Schermerhorn
Quoted 8 lines · Nishanth Aravamudan
Quoted 7 lines · Christoph Lameter
Quoted 4 lines · Christoph Lameter
Uhhh... Right there is another special case. The recently introduces zonelist swizzle makes the DMA zone come last and if a node had only a DMA zone then it may become swizzled to the end of the zonelist.
Quoted 5 lines
Quoted 2 lines
Quoted 2 lines
Maybe we can ignore that case for now:
I wish we wouldn't. We need the "DMA zone comes last" for both HP and Fujitsu platforms. That's why Kame and I worked on that patch together.
Right. I interpreted the "for now" as for this first stack of patches. We'll need a fix for your platform on top, but it seems to be a minority case? Not saying it shouldn't be fixed, by any means, just trying to get a handle on it.
Quoted 38 lines
Quoted 27 lines
Quoted 27 lines
Fix
GFP_THISNODEbehavior for memoryless nodes
GFP_THISNODEchecks that the zone selected is within the pgdat (node) of the first zone of a nodelist. That only works if the node has memory. A memoryless node will have its first node on another pgdat (node).
GFP_THISNODEcurrently will return simply memory on the first pgdat. Thus it is returning memory on other nodes.GFP_THISNODEshould fail if there is no local memory on a node.So we add a check to verify that the node specified has memory in
alloc_pages_node(). If the node has no memory then return NULL.The case of
alloc_pages(GFP_THISNODE)is not changed.alloc_pages()(with no memory policies in effect)Signed-off-by Christoph Lameter <[email protected]>Signed-off-by Nishanth Aravamudan <[email protected]>Index:
linux-2.6.22-rc4-mm2/include/linux/gfp.h
===================================================================include/linux/gfp.h +0
-0@@ -175,6 +175,13 @@ static inline struct page *alloc_pages_nif (nid <0 ) nid =numa_node_id ();Quoted 10 lines
include/linux/gfp.h static inline struct page *alloc_pages_n · line 184
Quoted 7 lines
include/linux/gfp.h +7
-0+/* +* Check for the special case that GFP_THISNODE is used on a +* memoryless node +*/ +if ((gfp_mask & __GFP_THISNODE) && !node_memory (nid)) +return NULL ; +Yep, this seems to be the right thing to do, and was in my rolled-up patch.
Quoted 7 lines
I think that the "node has memory" mask is fine for scanning nodes that might have memory in the zone of interest--including in the hugetlb
alloc_fresh_huge_page()loop. However, I think that to support all platforms in a generic way,alloc_pages_node()andalloc_page_interleave()[both take a node id arg] should be more strict when the gfp mask includes 'THISNODE and not assume that a populated node always has on-node memory in the zone of interest.
Hrm, perhaps.
Quoted 22 lines
E.g., something like:
pgdat_t *pgdat; struct zonelist *zonelist; ... /* * after validating nid, ... * Note that we need to fetch these values anyway for the * [likely?] call to __alloc_pages(). */ pgdat = NODE_DATA(nid); zonelist = pgdat->node_zonelists + gfp_zone(gfp_mask); if ((gfp_mask & __GFP_THISNODE) && zonelist->zones[0]->zone_pgdat != pgdat) return NULL; return __alloc_pages(gfp_mask, order, zonelist);
Quoted 3 lines
I see you've submitted a new patch set. I grab it [when Nish reposts] and test it as is and modified to look something like the above, if needed.
I think your code above makes sense -- I'd still leave in the earlier check, though.
So it probably should be:
pgdat = NODE_DATA(nid); zonelist = pgdat->node_zonelists + gfp_zone(gfp_mask); if (unlikely((gfp_mask & __GFP_THISNODE) && (!node_memory(nid) || zonelist->zones[0]->zone_pgdat != pgdat))) return NULL;
That way, if the node has no memory whatsoever, we don't bother checking the pgdat of the relevant zone?
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 12 lines · Nishanth Aravamudan
Quoted 11 lines · Lee Schermerhorn
Quoted 10 lines · Nishanth Aravamudan
Quoted 9 lines · Christoph Lameter
Quoted 4 lines · Christoph Lameter
Uhhh... Right there is another special case. The recently introduces zonelist swizzle makes the DMA zone come last and if a node had only a DMA zone then it may become swizzled to the end of the zonelist.
Maybe we can ignore that case for now:
Quoted 8 lines
Quoted 3 lines
I wish we wouldn't. We need the "DMA zone comes last" for both HP and Fujitsu platforms. That's why Kame and I worked on that patch together.
Right. I interpreted the "for now" as for this first stack of patches. We'll need a fix for your platform on top, but it seems to be a minority case? Not saying it shouldn't be fixed, by any means, just trying to get a handle on it.
Yep. I'm testing the stack "as is" now. If it doesn't spread the huge pages evenly because of our funky DMA-only node, I'll post a fix up patch for consideration.
By the way, your sysfs attribute patch doesn't compile. I'll post comments/fixes in response to your message that submitted the patch.
Quoted 1 line
<snip>
Quoted 50 lines
Quoted 8 lines
I think that the "node has memory" mask is fine for scanning nodes that might have memory in the zone of interest--including in the hugetlb
alloc_fresh_huge_page()loop. However, I think that to support all platforms in a generic way,alloc_pages_node()andalloc_page_interleave()[both take a node id arg] should be more strict when the gfp mask includes 'THISNODE and not assume that a populated node always has on-node memory in the zone of interest.Hrm, perhaps.
Quoted 22 lines
E.g., something like:
pgdat_t *pgdat; struct zonelist *zonelist; ... /* * after validating nid, ... * Note that we need to fetch these values anyway for the * [likely?] call to __alloc_pages(). */ pgdat = NODE_DATA(nid); zonelist = pgdat->node_zonelists + gfp_zone(gfp_mask); if ((gfp_mask & __GFP_THISNODE) && zonelist->zones[0]->zone_pgdat != pgdat) return NULL; return __alloc_pages(gfp_mask, order, zonelist);Quoted 3 lines
I see you've submitted a new patch set. I grab it [when Nish reposts] and test it as is and modified to look something like the above, if needed.
I think your code above makes sense -- I'd still leave in the earlier check, though.
So it probably should be:
pgdat = NODE_DATA(nid); zonelist = pgdat->node_zonelists + gfp_zone(gfp_mask); if (unlikely((gfp_mask & __GFP_THISNODE) && (!node_memory(nid) || zonelist->zones[0]->zone_pgdat != pgdat))) return NULL;
Quoted 2 lines
That way, if the node has no memory whatsoever, we don't bother checking the pgdat of the relevant zone?
Well, since most nodes WILL, I think, have memory, that just adds an extra check in the most frequent case. Then, we'll have to go ahead and check the pgdat. However, if the first zone in the selected zonelist IS "on-node" [pgdats match], we know that the node has memory [altho' the zone may not have available pages]. And since we have to fetch the pgdat and the zonelist, anyway, as the argument to __alloc_pages(), I don't think my proposed change adds any additional memory ref's, while eliminating the ref to the node_memory_map. I'm assuming here that the compiler will optimize away any stores to the pgdat/zonelist variables.
So, we can use the node_memory() test at higher levels--like the alloc_fresh_huge_page() loop, to avoid attempting allocations from nodes that we know have no memory, but I think the allocate_pages_node() and allocate_interleave_page() should test the selected zonelist explicitly.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 17 lines · Lee Schermerhorn
Quoted 16 lines · Nishanth Aravamudan
Quoted 14 lines · Lee Schermerhorn
Quoted 10 lines · Nishanth Aravamudan
Quoted 9 lines · Christoph Lameter
Quoted 4 lines · Christoph Lameter
Uhhh... Right there is another special case. The recently introduces zonelist swizzle makes the DMA zone come last and if a node had only a DMA zone then it may become swizzled to the end of the zonelist.
Maybe we can ignore that case for now:
I wish we wouldn't. We need the "DMA zone comes last" for both HP and Fujitsu platforms. That's why Kame and I worked on that patch together.
Quoted 8 lines
Quoted 4 lines
Right. I interpreted the "for now" as for this first stack of patches. We'll need a fix for your platform on top, but it seems to be a minority case? Not saying it shouldn't be fixed, by any means, just trying to get a handle on it.
Yep. I'm testing the stack "as is" now. If it doesn't spread the huge pages evenly because of our funky DMA-only node, I'll post a fix up patch for consideration.
Great, thanks.
Quoted 2 lines
By the way, your sysfs attribute patch doesn't compile. I'll post comments/fixes in response to your message that submitted the patch.
Dang, much appreciated.
Quoted 55 lines
<snip>
Quoted 50 lines
Quoted 8 lines
I think that the "node has memory" mask is fine for scanning nodes that might have memory in the zone of interest--including in the hugetlb
alloc_fresh_huge_page()loop. However, I think that to support all platforms in a generic way,alloc_pages_node()andalloc_page_interleave()[both take a node id arg] should be more strict when the gfp mask includes 'THISNODE and not assume that a populated node always has on-node memory in the zone of interest.Hrm, perhaps.
Quoted 22 lines
E.g., something like:
pgdat_t *pgdat; struct zonelist *zonelist; ... /* * after validating nid, ... * Note that we need to fetch these values anyway for the * [likely?] call to __alloc_pages(). */ pgdat = NODE_DATA(nid); zonelist = pgdat->node_zonelists + gfp_zone(gfp_mask); if ((gfp_mask & __GFP_THISNODE) && zonelist->zones[0]->zone_pgdat != pgdat) return NULL; return __alloc_pages(gfp_mask, order, zonelist);Quoted 3 lines
I see you've submitted a new patch set. I grab it [when Nish reposts] and test it as is and modified to look something like the above, if needed.
I think your code above makes sense -- I'd still leave in the earlier check, though.
So it probably should be:
pgdat = NODE_DATA(nid); zonelist = pgdat->node_zonelists + gfp_zone(gfp_mask); if (unlikely((gfp_mask & __GFP_THISNODE) && (!node_memory(nid) || zonelist->zones[0]->zone_pgdat != pgdat))) return NULL;Quoted 2 lines
That way, if the node has no memory whatsoever, we don't bother checking the pgdat of the relevant zone?
Quoted 10 lines
Well, since most nodes WILL, I think, have memory, that just adds an extra check in the most frequent case. Then, we'll have to go ahead and check the pgdat. However, if the first zone in the selected zonelist IS "on-node" [pgdats match], we know that the node has memory [altho' the zone may not have available pages]. And since we have to fetch the pgdat and the zonelist, anyway, as the argument to
__alloc_pages(), I don't think my proposed change adds any additional memory ref's, while eliminating the ref to thenode_memory_map. I'm assuming here that the compiler will optimize away any stores to the pgdat/zonelist variables.
You're right, sorry for the noise.
Quoted 5 lines
So, we can use the
node_memory()test at higher levels--like thealloc_fresh_huge_page()loop, to avoid attempting allocations from nodes that we know have no memory, but I think theallocate_pages_node()andallocate_interleave_page()should test the selected zonelist explicitly.
Yep.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
In reply to Lee SchermerhornQuoted 3 lines · Lee Schermerhorn
Yep. I'm testing the stack "as is" now. If it doesn't spread the huge pages evenly because of our funky DMA-only node, I'll post a fix up patch for consideration.
Note that the memory from your DMA only node is allocated without requiring DMA memory. We just fall back in the allocation to DMA memory. Thus you do not need special handling as far as I can tell.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 9 lines · Christoph Lameter
Quoted 3 lines · Lee Schermerhorn
Yep. I'm testing the stack "as is" now. If it doesn't spread the huge pages evenly because of our funky DMA-only node, I'll post a fix up patch for consideration.
Note that the memory from your DMA only node is allocated without requiring DMA memory. We just fall back in the allocation to DMA memory. Thus you do not need special handling as far as I can tell.
Just a note to clarify what was happening. I already described the zonelist selected by the gfp_zone for that node. The first zone in the list was on node 0, so everytime the interleave cursor specified node 4, I got a page on node0. I ended up with twice as many huge pages on node 0 as any other node.
Nish's code also got the accounting wrong when he changed "nr_huge_pages_node[page_to_nid(page)]++;" to "nr_huge_pages_node[nid]++;" in his "numafy several functions" patch. This caused the total/free counts to get out of sync and the total count on node 0 to go negative when I free the pages. This won't happen if alloc_pages_node() never returns off-node pages.
On my particular config [number of nodes/amount of memory], if the dma zone had been first in the list [old, "node order" zonelists], the allocation would have failed because no page of the requested order would have been available there. alloc_pages_node() would have failed because get_page_from_freelist() would have detected that the 2nd zone was off node and bailed out. The "right thing" would have happened here because of the order of the allocation. Regular page allocations would succeed and consume all of DMA--why we added "node order" zonelists. Also, on a larger config, there would be more DMA memory, so a few [2 or 3?] huge pages might come from the dma memory.
It's even more complicated: I can configure the platform so that more of the memory from each of the real nodes in available in the pseudo-node that contains memory that is hardware interleaved at the
cache-line granularity--all the way up to 100% interleaved. At 100%
interleaved, all of the real nodes become "memoryless" and all memory
exists in the pseudo-node. Up to the 1st 4GB will be in zone DMA and
the remainder in zone NORMAL. This interleaved memory has different latency/bandwidth properties from node local memory, so in a mixed local/interleaved configuration, I'd like to handle it separately--e.g., not automatically used for task memory interleaving. It will never be "local" to any cpu, so default policy won't allocate there. I'd love to make the default page cache policy prefer that node, or use it for a data base shared global area, ...
The point of all this is that, as you've pointed out, the original NUMA and memory policy designs assumed a fairly symmetric system configuration with all nodes populated with [similar amounts?] of roughly equivalent memory. That probably describes a majority of NUMA systems, so the system should handle this well, as a default. We still need to be able to handle the less symmetric configs--with boot parameters, sysctls, cpusets, ...--that specify non-default behavior, and cause the generic code to do the right thing. Certainly, the generic code can't "fall over and die" in the presence of memoryless nodes or other "interesting" configurations.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 10 lines · Lee Schermerhorn
The point of all this is that, as you've pointed out, the original NUMA and memory policy designs assumed a fairly symmetric system configuration with all nodes populated with [similar amounts?] of roughly equivalent memory. That probably describes a majority of NUMA systems, so the system should handle this well, as a default. We still need to be able to handle the less symmetric configs--with boot parameters, sysctls, cpusets, ...--that specify non-default behavior, and cause the generic code to do the right thing. Certainly, the generic code can't "fall over and die" in the presence of memoryless nodes or other "interesting" configurations.
The hugepage distribution issues have to be handled by the hugepage code. There is no point in adding inconsistencies in the definition of a memoryless node to satisfy hugepage distribution issues on one platform.
The memoryless node handling addresses one particular assymmetry: No memory vs. some memory. The fine grained stuff that relates to particular page types (like I do not want hugepages on my DMA node...) have to be handled by the management of that particular page type. Here we need some control over huge page distribution. There is already another case where we may need to control the nodes that slab uses for its allocations. The slab node restrictions have to be handled by the slab code. Same thing for hugepages.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 13 lines · Christoph Lameter
Quoted 10 lines · Lee Schermerhorn
The point of all this is that, as you've pointed out, the original NUMA and memory policy designs assumed a fairly symmetric system configuration with all nodes populated with [similar amounts?] of roughly equivalent memory. That probably describes a majority of NUMA systems, so the system should handle this well, as a default. We still need to be able to handle the less symmetric configs--with boot parameters, sysctls, cpusets, ...--that specify non-default behavior, and cause the generic code to do the right thing. Certainly, the generic code can't "fall over and die" in the presence of memoryless nodes or other "interesting" configurations.
Quoted 3 lines
The hugepage distribution issues have to be handled by the hugepage code. There is no point in adding inconsistencies in the definition of a memoryless node to satisfy hugepage distribution issues on one platform.
I don't disagree. I originally tried to fix this in the hugetlb allocation code. But, I was using zonelist internal knowledge [ensuring that the first zone was on-node], but I recall that both you and Nish didn't like this--huge page code having knowledge of zonelist internals. That led me off to defining a node_populated_map that had the right semantics for hugetlb fresh page allocation [for my platform, anyway]. Then, we started using the node_populated_map for other things and it evolved to where alloc_pages_node() can leak off-node pages for some platforms [mine :-(].
Quoted 9 lines
The memoryless node handling addresses one particular assymmetry: No memory vs. some memory. The fine grained stuff that relates to particular page types (like I do not want hugepages on my DMA node...) have to be handled by the management of that particular page type. Here we need some control over huge page distribution. There is already another case where we may need to control the nodes that slab uses for its allocations. The slab node restrictions have to be handled by the slab code. Same thing for hugepages.
If we agree that I can filter off-node pages in alloc_fresh_huge_page_node(), freeing a page and returning NULL if it's off-node, that will solve the problem for huge page setup.
I'll try that atop your latest patch stream, once Nish has reposted his huge page allocation set.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
In reply to Lee SchermerhornQuoted 17 lines · Lee Schermerhorn
Quoted 9 lines · Christoph Lameter
Quoted 3 lines · Lee Schermerhorn
Yep. I'm testing the stack "as is" now. If it doesn't spread the huge pages evenly because of our funky DMA-only node, I'll post a fix up patch for consideration.
Note that the memory from your DMA only node is allocated without requiring DMA memory. We just fall back in the allocation to DMA memory. Thus you do not need special handling as far as I can tell.
Just a note to clarify what was happening. I already described the zonelist selected by the
gfp_zonefor that node. The first zone in the list was on node 0, so everytime the interleave cursor specified node 4, I got a page on node0. I ended up with twice as many huge pages on node 0 as any other node.
Quoted 6 lines
Nish's code also got the accounting wrong when he changed "nr_huge_pages_node[page_to_nid(page)]++;" to "nr_huge_pages_node[nid]++;" in his "numafy several functions" patch. This caused the total/free counts to get out of sync and the total count on node 0 to go negative when I free the pages. This won't happen if
alloc_pages_node()never returns off-node pages.
Yep, that last sentence is the key. Regardless of NUMA layout, I would like to rely (and I believe these are the semantics we are striving for) on GFP_THISNODE allocations only returning pages on the node. Perhaps we should add some WARN_ON()'s to the VM so any modifications that break this assumption will be detected quickly? e.g.
WARN_ON(page_to_nid(page) != nid)
<snip>
Quoted 10 lines
The point of all this is that, as you've pointed out, the original NUMA and memory policy designs assumed a fairly symmetric system configuration with all nodes populated with [similar amounts?] of roughly equivalent memory. That probably describes a majority of NUMA systems, so the system should handle this well, as a default. We still need to be able to handle the less symmetric configs--with boot parameters, sysctls, cpusets, ...--that specify non-default behavior, and cause the generic code to do the right thing. Certainly, the generic code can't "fall over and die" in the presence of memoryless nodes or other "interesting" configurations.
Agreed,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 11 lines · Nishanth Aravamudan
Quoted 10 lines
The point of all this is that, as you've pointed out, the original NUMA and memory policy designs assumed a fairly symmetric system configuration with all nodes populated with [similar amounts?] of roughly equivalent memory. That probably describes a majority of NUMA systems, so the system should handle this well, as a default. We still need to be able to handle the less symmetric configs--with boot parameters, sysctls, cpusets, ...--that specify non-default behavior, and cause the generic code to do the right thing. Certainly, the generic code can't "fall over and die" in the presence of memoryless nodes or other "interesting" configurations.
Quoted 2 lines
Agreed,
Nish
The generic code currently does not fail. It (slab allocators etc) simply gets memory that it thinks comes from a memoryless node but it came from a neighboring node.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 13 lines · Christoph Lameter
Quoted 11 lines · Nishanth Aravamudan
Quoted 10 lines
The point of all this is that, as you've pointed out, the original NUMA and memory policy designs assumed a fairly symmetric system configuration with all nodes populated with [similar amounts?] of roughly equivalent memory. That probably describes a majority of NUMA systems, so the system should handle this well, as a default. We still need to be able to handle the less symmetric configs--with boot parameters, sysctls, cpusets, ...--that specify non-default behavior, and cause the generic code to do the right thing. Certainly, the generic code can't "fall over and die" in the presence of memoryless nodes or other "interesting" configurations.
Quoted 7 lines
Quoted 2 lines
Agreed,
NishThe generic code currently does not fail. It (slab allocators etc) simply gets memory that it thinks comes from a memoryless node but it came from a neighboring node.
If it (slab allocators etc) wants and/or can use memory from a different node from what it requested, then, it shouldn't be calling with GFP_THISNODE, right? I mean what's the point? If GFP_THISNODE never returned off-node memory, then one couldn't use it without checking for and dealing with failure. And, 'THISNODE allocations CAN fail, when the first zone in the selected zonelist is empty and subsequent zones are off-node. __alloc_pages() et al WILL fail this case and return NULL, so callers must be prepared to deal with it--even [especially?] early boot code, IMO, anyway.
Again, I'll try your latest stack with Nish's patches and see what happens.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 3 lines · Lee Schermerhorn
If it (slab allocators etc) wants and/or can use memory from a different node from what it requested, then, it shouldn't be calling with
GFP_THISNODE, right? I mean what's the point? IfGFP_THISNODEnever
The code wanted memory from a certain node because a certain structure is performance sensitive and it did get something else. Both slab and slub will fail at some point when trying to touch the structure that was not allocated.
Quoted 2 lines
returned off-node memory, then one couldn't use it without checking for and dealing with failure. And, 'THISNODE allocations CAN fail, when the
GFP_THISNODE *never* should return off node memory. That it happened is due to people not reviewing the VM as I told them to when we starting allowing memoryless nodes in the core VM.
Quoted 4 lines
first zone in the selected zonelist is empty and subsequent zones are off-node.
__alloc_pages()et al WILL fail this case and return NULL, so callers must be prepared to deal with it--even [especially?] early boot code, IMO, anyway.
Bootstrap is a special case. It is a reasonable expectation to find memory on nodes that have memory (i.e. formerly online nodes were guaranteed to have memory now we guarantee that for "memory nodes").
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 8 lines · Christoph Lameter
Quoted 3 lines · Lee Schermerhorn
If it (slab allocators etc) wants and/or can use memory from a different node from what it requested, then, it shouldn't be calling with
GFP_THISNODE, right? I mean what's the point? IfGFP_THISNODEneverThe code wanted memory from a certain node because a certain structure is performance sensitive and it did get something else.
Yes, and if they're fine with that, why did they need to specify 'THISNODE. They called alloc_pages_node() which effectively "prefers" the specified node without the 'THISNODE flag. If they're willing to fallback to off-node allocations, just drop the THISNODE flag...
Quoted 3 lines
Both slab and slub
will fail at some point when trying to touch the structure that was not allocated.
Because they failed to check the return from an allocation?
Quoted 5 lines
Quoted 3 lines
returned off-node memory, then one couldn't use it without checking for and dealing with failure. And, 'THISNODE allocations CAN fail, when the
GFP_THISNODE*never* should return off node memory.
I agree! But the current [generic] code can and will for some hardware configurations and zonelist order.
Quoted 3 lines
That it happened is
due to people not reviewing the VM as I told them to when we starting allowing memoryless nodes in the core VM.
Certainly, more reviewing is a good thing. My review shows that an allocation with 'THISNODE specified WILL return off-node memory if the specified zonelist has an off-node zone in the first slot and some on-node memory in lower zones later in the list [node zonelist order]. This configuration does occur.
I think the disconnect is in whether we want THISNODE allocations to attempt to look past any higher off-zone nodes and return on-node memory from a lower [DMA/32] zone. Sound's like this is what you want, but the current implementation doesn't do that either, when the zonelists are in node order. It returns off-node memory for the first zone in the list, if any. If the allocation can't be satisfied from the first zone, it looks at the next. If the second or subsequent zones are off-node, it WILL fail, and never get to the on-node DMA/32 zone.
Idea: in get_page_from_freelist() [called from __alloc_pages()]:
1) enhance to add check that first zone in zonelist is also on-node--something it doesn't do now.
2) instead of bailing out when 'THISNODE is set and we encounter an off-node zone, keep scanning the zonelist for on-node zones. Bail out only if we hit the end of the list and haven't satisfied the request.
This will handle zonelists in node order with no local memory in the requested zone. 'THISNODE allocations can still fail, once the lower order local zone is exhausted, but at least it won't return off-node memory.
I'll still have an issue with huge pages coming from the DMA zone for some configurations, but I can look at tackling that from another direction.
Quoted 9 lines
Quoted 5 lines
first zone in the selected zonelist is empty and subsequent zones are off-node.
__alloc_pages()et al WILL fail this case and return NULL, so callers must be prepared to deal with it--even [especially?] early boot code, IMO, anyway.Bootstrap is a special case. It is a reasonable expectation to find memory on nodes that have memory (i.e. formerly online nodes were guaranteed to have memory now we guarantee that for "memory nodes").
Whether that expectation is reasonable seems to be configuration dependent. I still think you should be able to handle allocation failures when setting up slub caches at boot time. A BUG_ON in the boot path is very unfriendly--system stops dead. Just treat the node as memoryless from the slab/slub viewpoint if the allocation fails; or explicitly allocate slab/slub resources from a nearby node by dropping the 'THISNODE' [if THISNODE behaved consistently...] and retrying. Just don't freeze up the machine.
Later,
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
In reply to Lee SchermerhornQuoted 32 lines · Lee Schermerhorn
Quoted 13 lines · Christoph Lameter
Quoted 11 lines · Nishanth Aravamudan
Quoted 10 lines
The point of all this is that, as you've pointed out, the original NUMA and memory policy designs assumed a fairly symmetric system configuration with all nodes populated with [similar amounts?] of roughly equivalent memory. That probably describes a majority of NUMA systems, so the system should handle this well, as a default. We still need to be able to handle the less symmetric configs--with boot parameters, sysctls, cpusets, ...--that specify non-default behavior, and cause the generic code to do the right thing. Certainly, the generic code can't "fall over and die" in the presence of memoryless nodes or other "interesting" configurations.
Quoted 7 lines
Quoted 2 lines
Agreed,
NishThe generic code currently does not fail. It (slab allocators etc) simply gets memory that it thinks comes from a memoryless node but it came from a neighboring node.
If it (slab allocators etc) wants and/or can use memory from a different node from what it requested, then, it shouldn't be calling with
GFP_THISNODE, right? I mean what's the point? IfGFP_THISNODEnever returned off-node memory, then one couldn't use it without checking for and dealing with failure. And, 'THISNODE allocations CAN fail, when the first zone in the selected zonelist is empty and subsequent zones are off-node.__alloc_pages()et al WILL fail this case and return NULL, so callers must be prepared to deal with it--even [especially?] early boot code, IMO, anyway.
Quoted 2 lines
Again, I'll try your latest stack with Nish's patches and see what happens.
The three latest versions of my patches appear to apply cleanly on top of Christoph's set of 10.
Am starting testing now.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
In reply to Nishanth AravamudanQuoted 13 lines · Nishanth Aravamudan
I think your code above makes sense -- I'd still leave in the earlier check, though.
So it probably should be:
pgdat = NODE_DATA(nid); zonelist = pgdat->node_zonelists + gfp_zone(gfp_mask); if (unlikely((gfp_mask & __GFP_THISNODE) && (!node_memory(nid) || zonelist->zones[0]->zone_pgdat != pgdat))) return NULL;
Quoted 2 lines
That way, if the node has no memory whatsoever, we don't bother checking the pgdat of the relevant zone?
Checking the pgdat is already done in __alloc_pages. No need to repeat it here.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 15 lines · Christoph Lameter
Quoted 13 lines · Nishanth Aravamudan
I think your code above makes sense -- I'd still leave in the earlier check, though.
So it probably should be:
pgdat = NODE_DATA(nid); zonelist = pgdat->node_zonelists + gfp_zone(gfp_mask); if (unlikely((gfp_mask & __GFP_THISNODE) && (!node_memory(nid) || zonelist->zones[0]->zone_pgdat != pgdat))) return NULL;
Quoted 5 lines
Quoted 2 lines
That way, if the node has no memory whatsoever, we don't bother checking the pgdat of the relevant zone?
Checking the pgdat is already done in
__alloc_pages. No need to repeat it here.
Except that check is broken in the same way it is for memoryless nodes, right?
from get_page_from_freelist():
if (unlikely(NUMA_BUILD && (gfp_mask & __GFP_THISNODE) &&
zone->zone_pgdat != zonelist->zones[0]->zone_pgdat))Which asks if for this zone, is the first node the same as each node we look at for THISNODE requests. But if the first node for the zone is a *different* node, we still satisfy the request, but go off-node?
Just trying to see if that maybe is the problem here?
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 11 lines · Nishanth Aravamudan
Quoted 5 lines
Quoted 2 lines
That way, if the node has no memory whatsoever, we don't bother checking the pgdat of the relevant zone?
Checking the pgdat is already done in
__alloc_pages. No need to repeat it here.Except that check is broken in the same way it is for memoryless nodes, right?
from
get_page_from_freelist():
Quoted 8 lines
if (unlikely(NUMA_BUILD && (gfp_mask & __GFP_THISNODE) && zone->zone_pgdat != zonelist->zones[0]->zone_pgdat))Which asks if for this zone, is the first node the same as each node we look at for THISNODE requests. But if the first node for the zone is a *different* node, we still satisfy the request, but go off-node?
Just trying to see if that maybe is the problem here?
Right. But we do not have the pgdat pointer available in alloc_pages. Thus Lee's check works in alloc_pages_node(). Hmmm... This gets pretty difficult to comprehend. Maybe there is another easier way to implement GFP_THISNODE?
The breakage of SLUB makes it pretty evident that if GFP_THISNODE returns NULL for a memoryless node then lots of
for_each_online_node()
loops in the VM that assume that an online node contain memory are no longer working properly. We need to review the VM and convert those loops to use the node_memory_map.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 16 lines · Christoph Lameter
Quoted 14 lines · Nishanth Aravamudan
Quoted 5 lines
Quoted 2 lines
That way, if the node has no memory whatsoever, we don't bother checking the pgdat of the relevant zone?
Checking the pgdat is already done in
__alloc_pages. No need to repeat it here.Except that check is broken in the same way it is for memoryless nodes, right?
from
get_page_from_freelist():if (unlikely(NUMA_BUILD && (gfp_mask & __GFP_THISNODE) && zone->zone_pgdat != zonelist->zones[0]->zone_pgdat))
Quoted 8 lines
Quoted 5 lines
Which asks if for this zone, is the first node the same as each node we look at for THISNODE requests. But if the first node for the zone is a *different* node, we still satisfy the request, but go off-node?
Just trying to see if that maybe is the problem here?
Right. But we do not have the pgdat pointer available in
alloc_pages. Thus Lee's check works inalloc_pages_node().
Yep, exactly.
Quoted 2 lines
Hmmm... This gets pretty difficult to comprehend. Maybe there is another easier way to implement
GFP_THISNODE?
Well...maybe we can do better by just adding another GFP flag?
GFP_ONLYTHISNODE?
THISNODE has the current semantics, that the "closest" node is preferred, which may be local, and it will succeed if memory exists somewhere for the allocation you want (I think).
ONLYTHISNODE will return NULL if it has to go off-node for any reason.
Quoted 8 lines
The breakage of SLUB makes it pretty evident that if
GFP_THISNODEreturns NULL for a memoryless node then lots of
for_each_online_node()loops in the VM that assume that an online node contain memory are no longer working properly. We need to review the VM and convert those loops to use the
node_memory_map.
That would avoid having to make these changes too.
Maybe with time, we can audit the users of THISNODE and move them over to ONLYTHISNODE, as appropriate?
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 7 lines · Nishanth Aravamudan
Well...maybe we can do better by just adding another GFP flag?
GFP_ONLYTHISNODE?THISNODE has the current semantics, that the "closest" node is preferred, which may be local, and it will succeed if memory exists somewhere for the allocation you want (I think).
No we want one GFP_THISNODE working in a consistent way.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 11 lines · Christoph Lameter
Quoted 7 lines · Nishanth Aravamudan
Well...maybe we can do better by just adding another GFP flag?
GFP_ONLYTHISNODE?THISNODE has the current semantics, that the "closest" node is preferred, which may be local, and it will succeed if memory exists somewhere for the allocation you want (I think).
No we want one
GFP_THISNODEworking in a consistent way.
Ok, I've started auditing things. I have a final exam tomorrow, however, so probably won't make much progress before then.
I did notice that ia64/mm/discontig.c actually already tries to deal with memoryless nodes, but all static to that file. See memory_less_mask. Probably can be replaced via an inverted node_memory_map.
Are you sure just the VM needs to be audited? I'm going to try the other way around and look at GFP_THISNODE callers and go up from there.
Will let you know what I find.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
In reply to Christoph LameterQuoted 15 lines · Christoph Lameter
Quoted 13 lines · Nishanth Aravamudan
I think your code above makes sense -- I'd still leave in the earlier check, though.
So it probably should be:
pgdat = NODE_DATA(nid); zonelist = pgdat->node_zonelists + gfp_zone(gfp_mask); if (unlikely((gfp_mask & __GFP_THISNODE) && (!node_memory(nid) || zonelist->zones[0]->zone_pgdat != pgdat))) return NULL;
Quoted 5 lines
Quoted 2 lines
That way, if the node has no memory whatsoever, we don't bother checking the pgdat of the relevant zone?
Checking the pgdat is already done in
__alloc_pages. No need to repeat it here.
As discussed in prior mail, that's too late given the check that's being done. Down in get_page_from_freelist(), where this check is made, we don't have the node id nor pgdat from which the allocation is being attempted. The node id of the first zone in the list may already be off-node [even tho' the node_memory_map says the node is populated/has memory], so we can't rely on that.
I suppose we could add the pgdat pointer to the zonelist itself or try to backup to the original pgdat from the zonelist and gfp_zone(gfp_mask). Then we could do the check in get_page_from_freelist() that each zone in the list is on-node.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
In reply to Lee SchermerhornQuoted 6 lines · Lee Schermerhorn
alloc_fresh_huge_page()loop. However, I think that to support all platforms in a generic way,alloc_pages_node()andalloc_page_interleave()[both take a node id arg] should be more strict when the gfp mask includes 'THISNODE and not assume that a populated node always has on-node memory in the zone of interest. E.g., something like:
So a node with memory may have no memory in that particular zone.
This can only be true for DMA and DMA32. So we need a node_has_dma(node)?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
In reply to Lee SchermerhornQuoted 16 lines · Lee Schermerhorn
Quoted 9 lines · Christoph Lameter
Quoted 5 lines · Lee Schermerhorn
Well, my patch [v4] fixed it on my platform. So this is a regression relative to my patch. But, then, my patch had an issue with an
x86_64system where one node is all/mostly DMA32 and other nodes have memory in higher zones. Maybe that's OK [or not] for hugepage allocation, but almost certainly not for regular page interleaving, ...Well this means your patch was arch specific.
Worse than that--the problem is platform specific. I thought the patch was generic--that's what I was striving for. I just hadn't thought through the implications for
x86_64platforms with just the right amount of memory to cause a problem.
Quoted 7 lines
I tested on a 2 socket, 4GB blade. All memory, both nodes, was DMA32 or lower, so
policy_zone==ZONE_DMA32and it worked fine. I tested on a 4 socket, 32GB server--8GB per node.Policy_zonewasZONE_NORMAL, but all nodes had at least 4G of normal memory. For thenr_hugepagesthat I tried, I saw the pages allocated evenly across the nodes. Guess I didn't ask for enough pages to consume all of the normal memory on node 0 to see any imbalance thereafter.
Yeah, it's tricky to get testing across all the corner cases, to say the least. Although between the two of us, we might have enough h/w that breaks assumptions :)
Quoted 20 lines
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
I'm much more concerned in the short term about the whole memoryless-node issue, which I think is more straight-forward, and generic to fix.
Quoted 8 lines
Quoted 5 lines
Perhaps, but I think we're still going to get off node allocations with the revised definition of the populated map and the new zonelist ordering. I think we'll need to check for and reject off-node allocations when '
_THISNODEis specified. We can't assume that the first zone in a node's zonelist for a givengfp_zoneis on-node.We do not do that anymore.
GFP_THISNODEguarantees the allocation on the node withalloc_pages_node. Read on.I have been reading. Might work as you say. Not because you're testing the populated map in
alloc_pages_node(). That can still pass an off-node zonelist to__alloc_pages(). However, I'm hoping that the test of thezone_pgdatinget_page_from_freelist()will do the right thing. I'm referring to:
Quoted 8 lines
if (unlikely(NUMA_BUILD && (gfp_mask & __GFP_THISNODE) && zone->zone_pgdat != zonelist->zones[0]->zone_pgdat)) break;But, I'm not convinced that zonelist->zones[0]->zone_pgdat always refers to the node specified the 'nid' argument of
alloc_pages_node(). It was with my definition of the populated map, but I don't think so, now.
It doesn't, for sure. That is the problem for memoryless nodes. But, we bail out of alloc_pages_node if GFP_THISNODE and !node_populated(nid) now, so we shouldn't hit __alloc_pages (and thus not hit get_page_from_freelist) in that path. Still trying to get a handle on the other paths...
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
In reply to Lee SchermerhornQuoted 9 lines · Lee Schermerhorn
page = alloc_pages_node(nid, GFP_HIGHUSER|__GFP_COMP|GFP_THISNODE, HUGETLB_PAGE_ORDER);I need to get a page that is on nid. On our platform,
GFP_HIGHUSERis going to specify the zonelist forZONE_NORMAL. The first zone on this list needs to be on-node for nid. With the changes you've made to the definition of populated map, I think this won't be the case. I need to test your latest patches and fix that, if it's broken.
Yes that is the intend of the fixes.
Quoted 7 lines
I still think using policy zone is the "right way" to go, here. After all, only pages in the policy zone are controlled by policy, and that's the goal of spreading out the huge pages across nodes--to make them available to satisfy memory policy at allocation time. But that would need some adjustments for
x86_64systems that have some nodes that are all/mostly DMA32 and other nodes that are populated in zones > DMA32, if we want to allocate huge pages out of the DMA32 zone.
GFP_THISNODE will work right for that case if we get the intended fix in.
Quoted 10 lines
As far as the static variable, and round-robin allocation: the current method "works" both for huge pages allocated at boot time and for huge pages allocated at run-time vi the vm.nr_hugepages sysctl. By "works", I mean that it continues to spread the pages evenly across the "populated" nodes. If, however, you use the task local counter to interleave fresh huge pages, each write to the
nr_hugepagesfrom a different task ["echo NN >.../nr_hugepages"] will start at node zero or the first populated node--assuming you're interleaving across populated nodes and not on-line nodes. That's probably OK if you always change
We may want to change that behavior. Interleave should start at the local node and then proceed from there. If there are just a few pages needed then they would be better placed local to the process.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 22 lines · Christoph Lameter
Quoted 9 lines · Lee Schermerhorn
page = alloc_pages_node(nid, GFP_HIGHUSER|__GFP_COMP|GFP_THISNODE, HUGETLB_PAGE_ORDER);I need to get a page that is on nid. On our platform,
GFP_HIGHUSERis going to specify the zonelist forZONE_NORMAL. The first zone on this list needs to be on-node for nid. With the changes you've made to the definition of populated map, I think this won't be the case. I need to test your latest patches and fix that, if it's broken.Yes that is the intend of the fixes.
Quoted 7 lines
I still think using policy zone is the "right way" to go, here. After all, only pages in the policy zone are controlled by policy, and that's the goal of spreading out the huge pages across nodes--to make them available to satisfy memory policy at allocation time. But that would need some adjustments for
x86_64systems that have some nodes that are all/mostly DMA32 and other nodes that are populated in zones > DMA32, if we want to allocate huge pages out of the DMA32 zone.
Quoted 1 line
GFP_THISNODEwill work right for that case if we get the intended fix in.
OK. So, allocations with 'THISNODE will ensure that we don't get an off-node page if the any zone in the zonelist indicated by the gfp zone happens to point off-node? That wasn't the case previously, and that's why I created the populated map with the semantics I did. I agree it's better to have alloc_page_*() handle this.
Quoted 12 lines
Quoted 11 lines
As far as the static variable, and round-robin allocation: the current method "works" both for huge pages allocated at boot time and for huge pages allocated at run-time vi the vm.nr_hugepages sysctl. By "works", I mean that it continues to spread the pages evenly across the "populated" nodes. If, however, you use the task local counter to interleave fresh huge pages, each write to the
nr_hugepagesfrom a different task ["echo NN >.../nr_hugepages"] will start at node zero or the first populated node--assuming you're interleaving across populated nodes and not on-line nodes. That's probably OK if you always change
Quoted 3 lines
We may want to change that behavior. Interleave should start at the local node and then proceed from there. If there are just a few pages needed then they would be better placed local to the process.
For page interleaving for some memory object, I agree. The usage here was for the allocation of reserved huge pages--trying to spread those
evenly across nodes with appropriate [non-DMA] memory. Then, normal
interleaving will work as huge pages are allocated from the per node reserved lists until some node's huge pages are exhausted.
I think that using a local "cursor", as you propose, will work, tho'--even for spreading huge page allocations for the reserved lists. We may tend to favor low order nodes if one incrementally increases nr_hugepages via the sysctl. But, I don't think that's too regular an occurrence. I'm not sure Nish can use the mempolicy huge page interleaving allocator, tho' That allocates FROM the per node reserved lists, and alloc_fresh_huge_page[_node]() is used to fill those lists.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH] populated_map: fix !NUMA case, remove comment
Quoted 7 lines · Lee Schermerhorn
I think that using a local "cursor", as you propose, will work, tho'--even for spreading huge page allocations for the reserved lists. We may tend to favor low order nodes if one incrementally increases
nr_hugepagesvia the sysctl. But, I don't think that's too regular an occurrence. I'm not sure Nish can use the mempolicy huge page interleaving allocator, tho' That allocates FROM the per node reserved lists, and alloc_fresh_huge_page[_node]() is used to fill those lists.
Yeah one would need to put some thought into it to have the logic in one place so that future maintenance will be easier.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 25 lines · Christoph Lameter
Quoted 2 lines · Nishanth Aravamudan
Already done in the original patch (
node_populated()returns (node == 0) ifMAX_NUMODES<= 1), I think.Ah good.
Quoted 18 lines
mm/page_alloc.c +12
-0@@ -2299,6 +2303,18 @@ static void build_zonelists(pg_data_t *pgdat)/* calculate node order -- i.e., DMA last! */ build_zonelists_in_zone_order (pgdat, j); } + +/* +* record nodes whose first fallback zone is "on-node" as +* populated +*/ + z = pgdat->node_zonelists->zones[0 ]; + +VM_BUG_ON (!z); +if (z->zone_pgdat == pgdat) +node_set_populated (local_node); +else +node_not_populated (local_node); }
Quoted 7 lines
mm/page_alloc.c static void build_zonelists(pg_data_t *pgdat) · line 2320
Quoted 2 lines
mm/page_alloc.c +0
-0/* Construct the zonelist performance cache - see further mmzone.h */ Could be much simpler:
if (
pgdat->node_present_pages)node_set_populated(local_node);
As a minimum, we need to exclude a node with only zone DMA memory for this to work on our platforms. For that, I think the current code is the simplest because we still need to check if the first zone is "on-node" and !DMA.
And, I think we need both cases--set and reset populated map bit--to handle memory/node hotplug. So something like:
if (z->zone_pgdat == pgdat && !is_zone_dma(z)) node_set_populated(local_node); else node_not_populated(local_node);
Need to define 'is_zone-dma()' to test the zone or unconditionally return false depending on whether ZONE_DMA is configured.
I will repost Nish's repost to "fix" this.
Lee
Quoted 2 lines
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 34 lines · Lee Schermerhorn
Quoted 25 lines · Christoph Lameter
Quoted 2 lines · Nishanth Aravamudan
Already done in the original patch (
node_populated()returns (node == 0) ifMAX_NUMODES<= 1), I think.Ah good.
Quoted 18 lines
mm/page_alloc.c +12
-0@@ -2299,6 +2303,18 @@ static void build_zonelists(pg_data_t *pgdat)/* calculate node order -- i.e., DMA last! */ build_zonelists_in_zone_order (pgdat, j); } + +/* +* record nodes whose first fallback zone is "on-node" as +* populated +*/ + z = pgdat->node_zonelists->zones[0 ]; + +VM_BUG_ON (!z); +if (z->zone_pgdat == pgdat) +node_set_populated (local_node); +else +node_not_populated (local_node); }Quoted 7 lines
mm/page_alloc.c static void build_zonelists(pg_data_t *pgdat) · line 2320
Quoted 2 lines
mm/page_alloc.c +0
-0/* Construct the zonelist performance cache - see further mmzone.h */ Could be much simpler:
if (
pgdat->node_present_pages)node_set_populated(local_node);
Quoted 7 lines
As a minimum, we need to exclude a node with only zone DMA memory for this to work on our platforms. For that, I think the current code is the simplest because we still need to check if the first zone is "on-node" and !DMA.
And, I think we need both cases--set and reset populated map bit--to handle memory/node hotplug. So something like:
That's a good point -- build_zonelists() will get called for the rebuild, but won't remove nodes from the populated_map. Admittedly, only hot-add is currently supported, right?
Quoted 4 lines
if (z->zone_pgdat == pgdat && !is_zone_dma(z)) node_set_populated(local_node); else node_not_populated(local_node);
Hrm, but then node_populated == node has non-DMA pages, which is altogether unintuitive. Again, I think this obfuscates things -- perhaps the map should be renamed to something closer to what you actually want it to represent?
Quoted 2 lines
Need to define 'is_zone-dma()' to test the zone or unconditionally return false depending on whether
ZONE_DMAis configured.
@Andrew: would you be ok dropping the populated_map patches while I hammer out whether it's what we want with Lee; and decide whether the fix-patch on top is needed, as well, based on Christoph's feedback?
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 9 lines · Lee Schermerhorn
Quoted 4 lines
Could be much simpler:
if (
pgdat->node_present_pages)node_set_populated(local_node);As a minimum, we need to exclude a node with only zone DMA memory for this to work on our platforms. For that, I think the current code is the simplest because we still need to check if the first zone is "on-node" and !DMA.
You are changing the definition of populated node.
Quoted 2 lines
And, I think we need both cases--set and reset populated map bit--to handle memory/node hotplug. So something like:
Yes memory unplug will need to clear the bit if a complete node is cleared. But we do not support node unplug yet. So it is okay for now and it is doubtful that the build_zonelist function is going to be called for the node that is being removed.
Quoted 2 lines
Need to define 'is_zone-dma()' to test the zone or unconditionally return false depending on whether
ZONE_DMAis configured.
CONFIG_ZONE_DMA already exists.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 7 lines · Christoph Lameter
Quoted 5 lines · Lee Schermerhorn
Quoted 4 lines
Could be much simpler:
if (
pgdat->node_present_pages)node_set_populated(local_node);
Quoted 6 lines
Quoted 4 lines
As a minimum, we need to exclude a node with only zone DMA memory for this to work on our platforms. For that, I think the current code is the simplest because we still need to check if the first zone is "on-node" and !DMA.
You are changing the definition of populated node.
Well, I initially created the populated node map to mean nodes that contained memory at "policy zone"--specifically for use by the huge page allocator. I did this because you and others didn't want the hugetlb code to know about the innards of zonelists, etc. Made sense, so I came up with a definition that worked for the platforms I tried it on. However, as we've discussed here, it would prevent allocation of hugepages on a DMA32-only x86_64 node if any other node had higher order memory.
Now, Nish is proposing to use the populated map to filter policy-based interleaved allocations. My definition of populated map won't work for that. So, YOU are the one changing the definition. I'm OK with that if it solves a more generic problem. My patch hadn't gone in anyway.
Quoted 8 lines
Quoted 2 lines
And, I think we need both cases--set and reset populated map bit--to handle memory/node hotplug. So something like:
Yes memory unplug will need to clear the bit if a complete node is cleared. But we do not support node unplug yet. So it is okay for now and it is doubtful that the
build_zonelistfunction is going to be called for the node that is being removed.
Quoted 4 lines
Quoted 2 lines
Need to define 'is_zone-dma()' to test the zone or unconditionally return false depending on whether
ZONE_DMAis configured.
CONFIG_ZONE_DMAalready exists.
Yes, but I didn't want to stick #ifdefs in the functions if I didn't have to. But, it's a moot point. After looking at it more, I've decided there may be no definition of populated map that works reliably for huge page allocation on all of the platform configurations. However, if GFP_THISNODE guarantees no off-node allocations, that may do the trick.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 5 lines · Lee Schermerhorn
On Tue, 2007-06-12 at 11:45 -0700, Christoph Lameter wrote:
Now, Nish is proposing to use the populated map to filter policy-based interleaved allocations. My definition of populated map won't work for that. So, YOU are the one changing the definition. I'm OK with that if it solves a more generic problem. My patch hadn't gone in anyway.
Ok. So how about renaming the populated_map to
node_memory_map
so that its clear that this is a map of node with memory?
GFP_THISNODE needs this map to fail on memoryless nodes.
Quoted 6 lines
Yes, but I didn't want to stick #ifdefs in the functions if I didn't have to. But, it's a moot point. After looking at it more, I've decided there may be no definition of populated map that works reliably for huge page allocation on all of the platform configurations. However, if
GFP_THISNODEguarantees no off-node allocations, that may do the trick.
It can do that if the populated map works the right way.... circle is closing ... I can sent out a patchset in a few minutes that fixes the GFP_THISNODE issue and introduces node_memory_map.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 23 lines · Christoph Lameter
Quoted 5 lines · Lee Schermerhorn
On Tue, 2007-06-12 at 11:45 -0700, Christoph Lameter wrote:
Now, Nish is proposing to use the populated map to filter policy-based interleaved allocations. My definition of populated map won't work for that. So, YOU are the one changing the definition. I'm OK with that if it solves a more generic problem. My patch hadn't gone in anyway.Ok. So how about renaming the
populated_mapto
node_memory_mapso that its clear that this is a map of node with memory?
GFP_THISNODEneeds this map to fail on memoryless nodes.Quoted 6 lines
Yes, but I didn't want to stick #ifdefs in the functions if I didn't have to. But, it's a moot point. After looking at it more, I've decided there may be no definition of populated map that works reliably for huge page allocation on all of the platform configurations. However, if
GFP_THISNODEguarantees no off-node allocations, that may do the trick.
Quoted 3 lines
It can do that if the populated map works the right way.... circle is closing ... I can sent out a patchset in a few minutes that fixes the
GFP_THISNODEissue and introducesnode_memory_map.
Something like the following (need to s/populated/memory/ as approparitely, still... so not s-o-b...
include/linux/gfp.h +3 -0
@@ -175,6 +175,9 @@ static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,if (nid <0 ) nid =numa_node_id (); +if ((gfp_mask & __GFP_THISNODE) && !node_is_populated (nid)) +return NULL ; +return __alloc_pages (gfp_mask, order,NODE_DATA (nid)->node_zonelists +gfp_zone (gfp_mask)); }
include/linux/nodemask.h +11 -0
@@ -70,6 +70,10 @@* node_set_online(node) set bit 'node' in node_online_map * node_set_offline(node) clear bit 'node' in node_online_map * +* node_set_populated(node) set bit 'node' in node_populated_map +* node_set_unpopulated(node) clear bit 'node' in node_populated_map +* int node_is_populated(node) Does some node have pages_present != 0? +* * for_each_node(node) for-loop node over node_possible_map * for_each_online_node(node) for-loop node over node_online_map *
@@ -353,6 +357,10 @@ extern nodemask_t node_possible_map;#define first_online_node first_node(node_online_map)#define next_online_node (nid) next_node((nid), node_online_map)extern int nr_node_ids; +extern nodemask_t node_populated_map; +#define node_set_populated (node) set_bit((node), node_populated_map.bits) +#define node_set_unpopulated (node) clear_bit((node), node_populated_map.bits) +#define node_is_populated (node) node_isset((node), node_populated_map)#else #define num_online_nodes () 1#define num_possible_nodes () 1
@@ -361,6 +369,9 @@ extern int nr_node_ids;#define first_online_node 0#define next_online_node (nid) (MAX_NUMNODES)#define nr_node_ids 1 +#define node_set_populated (node) do { } while (0) +#define node_set_unpopulated (node) do { } while (0) +#define node_is_populated (nid) ((node) == 0)#endif #define any_online_node (mask) \
mm/page_alloc.c +9 -0
@@ -54,6 +54,8 @@ nodemask_t node_online_map __read_mostly = { { [0] = 1UL } };EXPORT_SYMBOL (node_online_map);nodemask_t node_possible_map__read_mostly =NODE_MASK_ALL ;EXPORT_SYMBOL (node_possible_map); +nodemask_t node_populated_map__read_mostly = { { [0 ] =1UL } }; +EXPORT_SYMBOL (node_populated_map);unsigned long totalram_pages__read_mostly ;unsigned long totalreserve_pages__read_mostly ;long nr_swap_pages;
@@ -2299,6 +2301,13 @@ static void build_zonelists(pg_data_t *pgdat)/* calculate node order -- i.e., DMA last! */ build_zonelists_in_zone_order (pgdat, j); } + +/* +* Node and Memory Hot-Unplug will need to invoke +* node_set_unpopulated if a node is made to be memory-less +*/ +if (pgdat->node_present_pages) +node_set_populated (local_node); }/* Construct the zonelist performance cache - see further mmzone.h */
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
I thought more along these lines?
NUMA: introduce node_memory_map
It is necessary to know if nodes have memory since we have recently begun to add support for memoryless nodes. For that purpose we introduce a new bitmap called
node_memory_map
A node has its bit in node_memory_map set if it has memory. If a node has memory then it has at least one zone defined in its pgdat structure that is located in the pgdat itself.
The node_memory_map can then be used in various places to insure that we do the right thing when we encounter a memoryless node.
include/linux/nodemask.h +10 -0
@@ -64,12 +64,16 @@* * int node_online(node) Is some node online? * int node_possible(node) Is some node possible? +* int node_memory(node) Does a node have memory? * * int any_online_node(mask) First online node in mask * * node_set_online(node) set bit 'node' in node_online_map * node_set_offline(node) clear bit 'node' in node_online_map * +* node_set_memory(node) set bit 'node' in node_memory_map +* node_clear_memoryd(node) clear bit 'node' in node_memory_map +* * for_each_node(node) for-loop node over node_possible_map * for_each_online_node(node) for-loop node over node_online_map *
@@ -344,12 +348,14 @@ static inline void __nodes_remap(nodemasextern nodemask_t node_online_map;extern nodemask_t node_possible_map; +extern nodemask_t node_memory_map;#if MAX_NUMNODES >1 #define num_online_nodes () nodes_weight(node_online_map)#define num_possible_nodes () nodes_weight(node_possible_map)#define node_online (node) node_isset((node), node_online_map)#define node_possible (node) node_isset((node), node_possible_map) +#define node_memory (node) node_isset((node), node_memory_map)#define first_online_node first_node(node_online_map)#define next_online_node (nid) next_node((nid), node_online_map)extern int nr_node_ids;
@@ -358,6 +364,7 @@ extern int nr_node_ids;#define num_possible_nodes () 1#define node_online (node) ((node) == 0)#define node_possible (node) ((node) == 0) +#define node_populated (node) ((node) == 0)#define first_online_node 0#define next_online_node (nid) (MAX_NUMNODES)#define nr_node_ids 1
@@ -375,6 +382,9 @@ extern int nr_node_ids;#define node_set_online (node) set_bit((node), node_online_map.bits)#define node_set_offline (node) clear_bit((node), node_online_map.bits) +#define node_set_memory (node) set_bit((node), node_memory_map.bits) +#define node_clear_memory (node) clear_bit((node), node_memory_map.bits) +#define for_each_node (node) for_each_node_mask((node), node_possible_map)#define for_each_online_node (node) for_each_node_mask((node), node_online_map)
mm/page_alloc.c +6 -0
@@ -54,6 +54,9 @@ nodemask_t node_online_map __read_mostlyEXPORT_SYMBOL (node_online_map);nodemask_t node_possible_map__read_mostly =NODE_MASK_ALL ;EXPORT_SYMBOL (node_possible_map); +nodemask_t node_memory_map__read_mostly =NODE_MASK_NONE ; +EXPORT_SYMBOL (node_memory_map); +unsigned long totalram_pages__read_mostly ;unsigned long totalreserve_pages__read_mostly ;long nr_swap_pages;
@@ -2299,6 +2302,9 @@ static void build_zonelists(pg_data_t *p/* calculate node order -- i.e., DMA last! */ build_zonelists_in_zone_order (pgdat, j); } + +if (pgdat->node_present_pages) +node_set_memory (local_node); }/* Construct the zonelist performance cache - see further mmzone.h */
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 29 lines · Christoph Lameter
I thought more along these lines?
NUMA: introduce
node_memory_mapIt is necessary to know if nodes have memory since we have recently begun to add support for memoryless nodes. For that purpose we introduce a new bitmap called
node_memory_mapA node has its bit in
node_memory_mapset if it has memory. If a node has memory then it has at least one zone defined in its pgdat structure that is located in the pgdat itself.The
node_memory_mapcan then be used in various places to insure that we do the right thing when we encounter a memoryless node.Signed-off-by Lee Schermerhorn <[email protected]>Signed-off-by Nishanth Aravamudan <[email protected]>Signed-off-by Christoph Lameter <[email protected]>Index:
linux-2.6.22-rc4-mm2/include/linux/nodemask.h
===================================================================include/linux/nodemask.h +0
-0@@ -64,12 +64,16 @@* * int node_online(node) Is some node online? * int node_possible(node) Is some node possible?
include/linux/nodemask.h line 76
Quoted 10 lines
include/linux/nodemask.h +4
-0+* int node_memory(node) Does a node have memory? * * int any_online_node(mask) First online node in mask * * node_set_online(node) set bit 'node' in node_online_map * node_set_offline(node) clear bit 'node' in node_online_map * +* node_set_memory(node) set bit 'node' in node_memory_map +* node_clear_memoryd(node) clear bit 'node' in node_memory_map +*
These are terrible names :) Something more like node_set_has_memory(node) and node_set_has_no_memory(node), maybe? [why be arbitrarily different than node_set_{on,off}line?].
And there is a typo ;)
Quoted 41 lines
include/linux/nodemask.h +6
-0* for_each_node(node) for-loop node over node_possible_map * for_each_online_node(node) for-loop node over node_online_map * @@ -344,12 +348,14 @@ static inline void __nodes_remap(nodemasextern nodemask_t node_online_map;extern nodemask_t node_possible_map; +extern nodemask_t node_memory_map;#if MAX_NUMNODES >1 #define num_online_nodes () nodes_weight(node_online_map)#define num_possible_nodes () nodes_weight(node_possible_map)#define node_online (node) node_isset((node), node_online_map)#define node_possible (node) node_isset((node), node_possible_map) +#define node_memory (node) node_isset((node), node_memory_map)#define first_online_node first_node(node_online_map)#define next_online_node (nid) next_node((nid), node_online_map)extern int nr_node_ids;@@ -358,6 +364,7 @@ extern int nr_node_ids;#define num_possible_nodes () 1#define node_online (node) ((node) == 0)#define node_possible (node) ((node) == 0) +#define node_populated (node) ((node) == 0)#define first_online_node 0#define next_online_node (nid) (MAX_NUMNODES)#define nr_node_ids 1@@ -375,6 +382,9 @@ extern int nr_node_ids;#define node_set_online (node) set_bit((node), node_online_map.bits)#define node_set_offline (node) clear_bit((node), node_online_map.bits) +#define node_set_memory (node) set_bit((node), node_memory_map.bits) +#define node_clear_memory (node) clear_bit((node), node_memory_map.bits) +#define for_each_node (node) for_each_node_mask((node), node_possible_map)#define for_each_online_node (node) for_each_node_mask((node), node_online_map)Index:
linux-2.6.22-rc4-mm2/mm/page_alloc.c
===================================================================
mm/page_alloc.c nodemask_t node_online_map __read_mostly · line 58
Quoted 5 lines
mm/page_alloc.c +2
-0@@ -54,6 +54,9 @@ nodemask_t node_online_map __read_mostlyEXPORT_SYMBOL (node_online_map);nodemask_t node_possible_map__read_mostly =NODE_MASK_ALL ;EXPORT_SYMBOL (node_possible_map); +nodemask_t node_memory_map__read_mostly =NODE_MASK_NONE ; +EXPORT_SYMBOL (node_memory_map);
SERIOUSLY!? After saying that node_populated_map should be NUMA-only over and over, you made it global here :-P
mm/page_alloc.c static void build_zonelists(pg_data_t *p · line 2308
Quoted 11 lines
mm/page_alloc.c +3
-0unsigned long totalram_pages__read_mostly ;unsigned long totalreserve_pages__read_mostly ;long nr_swap_pages;@@ -2299,6 +2302,9 @@ static void build_zonelists(pg_data_t *p/* calculate node order -- i.e., DMA last! */ build_zonelists_in_zone_order (pgdat, j); } + +if (pgdat->node_present_pages) +node_set_memory (local_node); }
Other than the naming, looks sane.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 2 lines · Nishanth Aravamudan
SERIOUSLY!? After saying that
node_populated_mapshould be NUMA-only over and over, you made it global here :-P
yeah looking at it: The nodemask_t becomes very small so its not worth it.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 4 lines · Nishanth Aravamudan
These are terrible names :) Something more like
node_set_has_memory(node)andnode_set_has_no_memory(node), maybe? [why be arbitrarily different than node_set_{on,off}line?].
Because node_set_on/off is already inconsisted with node_set and node_clear.
Another possible name may be
node_clear_has_memorynode_clear_has_memory
but that is awkward.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Interleave fix patch:
Fix MPOL_INTERLEAVE behavior for memoryless nodes
MPOL_INTERLEAVE currently simply loops over all nodes. Allocations on memoryless nodes will be redirected to nodes with memory. This results in an imbalance because the neighboring nodes to memoryless nodes will get significantly more interleave hits that the rest of the nodes on the system.
We can avoid this imbalance by clearing the nodes in the interleave node set that have no memory.
mm/mempolicy.c +1 -0
@@ -185,6 +185,7 @@ static struct mempolicy *mpol_new(int moswitch (mode) {case MPOL_INTERLEAVE : policy->v.nodes = *nodes; +nodemask_and (policy->v.nodes, policy->v.nodes, node_memory_map);if (nodes_weight (*nodes) ==0 ) {kmem_cache_free (policy_cache, policy);return ERR_PTR (-EINVAL );
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
mm/mempolicy.c static struct mempolicy *mpol_new(int mo · line 188
Quoted 1 line · Christoph Lameter
mm/mempolicy.c +1
-0+nodemask_and (policy->v.nodes, policy->v.nodes, node_memory_map);
^^^ has to be nodes_and
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 20 lines · Christoph Lameter
Interleave fix patch:
Fix
MPOL_INTERLEAVEbehavior for memoryless nodes
MPOL_INTERLEAVEcurrently simply loops over all nodes. Allocations on memoryless nodes will be redirected to nodes with memory. This results in an imbalance because the neighboring nodes to memoryless nodes will get significantly more interleave hits that the rest of the nodes on the system.We can avoid this imbalance by clearing the nodes in the interleave node set that have no memory.
Signed-off-by Christoph Lameter <[email protected]>Signed-off-by Nishanth Aravamudan <[email protected]>Index:
linux-2.6.22-rc4-mm2/mm/mempolicy.c
===================================================================
mm/mempolicy.c static struct mempolicy *mpol_new(int mo · line 189
Quoted 5 lines
mm/mempolicy.c +1
-0@@ -185,6 +185,7 @@ static struct mempolicy *mpol_new(int moswitch (mode) {case MPOL_INTERLEAVE : policy->v.nodes = *nodes; +nodemask_and (policy->v.nodes, policy->v.nodes, node_memory_map);if (nodes_weight (*nodes) ==0 ) {
Shouldn't this be changed to
if (nodes_weight(policy->v.nodes) == 0) {??
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 12 lines · Nishanth Aravamudan
mm/mempolicy.c static struct mempolicy *mpol_new(int mo · line 189
Quoted 9 lines
===================================================================
mm/mempolicy.c +1
-0@@ -185,6 +185,7 @@ static struct mempolicy *mpol_new(int moswitch (mode) {case MPOL_INTERLEAVE : policy->v.nodes = *nodes; +nodemask_and (policy->v.nodes, policy->v.nodes, node_memory_map);if (nodes_weight (*nodes) ==0 ) {Shouldn't this be changed to
Quoted 1 line
if (nodes_weight(policy->v.nodes) == 0) {You are right. Fix applied. I will post a patchset when I got my testing done.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 38 lines · Christoph Lameter
Quoted 10 lines · Nishanth Aravamudan
mm/page_alloc.c +1
-1@@ -2161,7 +2164,7 @@ static int node_order[MAX_NUMNODES];static void build_zonelists_in_zone_order (pg_data_t *pgdat,int nr_nodes) {enum zone_type i; -int pos, j, node; +int pos, j;int zone_type;/* needs to be signed */ struct zone *z;struct zonelist *zonelist;mm/page_alloc.c static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes) · line 2180
Quoted 8 lines
mm/page_alloc.c +1
-1@@ -2171,7 +2174,7 @@ static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes) pos =0 ;for (zone_type = i; zone_type >=0 ; zone_type--) {for (j =0 ; j < nr_nodes; j++) { - node = node_order[j]; +int node = node_order[j]; z = &NODE_DATA (node)->node_zones[zone_type];if (populated_zone (z)) { zonelist->zones[pos++] = z;Unrelated modifications.
Quoted 15 lines
mm/page_alloc.c +11
-0@@ -2244,6 +2247,22 @@ static void set_zonelist_order(void) current_zonelist_order = user_zonelist_order; } +/* +* setup_populate_map() - record nodes whose "policy_zone" is "on-node". +*/ +static void setup_populated_map (int nid) +{ +pg_data_t *pgdat =NODE_DATA (nid); +struct zonelist *zl = pgdat->node_zonelists + policy_zone; +struct zone *z = zl->zones[0 ]; + +VM_BUG_ON (!z); +if (z->zone_pgdat == pgdat)
Quoted 8 lines
mm/page_alloc.c static void set_zonelist_order(void) · line 2264
Quoted 4 lines
mm/page_alloc.c +4
-0+node_set_populated (nid); + else +node_not_populated (nid ); +}A node is only populated if it has memory in the policy zone? I would say a node is populated if it has any memory in any zone.
Mea culpa. Our platforms have a [pseudo-]node with just O(1G) memory all in zone DMA. That node can't look populated for allocating huge pages.
Quoted 4 lines
The above check may fail on
x86_64where only some nodes may haveZONE_NORMAL. Others only haveZONE_DMA32. Policy zone will be set toZONE_NORMAL.
Yes. I thought of this after I created the patch. I've been looking for a platform with exactly 4GB per node to test on. I believe that, on our platforms, all of node zero would be in zone DMA32 and all other nodes would be > DMA32.
Maybe we can just exclude zone DMA from the populated map?
Quoted 37 lines
Quoted 8 lines
mm/page_alloc.c +1
-0+static void build_zonelists (pg_data_t *pgdat) {int j, node, load;@@ -2327,6 +2346,15 @@ static void set_zonelist_order(void) current_zonelist_order =ZONELIST_ORDER_ZONE ;mm/page_alloc.c static void set_zonelist_order(void) · line 2356
Quoted 10 lines
mm/page_alloc.c +8
-0} +/* +* setup_populated_map - non-NUMA case +* Only node 0 should be on-line, and it MUST be populated! +*/ +static void setup_populated_map (int nid) +{ +node_set_populated (nid); +}I'd say provide fallback functions so that
node_populated()always returns true for !NUMA. That way it can be optimized out at compile time.mm/page_alloc.c static void set_zonelist_order(void) · line 2360
Quoted 3 lines
mm/page_alloc.c +0
-0static void build_zonelists (pg_data_t *pgdat) {int node, local_node;I'd say provide fallback functions so that
node_populated()always returns true for !NUMA. That way it can be optimized out at compile time.mm/page_alloc.c static int __build_all_zonelists(void *dummy) · line 2413
Quoted 6 lines
mm/page_alloc.c +1
-0@@ -2381,6 +2409,7 @@ static int __build_all_zonelists(void *dummy)for_each_online_node (nid) {build_zonelists (NODE_DATA (nid));build_zonelist_cache (NODE_DATA (nid)); +setup_populated_map (nid); }Is it possible to move the
set_populated_nodeintobuild_zonelistssomehow?
Quoted 3 lines
F.e. In
build_zonelists_nodeyou can check ifnr_zones> 0 and then set it up?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 48 lines · Lee Schermerhorn
Quoted 38 lines · Christoph Lameter
Quoted 10 lines · Nishanth Aravamudan
mm/page_alloc.c +1
-1@@ -2161,7 +2164,7 @@ static int node_order[MAX_NUMNODES];static void build_zonelists_in_zone_order (pg_data_t *pgdat,int nr_nodes) {enum zone_type i; -int pos, j, node; +int pos, j;int zone_type;/* needs to be signed */ struct zone *z;struct zonelist *zonelist;mm/page_alloc.c static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes) · line 2180
Quoted 8 lines
mm/page_alloc.c +1
-1@@ -2171,7 +2174,7 @@ static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes) pos =0 ;for (zone_type = i; zone_type >=0 ; zone_type--) {for (j =0 ; j < nr_nodes; j++) { - node = node_order[j]; +int node = node_order[j]; z = &NODE_DATA (node)->node_zones[zone_type];if (populated_zone (z)) { zonelist->zones[pos++] = z;Unrelated modifications.
Quoted 15 lines
mm/page_alloc.c +11
-0@@ -2244,6 +2247,22 @@ static void set_zonelist_order(void) current_zonelist_order = user_zonelist_order; } +/* +* setup_populate_map() - record nodes whose "policy_zone" is "on-node". +*/ +static void setup_populated_map (int nid) +{ +pg_data_t *pgdat =NODE_DATA (nid); +struct zonelist *zl = pgdat->node_zonelists + policy_zone; +struct zone *z = zl->zones[0 ]; + +VM_BUG_ON (!z); +if (z->zone_pgdat == pgdat)Quoted 8 lines
mm/page_alloc.c static void set_zonelist_order(void) · line 2264
Quoted 4 lines
mm/page_alloc.c +4
-0+node_set_populated (nid); + else +node_not_populated (nid ); +}A node is only populated if it has memory in the policy zone? I would say a node is populated if it has any memory in any zone.
Quoted 3 lines
Mea culpa. Our platforms have a [pseudo-]node with just O(1G) memory all in zone DMA. That node can't look populated for allocating huge pages.
Because you don't want to use up any of the DMA pages, right? That seems *very* platform specific. And it doesn't seem right to make common code more complicated for one platform. Maybe there isn't a better solution, but I'd like to mull it over.
Quoted 10 lines
Quoted 3 lines
The above check may fail on
x86_64where only some nodes may haveZONE_NORMAL. Others only haveZONE_DMA32. Policy zone will be set toZONE_NORMAL.Yes. I thought of this after I created the patch. I've been looking for a platform with exactly 4GB per node to test on. I believe that, on our platforms, all of node zero would be in zone DMA32 and all other nodes would be > DMA32.
Maybe we can just exclude zone DMA from the populated map?
Maybe I don't know enough about NUMA and such, but I'm not sure I understand how this would make it a populated map anymore?
Maybe we need two maps, really?
One is for nodes that have memory, period (pages_present) == populated_map as currently implemented.
Another is for nodes that can satisfy hugepage allocations (policy_zone?) (a subset of the populated nodes).
That may solve both the memoryless nodes problem and your platform's problem?
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 8 lines · Nishanth Aravamudan
Quoted 3 lines
Mea culpa. Our platforms have a [pseudo-]node with just O(1G) memory all in zone DMA. That node can't look populated for allocating huge pages.
Because you don't want to use up any of the DMA pages, right? That seems *very* platform specific. And it doesn't seem right to make common code more complicated for one platform. Maybe there isn't a better solution, but I'd like to mull it over.
Right. Please Lee be generic and avoid the exceptional cases.
Quoted 6 lines
Quoted 1 line
Maybe we can just exclude zone DMA from the populated map?
Maybe I don't know enough about NUMA and such, but I'm not sure I understand how this would make it a populated map anymore?
Maybe we need two maps, really?
No need. If you want to exclude a node from huge pages then you need to use the patch that allows per node huge page specifications and set the number of huge pages for that node to zero.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 6 lines · Christoph Lameter
Quoted 4 lines · Nishanth Aravamudan
Quoted 3 lines
Mea culpa. Our platforms have a [pseudo-]node with just O(1G) memory all in zone DMA. That node can't look populated for allocating huge pages.
Quoted 6 lines
Quoted 4 lines
Because you don't want to use up any of the DMA pages, right? That seems *very* platform specific. And it doesn't seem right to make common code more complicated for one platform. Maybe there isn't a better solution, but I'd like to mull it over.
Right. Please Lee be generic and avoid the exceptional cases.
I was trying to be generic. But it broke for the exceptional case of an x86_64 with all/mostly DMA32 in one node and higher zone memory in other nodes.
Quoted 11 lines
Quoted 7 lines
Quoted 2 lines
Maybe we can just exclude zone DMA from the populated map?
Maybe I don't know enough about NUMA and such, but I'm not sure I understand how this would make it a populated map anymore?
Maybe we need two maps, really?
No need. If you want to exclude a node from huge pages then you need to use the patch that allows per node huge page specifications and set the number of huge pages for that node to zero.
Perhaps. But, be aware that allocating pages via the 'hugepages' boot parameter or the vm.nr_hugepages sysctl won't spread pages evenly--on our platforms, anyway--if we don't get this right. From what I've seen in the mailing lists, this approach [fixing it up with the per node attributes] runs counter to the general approach of having the kernel figure it out.
So, I'll wait for this to settle down. Then I'll see how it works on our platforms and propose whatever generic fixes I can to make it work.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 6 lines · Lee Schermerhorn
Perhaps. But, be aware that allocating pages via the 'hugepages' boot parameter or the vm.nr_hugepages sysctl won't spread pages evenly--on our platforms, anyway--if we don't get this right. From what I've seen in the mailing lists, this approach [fixing it up with the per node attributes] runs counter to the general approach of having the kernel figure it out.
Hmm.. shmem does the same with the boot parameter there?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 11 lines · Lee Schermerhorn
Split up Lee and Anton's original patch
(http://marc.info/?l=linux-mm&m=118133042025995&w=2), to allow for thepopulated_mapchanges to go in on their own.Add a
populated_mapnodemask to indicate a node has memory or not. We have run into a number of issues (in practice and in code) with assumptions about every node having memory. Having this nodemask allows us to fix these issues; in particular, THISNODE allocations will come from the node specified, only, and the INTERLEAVE policy will be able to do the right thing with memoryless nodes.
Thank you, I like this work.
Quoted 1 line
+extern
nodemask_tnode_populated_map;
please add /* node has memory */ here.
I don't think "populated node" means "node-with-memory" if there is no comments.
Thanks,
-Kame
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 7 lines · KAMEZAWA Hiroyuki
Quoted 4 lines · Lee Schermerhorn
Split up Lee and Anton's original patch
(http://marc.info/?l=linux-mm&m=118133042025995&w=2), to allow for thepopulated_mapchanges to go in on their own.
Quoted 8 lines
Quoted 7 lines
Add a
populated_mapnodemask to indicate a node has memory or not. We have run into a number of issues (in practice and in code) with assumptions about every node having memory. Having this nodemask allows us to fix these issues; in particular, THISNODE allocations will come from the node specified, only, and the INTERLEAVE policy will be able to do the right thing with memoryless nodes.Thank you, I like this work.
Thanks, I hope it is useful :)
Quoted 4 lines
Quoted 1 line
+extern
nodemask_tnode_populated_map;please add /* node has memory */ here.
I don't think "populated node" means "node-with-memory" if there is no comments.
Good point, I'll send a small diff for Andrew to pick up when I refresh the other patches tomorrow.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 14 lines · KAMEZAWA Hiroyuki
Quoted 11 lines · Lee Schermerhorn
Split up Lee and Anton's original patch
(http://marc.info/?l=linux-mm&m=118133042025995&w=2), to allow for thepopulated_mapchanges to go in on their own.Add a
populated_mapnodemask to indicate a node has memory or not. We have run into a number of issues (in practice and in code) with assumptions about every node having memory. Having this nodemask allows us to fix these issues; in particular, THISNODE allocations will come from the node specified, only, and the INTERLEAVE policy will be able to do the right thing with memoryless nodes.
Quoted 6 lines
Thank you, I like this work.
Quoted 1 line
+extern
nodemask_tnode_populated_map;please add /* node has memory */ here.
I don't think "populated node" means "node-with-memory" if there is no comments.
What else could it mean?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 9 lines · On Mon, 11 Jun 2007 19:53:10 -0700 (PDT) Christoph Lameter <[email protected]>…
Quoted 6 lines
Thank you, I like this work.
Quoted 1 line
+extern
nodemask_tnode_populated_map;please add /* node has memory */ here.
I don't think "populated node" means "node-with-memory" if there is no comments.
What else could it mean?
"a node has cpu(s) or device(s)" is not populated ?
-Kame
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>