akaros/tests/pthread_switch.c
<<
>>
Prefs
   1/* Copyright (c) 2014 The Regents of the University of California
   2 * Barret Rhoden <brho@cs.berkeley.edu>
   3 * See LICENSE for details.
   4 *
   5 * Basic pthread switcher, bypassing the 2LS.  Use for benchmarking and
   6 * 2LS-inspiration. */
   7
   8#include <stdio.h>
   9#include <pthread.h>
  10#include <stdlib.h>
  11#include <unistd.h>
  12#include <sys/time.h>
  13
  14pthread_t th1, th2;
  15int nr_switch_loops = 100;
  16pthread_barrier_t barrier;
  17bool should_exit = FALSE;
  18
  19static void __pth_switch_cb(struct uthread *uthread, void *target)
  20{
  21        /* by not returning, this bypasses vcore entry and event checks, though
  22         * when we pop back out of the 2LS, we'll check notif pending.  think
  23         * about this if you put this into your 2LS. */
  24        current_uthread = NULL;
  25        run_uthread((struct uthread*)target);
  26        assert(0);
  27}
  28
  29static void pth_switch_to(struct pthread_tcb *target)
  30{
  31        uthread_yield(TRUE, __pth_switch_cb, target);
  32}
  33
  34void *switch_thread(void *arg)
  35{       
  36        pthread_t other_thr = *(pthread_t*)arg;
  37
  38        pthread_barrier_wait(&barrier);
  39        for (int i = 0; i < nr_switch_loops; i++) {
  40                cmb();
  41                if (should_exit)
  42                        return 0;
  43                pth_switch_to(other_thr);
  44        }
  45        if (pthread_self() == th1) {
  46                /* we need to break out of the switching cycle.  when th2 runs
  47                 * again, it'll know to stop.  but th1 needs to both exit and
  48                 * switch to th2.  we do this by making th2 runnable by the pth
  49                 * schedop, then exiting */
  50                should_exit = TRUE;
  51                /* we also need to do this to th2 before it tries to exit, o/w
  52                 * we'll PF in __pthread_generic_yield. */
  53                sched_ops->thread_runnable((struct uthread*)th2);
  54        }
  55        return 0;
  56}
  57
  58int main(int argc, char** argv) 
  59{
  60        struct timeval start_tv = {0};
  61        struct timeval end_tv = {0};
  62        long usec_diff;
  63        long nr_ctx_switches;
  64        void *join_ret;
  65
  66        if (argc > 1)
  67                nr_switch_loops = strtol(argv[1], 0, 10);
  68        printf("Making 2 threads of %d switches each\n", nr_switch_loops);
  69
  70        parlib_never_yield = TRUE;
  71        parlib_never_vc_request = TRUE;
  72        pthread_need_tls(FALSE);
  73        pthread_mcp_init();             /* gives us one vcore */
  74
  75        pthread_barrier_init(&barrier, NULL, 2);
  76        /* each is passed the other's pthread_t.  th1 starts the switching. */
  77        if (pthread_create(&th1, NULL, &switch_thread, &th2))
  78                perror("pth_create 1 failed");
  79        /* thread 2 is created, but not put on the runnable list */
  80        if (__pthread_create(&th2, NULL, &switch_thread, &th1))
  81                perror("pth_create 2 failed");
  82
  83        if (gettimeofday(&start_tv, 0))
  84                perror("Start time error...");
  85
  86        pthread_join(th1, &join_ret);
  87        pthread_join(th2, &join_ret);
  88
  89        if (gettimeofday(&end_tv, 0))
  90                perror("End time error...");
  91        nr_ctx_switches = 2 * nr_switch_loops;
  92        usec_diff = (end_tv.tv_sec - start_tv.tv_sec) * 1000000 +
  93                    (end_tv.tv_usec - start_tv.tv_usec);
  94        printf("Done: %d loops\n", nr_switch_loops);
  95        printf("Nr context switches: %ld\n", nr_ctx_switches);
  96        printf("Time to run: %ld usec\n", usec_diff);
  97        printf("Context switch latency: %d nsec\n",
  98               (int)(1000LL*usec_diff / nr_ctx_switches));
  99        printf("Context switches / sec: %d\n\n",
 100               (int)(1000000LL*nr_ctx_switches / usec_diff));
 101} 
 102