x86: Try to fix MP table I/O interrupt assignment entries
[akaros.git] / tests / pthread_test.c
index 283472d..e7f568d 100644 (file)
@@ -1,13 +1,26 @@
+/* Copyright (c) 2010-14 The Regents of the University of California
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * Basic test for pthreading.  Spawns a bunch of threads that yield.
+ *
+ * To build on linux, cd into tests and run:
+ * $ gcc -O2 -std=gnu99 -fno-stack-protector -g pthread_test.c -lpthread
+ *
+ * Make sure you run it with taskset to fix the number of vcores/cpus. */
+
+#define _GNU_SOURCE /* for pth_yield on linux */
+
 #include <stdio.h>
 #include <pthread.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/time.h>
+#include "misc-compat.h" /* OS dependent #incs */
 
-/* OS dependent #incs */
-#include <parlib.h>
-#include <vcore.h>
-#include <timing.h>
+/* These are here just to have the compiler test the _INITIALIZERS */
+pthread_cond_t dummy_cond = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t dummy_mutex = PTHREAD_MUTEX_INITIALIZER;
 
 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 #define printf_safe(...) {}
@@ -25,20 +38,20 @@ int amt_fake_work = 0;
 pthread_t my_threads[MAX_NR_TEST_THREADS];
 void *my_retvals[MAX_NR_TEST_THREADS];
 
-bool ready = FALSE;
+pthread_barrier_t barrier;
 
 void *yield_thread(void* arg)
 {      
        /* Wait til all threads are created */
-       while (!ready)
-               cpu_relax();
+       pthread_barrier_wait(&barrier);
        for (int i = 0; i < nr_yield_loops; i++) {
-               printf_safe("[A] pthread %d %p on vcore %d, itr: %d\n", pthread_self()->id,
-                      pthread_self(), vcore_id(), i);
-               /* Fakes some work by spinning a bit.  Amount varies per uth/vcore,
-                * scaled by fake_work */
+               printf_safe("[A] pthread %d %p on vcore %d, itr: %d\n",
+                           pthread_id(), pthread_self(), vcore_id(), i);
+               /* Fakes some work by spinning a bit.  Amount varies per
+                * uth/vcore, scaled by fake_work */
                if (amt_fake_work)
-                       udelay(amt_fake_work * (pthread_self()->id * (vcore_id() + 1)));
+                       udelay(amt_fake_work * (pthread_id() * (vcore_id() +
+                                                               2)));
                pthread_yield();
                printf_safe("[A] pthread %p returned from yield on vcore %d, itr: %d\n",
                            pthread_self(), vcore_id(), i);
@@ -66,27 +79,50 @@ int main(int argc, char** argv)
               nr_yield_threads, nr_yield_loops, nr_vcores, amt_fake_work);
 
        /* OS dependent prep work */
+#ifdef __ros__
        if (nr_vcores) {
                /* Only do the vcore trickery if requested */
-               pthread_can_vcore_request(FALSE);       /* 2LS won't manage vcores */
-               pthread_lib_init();                                     /* gives us one vcore */
-               vcore_request(nr_vcores - 1);           /* ghetto incremental interface */
+               parlib_never_yield = TRUE;
+               pthread_need_tls(FALSE);
+               pthread_mcp_init();             /* gives us one vcore */
+               vcore_request_total(nr_vcores);
+               parlib_never_vc_request = TRUE;
+               for (int i = 0; i < nr_vcores; i++) {
+                       printf_safe("Vcore %d mapped to pcore %d\n", i,
+                                   __procinfo.vcoremap[i].pcoreid);
+               }
        }
+       struct uth_join_request *join_reqs;
+
+       join_reqs = malloc(nr_yield_threads * sizeof(struct uth_join_request));
+       for (int i = 0; i < nr_yield_threads; i++)
+               join_reqs[i].retval_loc = &my_retvals[i];
+       assert(join_reqs);
+#endif /* __ros__ */
 
+       pthread_barrier_init(&barrier, NULL, nr_yield_threads);
        /* create and join on yield */
        for (int i = 0; i < nr_yield_threads; i++) {
                printf_safe("[A] About to create thread %d\n", i);
-               assert(!pthread_create(&my_threads[i], NULL, &yield_thread, NULL));
+               if (pthread_create(&my_threads[i], NULL, &yield_thread, NULL))
+                       perror("pth_create failed");
        }
        if (gettimeofday(&start_tv, 0))
                perror("Start time error...");
-       ready = TRUE;                   /* signal to any spinning uthreads to start */
+       /* Akaros supports parallel join */
+#ifdef __ros__
+       for (int i = 0; i < nr_yield_threads; i++)
+               join_reqs[i].uth = (struct uthread*)my_threads[i];
+       uthread_join_arr(join_reqs, nr_yield_threads);
+#else
        for (int i = 0; i < nr_yield_threads; i++) {
-               printf_safe("[A] About to join on thread %d(%p)\n", i, my_threads[i]);
+               printf_safe("[A] About to join on thread %d(%p)\n",
+                           i, my_threads[i]);
                pthread_join(my_threads[i], &my_retvals[i]);
-               printf_safe("[A] Successfully joined on thread %d (retval: %p)\n", i,
-                           my_retvals[i]);
+               printf_safe("[A] Successful join on thread %d (retval: %p)\n",
+                           i, my_retvals[i]);
        }
+#endif
        if (gettimeofday(&end_tv, 0))
                perror("End time error...");
        nr_ctx_switches = nr_yield_threads * nr_yield_loops;
@@ -94,8 +130,8 @@ int main(int argc, char** argv)
                    (end_tv.tv_usec - start_tv.tv_usec);
        printf("Done: %d uthreads, %d loops, %d vcores, %d work\n",
               nr_yield_threads, nr_yield_loops, nr_vcores, amt_fake_work);
-       printf("Nr context switches: %d\n", nr_ctx_switches);
-       printf("Time to run: %d usec\n", usec_diff);
+       printf("Nr context switches: %ld\n", nr_ctx_switches);
+       printf("Time to run: %ld usec\n", usec_diff);
        if (nr_vcores == 1)
                printf("Context switch latency: %d nsec\n",
                       (int)(1000LL*usec_diff / nr_ctx_switches));