Memory Binding API v0.3 2.5.41
Subsystems (6)
RFC PATCH 1/1 Memory Binding API v0.3 2.5.41
Greetings & Salutations,
Here's a wonderful patch that I know you're all dying for... Memory
Binding! It works just like CPU Affinity (binding) except that it binds a processes memory allocations (just buddy allocator for now) to specific memory blocks.
I've sent this out in the past, but haven't touched it in months. Since
the feature freeze is rapidly approaching, I want to get this out there again and see if anyone has any interest in it.
It's a fairly large patch, mostly because it includes a few odds and ends
that are topology related, and don't strictly belong in this patch, but are pre-requisites for it (ie: the [memblk|node]_online_map stuff, and some of the cleanups to page_alloc). I'll probably try and break it up into more discrete parts very soon.
[mcd@arrakis src]$ diffstat ~/patches/api_patches/mem_api/memory_binding_api-v0.3-2.5.41.patch
arch/i386/kernel/entry.S | 2 + arch/i386/kernel/numaq.c | 4 ++ arch/i386/kernel/smpboot.c | 4 ++ include/asm-i386/smp.h | 16 ++++++++ include/asm-i386/unistd.h | 2 + include/linux/init_task.h | 4 ++ include/linux/membind.h | 50 +++++++++++++++++++++++++ include/linux/mmzone.h | 23 +++++++++++ include/linux/sched.h | 4 ++ include/linux/smp.h | 8 +++- kernel/sys.c | 90 +++++++++++++++++++++++++++++++++++++++++++++ mm/numa.c | 8 ++++ mm/page_alloc.c | 67 ++++++++++++--------------------- 13 files changed, 237 insertions(+), 45 deletions(-)
Questions, comments, flames, and indifferent shrugs are all welcome.
btw, It applies (mostly) cleanly to mm1 as well. The mm/page_alloc.c changes fail, but if anyone is interested, they'll clean up easily, and I'll send you a patch.
Cheers!
-Matt
arch/i386/kernel/entry.S +2 -0
@@ -736,6 +736,8 @@ .long sys_alloc_hugepages /* 250 */ .long sys_free_hugepages .long sys_exit_group + .long sys_mem_setbinding + .long sys_mem_getbinding .rept NR_syscalls-(.-sys_call_table)/4 .long sys_ni_syscall
arch/i386/kernel/numaq.c +4 -0
@@ -52,6 +52,10 @@ numnodes =0 ;for (node =0 ; node <MAX_NUMNODES ; node++) {if (scd->quads_present31_0 & (1 << node)) { +if (test_and_set_bit (numnodes, &node_online_map)){ +printk ("smp_dump_qct: node alread counted?!?!\n" ); +BUG (); + } numnodes++; eq = &scd->eq[node];/* Convert to pages */
arch/i386/kernel/smpboot.c +4 -0
@@ -61,6 +61,10 @@/* Bitmask of currently online CPUs */ unsigned long cpu_online_map; +/* Bitmask of currently online memory blocks */ +unsigned long memblk_online_map =0UL ; +/* Bitmask of currently online nodes */ +unsigned long node_online_map =0UL ;static volatile unsigned long cpu_callin_map;volatile unsigned long cpu_callout_map;
include/asm-i386/smp.h +16 -0
@@ -54,6 +54,8 @@extern void smp_alloc_memory (void );extern unsigned long phys_cpu_present_map;extern unsigned long cpu_online_map; +extern unsigned long memblk_online_map; +extern unsigned long node_online_map;extern volatile unsigned long smp_invalidate_needed;extern int pic_mode;extern int smp_num_siblings;
@@ -102,6 +104,20 @@return -1 ; } +#define memblk_online (memblk) (memblk_online_map & (1<<(memblk))) + +extern inline unsigned int num_online_memblks (void ) +{ +return hweight32 (memblk_online_map); +} + +#define node_online (node) (node_online_map & (1<<(node))) + +extern inline unsigned int num_online_nodes (void ) +{ +return hweight32 (node_online_map); +} +static __inlineint hard_smp_processor_id (void ) {/* we don't want to mark this access volatile - bad code generation */
include/asm-i386/unistd.h +2 -0
@@ -257,6 +257,8 @@#define __NR_alloc_hugepages 250#define __NR_free_hugepages 251#define __NR_exit_group 252 +#define __NR_mem_setbinding 253 +#define __NR_mem_getbinding 254/* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
include/linux/init_task.h +4 -0
@@ -76,6 +76,10 @@ .children = LIST_HEAD_INIT(tsk.children), \ .sibling = LIST_HEAD_INIT(tsk.sibling), \ .group_leader = &tsk, \ + .memblk_binding = { \ + .bitmask = MEMBLK_NO_BINDING, \ + .behavior = MPOL_STRICT, \ + }, \ .wait_chldexit = __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\ .real_timer = { \ .function = it_real_fn \
include/linux/membind.h +50 -0
50 lines not on this page · raw message
include/linux/mmzone.h +22 -1
@@ -167,8 +167,9 @@unsigned long node_start_pfn;unsigned long node_size;int node_id; +int memblk_id;/* A unique ID for each memory block */ struct pglist_data *pgdat_next; -wait_queue_head_t kswapd_wait; +wait_queue_head_t kswapd_wait; } pg_data_t;extern int numnodes;
@@ -249,6 +250,26 @@#define for_each_zone (zone) \ for (zone = pgdat_list->node_zones; zone; zone = next_zone(zone)) +/** +* for_each_valid_zone - helper macro to iterate over all memory zones +* in a zonelist +* @zone - pointer to struct zone variable +* @zonelist - pointer to struct zonelist variable +* +* for_each_valid_zone() is basically an easier to read version of this +* piece of code: +* +* for (i = 0; zonelist->zones[i] != NULL; i++) { +* struct zone *z = zonelist->zones[i]; +* ... +* } +* +* Useful for several loops in __alloc_pages. +*/ +#define for_each_valid_zone (zone, zonelist) \ + for (zone = *zonelist->zones; zone; zone++) \ + if (current->memblk_binding.bitmask & (1 << zone->zone_pgdat->memblk_id)) +#ifdef CONFIG_NUMA #define MAX_NR_MEMBLKS BITS_PER_LONG/* Max number of Memory Blocks */ #else /* !CONFIG_NUMA */
include/linux/sched.h +4 -0
@@ -29,6 +29,7 @@#include <linux/compiler.h> #include <linux/completion.h> #include <linux/pid.h> +#include <linux/membind.h> struct exec_domain ;
@@ -335,6 +336,9 @@/* PID/PID hash table linkage. */ struct pid_link pids[PIDTYPE_MAX ]; +/* additional Memory Binding stuff */ +memblk_list_t memblk_binding; +wait_queue_head_t wait_chldexit;/* for wait4() */ struct completion *vfork_done;/* for vfork() */ int *user_tid;/* for CLONE_CLEARTID */
include/linux/smp.h +7 -1
@@ -94,7 +94,13 @@#define cpu_online (cpu) ({ BUG_ON((cpu) != 0); 1; })#define num_online_cpus () 1#define num_booting_cpus () 1 -#define cpu_possible (cpu) ({ BUG_ON((cpu) != 0); 1; }) +#define cpu_possible (cpu) ({ BUG_ON((cpu) != 0); 1; }) +#define memblk_online_map 1 +#define memblk_online (memblk) ({ BUG_ON((memblk) != 0); 1; }) +#define num_online_memblks () 1 +#define node_online_map 1 +#define node_online (node) ({ BUG_ON((node) != 0); 1; }) +#define num_online_nodes () 1struct notifier_block ;
kernel/sys.c +90 -0
96 lines not on this page · raw message
mm/numa.c +8 -0
@@ -8,6 +8,7 @@#include <linux/bootmem.h> #include <linux/mmzone.h> #include <linux/spinlock.h> +#include <linux/membind.h> int numnodes =1 ;/* Initialized for UMA platforms */
@@ -29,6 +30,7 @@ pgdat = &contig_page_data; contig_page_data.node_id =0 ; + contig_page_data.memblk_id =0 ; contig_page_data.node_start_pfn = node_start_pfn;calculate_totalpages (&contig_page_data, zones_size, zholes_size);if (pmap == (struct page *)0 ) {
@@ -37,6 +39,7 @@ } contig_page_data.node_mem_map = pmap;free_area_init_core (&contig_page_data, zones_size, zholes_size); + memblk_online_map =1UL ; mem_map = contig_page_data.node_mem_map; }
@@ -66,6 +69,7 @@unsigned long size; pgdat->node_id = nid; + pgdat->memblk_id =__node_to_memblk (nid); pgdat->node_start_pfn = node_start_pfn;calculate_totalpages (pgdat, zones_size, zholes_size);if (pmap == (struct page *)0 ) {
@@ -74,6 +78,10 @@ } pgdat->node_mem_map = pmap;free_area_init_core (pgdat, zones_size, zholes_size); +if (test_and_set_bit (num_online_memblks (), &memblk_online_map)){ +printk ("free_area_init_core: memblk alread counted?!?!\n" ); +BUG (); + }/* * Get space for the valid bitmap.
mm/page_alloc.c +24 -43
109 lines not on this page · raw message
Quoted 4 lines · Matthew Dobson
Greetings & Salutations,
Here's a wonderful patch that I know you're all dying for... Memory
Binding!
Seems reasonable to me.
Could you tell us a bit about the operator's view of this?
I assume that a typical usage scenario would be to bind a process to a bunch of CPUs and to then bind that process to a bunch of memblks as well?
If so, then how does the operator know how to identify those memblks? To perform the (cpu list) <-> (memblk list) mapping?
Also, what advantage does this provide over the current node-local allocation policy? I'd have thought that once you'd bound a process to a CPU (or to a node's CPUs) that as long as the zone fallback list was right, that process would be getting local memory pretty much all the time anyway?
Last but not least: you got some benchmark numbers for this?
Thanks.
Quoted 5 lines · Andrew Morton
Quoted 3 lines · Matthew Dobson
Greetings & Salutations,
Here's a wonderful patch that I know you're all dying for... Memory
Binding!Seems reasonable to me.
Good news!
Quoted 8 lines
Could you tell us a bit about the operator's view of this?
I assume that a typical usage scenario would be to bind a process to a bunch of CPUs and to then bind that process to a bunch of memblks as well?
If so, then how does the operator know how to identify those memblks? To perform the (cpu list) <-> (memblk list) mapping?
Well, that's what the super-duper In-Kernel topology API is for! ;) If the operator wanted to ensure that all the processes memory was *only* allocated from the memblks closest to her bound CPUs, she'd loop over her cpu binding, and for each set bit, she'd:
bitmask &= 1 << __node_to_memblk(__cpu_to_node(cpu));
I suppose that I could include a macro to do this in the patch, but I was a bit afraid (and still am) that it already may be a bit large for people's tastes. I've got some suggestions on how to split it up/pare it down, so we'll see.
Quoted 4 lines
Also, what advantage does this provide over the current node-local
allocation policy? I'd have thought that once you'd bound a process to a CPU (or to a node's CPUs) that as long as the zone fallback list was right, that process would be getting local memory
pretty much all the time anyway?
Very true... This is to specifically allow for processes that want to do something *different* than the default policy. Again, akin to CPU affinity, this is not something that the average process is going to ever use, or even care about. The majority of processes don't specifically bind themselves to certain CPUs or groups of CPUs, because for them the default scheduler policies are fine. For the majority of processes, the default memory allocation policy works just dandy. This is for processes that want to do something different: Testing/debugging apps on a large (likely NUMA) system, high-end databases, and who knows what else? There is also a plan to add a function call to bind specific regions of a processes memory to certain memblks, and this would allow for efficient shared memory for process groups spread across a large system.
Quoted 1 line
Last but not least: you got some benchmark numbers for this?
Nope.. It is not something that is going to (on average) improve benchmark numbers for something like a kernel compile... As you mentioned above, the default policy is to allocate from the local memory block anyway. This API is more useful for something where you want to pin your memory close to a particular process that your process is working with, or pin you memory to a different node than the one you're executing on to purposely test/debug something. If you'd like, I can do some kernbench runs or something to come up with some numbers to show that it doesn't negatively affect performance, but I don't know of any benchmarking suites offhand that would show positive numbers.
Quoted 1 line
Thanks.
My pleasure! ;)
Cheers!
-Matt
include/linux/mmzone.h line 271
Quoted 4 lines
include/linux/mmzone.h +3
-0+#define for_each_valid_zone (zone, zonelist) \ + for (zone = *zonelist->zones; zone; zone++) \ + if (current->memblk_binding.bitmask & (1 << zone->zone_pgdat->memblk_id))
Does the compiler optimise the last bit away on non-NUMA? Want to wrap it in #ifdef CONFIG_NUMA_MEMBIND or something? Not sure what the speed impact of this would be, but I'd rather it was optional, even on NUMA boxen.
Other than that, looks pretty good.
M.
Quoted 5 lines · Martin J. Bligh
include/linux/mmzone.h line 271
Quoted 3 lines
include/linux/mmzone.h +3
-0+#define for_each_valid_zone (zone, zonelist) \ + for (zone = *zonelist->zones; zone; zone++) \ + if (current->memblk_binding.bitmask & (1 << zone->zone_pgdat->memblk_id))Does the compiler optimise the last bit away on non-NUMA?
Nope.
Quoted 1 line
Want to wrap it in #ifdef
CONFIG_NUMA_MEMBINDor something?
Not a problem... I've got some free time this afternoon... Should only take me a few hours to retool the patch to include this change. ;)
Quoted 2 lines
Not sure what the speed impact of this would be, but I'd rather it was optional, even on NUMA boxen.
Sounds reasonable... It'll be in the next itteration.
Quoted 1 line
Other than that, looks pretty good.
Glad to hear!
Quoted 1 line
M.
Quoted 5 lines · Matthew Dobson
Greetings & Salutations,
Here's a wonderful patch that I know you're all dying for... Memory
Binding! It works just like CPU Affinity (binding) except that it binds a processes memory allocations (just buddy allocator for now) to specific memory blocks.
If the VM works right just doing CPU binding ought to be enough, surely?
Quoted 7 lines · Arjan van de Ven
Quoted 3 lines · Matthew Dobson
Greetings & Salutations,
Here's a wonderful patch that I know you're all dying for... Memory
Binding! It works just like CPU Affinity (binding) except that it binds a processes memory allocations (just buddy allocator for now) to specific memory blocks.If the VM works right just doing CPU binding ought to be enough, surely?
You'll have to look at the response I wrote to Andrew's question along the same lines... This patch is for processes who feel that the VM *isn't* doing quite what they want, and want different behavior.
Cheers!
-Matt
kernel/sys.c line 1314
Quoted 10 lines
kernel/sys.c +9
-0+/** +* sys_mem_setbinding - set the memory binding of a process +* @pid: pid of the process +* @memblks: new bitmask of memory blocks +* @behavior: new behavior +*/ +asmlinkage long sys_mem_setbinding (pid_t pid,unsigned long memblks, +unsigned int behavior) +{
Do you really think exposing low level internals as memory layout / zone split up to userspace is a good idea ? (and worth it given that the VM already has a cpu locality preference?)
I'd much rather see the VM have an arch-specified "cost" for getting memory from not-the-prefered zones than exposing all this stuff to userspace and depending on userspace to do the right thing.... it's the kernel's task to abstract the low level details of the hardware after all.
Greetings,
Arjan van de Ven
Quoted 14 lines · Arjan van de Ven
kernel/sys.c line 1314
Quoted 10 lines
kernel/sys.c +9
-0+/** +* sys_mem_setbinding - set the memory binding of a process +* @pid: pid of the process +* @memblks: new bitmask of memory blocks +* @behavior: new behavior +*/ +asmlinkage long sys_mem_setbinding (pid_t pid,unsigned long memblks, +unsigned int behavior) +{Do you really think exposing low level internals as memory layout / zone split up to userspace is a good idea ? (and worth it given that the VM already has a cpu locality preference?)
At least in the embedded world that level is a good idea. I'm not sure about the syscall interface. An "unsigned long" mask of blocks sounds like a good way to ensure a broken syscall in the future
Quoted 2 lines · Matthew Dobson
Quoted 2 lines
Quoted 2 lines
kernel/sys.c +2
-0+asmlinkage long sys_mem_setbinding (pid_t pid,unsigned long memblks, +unsigned int behavior)
Quoted 3 lines · Arjan van de Ven
Quoted 3 lines
Do you really think exposing low level internals as memory layout / zone split up to userspace is a good idea ? (and worth it given that the VM already has a cpu locality preference?)
Quoted 3 lines · Alan Cox
At least in the embedded world that level is a good idea. I'm not sure about the syscall interface. An "unsigned long" mask of blocks sounds like a good way to ensure a broken syscall in the future
Seconded wrt. memblk bitmask interface.
IMHO this level of topology exposure is not inappropriate. These kinds of details are already exported (unidirectionally) by /proc/, if not dmesg(1) and in my mind there is neither an aesthetic nor practical barrier to referring to these machine features in userspace API's in an advisory way (and absolutely not any kind of reliance). It's simply another kind of request, and one which several high-performance applications would like to make. I would also be interested in hearing more of how embedded applications would make use of this, as my direct experience in embedded systems is somewhat lacking.
Also, I've already privately replied with some of my stylistic concerns, including things like the separability of the for_each_in_zonelist() cleanup bundled into the patch and a typedef or so.
Bill
Quoted 13 lines · William Lee Irwin III
Quoted 3 lines · Matthew Dobson
Quoted 3 lines
Quoted 2 lines
kernel/sys.c +2
-0+asmlinkage long sys_mem_setbinding (pid_t pid,unsigned long memblks, +unsigned int behavior)Quoted 4 lines · Arjan van de Ven
Quoted 3 lines
Do you really think exposing low level internals as memory layout / zone split up to userspace is a good idea ? (and worth it given that the VM already has a cpu locality preference?)
Quoted 6 lines
Quoted 3 lines · Alan Cox
At least in the embedded world that level is a good idea. I'm not sure about the syscall interface. An "unsigned long" mask of blocks sounds like a good way to ensure a broken syscall in the future
Seconded wrt. memblk bitmask interface.
Glad to have your support! :)
Quoted 3 lines
Also, I've already privately replied with some of my stylistic concerns, including things like the separability of the
for_each_in_zonelist()cleanup bundled into the patch and a typedef or so.
Some very good points in your email. Most (if not all) will be incorporated in v0.4 (later today or tomorrow).
Cheers!
-Matt
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/
Quoted 16 lines · Alan Cox
Quoted 5 lines · Arjan van de Ven
Quoted 5 lines
+/**
+ *sys_mem_setbinding- set the memory binding of a process
+ * @pid: pid of the process
+ * @memblks: new bitmask of memory blocks
+ * @behavior: new behaviorQuoted 8 lines
kernel/sys.c line 1314
Quoted 4 lines
+ */
kernel/sys.c +3
-0+asmlinkage long sys_mem_setbinding (pid_t pid,unsigned long memblks, +unsigned int behavior) +{Do you really think exposing low level internals as memory layout / zone split up to userspace is a good idea ? (and worth it given that the VM already has a cpu locality preference?)
Quoted 3 lines
At least in the embedded world that level is a good idea. I'm not sure about the syscall interface. An "unsigned long" mask of blocks sounds like a good way to ensure a broken syscall in the future
Agreed. This is a first pass (well 3rd, but the first two were long ago), and I'll probably immitate the sys_sched_(s|g)etaffinity calls (even more than I already have ;) and add a 'length' argument in the next itteration.
Cheers!
-Matt
Quoted 5 lines · Arjan van de Ven
Quoted 5 lines
+/**
+ *sys_mem_setbinding- set the memory binding of a process
+ * @pid: pid of the process
+ * @memblks: new bitmask of memory blocks
+ * @behavior: new behavior
Quoted 8 lines
kernel/sys.c line 1314
Quoted 4 lines
+ */
kernel/sys.c +3
-0+asmlinkage long sys_mem_setbinding (pid_t pid,unsigned long memblks, +unsigned int behavior) +{Do you really think exposing low level internals as memory layout / zone split up to userspace is a good idea ? (and worth it given that the VM already has a cpu locality preference?)
Yes, I actually do. If userspace processes/users don't care about the memory/zone layout, they don't have to look. But if they *do* care, they should be able to find out, and not be left in the proverbial dark.
Embedded systems will care, as will really large NUMA/Discontig
systems. As with some other patches, this functionality will not affect the average user on the average computer... They are useful for really small systems, and really large systems, however.
Quoted 5 lines
I'd much rather see the VM have an arch-specified "cost" for getting memory from not-the-prefered zones than exposing all this stuff to userspace and depending on userspace to do the right thing.... it's the kernel's task to abstract the low level details of the hardware after all.
The arch-specified 'cost' is also a good idea. Some of the topology stuff I'm working on will allow that sort of interface as well. And this patch does not 'depend' on userspace to do the right thing. The patch does not alter the default VM behavior unless userspace *specifically* asks to alter it.
Cheers!
-Matt
Quoted 7 lines · Matthew Dobson
Greetings & Salutations,
Here's a wonderful patch that I know you're all dying for... Memory
Binding! It works just like CPU Affinity (binding) except that it binds a processes memory allocations (just buddy allocator for now) to specific memory blocks.
I've sent this out in the past, but haven't touched it in months. Since
Quoted 8 lines
the feature freeze is rapidly approaching, I want to get this out there again and see if anyone has any interest in it.
It's a fairly large patch, mostly because it includes a few odds and
ends that are topology related, and don't strictly belong in this patch, but arepre-requisites for it (ie: the [memblk|node]_online_map stuff, and some of the cleanups to
page_alloc). I'll probably try and break it up into more discrete parts very soon.
Due we want this per numa area or simply per zone? My suspicion is that internally at least we want this per zone.
Quoted 5 lines
Questions, comments, flames, and indifferent shrugs are all welcome.
btw, It applies (mostly) cleanly to mm1 as well. The
mm/page_alloc.cchanges fail, but if anyone is interested, they'll clean up easily, and I'll send you a patch.
The API doesn't make much sense at the moment.
1) You are operating on tasks and not mm's, or preferably vmas.
2) sys_mem_setbinding does not move the mm to the new binding.
3) You specify a pid and then change current task instead of the specified one.
4) An ordered zone list is probably the more natural mapping.
5) mprotect is the more natural model rather than set_cpu_affinity.
6) The code belongs in mm/* not kernel/*
Eric
Quoted 8 lines · Eric W. Biederman
Quoted 5 lines · Matthew Dobson
Greetings & Salutations,
Here's a wonderful patch that I know you're all dying for... Memory
Binding! It works just like CPU Affinity (binding) except that it binds a processes memory allocations (just buddy allocator for now) to specific memory blocks.Due we want this per numa area or simply per zone? My suspicion is that internally at least we want this per zone.
I think that per memory block is better. We already have a method for allocating from specific zones (GFP_* flags). Also, using per zone binding would involve setting up some way of enumerating the zones, which would not be immediately obvious to the users of the API. The memory block already has a straight-forward definition and an easy way for users to get the appropriate number for the appropriate block (in-kernel topology). I'm not fanatically opposed to per zone binding, though, and if there is a general agreement that it would be better that way, I don't think it would be unreasonably difficult to change it.
Quoted 1 line
The API doesn't make much sense at the moment.
Hmm.. That is unfortunate, I'd aimed to make it as simple as possible.
Quoted 1 line
1) You are operating on tasks and not mm's, or preferably vmas.
Correct. There are plans (somewhere inside my cranium) to allow binding at that granularity. For now, per task seemed an appropriate level.
Quoted 1 line
2)
sys_mem_setbindingdoes not move the mm to the new binding.
Also correct. A task may wish to allocate several large data structures from one memory area, rebind, do more allocations, rebind, ad nauseum. There are plans to have a flag that, if set, would force relocation of all currently allocated memory.
Quoted 2 lines
3) You specify a pid and then change current task instead of the specified one.
Yep... That was definitely a typo... fixed.
Quoted 1 line
4) An ordered zone list is probably the more natural mapping.
See my comments above about per zone/memblk. And you reemphasize my point, how do we order the zone lists in such a way that a user of the API can easily know/find out what zone #5 is?
Quoted 1 line
5) mprotect is the more natural model rather than
set_cpu_affinity.
Well, I think that may be true for the API you are imagining (per zone, per mm/vma, etc), not the one that I've written.
Quoted 1 line
6) The code belongs in
mm/*notkernel/*
Possibly... I just stuck it in with the vast majority of other syscalls in kernel/sys.c. As those changes are just code additions, they can easily be moved if it is deemed appropriate.
Cheers!
-Matt
Quoted 3 lines
Quoted 2 lines
4) An ordered zone list is probably the more natural mapping.
See my comments above about per zone/memblk. And you reemphasize my point, how do we order the zone lists in such a way that a user of the API can easily know/find out what zone #5 is?
Could you explain how that problem is different from finding out what memblk #5 is ... I don't see the difference?
M.
Quoted 5 lines · Martin J. Bligh
Quoted 3 lines
Quoted 1 line
4) An ordered zone list is probably the more natural mapping.
See my comments above about per zone/memblk. And you reemphasize my point, how do we order the zone lists in such a way that a user of the API can easily know/find out what zone #5 is?
Could you explain how that problem is different from finding out what memblk #5 is ... I don't see the difference?
Errm... __memblk_to_node(5)
I"m not saying that we couldn't add a similar interface for zones... something along the lines of:
__memblk_and_zone_to_flat_zone_number(5, DMA)
or some such. It just isn't there now...
Also, right now, memblks map to nodes in a straightforward manner (1-1 on NUMA-Q, the only architecture that has defined them). It will likely look the same on most architectures, too.
Cheers!
-Matt
Quoted 6 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
4) An ordered zone list is probably the more natural mapping.
See my comments above about per zone/memblk. And you reemphasize my point, how do we order the zone lists in such a way that a user of the API can easily know/find out what zone #5 is?
Could you explain how that problem is different from finding out what memblk #5 is ... I don't see the difference?
Errm...
__memblk_to_node(5)
As opposed to creating __zone_to_node(5) ?
Quoted 3 lines
I"m not saying that we couldn't add a similar interface for zones... something along the lines of:
__memblk_and_zone_to_flat_zone_number(5, DMA)or some such. It just isn't there now...
Surely this would dispose of the need for memblks? If not, then I'd agree it's probably just adding more complication.
M.
Quoted 9 lines · Martin J. Bligh
Quoted 8 lines
Quoted 6 lines
Quoted 3 lines
Quoted 1 line
4) An ordered zone list is probably the more natural mapping.
See my comments above about per zone/memblk. And you reemphasize my point, how do we order the zone lists in such a way that a user of the API can easily know/find out what zone #5 is?
Could you explain how that problem is different from finding out what memblk #5 is ... I don't see the difference?
Errm...
__memblk_to_node(5)
Quoted 8 lines
As opposed to creating
__zone_to_node(5)?Quoted 3 lines
I"m not saying that we couldn't add a similar interface for zones... something along the lines of:
__memblk_and_zone_to_flat_zone_number(5, DMA)or some such. It just isn't there now...
Surely this would dispose of the need for memblks? If not, then I'd agree it's probably just adding more complication.
Well, since each node's memory (or memblk in the parlance of my head ;) has several 'zones' in it (DMA, HIGHMEM, etc), this conversion function will need 2 parameters. It may well be called __node_and_zone_type_to_flat_zone_number(node, DMA|NORMAL|HIGHMEM).
Or, we could have:__zone_to_node(5) = node #
and__zone_to_zone_type(5) = DMA|NORMAL|HIGHMEM.
But either way, we would need to specify both pieces.
Cheers!
-Matt
Quoted 11 lines · Matthew Dobson
Well, since each node's memory (or memblk in the parlance of my head ;) has several 'zones' in it (DMA, HIGHMEM, etc), this conversion function will need 2 parameters. It may well be called
__node_and_zone_type_to_flat_zone_number(node, DMA|NORMAL|HIGHMEM). Or, we could have:__zone_to_node(5)= node #
and__zone_to_zone_type(5)= DMA|NORMAL|HIGHMEM.
But either way, we would need to specify both pieces. Cheers!
-Matt
Zone "type" can be found in (page->flags >> ZONE_SHIFT) & 0x3UL and similarly node ID can be found in page_zone(page)->zone_pgdat->node_id and these are from the page.
zone->zone_pgdat->node_id does the zone to node conversion zone - zone_pgdat->node_zones does the zone to zone type conversion.
Node and zone type to flat zone number would be
NODE_DATA(nid)->node_zones[type]
Basically there's a number written in page->flags that should be easy to decode if you can go on arithmetic alone, and if you need details, there's a zone_table[] you can get at the zones (and hence pgdats) with.
Bill
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/
Quoted 3 lines · Matthew Dobson
Also, right now, memblks map to nodes in a straightforward manner (1-1 on NUMA-Q, the only architecture that has defined them). It will likely look the same on most architectures, too.
Just an FYI: I believe the x440 breaks this assumption.
There are 2 chunks on the first CEC. The current discontig patch for it has to drop the second chunk (anything over 3.5G on the first CEC) in order to work w/ the existing code. However, that will probably need to be addressed at some point, so be aware that this might affect you as well.
thanks
-john
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/
Quoted 3 lines · Matthew Dobson
Quoted 3 lines
Also, right now, memblks map to nodes in a straightforward manner (1-1 on NUMA-Q, the only architecture that has defined them). It will likely look the same on most architectures, too.
Quoted 6 lines · john stultz
Just an FYI: I believe the x440 breaks this assumption. There are 2 chunks on the first CEC. The current discontig patch for it has to drop the second chunk (anything over 3.5G on the first CEC) in order to work w/ the existing code. However, that will probably need to be addressed at some point, so be aware that this might affect you as well.
MAP_NR_DENSE()-based zone-relative pfn to zone->zone_mem_map index remapping is designed to handle this (and actually more severe situations). The only constraint is that pfn's must be monotonically increasing with ->zone_mem_map index. Some non-i386 architectures virtually remap physical memory to provide the illusion of contiguity of kernel virtual memory, but in a mature port (e.g. i386) there's high risk of breaking numerous preexisting drivers.
Bill
Quoted 7 lines
MAP_NR_DENSE()-based zone-relative pfn to
zone->zone_mem_mapindex remapping is designed to handle this (and actually more severe situations). The only constraint is that pfn's must be monotonically increasing with ->zone_mem_map index. Some non-i386 architectures virtually remap physical memory to provide the illusion of contiguity of kernel virtual memory, but in a mature port (e.g. i386) there's high risk of breaking numerous preexisting drivers.
As long as you don't need a hole between 0 and 896Mb (s/896/ appropriate defines/) I don't see that would be a problem. I purged direct usage of mem_map already, and made people use the macro wrappers.
Basically a "mini config_nonlinear".
M.
Quoted 11 lines
Quoted 3 lines
Also, right now, memblks map to nodes in a straightforward manner (1-1 on NUMA-Q, the only architecture that has defined them). It will likely look the same on most architectures, too.
Just an FYI: I believe the x440 breaks this assumption.
There are 2 chunks on the first CEC. The current discontig patch for it has to drop the second chunk (anything over 3.5G on the first CEC) in order to work w/ the existing code. However, that will probably need to be addressed at some point, so be aware that this might affect you as well.
No, the NUMA code in the kernel doesn't support that anyway. You have to use zholes_size, and waste some struct pages, or config_nonlinear. Either way you get 1 memblk.
M.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/
Quoted 6 lines · jstultz
Quoted 6 lines
Just an FYI: I believe the x440 breaks this assumption. There are 2 chunks on the first CEC. The current discontig patch for it has to drop the second chunk (anything over 3.5G on the first CEC) in order to work w/ the existing code. However, that will probably need to be addressed at some point, so be aware that this might affect you as well.
Quoted 3 lines · Martin J. Bligh
No, the NUMA code in the kernel doesn't support that anyway. You have to use
zholes_size, and waste some struct pages, orconfig_nonlinear. Either way you get 1 memblk.
I thought zholes stuff freed the struct pages. Maybe that was done by hand.
Bill
Quoted 6 lines
Quoted 3 lines
No, the NUMA code in the kernel doesn't support that anyway. You have to use
zholes_size, and waste some struct pages, orconfig_nonlinear. Either way you get 1 memblk.I thought zholes stuff freed the struct pages. Maybe that was done by hand.
The only place I see that used in generic code is calculate_zone_totalpages, free_area_init_core, free_area_init_node, none of which seem to do that. But cscope might be borked again, I guess. Must be done in each arch if at all ... which arch did you think did it?
M.
Quoted 2 lines · At some point in the past, I wrote:
Quoted 2 lines
I thought zholes stuff freed the struct pages. Maybe that was done by hand.
Quoted 5 lines · Martin J. Bligh
The only place I see that used in generic code is
calculate_zone_totalpages,free_area_init_core,free_area_init_node, none of which seem to do that. But cscope might be borked again, I guess. Must be done in each arch if at all ... which arch did you think did it?
Not sure, ISTR something about this going on but I don't see any extant examples. At any rate, it should be easy to do it by hand, just make sure there are struct pages tracking the holes in mem_map and free the space in mem_map that would track the holes.
Bill
Quoted 5 lines · Martin J. Bligh
Quoted 5 lines
The only place I see that used in generic code is
calculate_zone_totalpages,free_area_init_core,free_area_init_node, none of which seem to do that. But cscope might be borked again, I guess. Must be done in each arch if at all ... which arch did you think did it?
Quoted 4 lines · William Lee Irwin III
Not sure, ISTR something about this going on but I don't see any extant examples. At any rate, it should be easy to do it by hand, just make sure there are struct pages tracking the holes in
mem_mapand free the space inmem_mapthat would track the holes.
And buddy bitmaps and ->node_valid_addr too. Which stands a good chance of explaining why it broke, if it ever worked.
Bill
Quoted 11 lines · Matthew Dobson
Quoted 9 lines · Eric W. Biederman
Quoted 6 lines · Matthew Dobson
Greetings & Salutations,
Here's a wonderful patch that I know you're all dying for... Memory
Binding! It works just like CPU Affinity (binding) except that it binds a processes memory allocations (just buddy allocator for now) to specific memoryblocks.
Due we want this per numa area or simply per zone? My suspicion is that internally at least we want this per zone.
I think that per memory block is better.
[snip]
Quoted 4 lines
I'm not fanatically
opposed to per zone binding, though, and if there is a general agreement that it would be better that way, I don't think it would be unreasonably difficult to change it.
My only feeling with zones is that it could be useful in the non numa cases, if it was per zone.
But unless this API becomes is a pure hint we need at least one specifier that says writing to swap is o.k.
Quoted 2 lines
Quoted 1 line
The API doesn't make much sense at the moment.
Hmm.. That is unfortunate, I'd aimed to make it as simple as possible.
Simple is good only if the proper pieces are connected.
Quoted 4 lines
Quoted 1 line
1) You are operating on tasks and not mm's, or preferably vmas.
Correct. There are plans (somewhere inside my cranium) to allow binding at that
granularity. For now, per task seemed an appropriate level.
It makes it terribly unpredictable. If you have two threads each bound to a different location there are race conditions which area the memory is allocated from.
Quoted 5 lines
Quoted 1 line
2)
sys_mem_setbindingdoes not move the mm to the new binding.Also correct. A task may wish to allocate several large data structures from one memory area, rebind, do more allocations, rebind, ad nauseum. There are plans to have a flag that, if set, would force relocation of all currently allocated memory.
Actually the bindings need to stick to the vma or to the struct address_space. Otherwise you are talking about an allocation hint, as swapping can trivially undue it and nothing happens when the actual call is made. A hint is a very different thing from a binding.
And if we stick this to struct address_space for the non anonymous cases having a fmem_setbinding(struct fd) that works on files would be a useful thing as well.
Quoted 3 lines
Quoted 1 line
5) mprotect is the more natural model rather than
set_cpu_affinity.Well, I think that may be true for the API you are imagining (per zone, per mm/vma, etc), not the one that I've written.
For a binding with respect to memory I imagine things like mlock(). For anything else you are talking a future hint to the memory allocators, which feels less much useful.
Eric