2.5.11 NUMA API
Subsystems (7)
PATCH 1/1 2.5.11 NUMA API
Greetings and Salutations,
Sorry about the cross-post, but this patch should be of interest to both
lists. Attatched is a copy of my implementation of the NUMA API that I would like to see included in the mainline kernel. The NUMA API is an API designed to facilitate using NUMA machines. The complete API is specified at:
http://lse.sourceforge.net/numa/numa_api.html
The patch facilitates the binding of processes to particular CPUs, groups of CPUs, nodes, and/or memory blocks. It also allows for a rudimentary form of topology discovery via the xxx_to_node() and node_to_xxx() calls. The API is currently implemented through prctl() calls, although I do have a version that uses syscalls instead if anyone is interested in that.
The patch is against 2.5.11, although it has only been tested on 2.5.8, because 2.5.[9-11] do not boot on our NUMA-Q boxen. I will be having a look at that problem now that I've finished this. Having looked through changelogs, I do not see any code that would break the patch, and it applies cleanly. Some of the code is only useful if CONFIG_DISCONTIGMEM and/or CONFIG_NUMA is turned on, like the memory allocation changes...
As always, questions, comments, and criticism welcome!
-Matt
[email protected]
arch/i386/Config.help +7 -0
@@ -48,6 +48,13 @@ You will need a new lynxer.elf file to flash your firmware with - send email to [email protected] +CONFIG_NUMA_API + This option is used to turn on support for the NUMA API, which allows + the binding of processes to specific processors/nodes/memory blocks. + This option is also used for some of the NUMA Topology features. + Please email Matthew Dobson <[email protected]> with questions + and/or concerns. + CONFIG_X86_UP_IOAPIC An IO-APIC (I/O Advanced Programmable Interrupt Controller) is an SMP-capable replacement for PC-style interrupt controllers. Most
arch/i386/config.in +1 -0
@@ -198,6 +198,7 @@ fi else bool 'Multiquad NUMA system' CONFIG_MULTIQUAD + bool 'Non-Uniform Memory Access API support' CONFIG_NUMA_API fi if [ "$CONFIG_SMP" = "y" -o "$CONFIG_PREEMPT" = "y" ]; then
include/asm-i386/mmzone.h +72 -0
72 lines not on this page · raw message
include/linux/init_task.h +4 -0
@@ -59,6 +59,10 @@ children: LIST_HEAD_INIT(tsk.children), \ sibling: LIST_HEAD_INIT(tsk.sibling), \ thread_group: LIST_HEAD_INIT(tsk.thread_group), \ + numa_restrict: NEW_NUMA_SET, \ + numa_binding: NEW_NUMA_SET, \ + numa_launch_policy: NEW_NUMA_SET, \ + numa_api_lock: RW_LOCK_UNLOCKED, \ wait_chldexit: __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\ real_timer: { \ function: it_real_fn \
include/linux/mmzone.h +5 -3
@@ -136,6 +136,7 @@unsigned long node_start_mapnr;unsigned long node_size;int node_id; +int memblk_id;/* A unique ID for each memory block (physical contiguous chunk of memory) */ struct pglist_data *node_next; } pg_data_t;
@@ -163,14 +164,15 @@#define NODE_MEM_MAP (nid) mem_map#define MAX_NR_NODES 1 -#else /* !CONFIG_DISCONTIGMEM */ +#endif /* !CONFIG_DISCONTIGMEM */ -#include <asm/mmzone.h> +#if defined (CONFIG_DISCONTIGMEM ) || defined (CONFIG_NUMA_API ) +#include <asm/mmzone.h> /* page->zone is currently 8 bits ... */ #define MAX_NR_NODES (255 / MAX_NR_ZONES) -#endif /* !CONFIG_DISCONTIGMEM */ +#endif /* CONFIG_DISCONTIGMEM || CONFIG_NUMA_API */ #define MAP_ALIGN (x) ((((x) % sizeof(mem_map_t)) == 0) ? (x) : ((x) + \ sizeof(mem_map_t) - ((x) % sizeof(mem_map_t))))
include/linux/numa.h +70 -0
70 lines not on this page · raw message
include/linux/prctl.h +27 -0
@@ -26,4 +26,31 @@# define PR_FPEMU_NOPRINT 1/* silently emulate fp operations accesses */ # define PR_FPEMU_SIGFPE 2/* don't emulate fp operations, send SIGFPE instead */ +/* Get/Set Restricted CPUs and MemBlks */ +#define PR_SET_RESTRICTED_CPUS 11 +#define PR_SET_RESTRICTED_MEMBLKS 12 +#define PR_GET_RESTRICTED_CPUS 13 +#define PR_GET_RESTRICTED_MEMBLKS 14 + +/* Get CPU/Node */ +#define PR_GET_CPU 15 +#define PR_GET_NODE 16 + +/* X to Node conversion functions */ +#define PR_CPU_TO_NODE 17 +#define PR_MEMBLK_TO_NODE 18 +#define PR_NODE_TO_NODE 19 + +/* Node to X conversion functions */ +#define PR_NODE_TO_CPU 20 +#define PR_NODE_TO_MEMBLK 21 + +/* Set CPU/MemBlk/Memory Bindings */ +#define PR_BIND_TO_CPUS 22 +#define PR_BIND_TO_MEMBLKS 23 +#define PR_BIND_MEMORY 24 + +/* Set Launch Policy */ +#define PR_SET_LAUNCH_POLICY 25 +#endif /* _LINUX_PRCTL_H */
include/linux/sched.h +7 -0
@@ -28,6 +28,7 @@#include <linux/securebits.h> #include <linux/fs_struct.h> #include <linux/compiler.h> +#include <linux/numa.h> struct exec_domain ;
@@ -286,6 +287,12 @@struct task_struct *pidhash_next;struct task_struct **pidhash_pprev; +/* additional NUMA stuff */ +numa_set_t numa_restrict; +numa_set_t numa_binding; +numa_set_t numa_launch_policy; +rwlock_t numa_api_lock;/* protects the preceding 3 structs */ +wait_queue_head_t wait_chldexit;/* for wait4() */ struct completion *vfork_done;/* for vfork() */
include/linux/smp.h +1 -0
@@ -90,6 +90,7 @@#define cpu_number_map (cpu) 0#define smp_call_function (func,info,retry,wait) ({ 0; })#define cpu_online_map 1 +#define memblk_online_map 1static inline void smp_send_reschedule (int cpu) { }static inline void smp_send_reschedule_all (void ) { }#define __per_cpu_data
kernel/Makefile +1 -1
@@ -15,7 +15,7 @@ obj-y = sched.o dma.o fork.o exec_domain.o panic.o printk.o \ module.o exit.o itimer.o info.o time.o softirq.o resource.o \ sysctl.o capability.o ptrace.o timer.o user.o \ - signal.o sys.o kmod.o context.o futex.o platform.o + signal.o sys.o kmod.o context.o futex.o platform.o numa.o obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o
kernel/fork.c +14 -0
@@ -707,6 +707,20 @@spin_lock_init (&p->sigmask_lock); }#endif +if (!is_empty_numa_set (&p->numa_launch_policy)){ + p->numa_binding = p->numa_launch_policy; + p->cpus_allowed = p->numa_binding.cpus.list & p->numa_restrict.cpus.list; +if (!(p->cpus_allowed & cpu_online_map)) +BUG (); +if (p->cpus_allowed & (1UL <<smp_processor_id ())) + p->thread_info->cpu =smp_processor_id (); +else + p->thread_info->cpu =__ffs (p->cpus_allowed & cpu_online_map); + }else + p->thread_info->cpu =smp_processor_id (); +numa_set_init (&p->numa_launch_policy); +rwlock_init (&p->numa_api_lock); + p->array =NULL ; p->lock_depth =-1 ;/* -1 = no lock */ p->start_time = jiffies;
kernel/numa.c +378 -0
378 lines not on this page · raw message
kernel/sched.c +2 -4
@@ -352,7 +352,7 @@runqueue_t *rq;preempt_disable (); - rq =this_rq (); + rq =task_rq (p);spin_lock_irq (&rq->lock); p->state =TASK_RUNNING ;
@@ -366,7 +366,6 @@ p->sleep_avg = p->sleep_avg *CHILD_PENALTY /100 ; p->prio =effective_prio (p); } - p->thread_info->cpu =smp_processor_id ();activate_task (p, rq);spin_unlock_irq (&rq->lock);
@@ -1645,8 +1644,7 @@migration_req_t req;runqueue_t *rq; - new_mask &= cpu_online_map; -if (!new_mask) +if (!(new_mask & cpu_online_map))BUG ();preempt_disable ();
kernel/sys.c +46 -0
58 lines not on this page · raw message
mm/numa.c +76 -13
137 lines not on this page · raw message
mm/page_alloc.c +7 -0
@@ -39,6 +39,9 @@static int zone_balance_min[MAX_NR_ZONES ]__initdata = {20 ,20 ,20 , };static int zone_balance_max[MAX_NR_ZONES ]__initdata = {255 ,255 ,255 , }; +extern int nummemblks; +extern unsigned long memblk_online_map; +/* * Free_page() adds the page to the free lists. This is optimized for * fast normal cases (no error jumps taken normally).
@@ -866,6 +869,10 @@void __init free_area_init (unsigned long *zones_size) {free_area_init_core (0 , &contig_page_data, &mem_map, zones_size,0 ,0 ,0 ); + contig_page_data.node_id =0 ; + contig_page_data.memblk_id =0 ; + nummemblks =1 ; + memblk_online_map =1UL ; }static int __init setup_mem_frac (char *str)