OSDI Microbenchmarks
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 3 May 2010 03:22:17 +0000 (20:22 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:47 +0000 (17:35 -0700)
Adds new testing files and a new developer name.  Use the developer
"tests" to run the scripted tests.  Make sure you have KFS running.

Makelocal.template
kern/src/Makefrag
kern/src/kfs.c
kern/src/manager.c
kern/src/process.c
tests/msr_cycling_vcores.c
tests/msr_dumb_while.c
tests/msr_get_cores.c
tests/msr_get_singlecore.c [new file with mode: 0644]
tests/tsc_spitter.c [new file with mode: 0644]

index f70aee2..c18f18d 100644 (file)
@@ -25,6 +25,8 @@
 
 #KERN_CFLAGS += -DDEVELOPER_NAME=waterman
 #KERN_CFLAGS += -DDEVELOPER_NAME=brho
+# This manager runs the OSDI microbenchmarks from KFS
+#KERN_CFLAGS += -DDEVELOPER_NAME=tests
 
 # Userspace configuration parameters
 #USER_CFLAGS += $(CONFIG_SYSCALL_TRAP)
index bcade7a..b092aed 100644 (file)
@@ -61,7 +61,9 @@ KERN_APPFILES += \
                  $(TESTS_DIR)/pthread_barrier_test \
                  $(TESTS_DIR)/idle \
                  $(TESTS_DIR)/fillmeup \
+                 $(TESTS_DIR)/tsc_spitter \
                  $(TESTS_DIR)/msr_get_cores \
+                 $(TESTS_DIR)/msr_get_singlecore \
                  $(TESTS_DIR)/msr_dumb_while \
                  $(TESTS_DIR)/msr_nice_while \
                  $(TESTS_DIR)/msr_single_while \
index 8562747..ddd5e68 100644 (file)
@@ -48,7 +48,9 @@ DECL_PROG(pthread_test);
 DECL_PROG(pthread_barrier_test);
 DECL_PROG(idle);
 DECL_PROG(fillmeup);
+DECL_PROG(tsc_spitter);
 DECL_PROG(msr_get_cores);
+DECL_PROG(msr_get_singlecore);
 DECL_PROG(msr_dumb_while);
 DECL_PROG(msr_nice_while);
 DECL_PROG(msr_single_while);
@@ -68,7 +70,9 @@ struct kfs_entry kfs[MAX_KFS_FILES] = {
        KFS_PENTRY(pthread_barrier_test)
        KFS_PENTRY(idle)
        KFS_PENTRY(fillmeup)
+       KFS_PENTRY(tsc_spitter)
        KFS_PENTRY(msr_get_cores)
+       KFS_PENTRY(msr_get_singlecore)
        KFS_PENTRY(msr_dumb_while)
        KFS_PENTRY(msr_nice_while)
        KFS_PENTRY(msr_single_while)
index 5a30b8c..84ea70f 100644 (file)
@@ -31,6 +31,8 @@
 #include <colored_caches.h>
 #include <string.h>
 #include <pmap.h>
+#include <ros/timer.h>
+#include <ros/arch/membar.h>
 
 /*
  * Currently, if you leave this function by way of proc_run (process_workqueue
@@ -51,12 +53,20 @@ void manager(void)
        MANAGER_FUNC(DEVELOPER_NAME)();
 }
 
+/* Helper macro for quickly running something out of KFS.  Pass it a string and
+ * a proc pointer. */
+#define quick_proc_run(x, p)                                                     \
+       (p) = kfs_proc_create(kfs_lookup_path((x)));                                 \
+       spin_lock(&(p)->proc_lock);                                                  \
+       __proc_set_state((p), PROC_RUNNABLE_S);                                      \
+       spin_unlock(&(p)->proc_lock);                                                \
+       proc_run((p));                                                               \
+       proc_decref((p), 1);
+
 void manager_brho(void)
 {
        static uint8_t RACY progress = 0;
-
-       static struct proc *envs[256];
-       static struct proc *p ;
+       static struct proc *p;
 
        // for testing taking cores, check in case 1 for usage
        uint32_t corelist[MAX_NUM_CPUS];
@@ -64,17 +74,7 @@ void manager_brho(void)
 
        switch (progress++) {
                case 0:
-                       // TODO: need to store the pid for future manager runs, not the *p
-                       //p = kfs_proc_create(kfs_lookup_path("pthread_test"));
-                       //p = kfs_proc_create(kfs_lookup_path("mhello"));
-                       p = kfs_proc_create(kfs_lookup_path("msr_dumb_while"));
-                       // being proper and all:
-                       spin_lock(&p->proc_lock);
-                       __proc_set_state(p, PROC_RUNNABLE_S);
-                       // normal single-cored way
-                       spin_unlock(&p->proc_lock);
-                       proc_run(p);
-                       proc_decref(p, 1);
+                       quick_proc_run("msr_dumb_while", p);
                        #if 0
                        // this is how you can transition to a parallel process manually
                        // make sure you don't proc run first
@@ -87,7 +87,6 @@ void manager_brho(void)
                        #endif
                        break;
                case 1:
-                       //monitor(0);
                        #if 0
                        udelay(10000000);
                        // this is a ghetto way to test restarting an _M
@@ -135,6 +134,7 @@ void manager_brho(void)
                        schedule();
        }
        panic("If you see me, then you probably screwed up");
+       monitor(0);
 
        /*
        printk("Servicing syscalls from Core 0:\n\n");
@@ -212,6 +212,382 @@ void manager_pearce()
 
 }
 
+#ifdef __CONFIG_OSDI__
+/* Manager for Micro benchmarks, OSDI, etc */
+struct proc *mgr_p1 = 0;
+struct proc *mgr_p2 = 0;
+static void exper_1_part2(struct proc **pp);
+static void exper_2_part2(struct proc **pp);
+static void exper_3_part2(struct proc **pp);
+static void exper_4_part2(struct proc **pp);
+static void exper_5_part2(struct proc **pp);
+static void exper_6_part2(struct proc **pp);
+static void exper_7_part2(struct proc **pp);
+static void exper_8_part2(struct proc **pp);
+static void exper_9_part2(struct proc **pp);
+
+void manager_tests(void)
+{
+       static uint8_t RACY progress = 0;
+
+       printk("Test Progress: %d\n", progress);
+       /* 10 runs of every experiment.  Finishing/Part2 is harmless on a null
+        * pointer.  We need to clean up/ finish/ part2 after each quick_proc_run,
+        * since we leave the monitor and only enter on another run (with
+        * progress++).  That's why we run a part2 in the first case: of the next
+        * experiment. */
+       switch (progress++) {
+               /* Experiment 1: get max vcores */
+               case 0:
+                       printk("************* Starting experiment 1 ************** \n");
+               case 1:
+               case 2:
+               case 3:
+               case 4:
+               case 5:
+               case 6:
+               case 7:
+               case 8:
+               case 9:
+                       exper_1_part2(&mgr_p1);
+                       quick_proc_run("msr_get_cores", mgr_p1);
+                       break;
+               /* Experiment 2: get a single vcore */
+               case 10:
+                       exper_1_part2(&mgr_p1);
+                       printk("************* Starting experiment 2 ************** \n");
+               case 11:
+               case 12:
+               case 13:
+               case 14:
+               case 15:
+               case 16:
+               case 17:
+               case 18:
+               case 19:
+                       exper_2_part2(&mgr_p1);
+                       quick_proc_run("msr_get_singlecore", mgr_p1);
+                       break;
+               /* Experiment 3: kill a _M */
+               case 20: /* leftover from exp 2 */
+                       exper_2_part2(&mgr_p1);
+                       printk("************* Starting experiment 3 ************** \n");
+               case 21:
+               case 22:
+               case 23:
+               case 24:
+               case 25:
+               case 26:
+               case 27:
+               case 28:
+               case 29:
+                       exper_3_part2(&mgr_p1);
+                       quick_proc_run("msr_dumb_while", mgr_p1);
+                       break;
+               /* Experiment 4: _S create and death*/
+               case 30: /* leftover from exp 3 */
+                       exper_3_part2(&mgr_p1);
+                       printk("************* Starting experiment 4 ************** \n");
+               case 31:
+               case 32:
+               case 33:
+               case 34:
+               case 35:
+               case 36:
+               case 37:
+               case 38:
+               case 39:
+                       exper_4_part2(&mgr_p1);
+                       printk("[T]:004:S:%llu\n", read_tsc());
+                       quick_proc_run("tsc_spitter", mgr_p1);
+                       break;
+               /* Experiment 5: raw preempt, entire process*/
+               case 40:
+                       exper_4_part2(&mgr_p1);
+                       printk("************* Starting experiment 5 ************** \n");
+               case 41:
+               case 42:
+               case 43:
+               case 44:
+               case 45:
+               case 46:
+               case 47:
+               case 48:
+               case 49:
+                       exper_5_part2(&mgr_p1);
+                       quick_proc_run("msr_nice_while", mgr_p1);
+                       break;
+               /* Experiment 6: preempt-warn, entire process */
+               case 50:
+                       exper_5_part2(&mgr_p1);
+                       printk("************* Starting experiment 6 ************** \n");
+               case 51:
+               case 52:
+               case 53:
+               case 54:
+               case 55:
+               case 56:
+               case 57:
+               case 58:
+               case 59:
+                       exper_6_part2(&mgr_p1);
+                       quick_proc_run("msr_nice_while", mgr_p1);
+                       break;
+               /* Experiment 7: preempt-raw, single core */
+               case 60:
+                       exper_6_part2(&mgr_p1);
+                       printk("************* Starting experiment 7 ************** \n");
+               case 61:
+               case 62:
+               case 63:
+               case 64:
+               case 65:
+               case 66:
+               case 67:
+               case 68:
+               case 69:
+                       exper_7_part2(&mgr_p1);
+                       quick_proc_run("msr_nice_while", mgr_p1);
+                       break;
+               /* Experiment 8: preempt-warn, single core */
+               case 70:
+                       exper_7_part2(&mgr_p1);
+                       printk("************* Starting experiment 8 ************** \n");
+               case 71:
+               case 72:
+               case 73:
+               case 74:
+               case 75:
+               case 76:
+               case 77:
+               case 78:
+               case 79:
+                       exper_8_part2(&mgr_p1);
+                       quick_proc_run("msr_nice_while", mgr_p1);
+                       break;
+               /* Experiment 9: single notification time */
+               case 80:
+                       exper_8_part2(&mgr_p1);
+                       printk("************* Starting experiment 9 ************** \n");
+               case 81:
+               case 82:
+               case 83:
+               case 84:
+               case 85:
+               case 86:
+               case 87:
+               case 88:
+               case 89:
+                       exper_9_part2(&mgr_p1);
+                       quick_proc_run("msr_dumb_while", mgr_p1);
+                       break;
+               /* Experiment 10: cycling vcore */
+               case 90:
+                       exper_9_part2(&mgr_p1);
+                       printk("************* Starting experiment 10 ************* \n");
+                       quick_proc_run("msr_dumb_while", mgr_p1);
+                       break;
+               case 91:
+                       quick_proc_run("msr_cycling_vcores", mgr_p2);
+                       break;
+               case 92:
+                       printk("Will go on forever.  Udelaying for two minutes.\n");
+                       udelay(120000000);
+                       proc_incref(mgr_p1, 1);
+                       proc_destroy(mgr_p1);
+                       proc_decref(mgr_p1, 1);
+                       proc_incref(mgr_p2, 1);
+                       proc_destroy(mgr_p2);
+                       proc_decref(mgr_p2, 1);
+                       printk("Done with the tests!");
+                       monitor(0);
+                       break;
+               default:
+                       printd("Manager Progress: %d\n", progress);
+                       schedule();
+       }
+       monitor(0);
+       return;
+}
+
+/* OSDI experiment "bottom halves" */
+/* Experiment 1: get max vcores */
+static void exper_1_part2(struct proc **pp)
+{
+       while (*pp) /* make sure the previous run is over */
+               cpu_relax();
+}
+
+/* Experiment 2: get a single vcore */
+static void exper_2_part2(struct proc **pp)
+{
+       while (*pp) /* make sure the previous run is over */
+               cpu_relax();
+}
+
+/* Experiment 3: kill a _M */
+static void exper_3_part2(struct proc **pp)
+{
+       uint64_t begin = 0, diff = 0;
+
+       if (*pp) { /* need to kill, etc */
+               proc_incref(*pp, 1);
+               begin = start_timing(); 
+               proc_destroy(*pp);
+               proc_decref(*pp, 1);
+               wmb();
+               while (*pp) /* toggled in proc_free */
+                       cpu_relax();
+               diff = stop_timing(begin);      
+               printk("Took %llu usec (%llu nsec) to kill.\n",
+                      diff * 1000000 / system_timing.tsc_freq,
+                      diff * 1000000000 / system_timing.tsc_freq);
+               printk("[T]:003:%llu:%llu\n",
+                      diff * 1000000 / system_timing.tsc_freq,
+                      diff * 1000000000 / system_timing.tsc_freq);
+       }
+}
+
+/* Experiment 4: _S create and death*/
+static void exper_4_part2(struct proc **pp)
+{
+       while (*pp) /* make sure the previous run is over */
+               cpu_relax();
+}
+
+/* Experiment 5: raw preempt, entire process*/
+static void exper_5_part2(struct proc **pp)
+{
+       uint64_t begin = 0, diff = 0;
+       uint32_t end_refcnt = 0;
+       bool self_ipi_pending = FALSE;
+
+       if (*pp) {
+               proc_incref(*pp, 1);
+               spin_lock(&(*pp)->proc_lock);
+               end_refcnt = (*pp)->env_refcnt - (*pp)->procinfo->num_vcores;
+               begin = start_timing();
+               self_ipi_pending = __proc_preempt_all(*pp);
+               spin_unlock(&(*pp)->proc_lock);
+               __proc_kmsg_pending(*pp, self_ipi_pending);
+               spin_on((*pp)->env_refcnt != end_refcnt);
+               diff = stop_timing(begin);
+               printk("Took %llu usec (%llu nsec) to raw preempt all.\n",
+                      diff * 1000000 / system_timing.tsc_freq,
+                      diff * 1000000000 / system_timing.tsc_freq);
+               printk("[T]:005:%llu:%llu\n",
+                      diff * 1000000 / system_timing.tsc_freq,
+                      diff * 1000000000 / system_timing.tsc_freq);
+               proc_destroy(*pp);
+               proc_decref(*pp, 1);
+               while (*pp) /* toggled in proc_free */
+                       cpu_relax();
+       }
+}
+
+/* Experiment 6: preempt-warn, entire process */
+static void exper_6_part2(struct proc **pp)
+{
+       uint64_t begin = 0, diff = 0;
+
+       if (*pp) {
+               proc_incref(*pp, 1);
+               spin_lock(&(*pp)->proc_lock);
+               begin = start_timing();
+               __proc_preempt_warnall(*pp, 1000000);
+               spin_unlock(&(*pp)->proc_lock);
+               spin_on((*pp)->procinfo->num_vcores > 1);
+               diff = stop_timing(begin);
+               printk("Took %llu usec (%llu nsec) to warn preempt all.\n",
+                      diff * 1000000 / system_timing.tsc_freq,
+                      diff * 1000000000 / system_timing.tsc_freq);
+               printk("[T]:006:%llu:%llu\n",
+                      diff * 1000000 / system_timing.tsc_freq,
+                      diff * 1000000000 / system_timing.tsc_freq);
+               proc_destroy(*pp);
+               proc_decref(*pp, 1);
+               while (*pp) /* toggled in proc_free */
+                       cpu_relax();
+       }
+}
+
+/* Experiment 7: preempt-raw, single core */
+static void exper_7_part2(struct proc **pp)
+{
+       uint64_t begin = 0, diff = 0;
+       bool self_ipi_pending = FALSE;
+       uint32_t vcoreid, pcoreid = 7; // some core available on all systems
+
+       if (*pp) {
+               proc_incref(*pp, 1);
+               spin_lock(&(*pp)->proc_lock);
+               assert((*pp)->procinfo->pcoremap[pcoreid].valid);
+               begin = start_timing();
+               self_ipi_pending = __proc_preempt_core(*pp, pcoreid);
+               spin_unlock(&(*pp)->proc_lock);
+               __proc_kmsg_pending(*pp, self_ipi_pending);
+               spin_on((*pp)->procinfo->pcoremap[pcoreid].valid);
+               diff = stop_timing(begin);
+               printk("Took %llu usec (%llu nsec) to raw-preempt one core.\n",
+                      diff * 1000000 / system_timing.tsc_freq,
+                      diff * 1000000000 / system_timing.tsc_freq);
+               printk("[T]:007:%llu:%llu\n",
+                      diff * 1000000 / system_timing.tsc_freq,
+                      diff * 1000000000 / system_timing.tsc_freq);
+               proc_destroy(*pp);
+               proc_decref(*pp, 1);
+               while (*pp) /* toggled in proc_free */
+                       cpu_relax();
+       }
+}
+
+/* Experiment 8: preempt-warn, single core */
+static void exper_8_part2(struct proc **pp)
+{
+       uint64_t begin = 0, diff = 0;
+       uint32_t vcoreid, pcoreid = 7; // some core available on all systems
+
+       if (*pp) {
+               proc_incref(*pp, 1);
+               spin_lock(&(*pp)->proc_lock);
+               vcoreid = (*pp)->procinfo->pcoremap[pcoreid].vcoreid;
+               assert((*pp)->procinfo->pcoremap[pcoreid].valid);
+               begin = start_timing();
+               __proc_preempt_warn(*pp, vcoreid, 1000000); // 1 sec
+               spin_unlock(&(*pp)->proc_lock);
+               spin_on((*pp)->procinfo->pcoremap[pcoreid].valid);
+               diff = stop_timing(begin);
+               printk("Took %llu usec (%llu nsec) to warn-preempt one core.\n",
+                      diff * 1000000 / system_timing.tsc_freq,
+                      diff * 1000000000 / system_timing.tsc_freq);
+               printk("[T]:008:%llu:%llu\n",
+                      diff * 1000000 / system_timing.tsc_freq,
+                      diff * 1000000000 / system_timing.tsc_freq);
+               proc_destroy(*pp);
+               proc_decref(*pp, 1);
+               while (*pp) /* toggled in proc_free */
+                       cpu_relax();
+       }
+}
+
+/* Experiment 9: single notification time */
+static void exper_9_part2(struct proc **pp)
+{
+       struct notif_event ne = {0};
+
+       if (*pp) {
+               ne.ne_type = NE_ALARM;
+               proc_incref(*pp, 1);
+               printk("[T]:009:B:%llu\n", read_tsc());
+               proc_notify(*pp, NE_ALARM, &ne); 
+               proc_destroy(*pp);
+               proc_decref(*pp, 1);
+               while (*pp) /* toggled in proc_free */
+                       cpu_relax();
+       }
+}
+
+#endif /* __CONFIG_OSDI__ */
 
 #ifdef __sparc_v8__
 
index 744963a..d176b65 100644 (file)
@@ -469,6 +469,16 @@ static void __proc_free(struct proc *p)
 
        /* Dealloc the struct proc */
        kmem_cache_free(proc_cache, p);
+
+#ifdef __CONFIG_OSDI__ /* for experiment coordination */
+       extern struct proc *mgr_p1, *mgr_p2;
+       /* Signal to the monitor we're done */
+       if (p == mgr_p1)
+               mgr_p1 = 0;
+       if (p == mgr_p2)
+               mgr_p2 = 0;
+       printk("[T]:004:E:%llu\n", read_tsc());
+#endif /* __CONFIG_EXPER_TRADPROC__ */
 }
 
 /* Whether or not actor can control target.  Note we currently don't need
index 6805c1a..7debb6e 100644 (file)
@@ -55,6 +55,8 @@ void vcore_entry(void)
                        end = read_tsc();
                        printf("Took %llu usec (%llu nsec) to get my yielded cores back.\n",
                               udiff(begin, end), ndiff(begin, end));
+                       printf("[T]:010:%llu:%llu\n",
+                              udiff(begin, end), ndiff(begin, end));
                }
        }
        printf("We're screwed!\n");
index a56f583..f47a7a3 100644 (file)
@@ -1,9 +1,12 @@
 /* tests/msr_dumb_while.c
  *
- * This requests the max_vcores in the system, then just dumbly while loops. */
+ * This requests the max_vcores in the system, then just dumbly while loops.
+ * If you send it an NE_ALARM, it'll print its TSC. */
 
 #include <rstdio.h>
 #include <vcore.h>
+#include <arch/arch.h>
+#include <ros/bcq.h>
 
 int main(int argc, char** argv)
 {
@@ -21,6 +24,17 @@ int main(int argc, char** argv)
 
 void vcore_entry(void)
 {
+       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[0];
+       vcpd->notif_enabled = TRUE;
+
+       struct notif_method *nm = &__procdata.notif_methods[NE_ALARM];
+       nm->flags = NOTIF_WANTED | NOTIF_MSG | NOTIF_IPI;
+       nm->vcoreid = 1;
+
+       struct notif_event ne = {0};
+       bcq_dequeue(&vcpd->notif_evts, &ne, NR_PERCORE_EVENTS);
+       if (ne.ne_type == NE_ALARM)
+               printf("[T]:009:E:%llu\n", read_tsc());
        while(1);
 }
 
index 569d650..eeafb0e 100644 (file)
@@ -3,8 +3,13 @@
  * This measures the time it takes to request and receive the max_vcores() in
  * the system.  The clock starts before vcore_request(), which includes the time
  * it takes to allocate transition stacks and TLS.  The clock stops after
- * barriering in vcore_entry().  Alternatively, you can make vcore0 pop back out
- * and measure there (comment some things out in vcore entry()). */
+ * barriering in vcore_entry(), while vcore0 gets restarted and barriers.  You
+ * really want to restart vcore0's context so it releases the lock in
+ * vcore_request().
+ *
+ * This will measure both the hot and cold times, with the hot times not needing
+ * to have stacks mmaped and other things. */
+
 
 #include <parlib.h>
 #include <ros/mman.h>
@@ -27,6 +32,7 @@ uint64_t begin = 0, end = 0;
 int main(int argc, char** argv)
 {
        uint32_t vcoreid = vcore_id();
+       int retval = 0;
 
        mcs_barrier_init(&b, max_vcores());
 
@@ -51,13 +57,27 @@ int main(int argc, char** argv)
        vcpd->notif_enabled = TRUE;
 /* end: stuff userspace needs to do before switching to multi-mode */
 
-       /* should do this in the vcore entry */
        begin = read_tsc();
-       vcore_request(max_vcores());
+       retval = vcore_request(max_vcores());
+       if (retval)
+               printf("Fucked!\n");
        mcs_barrier_wait(&b, vcoreid);
        end = read_tsc();
 
-       printf("Took %llu usec (%llu nsec) to receive %d cores (restarting).\n",
+       printf("Took %llu usec (%llu nsec) to receive %d cores (cold).\n",
+              udiff(begin, end), ndiff(begin, end), max_vcores());
+       printf("[T]:001:%llu:%llu:%d:C.\n",
+              udiff(begin, end), ndiff(begin, end), max_vcores());
+       udelay(5000000);
+       begin = read_tsc();
+       retval = vcore_request(max_vcores() - 1);
+       if (retval)
+               printf("Fucked!\n");
+       mcs_barrier_wait(&b, vcoreid);
+       end = read_tsc();
+       printf("Took %llu usec (%llu nsec) to receive %d cores (warm).\n",
+              udiff(begin, end), ndiff(begin, end), max_vcores());
+       printf("[T]:001:%llu:%llu:%d:W.\n",
               udiff(begin, end), ndiff(begin, end), max_vcores());
 
        return 0;
@@ -65,21 +85,9 @@ int main(int argc, char** argv)
 
 void vcore_entry(void)
 {
-       uint32_t vcoreid = vcore_id(); // this will still be slow
-
-       /* try testing immediately.  remove from here to the while(1) if you want to
-        * count vcore0 restarting. */
-       mcs_barrier_wait(&b, vcoreid);
-       if (vcoreid == 0) {
-               end = read_tsc();
-               printf("Took %llu usec (%llu nsec) to receive %d cores (no restart).\n",
-                      udiff(begin, end), ndiff(begin, end), max_vcores());
-               exit(0);
-       }
-       while(1);
+       uint32_t vcoreid = vcore_id();
 
 /* begin: stuff userspace needs to do to handle notifications */
-
        struct vcore *vc = &__procinfo.vcoremap[vcoreid];
        struct preempt_data *vcpd;
        vcpd = &__procdata.vcore_preempt_data[vcoreid];
@@ -94,15 +102,16 @@ void vcore_entry(void)
                pop_ros_tf(&vcpd->notif_tf, vcoreid);
                panic("should never see me!");
        }       
-       /* unmask notifications once you can let go of the notif_tf and it is okay
-        * to clobber the transition stack.
-        * Check Documentation/processes.txt: 4.2.4.  In real code, you should be
-        * popping the tf of whatever user process you want (get off the x-stack) */
-       vcpd->notif_enabled = TRUE;
-       
 /* end: stuff userspace needs to do to handle notifications */
+
+       /* all other vcores are down here */
        mcs_barrier_wait(&b, vcoreid);
-       while(1);
 
+       udelay(1000000);
+       if (vcoreid == 1)
+               printf("Proc %d's vcores are yielding\n", getpid());
+       sys_yield(0);
+
+       while(1);
 }
 
diff --git a/tests/msr_get_singlecore.c b/tests/msr_get_singlecore.c
new file mode 100644 (file)
index 0000000..2260047
--- /dev/null
@@ -0,0 +1,118 @@
+/* tests/msr_get_singlecore.c
+ *
+ * Like msr_get_cores.c, but it only gets one core. */
+
+
+#include <parlib.h>
+#include <ros/mman.h>
+#include <ros/resource.h>
+#include <ros/procdata.h>
+#include <ros/notification.h>
+#include <ros/bcq.h>
+#include <arch/arch.h>
+#include <rstdio.h>
+#include <vcore.h>
+#include <mcs.h>
+#include <timing.h>
+#include <rassert.h>
+
+mcs_barrier_t b;
+
+void *core0_tls = 0;
+uint64_t begin = 0, end = 0;
+volatile bool core1_up = FALSE;
+
+int main(int argc, char** argv)
+{
+       uint32_t vcoreid = vcore_id();
+       int retval = 0;
+
+       mcs_barrier_init(&b, max_vcores());
+
+/* begin: stuff userspace needs to do before switching to multi-mode */
+       if (vcore_init())
+               printf("vcore_init() failed, we're fucked!\n");
+       /* tell the kernel where and how we want to receive notifications */
+       struct notif_method *nm;
+       for (int i = 0; i < MAX_NR_NOTIF; i++) {
+               nm = &__procdata.notif_methods[i];
+               nm->flags |= NOTIF_WANTED | NOTIF_MSG | NOTIF_IPI;
+               nm->vcoreid = i % 2; // vcore0 or 1, keepin' it fresh.
+       }
+       /* Need to save this somewhere that you can find it again when restarting
+        * core0 */
+       core0_tls = get_tls_desc(0);
+       /* Need to save our floating point state somewhere (like in the
+        * user_thread_tcb so it can be restarted too */
+       /* don't forget to enable notifs on vcore0 at some point */
+       struct preempt_data *vcpd;
+       vcpd = &__procdata.vcore_preempt_data[0];
+       vcpd->notif_enabled = TRUE;
+/* end: stuff userspace needs to do before switching to multi-mode */
+
+       /* get into multi mode */
+       retval = vcore_request(1);
+       if (retval)
+               printf("Fucked!\n");
+
+       printf("Proc %d requesting another vcore\n", getpid());
+       begin = read_tsc();
+       retval = vcore_request(1);
+       if (retval)
+               printf("Fucked!\n");
+       while (!core1_up)
+               cpu_relax;
+       end = read_tsc();
+       printf("Took %llu usec (%llu nsec) to receive 1 core (cold).\n",
+              udiff(begin, end), ndiff(begin, end));
+       printf("[T]:002:%llu:%llu:1:C.\n",
+              udiff(begin, end), ndiff(begin, end));
+       core1_up = FALSE;
+       udelay(2000000);
+       printf("Proc %d requesting the vcore again\n", getpid());
+       begin = read_tsc();
+       retval = vcore_request(1);
+       if (retval)
+               printf("Fucked!\n");
+       while (!core1_up)
+               cpu_relax();
+       end = read_tsc();
+       printf("Took %llu usec (%llu nsec) to receive 1 core (warm).\n",
+              udiff(begin, end), ndiff(begin, end));
+       printf("[T]:002:%llu:%llu:1:W.\n",
+              udiff(begin, end), ndiff(begin, end));
+       return 0;
+}
+
+void vcore_entry(void)
+{
+       uint32_t vcoreid = vcore_id();
+
+/* begin: stuff userspace needs to do to handle notifications */
+       struct vcore *vc = &__procinfo.vcoremap[vcoreid];
+       struct preempt_data *vcpd;
+       vcpd = &__procdata.vcore_preempt_data[vcoreid];
+       
+       /* Lets try to restart vcore0's context.  Note this doesn't do anything to
+        * set the appropriate TLS.  On x86, this will involve changing the LDT
+        * entry for this vcore to point to the TCB of the new user-thread. */
+       if (vcoreid == 0) {
+               vcpd->notif_pending = 0;
+               set_tls_desc(core0_tls, 0);
+               /* Load silly state (Floating point) too */
+               pop_ros_tf(&vcpd->notif_tf, vcoreid);
+               panic("should never see me!");
+       }       
+/* end: stuff userspace needs to do to handle notifications */
+
+       /* all other vcores are down here */
+       core1_up = TRUE;
+
+       while (core1_up)
+               cpu_relax();
+       printf("Proc %d's vcore %d is yielding\n", getpid(), vcoreid);
+       sys_yield(0);
+
+       while(1);
+}
+
diff --git a/tests/tsc_spitter.c b/tests/tsc_spitter.c
new file mode 100644 (file)
index 0000000..46a0594
--- /dev/null
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+#include <rstdio.h>
+#include <arch/arch.h>
+
+int main(int argc, char** argv)
+{
+       printf("[T]:004:M:%llu\n", read_tsc());
+       return 0;
+}