Moves the idlecoremap to the ksched
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 25 Jan 2012 19:10:39 +0000 (11:10 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sat, 28 Jan 2012 00:47:41 +0000 (16:47 -0800)
There's a lot of stuff built in to process code that belongs more in the
scheduler - such as the idlecoremap.  That one was an old example of how
things could be done.

The interfaces in sched.h are pretty ghetto, and a lot of this stuff is
just intermediate code.  And that hideous code for initing the number of
idle cores was simply moved to sched.c.

kern/include/process.h
kern/include/schedule.h
kern/src/process.c
kern/src/resource.c
kern/src/schedule.c

index 2c730b1..f6f8be3 100644 (file)
@@ -60,11 +60,6 @@ extern struct proc_list LCKD(&runnablelist_lock) proc_runnablelist;
 extern struct hashtable *pid_hash;
 extern spinlock_t pid_hash_lock;
 
-/* Idle cores: ones able to be exclusively given to a process (worker cores). */
-extern spinlock_t idle_lock;  // never grab this before a proc_lock
-extern uint32_t LCKD(&idle_lock) (RO idlecoremap)[MAX_NUM_CPUS];
-extern uint32_t LCKD(&idle_lock) num_idlecores;
-
 /* Initialization */
 void proc_init(void);
 
@@ -150,7 +145,6 @@ void proc_secure_trapframe(struct trapframe *tf);
 void __abandon_core(void);
 
 /* Degubbing */
-void print_idlecoremap(void);
 void print_allpids(void);
 void print_proc_info(pid_t pid);
 
index 7270df1..1e36cc0 100644 (file)
@@ -29,7 +29,17 @@ void deschedule_proc(struct proc *p);
 /* Pick and run a process.  Note that this can return. */
 void schedule(void);
 
+/* Gets called when a pcore becomes idle (like in proc yield) */
+void put_idle_core(uint32_t coreid);
+
+/* How many vcores p will think it can have */
+uint32_t max_vcores(struct proc *p);
+
+/* P wants some cores.  Put them in pc_arr */
+uint32_t proc_wants_cores(struct proc *p, uint32_t *pc_arr, uint32_t amt_new);
+
 /* Debugging */
 void dump_proclist(struct proc_list *list);
+void print_idlecoremap(void);
 
-#endif // !ROS_KERN_SCHEDULE_H
+#endif /* ROS_KERN_SCHEDULE_H */
index 1d2daf7..8dc7f64 100644 (file)
@@ -35,23 +35,6 @@ struct proc_list proc_runnablelist = TAILQ_HEAD_INITIALIZER(proc_runnablelist);
 spinlock_t runnablelist_lock = SPINLOCK_INITIALIZER;
 struct kmem_cache *proc_cache;
 
-/* Tracks which cores are idle, similar to the vcoremap.  Each value is the
- * physical coreid of an unallocated core. */
-spinlock_t idle_lock = SPINLOCK_INITIALIZER;
-uint32_t LCKD(&idle_lock) (RO idlecoremap)[MAX_NUM_CPUS];
-uint32_t LCKD(&idle_lock) num_idlecores = 0;
-uint32_t num_mgmtcores = 1;
-
-/* Helper function to return a core to the idlemap.  It causes some more lock
- * acquisitions (like in a for loop), but it's a little easier.  Plus, one day
- * we might be able to do this without locks (for the putting). */
-void put_idle_core(uint32_t coreid)
-{
-       spin_lock(&idle_lock);
-       idlecoremap[num_idlecores++] = coreid;
-       spin_unlock(&idle_lock);
-}
-
 /* Other helpers, implemented later. */
 static void __proc_startcore(struct proc *p, trapframe_t *tf);
 static bool is_mapped_vcore(struct proc *p, uint32_t pcoreid);
@@ -197,48 +180,7 @@ void proc_init(void)
        pid_hash = create_hashtable(100, __generic_hash, __generic_eq);
        spin_unlock(&pid_hash_lock);
        schedule_init();
-       /* Init idle cores. Core 0 is the management core. */
-       spin_lock(&idle_lock);
-#ifdef __CONFIG_DISABLE_SMT__
-       /* assumes core0 is the only management core (NIC and monitor functionality
-        * are run there too.  it just adds the odd cores to the idlecoremap */
-       assert(!(num_cpus % 2));
-       // TODO: consider checking x86 for machines that actually hyperthread
-       num_idlecores = num_cpus >> 1;
-#ifdef __CONFIG_ARSC_SERVER__
-       // Dedicate one core (core 2) to sysserver, might be able to share wit NIC
-       num_mgmtcores++;
-       assert(num_cpus >= num_mgmtcores);
-       send_kernel_message(2, (amr_t)arsc_server, 0,0,0, KMSG_ROUTINE);
-#endif
-       for (int i = 0; i < num_idlecores; i++)
-               idlecoremap[i] = (i * 2) + 1;
-#else
-       // __CONFIG_DISABLE_SMT__
-       #ifdef __CONFIG_NETWORKING__
-       num_mgmtcores++; // Next core is dedicated to the NIC
-       assert(num_cpus >= num_mgmtcores);
-       #endif
-       #ifdef __CONFIG_APPSERVER__
-       #ifdef __CONFIG_DEDICATED_MONITOR__
-       num_mgmtcores++; // Next core dedicated to running the kernel monitor
-       assert(num_cpus >= num_mgmtcores);
-       // Need to subtract 1 from the num_mgmtcores # to get the cores index
-       send_kernel_message(num_mgmtcores-1, (amr_t)monitor, 0,0,0, KMSG_ROUTINE);
-       #endif
-       #endif
-#ifdef __CONFIG_ARSC_SERVER__
-       // Dedicate one core (core 2) to sysserver, might be able to share wit NIC
-       num_mgmtcores++;
-       assert(num_cpus >= num_mgmtcores);
-       send_kernel_message(num_mgmtcores-1, (amr_t)arsc_server, 0,0,0, KMSG_ROUTINE);
-#endif
-       num_idlecores = num_cpus - num_mgmtcores;
-       for (int i = 0; i < num_idlecores; i++)
-               idlecoremap[i] = i + num_mgmtcores;
-#endif /* __CONFIG_DISABLE_SMT__ */
 
-       spin_unlock(&idle_lock);
        atomic_init(&num_envs, 0);
 }
 
@@ -247,12 +189,7 @@ static void proc_init_procinfo(struct proc* p)
 {
        p->procinfo->pid = p->pid;
        p->procinfo->ppid = p->ppid;
-       // TODO: maybe do something smarter here
-#ifdef __CONFIG_DISABLE_SMT__
-       p->procinfo->max_vcores = num_cpus >> 1;
-#else
-       p->procinfo->max_vcores = MAX(1,num_cpus-num_mgmtcores);
-#endif /* __CONFIG_DISABLE_SMT__ */
+       p->procinfo->max_vcores = max_vcores(p);
        p->procinfo->tsc_freq = system_timing.tsc_freq;
        p->procinfo->heap_bottom = (void*)UTEXT;
        /* 0'ing the arguments.  Some higher function will need to set them */
@@ -877,8 +814,8 @@ void proc_yield(struct proc *SAFE p, bool being_nice)
        if (!being_nice)
                p->resources[RES_CORES].amt_wanted = p->procinfo->num_vcores;
        __seq_end_write(&p->procinfo->coremap_seqctr);
-       // add to idle list
-       put_idle_core(pcoreid); /* TODO: prod the ksched? */
+       /* Hand the now-idle core to the ksched */
+       put_idle_core(pcoreid);
        // last vcore?  then we really want 1, and to yield the gang
        if (p->procinfo->num_vcores == 0) {
                p->resources[RES_CORES].amt_wanted = 1;
@@ -895,8 +832,6 @@ out_failed:
 out_yield_core:                        /* successfully yielded the core */
        spin_unlock(&p->proc_lock);
        proc_decref(p);                 /* need to eat the ref passed in */
-       /* TODO: (RMS) If there was a change to the idle cores, try and give our
-        * core to someone who was preempted. */
        /* Clean up the core and idle.  Need to do this before enabling interrupts,
         * since once we put_idle_core() and unlock, we could get a startcore. */
        clear_owning_proc(pcoreid);     /* so we don't restart */
@@ -1005,7 +940,6 @@ void __proc_preempt_core(struct proc *p, uint32_t pcoreid)
        p->procinfo->vcoremap[vcoreid].preempt_served = TRUE;
        // expects a pcorelist.  assumes pcore is mapped and running_m
        __proc_take_corelist(p, &pcoreid, 1, TRUE);
-       put_idle_core(pcoreid); /* TODO (IDLE) */
        /* Send a message about the preemption. */
        preempt_msg.ev_type = EV_VCORE_PREEMPT;
        preempt_msg.ev_arg2 = vcoreid;
@@ -1042,6 +976,7 @@ void proc_preempt_core(struct proc *p, uint32_t pcoreid, uint64_t usec)
        if (is_mapped_vcore(p, pcoreid)) {
                __proc_preempt_warn(p, get_vcoreid(p, pcoreid), warn_time);
                __proc_preempt_core(p, pcoreid);
+               put_idle_core(pcoreid);
        } else {
                warn("Pcore doesn't belong to the process!!");
        }
@@ -1293,11 +1228,6 @@ void __proc_take_corelist(struct proc *p, uint32_t *pc_arr, size_t num,
 {
        struct vcore *vc;
        uint32_t vcoreid;
-       /* Legacy sanity checks */
-       spin_lock(&idle_lock);
-       assert((num <= p->procinfo->num_vcores) &&
-              (num_idlecores + num <= num_cpus));
-       spin_unlock(&idle_lock);
        __seq_start_write(&p->procinfo->coremap_seqctr);
        for (int i = 0; i < num; i++) {
                vcoreid = get_vcoreid(p, pc_arr[i]);
@@ -1335,10 +1265,6 @@ uint32_t __proc_take_allcores(struct proc *p, uint32_t *pc_arr, bool preempt)
 {
        struct vcore *vc_i, *vc_temp;
        uint32_t num = 0;
-       /* Legacy sanity check */
-       spin_lock(&idle_lock);
-       assert(num_idlecores + p->procinfo->num_vcores <= num_cpus);
-       spin_unlock(&idle_lock);
        __seq_start_write(&p->procinfo->coremap_seqctr);
        /* Write out which pcores we're going to take */
        TAILQ_FOREACH(vc_i, &p->online_vcs, list)
@@ -1370,7 +1296,9 @@ uint32_t __proc_take_allcores(struct proc *p, uint32_t *pc_arr, bool preempt)
 }
 
 /* Dumb legacy helper, simply takes all cores and just puts them on the idle
- * core map (which belongs in the scheduler */
+ * core map (which belongs in the scheduler.
+ *
+ * TODO: no one should call this; the ksched should handle this internally */
 void __proc_take_allcores_dumb(struct proc *p, bool preempt)
 {
        uint32_t num_revoked;
@@ -1797,15 +1725,6 @@ void __tlbshootdown(struct trapframe *tf, uint32_t srcid, long a0, long a1,
        tlbflush();
 }
 
-void print_idlecoremap(void)
-{
-       spin_lock(&idle_lock);
-       printk("There are %d idle cores.\n", num_idlecores);
-       for (int i = 0; i < num_idlecores; i++)
-               printk("idlecoremap[%d] = %d\n", i, idlecoremap[i]);
-       spin_unlock(&idle_lock);
-}
-
 void print_allpids(void)
 {
        void print_proc_state(void *item)
index e7f1633..ef3f1c0 100644 (file)
@@ -87,25 +87,7 @@ ssize_t core_request(struct proc *p)
                return 0;
        }
        // else, we try to handle the request
-
-       /* TODO: someone needs to decide if the process gets the resources.
-        * we just check to see if they are available and give them out.  This
-        * should call out to the scheduler or some other *smart* function.  You
-        * could also imagine just putting it on the scheduler's queue and letting
-        * that do the core request */
-       spin_lock(&idle_lock);
-       if (num_idlecores >= amt_new) {
-               for (int i = 0; i < amt_new; i++) {
-                       // grab the last one on the list
-                       corelist[i] = idlecoremap[num_idlecores-1];
-                       num_idlecores--;
-               }
-               num_granted = amt_new;
-       } else {
-               /* In this case, you might want to preempt or do other fun things... */
-               num_granted = 0;
-       }
-       spin_unlock(&idle_lock);
+       num_granted = proc_wants_cores(p, corelist, amt_new);
 
        // Now, actually give them out
        if (num_granted) {
index 667d048..b86df8b 100644 (file)
@@ -17,6 +17,7 @@
 #include <assert.h>
 #include <atomic.h>
 #include <resource.h>
+#include <smp.h>
 #include <sys/queue.h>
 
 // This could be useful for making scheduling decisions.  
  * process is *really* running there. */
 struct proc *pcoremap[MAX_NUM_CPUS];
 
+/* Tracks which cores are idle, similar to the vcoremap.  Each value is the
+ * physical coreid of an unallocated core. */
+spinlock_t idle_lock = SPINLOCK_INITIALIZER;
+uint32_t idlecoremap[MAX_NUM_CPUS];
+uint32_t num_idlecores = 0;
+uint32_t num_mgmtcores = 1;
+
 void schedule_init(void)
 {
        TAILQ_INIT(&proc_runnablelist);
+
+       /* Ghetto old idle core init */
+       /* Init idle cores. Core 0 is the management core. */
+       spin_lock(&idle_lock);
+#ifdef __CONFIG_DISABLE_SMT__
+       /* assumes core0 is the only management core (NIC and monitor functionality
+        * are run there too.  it just adds the odd cores to the idlecoremap */
+       assert(!(num_cpus % 2));
+       // TODO: consider checking x86 for machines that actually hyperthread
+       num_idlecores = num_cpus >> 1;
+ #ifdef __CONFIG_ARSC_SERVER__
+       // Dedicate one core (core 2) to sysserver, might be able to share wit NIC
+       num_mgmtcores++;
+       assert(num_cpus >= num_mgmtcores);
+       send_kernel_message(2, (amr_t)arsc_server, 0,0,0, KMSG_ROUTINE);
+ #endif
+       for (int i = 0; i < num_idlecores; i++)
+               idlecoremap[i] = (i * 2) + 1;
+#else
+       // __CONFIG_DISABLE_SMT__
+       #ifdef __CONFIG_NETWORKING__
+       num_mgmtcores++; // Next core is dedicated to the NIC
+       assert(num_cpus >= num_mgmtcores);
+       #endif
+       #ifdef __CONFIG_APPSERVER__
+       #ifdef __CONFIG_DEDICATED_MONITOR__
+       num_mgmtcores++; // Next core dedicated to running the kernel monitor
+       assert(num_cpus >= num_mgmtcores);
+       // Need to subtract 1 from the num_mgmtcores # to get the cores index
+       send_kernel_message(num_mgmtcores-1, (amr_t)monitor, 0,0,0, KMSG_ROUTINE);
+       #endif
+       #endif
+ #ifdef __CONFIG_ARSC_SERVER__
+       // Dedicate one core (core 2) to sysserver, might be able to share with NIC
+       num_mgmtcores++;
+       assert(num_cpus >= num_mgmtcores);
+       send_kernel_message(num_mgmtcores-1, (amr_t)arsc_server, 0,0,0, KMSG_ROUTINE);
+ #endif
+       num_idlecores = num_cpus - num_mgmtcores;
+       for (int i = 0; i < num_idlecores; i++)
+               idlecoremap[i] = i + num_mgmtcores;
+#endif /* __CONFIG_DISABLE_SMT__ */
+       spin_unlock(&idle_lock);
        return;
 }
 
@@ -90,6 +141,50 @@ void schedule(void)
        return;
 }
 
+/* Helper function to return a core to the idlemap.  It causes some more lock
+ * acquisitions (like in a for loop), but it's a little easier.  Plus, one day
+ * we might be able to do this without locks (for the putting). */
+void put_idle_core(uint32_t coreid)
+{
+       spin_lock(&idle_lock);
+       idlecoremap[num_idlecores++] = coreid;
+       spin_unlock(&idle_lock);
+}
+
+/* Normally it'll be the max number of CG cores ever */
+uint32_t max_vcores(struct proc *p)
+{
+#ifdef __CONFIG_DISABLE_SMT__
+       return num_cpus >> 1;
+#else
+       return MAX(1, num_cpus - num_mgmtcores);
+#endif /* __CONFIG_DISABLE_SMT__ */
+}
+
+/* Ghetto old interface, hacked out of resource.c.  It doesn't even care about
+ * the proc yet, but in general the whole core_request bit needs reworked. */
+uint32_t proc_wants_cores(struct proc *p, uint32_t *pc_arr, uint32_t amt_new)
+{
+       uint32_t num_granted;
+       /* You should do something smarter than just giving the stuff out.  Like
+        * take in to account priorities, node locations, etc */
+       spin_lock(&idle_lock);
+       if (num_idlecores >= amt_new) {
+               for (int i = 0; i < amt_new; i++) {
+                       // grab the last one on the list
+                       pc_arr[i] = idlecoremap[num_idlecores - 1];
+                       num_idlecores--;
+               }
+               num_granted = amt_new;
+       } else {
+               /* In this case, you might want to preempt or do other fun things... */
+               num_granted = 0;
+       }
+       spin_unlock(&idle_lock);
+       return num_granted;
+}
+
+/************** Debugging **************/
 void dump_proclist(struct proc_list *list)
 {
        struct proc *p;
@@ -97,3 +192,12 @@ void dump_proclist(struct proc_list *list)
                printk("PID: %d\n", p->pid);
        return;
 }
+
+void print_idlecoremap(void)
+{
+       spin_lock(&idle_lock);
+       printk("There are %d idle cores.\n", num_idlecores);
+       for (int i = 0; i < num_idlecores; i++)
+               printk("idlecoremap[%d] = %d\n", i, idlecoremap[i]);
+       spin_unlock(&idle_lock);
+}