UP CPU number microoptimisation, updated
PATCH 1/1 UP CPU number microoptimisation, updated
This is an update to the ->thread_info->cpu microoptimisation patch posted last week. The main change is that the optimised access macros now are defined in <linux/thread_info.h>, which should allow this to work on all architectures, not just x86.
The patch eliminates ->thread_info->cpu accesses in UP configs, since ->cpu is known to be zero. This primarily affects the
scheduler: in my 2.5.9 kernel it eliminated 256 bytes of code from kernel/sched.o.
/Mikael
fs/proc/array.c +1 -1
@@ -389,7 +389,7 @@ task->nswap, task->cnswap, task->exit_signal, - task->thread_info->cpu); + thread_info_cpu(task->thread_info));if (mm)mmput (mm);return res;
include/asm-i386/thread_info.h +15 -7
@@ -24,26 +24,34 @@struct task_struct *task;/* main task structure */ struct exec_domain *exec_domain;/* execution domain */ unsigned long flags;/* low level flags */ -__u32 cpu;/* current CPU */ -__s32 preempt_count;/* 0 => preemptable, <0 => BUG */ -mm_segment_t addr_limit;/* thread address space: 0-0xBFFFFFFF for user-thead 0-0xFFFFFFFF for kernel-thread */ - +__s32 preempt_count;/* 0 => preemptable, <0 => BUG */ +#ifdef CONFIG_SMP +__u32 cpu;/* current CPU */ +#endif __u8 supervisor_stack[0]; }; +#ifdef CONFIG_SMP +#define TI_CPU_INIT cpu: 0, +#else +#define TI_CPU_INIT /*empty*/ +#endif +#else /* !__ASSEMBLY__ */ /* offsets into the thread_info struct for assembly code access */ #define TI_TASK 0x00000000#define TI_EXEC_DOMAIN 0x00000004#define TI_FLAGS 0x00000008 -#define TI_CPU 0x0000000C +#define TI_ADDR_LIMIT 0x0000000C#define TI_PRE_COUNT 0x00000010 -#define TI_ADDR_LIMIT 0x00000014 +#ifdef CONFIG_SMP +#define TI_CPU 0x00000014 +#endif #endif
@@ -58,8 +66,8 @@ task: &tsk, \ exec_domain: &default_exec_domain, \ flags: 0, \ - cpu: 0, \ addr_limit: KERNEL_DS, \ + TI_CPU_INIT \ }#define init_thread_info (init_thread_union.thread_info)
include/linux/thread_info.h +27 -0
@@ -13,6 +13,33 @@#ifdef __KERNEL__/* +* wrappers for thread_info->cpu accesses +* optimised away on UP (cpu == 0 is an invariant) +*/ +#ifdef CONFIG_SMP +static inline unsigned int thread_info_cpu (const struct thread_info *ti) +{ +return ti->cpu; +} + +static inline void set_thread_info_cpu (struct thread_info *ti,unsigned int cpu) +{ + ti->cpu = cpu; +} + +#else /* !CONFIG_SMP */ + +static inline unsigned int thread_info_cpu (const struct thread_info *ti) +{ +return 0 ; +} + +static inline void set_thread_info_cpu (struct thread_info *ti,unsigned int cpu) +{ +} +#endif /* CONFIG_SMP */ + +/* * flag set/clear/test wrappers * - pass TIF_xxxx constants to these functions */
kernel/sched.c +11 -11
@@ -153,7 +153,7 @@#define cpu_rq (cpu) (runqueues + (cpu))#define this_rq () cpu_rq(smp_processor_id()) -#define task_rq (p) cpu_rq((p)->thread_info->cpu) +#define task_rq (p) cpu_rq(thread_info_cpu((p)->thread_info))#define cpu_curr (cpu) (cpu_rq(cpu)->curr)#define rt_task (p) ((p)->prio < MAX_RT_PRIO)
@@ -264,8 +264,8 @@ need_resched =test_and_set_tsk_thread_flag (p,TIF_NEED_RESCHED ); nrpolling |=test_tsk_thread_flag (p,TIF_POLLING_NRFLAG ); -if (!need_resched && !nrpolling && (p->thread_info->cpu !=smp_processor_id ())) -smp_send_reschedule (p->thread_info->cpu); +if (!need_resched && !nrpolling && (thread_info_cpu (p->thread_info) !=smp_processor_id ())) +smp_send_reschedule (thread_info_cpu (p->thread_info));preempt_enable ();#else set_tsk_need_resched (p);
@@ -366,7 +366,7 @@ p->sleep_avg = p->sleep_avg *CHILD_PENALTY /100 ; p->prio =effective_prio (p); } - p->thread_info->cpu =smp_processor_id (); +set_thread_info_cpu (p->thread_info,smp_processor_id ());activate_task (p, rq);spin_unlock_irq (&rq->lock);
@@ -609,7 +609,7 @@*/ dequeue_task (next, array); busiest->nr_running--; - next->thread_info->cpu = this_cpu; +set_thread_info_cpu (next->thread_info, this_cpu); this_rq->nr_running++;enqueue_task (next, this_rq->active);if (next->prio < current->prio)
@@ -1535,7 +1535,7 @@void __init init_idle (task_t *idle,int cpu) { -runqueue_t *idle_rq =cpu_rq (cpu), *rq =cpu_rq (idle->thread_info->cpu); +runqueue_t *idle_rq =cpu_rq (cpu), *rq =cpu_rq (thread_info_cpu (idle->thread_info));unsigned long flags;__save_flags (flags);
@@ -1547,7 +1547,7 @@ idle->array =NULL ; idle->prio =MAX_PRIO ; idle->state =TASK_RUNNING ; - idle->thread_info->cpu = cpu; +set_thread_info_cpu (idle->thread_info, cpu);double_rq_unlock (idle_rq, rq);set_tsk_need_resched (idle);__restore_flags (flags);
@@ -1656,7 +1656,7 @@* Can the task run on the task's current CPU? If not then * migrate the process off to a proper CPU. */ -if (new_mask & (1UL << p->thread_info->cpu)) { +if (new_mask & (1UL <<thread_info_cpu (p->thread_info))) {task_rq_unlock (rq, &flags); goto out; }
@@ -1723,18 +1723,18 @@ cpu_dest =__ffs (p->cpus_allowed); rq_dest =cpu_rq (cpu_dest); repeat: - cpu_src = p->thread_info->cpu; + cpu_src =thread_info_cpu (p->thread_info); rq_src =cpu_rq (cpu_src);local_irq_save (flags);double_rq_lock (rq_src, rq_dest); -if (p->thread_info->cpu != cpu_src) { +if (thread_info_cpu (p->thread_info) != cpu_src) {double_rq_unlock (rq_src, rq_dest);local_irq_restore (flags); goto repeat; }if (rq_src == rq) { - p->thread_info->cpu = cpu_dest; +set_thread_info_cpu (p->thread_info, cpu_dest);if (p->array) {deactivate_task (p, rq_src);activate_task (p, rq_dest);
kernel/signal.c +1 -1
@@ -508,7 +508,7 @@* process of changing - but no harm is done by that * other than doing an extra (lightweight) IPI interrupt. */ -if ((t->state ==TASK_RUNNING ) && (t->thread_info->cpu !=smp_processor_id ())) +if ((t->state ==TASK_RUNNING ) && (thread_info_cpu (t->thread_info) !=smp_processor_id ()))kick_if_running (t);#endif if (t->state &TASK_INTERRUPTIBLE ) {