akaros/tests/pthread_test.c
<<
>>
Prefs
   1/* Copyright (c) 2010-14 The Regents of the University of California
   2 * Barret Rhoden <brho@cs.berkeley.edu>
   3 * See LICENSE for details.
   4 *
   5 * Basic test for pthreading.  Spawns a bunch of threads that yield.
   6 *
   7 * To build on linux, cd into tests and run:
   8 * $ gcc -O2 -std=gnu99 -fno-stack-protector -g pthread_test.c -lpthread
   9 *
  10 * Make sure you run it with taskset to fix the number of vcores/cpus. */
  11
  12#define _GNU_SOURCE /* for pth_yield on linux */
  13
  14#include <stdio.h>
  15#include <pthread.h>
  16#include <stdlib.h>
  17#include <unistd.h>
  18#include <sys/time.h>
  19#include "misc-compat.h" /* OS dependent #incs */
  20
  21/* These are here just to have the compiler test the _INITIALIZERS */
  22pthread_cond_t dummy_cond = PTHREAD_COND_INITIALIZER;
  23pthread_mutex_t dummy_mutex = PTHREAD_MUTEX_INITIALIZER;
  24
  25pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
  26#define printf_safe(...) {}
  27//#define printf_safe(...) \
  28        pthread_mutex_lock(&lock); \
  29        printf(__VA_ARGS__); \
  30        pthread_mutex_unlock(&lock);
  31
  32#define MAX_NR_TEST_THREADS 100000
  33int nr_yield_threads = 100;
  34int nr_yield_loops = 100;
  35int nr_vcores = 0;
  36int amt_fake_work = 0;
  37
  38pthread_t my_threads[MAX_NR_TEST_THREADS];
  39void *my_retvals[MAX_NR_TEST_THREADS];
  40
  41pthread_barrier_t barrier;
  42
  43void *yield_thread(void* arg)
  44{       
  45        /* Wait til all threads are created */
  46        pthread_barrier_wait(&barrier);
  47        for (int i = 0; i < nr_yield_loops; i++) {
  48                printf_safe("[A] pthread %d %p on vcore %d, itr: %d\n",
  49                            pthread_id(), pthread_self(), vcore_id(), i);
  50                /* Fakes some work by spinning a bit.  Amount varies per
  51                 * uth/vcore, scaled by fake_work */
  52                if (amt_fake_work)
  53                        udelay(amt_fake_work * (pthread_id() * (vcore_id() +
  54                                                                2)));
  55                pthread_yield();
  56                printf_safe("[A] pthread %p returned from yield on vcore %d, itr: %d\n",
  57                            pthread_self(), vcore_id(), i);
  58        }
  59        return (void*)(pthread_self());
  60}
  61
  62int main(int argc, char** argv) 
  63{
  64        struct timeval start_tv = {0};
  65        struct timeval end_tv = {0};
  66        long usec_diff;
  67        long nr_ctx_switches;
  68
  69        if (argc > 1)
  70                nr_yield_threads = strtol(argv[1], 0, 10);
  71        if (argc > 2)
  72                nr_yield_loops = strtol(argv[2], 0, 10);
  73        if (argc > 3)
  74                nr_vcores = strtol(argv[3], 0, 10);
  75        if (argc > 4)
  76                amt_fake_work = strtol(argv[4], 0, 10);
  77        nr_yield_threads = MIN(nr_yield_threads, MAX_NR_TEST_THREADS);
  78        printf("Making %d threads of %d loops each, on %d vcore(s), %d work\n",
  79               nr_yield_threads, nr_yield_loops, nr_vcores, amt_fake_work);
  80
  81        /* OS dependent prep work */
  82#ifdef __ros__
  83        if (nr_vcores) {
  84                /* Only do the vcore trickery if requested */
  85                parlib_never_yield = TRUE;
  86                pthread_need_tls(FALSE);
  87                pthread_mcp_init();             /* gives us one vcore */
  88                vcore_request_total(nr_vcores);
  89                parlib_never_vc_request = TRUE;
  90                for (int i = 0; i < nr_vcores; i++) {
  91                        printf_safe("Vcore %d mapped to pcore %d\n", i,
  92                                    __procinfo.vcoremap[i].pcoreid);
  93                }
  94        }
  95        struct uth_join_request *join_reqs;
  96
  97        join_reqs = malloc(nr_yield_threads * sizeof(struct uth_join_request));
  98        for (int i = 0; i < nr_yield_threads; i++)
  99                join_reqs[i].retval_loc = &my_retvals[i];
 100        assert(join_reqs);
 101#endif /* __ros__ */
 102
 103        pthread_barrier_init(&barrier, NULL, nr_yield_threads);
 104        /* create and join on yield */
 105        for (int i = 0; i < nr_yield_threads; i++) {
 106                printf_safe("[A] About to create thread %d\n", i);
 107                if (pthread_create(&my_threads[i], NULL, &yield_thread, NULL))
 108                        perror("pth_create failed");
 109        }
 110        if (gettimeofday(&start_tv, 0))
 111                perror("Start time error...");
 112        /* Akaros supports parallel join */
 113#ifdef __ros__
 114        for (int i = 0; i < nr_yield_threads; i++)
 115                join_reqs[i].uth = (struct uthread*)my_threads[i];
 116        uthread_join_arr(join_reqs, nr_yield_threads);
 117#else
 118        for (int i = 0; i < nr_yield_threads; i++) {
 119                printf_safe("[A] About to join on thread %d(%p)\n",
 120                            i, my_threads[i]);
 121                pthread_join(my_threads[i], &my_retvals[i]);
 122                printf_safe("[A] Successful join on thread %d (retval: %p)\n",
 123                            i, my_retvals[i]);
 124        }
 125#endif
 126        if (gettimeofday(&end_tv, 0))
 127                perror("End time error...");
 128        nr_ctx_switches = nr_yield_threads * nr_yield_loops;
 129        usec_diff = (end_tv.tv_sec - start_tv.tv_sec) * 1000000 +
 130                    (end_tv.tv_usec - start_tv.tv_usec);
 131        printf("Done: %d uthreads, %d loops, %d vcores, %d work\n",
 132               nr_yield_threads, nr_yield_loops, nr_vcores, amt_fake_work);
 133        printf("Nr context switches: %ld\n", nr_ctx_switches);
 134        printf("Time to run: %ld usec\n", usec_diff);
 135        if (nr_vcores == 1)
 136                printf("Context switch latency: %d nsec\n",
 137                       (int)(1000LL*usec_diff / nr_ctx_switches));
 138        printf("Context switches / sec: %d\n\n",
 139               (int)(1000000LL*nr_ctx_switches / usec_diff));
 140} 
 141