Skip to contentSkip to conversation

Add populated_map to account for memoryless nodes

PATCH Superseded Nishanth Aravamudan 6 participants 140 messages Jun 11, 2007 – Jul 23, 2007

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

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
index 52c54a5..751d3d7 100644
@@ -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
index 07cd5ae..8eea4ff 100644
@@ -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>

#1 lore raw
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 -0
 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);
 	}

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>

#2 lore raw

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 -1
 			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.

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_64 where only some nodes may have ZONE_NORMAL. Others only have ZONE_DMA32. Policy zone will be set to ZONE_NORMAL.

I agree here as well, updated below.

Quoted 7 lines
Quoted 7 lines
(quoted diff) +0 -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;
 }
 
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 -0
 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);
 	}

Is it possible to move the set_populated_node into build_zonelists somehow?

Quoted 2 lines

F.e. In build_zonelists_node you can check if nr_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
index 52c54a5..751d3d7 100644
@@ -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
index 07cd5ae..1d20f8f 100644
@@ -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>

#3 lore raw
Quoted 2 lines · Nishanth Aravamudan

Already done in the original patch (node_populated() returns (node == 0) if MAX_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>

#4 lore raw

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) if MAX_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
index 52c54a5..c00a249 100644
@@ -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
index 07cd5ae..456f2f6 100644
@@ -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>

#5 lore raw

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
index 49dcc2f..c83e56a 100644
@@ -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
index 144805c..4e7c48c 100644
@@ -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>

#6 lore raw

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
index 858c0b3..97ae1a3 100644
@@ -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>

#7 lore raw

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
index 97ae1a3..d1e1063 100644
@@ -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>

#8 lore raw

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
index cae346e..fc0b4a1 100644
@@ -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
index aa0dc9b..7df75c1 100644
@@ -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 lon
 int 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>

#9 lore raw

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>

#10 lore raw

Re: [PATCH][RFC] hugetlb: add per-node nr_hugepages sysfs attribute

In reply to Nishanth Aravamudan

drivers/base/node.c static ssize_t node_read_distance(struct sys_device * dev, char * buf) · line 138

Quoted 8 lines · Nishanth Aravamudan

}
static SYSDEV_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>

#11 lore raw

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

}
static SYSDEV_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>

#12 lore raw

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>

#13 lore raw

Re: [PATCH][RFC] hugetlb: add per-node nr_hugepages sysfs attribute

In reply to Christoph Lameter
Quoted 5 lines · Christoph Lameter
Quoted 3 lines · Nishanth Aravamudan

}
static SYSDEV_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>
#14 lore raw

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() and unregister_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>

#15 lore raw

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() and unregister_node() that are no-ops if !CONFIG_HUGETLB_PAGE? That is, rather than

	sysdev_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>
Acked-by on v1 1/1
#16 lore raw

Re: [PATCH][RFC] hugetlb: numafy several functions

In reply to Nishanth Aravamudan
Quoted 5 lines

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.

--
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>

#17 lore raw

Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes

In reply to Nishanth Aravamudan

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();

?

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>

#18 lore raw

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>

#19 lore raw

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>

#20 lore raw

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>
#21 lore raw

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>

#22 lore raw

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 constant

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.

--
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>

#23 lore raw

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>
#24 lore raw

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>

#25 lore raw

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() from mempolicy.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>
#26 lore raw

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() from mempolicy.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!

Well you just need to have the appropriate fallbacks defined in mempolicy.h

Quoted 8 lines

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?

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>

#27 lore raw

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() from mempolicy.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!

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.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?

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>
#28 lore raw

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>

#29 lore raw

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_next field 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>
#30 lore raw

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>

#31 lore raw

Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes

In reply to Christoph Lameter
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_next field 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>
#32 lore raw

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.c to 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'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.

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>

#33 lore raw

Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes

In reply to Christoph Lameter
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 constant

Remove 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>
#34 lore raw

Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes

In reply to Nishanth Aravamudan
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 to first_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>

#35 lore raw

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>

#36 lore raw

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>

#37 lore raw

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>

#38 lore raw

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>

#39 lore raw

Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes

In reply to William Lee Irwin III
Quoted 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 to first_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>
#40 lore raw

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>

#41 lore raw

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>
#42 lore raw

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>

#43 lore raw

Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes

In reply to William Lee Irwin III
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.

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>
#44 lore raw

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>

#45 lore raw

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.

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
index 22b668c..c8a68b8 100644
@@ -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
index 858c0b3..1c13687 100644
@@ -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
index 21458ca..c576d32 100644
@@ -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>
#46 lore raw

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.

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
index 1c13687..c4a966e 100644
@@ -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>
#47 lore raw

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.

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?

drivers/base/node.c +4 -0
index cae346e..24b13b0 100644
@@ -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
index aa0dc9b..e9f5928 100644
@@ -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 lon
 int 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 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.

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
index 1c13687..c4a966e 100644
@@ -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>
#48 lore raw

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 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.

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
index aa0dc9b..e9f5928 100644
@@ -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 lon
 int 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>

#49 lore raw

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 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.

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
index aa0dc9b..e9f5928 100644
@@ -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 -0
 struct ctl_table;
@@ -23,6 +24,11 @@ void __unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned lon
 int 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
index cae346e..c9d531f 100644
@@ -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
index aa0dc9b..7872031 100644
@@ -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 lon
 int 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>
#50 lore raw

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 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.

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>

#51 lore raw

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 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.

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>
#52 lore raw

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 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.

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>

#53 lore raw

Re: [PATCH v4][RFC] hugetlb: add per-node nr_hugepages sysfs attribute

In reply to Lee Schermerhorn
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 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.

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>

#54 lore raw

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 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.

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>

#55 lore raw

Re: [PATCH v7][RFC] Fix hugetlb pool allocation with empty nodes

In reply to Nishanth Aravamudan
Quoted 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_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.

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
index 22b668c..c8a68b8 100644
@@ -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
index 858c0b3..1c13687 100644
@@ -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>

#56 lore raw

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 initialize start_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.

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
index 22b668c..c8a68b8 100644
@@ -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
index 858c0b3..88e1a30 100644
@@ -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
index 21458ca..c576d32 100644
@@ -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>
#57 lore raw

Re: [PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes

In reply to Christoph Lameter
Quoted 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>

#58 lore raw

Re: [PATCH][RFC] Fix INTERLEAVE with memoryless nodes

In reply to Nishanth Aravamudan
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 to mempolicy.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>

#59 lore raw

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 to mempolicy.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
index 49dcc2f..c83e56a 100644
@@ -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
index 144805c..abadbf4 100644
@@ -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>

Acked-by on v2 1/1
#60 lore raw

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 above nodes_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>

maintainer
#61 lore raw

Re: [PATCH v2][RFC] Fix INTERLEAVE with memoryless nodes

In reply to Nishanth Aravamudan
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_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."

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 to mempolicy.c.

All confused.

Quoted 31 lines
include/linux/gfp.h +1 -13
index 49dcc2f..c83e56a 100644
@@ -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
index 144805c..abadbf4 100644

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 -1
 	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;

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

Cc Nishanth Aravamudan <[email protected]>
Cc Christoph Lameter <[email protected]>

---

 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
diff -puN include/linux/gfp.h~fix-interleave-with-memoryless-nodes-fix include/linux/gfp.h
@@ -130,7 +130,7 @@ static inline void arch_alloc_page(struc
 extern 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
diff -puN mm/mempolicy.c~fix-interleave-with-memoryless-nodes-fix mm/mempolicy.c
@@ -172,7 +172,6 @@ static struct zonelist *bind_zonelist(no
 static 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>

#62 lore raw

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 -1
 	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;

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>

#63 lore raw

Re: [PATCH v2][RFC] Fix INTERLEAVE with memoryless nodes

In reply to Andrew Morton
Quoted 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_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."

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 to mempolicy.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>
maintainer
#64 lore raw

Re: [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>

#65 lore raw

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>
Acked-by on v3 1/1
#66 lore raw
In reply to Nishanth Aravamudan
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>

#67 lore raw

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
index f964af6..8e3f43e 100644
@@ -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
index 52c54a5..c00a249 100644
@@ -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
index 07cd5ae..526c126 100644
@@ -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>

#68 lore raw
Quoted 3 lines · Nishanth Aravamudan

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?

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>

#69 lore raw

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_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?

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_pages just 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
index 456f2f6..825d2df 100644
@@ -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>

#70 lore raw

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>

#71 lore raw

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_mask can be moved into an #ifdef CONFIG_NUMA chunk in page_alloc.c and 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>
#72 lore raw

Re: [PATCH] populated_map: fix !NUMA case, remove comment

Quoted 2 lines · Nishanth Aravamudan

Ah, but we'll use it in mpol_new via nodes_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_NUMA code should use node_populated_mask, then I'll make that change and use node_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>

#73 lore raw

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_new via nodes_and() regardless of NUMA/!NUMA, right?

mempolicy.c will 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_NUMA code should use node_populated_mask, then I'll make that change and use node_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>
#74 lore raw

Re: [PATCH] populated_map: fix !NUMA case, remove comment

In reply to Christoph Lameter
Quoted 5 lines · Christoph Lameter
Quoted 2 lines · Nishanth Aravamudan

Ah, but we'll use it in mpol_new via nodes_and() regardless of NUMA/!NUMA, right?

Quoted 8 lines

mempolicy.c will only be compiled for the NUMA case.

Quoted 3 lines

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.

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>
#75 lore raw

Re: [PATCH] populated_map: fix !NUMA case, remove comment

In reply to Christoph Lameter
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_mask can be moved into an #ifdef CONFIG_NUMA chunk in page_alloc.c and we can have fallback functions.

No, see:

[PATCH v6][RFC] Fix hugetlb pool allocation with empty nodes

mm/hugetlb.c +15 -6
index 858c0b3..97ae1a3 100644
@@ -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>
#76 lore raw

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>

#77 lore raw

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.c that 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>
#78 lore raw

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.c that 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>

#79 lore raw

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.c that 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>
#80 lore raw

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_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.

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>

#81 lore raw

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_map should 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>
#82 lore raw

Re: [PATCH] populated_map: fix !NUMA case, remove comment

In reply to Nishanth Aravamudan
Quoted 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.c that 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_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.

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>

#83 lore raw

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.c that 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.

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_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.

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_64 systems that have some nodes that are all/mostly DMA32 and other nodes that are populated in zones

Quoted 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_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.

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>
#84 lore raw

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>

#85 lore raw

Re: [PATCH] populated_map: fix !NUMA case, remove comment

In reply to Nishanth Aravamudan
Quoted 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_map as 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_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.

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>

#86 lore raw

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_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, ...

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 '_THISNODE is specified. We can't assume that the first zone in a node's zonelist for a given gfp_zone is 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>

#87 lore raw

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_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, ...

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 '_THISNODE is specified. We can't assume that the first zone in a node's zonelist for a given gfp_zone is on-node.

We do not do that anymore. GFP_THISNODE guarantees the allocation on the node with alloc_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>

#88 lore raw

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 the zone_pgdat in get_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>

#89 lore raw

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
Index: linux-2.6.22-rc4-mm2/include/linux/gfp.h
===================================================================
@@ -175,6 +175,13 @@ static inline struct page *alloc_pages_n
 	if (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>

#90 lore raw

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_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)

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_n
 	if (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>
#91 lore raw

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_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)

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_n
 	if (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>

#92 lore raw

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_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)

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_n
 	if (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() 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.

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>
#93 lore raw

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() 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.

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>

#94 lore raw

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() 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.

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 the node_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 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.

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>
#95 lore raw

Re: [PATCH] populated_map: fix !NUMA case, remove comment

In reply to Lee Schermerhorn
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.

--
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>

#96 lore raw

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>

#97 lore raw

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>

#98 lore raw

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>

#99 lore raw

Re: [PATCH] populated_map: fix !NUMA case, remove comment

In reply to Lee Schermerhorn
Quoted 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_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.

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>
#100 lore raw

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>

#101 lore raw

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,
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.

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>

#102 lore raw

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? If GFP_THISNODE never

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>

#103 lore raw

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? If GFP_THISNODE never

The 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>

#104 lore raw

Re: [PATCH] populated_map: fix !NUMA case, remove comment

In reply to Lee Schermerhorn
Quoted 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,
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.

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.

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>
#105 lore raw

Re: [PATCH] populated_map: fix !NUMA case, remove comment

In reply to Nishanth Aravamudan
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 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>

#106 lore raw

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>
#107 lore raw

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>

#108 lore raw

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 in alloc_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_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.

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>
#109 lore raw

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>

#110 lore raw

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_THISNODE working 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>
#111 lore raw

Re: [PATCH] populated_map: fix !NUMA case, remove comment

In reply to Christoph Lameter
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.

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>

#112 lore raw

Re: [PATCH] populated_map: fix !NUMA case, remove comment

In reply to Lee Schermerhorn
Quoted 6 lines · Lee Schermerhorn

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:

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>

#113 lore raw

Re: [PATCH] populated_map: fix !NUMA case, remove comment

In reply to Lee Schermerhorn
Quoted 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_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, ...

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.

Quoted 7 lines

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.

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 '_THISNODE is specified. We can't assume that the first zone in a node's zonelist for a given gfp_zone is on-node.

We do not do that anymore. GFP_THISNODE guarantees the allocation on the node with alloc_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:

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>
#114 lore raw

Re: [PATCH] populated_map: fix !NUMA case, remove comment

In reply to Lee Schermerhorn
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_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.

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_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.

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_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

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>

#115 lore raw

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_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.

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_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.

Quoted 1 line

GFP_THISNODE will 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_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

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>

#116 lore raw

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_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.

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>

#117 lore raw
In reply to Christoph Lameter
Quoted 25 lines · Christoph Lameter
Quoted 2 lines · Nishanth Aravamudan

Already done in the original patch (node_populated() returns (node == 0) if MAX_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>

#118 lore raw
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) if MAX_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_DMA is 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>
#119 lore raw
In reply to Lee Schermerhorn
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_DMA is 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>

#120 lore raw
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_zonelist function 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_DMA is configured.

CONFIG_ZONE_DMA already 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>

#121 lore raw
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_THISNODE guarantees 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>

#122 lore raw
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_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_THISNODE guarantees 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_THISNODE issue and introduces node_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
index 49dcc2f..453cc32 100644
@@ -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
index 52c54a5..4fb054a 100644
@@ -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
index 07cd5ae..fab163d 100644
@@ -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>
#123 lore raw

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
Index: linux-2.6.22-rc4-mm2/include/linux/nodemask.h
===================================================================
@@ -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(nodemas
 
 extern 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
Index: linux-2.6.22-rc4-mm2/mm/page_alloc.c
===================================================================
@@ -54,6 +54,9 @@ nodemask_t node_online_map __read_mostly
 EXPORT_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>

#124 lore raw
Quoted 29 lines · Christoph Lameter

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.

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(nodemas
 
 extern 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_mostly
 EXPORT_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 -0
 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);
 }

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>
#125 lore raw
Quoted 2 lines · Nishanth Aravamudan

SERIOUSLY!? After saying that node_populated_map should 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>

#126 lore raw
In reply to Nishanth Aravamudan
Quoted 4 lines · Nishanth Aravamudan

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?].

Because node_set_on/off is already inconsisted with node_set and node_clear.

Another possible name may be

node_clear_has_memory
node_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>

#127 lore raw
In reply to Nishanth Aravamudan

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
Index: linux-2.6.22-rc4-mm2/mm/mempolicy.c
===================================================================
@@ -185,6 +185,7 @@ static struct mempolicy *mpol_new(int mo
 	switch (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>

#129 lore raw
In reply to Christoph Lameter
Quoted 20 lines · Christoph Lameter

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.

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 mo
 	switch (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>
#130 lore raw
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 mo
 	switch (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>

#131 lore raw
In reply to Christoph Lameter
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_64 where only some nodes may have ZONE_NORMAL. Others only have ZONE_DMA32. Policy zone will be set to ZONE_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 -0
 static 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_node into build_zonelists somehow?

Quoted 3 lines

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>

#132 lore raw
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_64 where only some nodes may have ZONE_NORMAL. Others only have ZONE_DMA32. Policy zone will be set to ZONE_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>
#133 lore raw
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>

#134 lore raw
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>

#135 lore raw
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>

#136 lore raw
In reply to Nishanth Aravamudan
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 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.

Thank you, I like this work.

Quoted 1 line

+extern nodemask_t node_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>

#137 lore raw
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 the populated_map changes to go in on their own.

Quoted 8 lines
Quoted 7 lines

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.

Thank you, I like this work.

Thanks, I hope it is useful :)

Quoted 4 lines
Quoted 1 line

+extern nodemask_t node_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>
#138 lore raw
In reply to KAMEZAWA Hiroyuki
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 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.

Quoted 6 lines

Thank you, I like this work.

Quoted 1 line

+extern nodemask_t node_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>

#139 lore raw
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_t node_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>