Advertisement
Guest User

sandy bridge/pthread slowness demo

a guest
Jul 3rd, 2012
375
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.34 KB | None | 0 0
  1.  
  2. /*
  3.  * snb_slow_demo.c
  4.  *
  5.  * - simple program to demonstrate specific cases where Sandy Bridge is
  6.  *   dramatically slower than Westmere:
  7.  *   (1) pthread mutex contention
  8.  *   (2) pthread condition variable signaling
  9.  *
  10.  * - compile with gcc as follows:
  11.  *   gcc -Wall -g -O2 snb_slow_demo.c -o snb_slow_demo -lpthread
  12.  *
  13.  * - tested on the following hardware:
  14.  *   Dell PowerEdge R620, E5-2690
  15.  *   HP dl360pg8, E5-2690
  16.  *   Dell PowerEdge R610, X5550
  17.  *   Dell PowerEdge R610, X5690
  18.  */
  19.  
  20.  
  21. #define _GNU_SOURCE
  22. #include <pthread.h>
  23. #include <unistd.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <stdint.h>
  28. #include <sys/time.h>
  29.  
  30. #define DEFAULT_N_ITER (50000000)
  31. #define USEC_PER_SEC (1000000UL)
  32. #define TIMEVAL_TO_UINT64(tv) \
  33.     ( (uint64_t)tv.tv_sec*(uint64_t)USEC_PER_SEC + (uint64_t)tv.tv_usec );
  34.  
  35. /*
  36.  * flatten struct timeval fields into one 64-bit unsigned integer
  37.  */
  38. uint64_t timestamp()
  39. {
  40.     struct timeval tv;
  41.     gettimeofday(&tv, NULL);
  42.     return TIMEVAL_TO_UINT64(tv);
  43. }
  44.  
  45. /*
  46.  * globals/types
  47.  */
  48. static pthread_cond_t condvar;
  49. static pthread_mutex_t mutex;
  50. static pthread_attr_t attr;
  51. static pthread_t thread;
  52. static int64_t shared_int;
  53. static cpu_set_t cpuset;
  54. static int n_iter = DEFAULT_N_ITER;
  55. static int cpu1 = -1;
  56. static int cpu2 = -1;
  57. typedef int (*test_function_t)();
  58.  
  59. /*
  60.  * threaded function for lock contention test
  61.  */
  62. void* lock_contention_thread(void *vptr)
  63. {
  64.     int i;
  65.     for (i=0; i<n_iter; i++)
  66.     {
  67.         pthread_mutex_lock(&mutex);
  68.         shared_int--;
  69.         //printf("DEBUG: shared_int: %ld\n", shared_int);
  70.         pthread_mutex_unlock(&mutex);
  71.     }
  72.     return NULL;
  73. }
  74.  
  75. /*
  76.  * main thread for lock contention test
  77.  * - two threads fighting over incrementing/decrementing an int
  78.  */
  79. int lock_contention_test()
  80. {
  81.     int rc, i;
  82.  
  83.     // create thread
  84.     pthread_create(&thread, &attr, lock_contention_thread, NULL);
  85.  
  86.     // pin this (main) thread to cpu1
  87.     CPU_ZERO(&cpuset);
  88.     CPU_SET(cpu1, &cpuset);
  89.     rc = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
  90.     if (0 != rc) { fprintf(stderr, "ERROR: pthread_setaffinity_np()\n"); }
  91.  
  92.     // pin child thread to cpu2
  93.     CPU_ZERO(&cpuset);
  94.     CPU_SET(cpu2, &cpuset);
  95.     rc = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
  96.     if (0 != rc) { fprintf(stderr, "ERROR: pthread_setaffinity_np()\n"); }
  97.  
  98.     // do stuff
  99.     for (i=0; i<n_iter; i++)
  100.     {
  101.         pthread_mutex_lock(&mutex);
  102.         shared_int++;
  103.         //printf("DEBUG: shared_int: %ld\n", shared_int);
  104.         pthread_mutex_unlock(&mutex);
  105.     }
  106.  
  107.     // wait for thread to finish
  108.     pthread_join(thread,  NULL);
  109.  
  110.     return 0;
  111. }
  112.  
  113. /*
  114.  * threaded function for condition variable test
  115.  * - this thread always wants to transition from 1 to 0
  116.  */
  117. void* condition_variable_thread(void *vptr)
  118. {
  119.     int i;
  120.     for (i=0; i<n_iter; i++)
  121.     {
  122.         pthread_mutex_lock(&mutex);
  123.         if (1!=shared_int) { pthread_cond_wait(&condvar, &mutex); }
  124.         shared_int--;
  125.         //printf("DEBUG: shared_int: %ld\n", shared_int);
  126.         pthread_cond_signal(&condvar);
  127.         pthread_mutex_unlock(&mutex);
  128.     }
  129.     return NULL;
  130. }
  131.  
  132. /*
  133.  * main thread for condition variable test
  134.  * - two threads "politely" incrementing and decrementing a shared integer by
  135.  *   communicating through a condition variable
  136.  * - this thread always wants to transition from 0 to 1
  137.  */
  138. int condition_variable_test()
  139. {
  140.     int rc, i;
  141.  
  142.     pthread_cond_init(&condvar, NULL);
  143.  
  144.     // create thread
  145.     pthread_create(&thread, &attr, condition_variable_thread, NULL);
  146.  
  147.     // pin this (main) thread to cpu1
  148.     CPU_ZERO(&cpuset);
  149.     CPU_SET(cpu1, &cpuset);
  150.     rc = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
  151.     if (0 != rc) { fprintf(stderr, "ERROR: pthread_setaffinity_np()\n"); }
  152.  
  153.     // pin child thread to cpu2
  154.     CPU_ZERO(&cpuset);
  155.     CPU_SET(cpu2, &cpuset);
  156.     rc = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
  157.     if (0 != rc) { fprintf(stderr, "ERROR: pthread_setaffinity_np()\n"); }
  158.  
  159.     for (i=0; i<n_iter; i++)
  160.     {
  161.         pthread_mutex_lock(&mutex);
  162.         if (0!=shared_int) { pthread_cond_wait(&condvar, &mutex); }
  163.         shared_int++;
  164.         //printf("DEBUG: shared_int: %ld\n", shared_int);
  165.         pthread_cond_signal(&condvar);
  166.         pthread_mutex_unlock(&mutex);
  167.     }
  168.  
  169.     // wait for thread to finish
  170.     pthread_join(thread,  NULL);
  171.     pthread_cond_destroy(&condvar);
  172.  
  173.     return 0;
  174. }
  175.  
  176. /*
  177.  * handy helper function
  178.  */
  179. void usage(const char* progname)
  180. {
  181.     fprintf(stderr,
  182.             "Usage: %s <-t test> <-c cpu1> <-C cpu2> [opts]\n"
  183.             "ARGUMENTS:\n"
  184.             "    -c cpu1 ..... set CPU #1 for pinning main thread\n"
  185.             "    -C cpu2 ..... set CPU #2 for pinning child thread\n"
  186.             "    -t test ..... run specified test; options are:\n"
  187.             "                  lc .... mutex lock contention\n"
  188.             "                  cv .... condition variable\n"
  189.             "OPTIONS:\n"
  190.             "    -n N ........ set number of iterations, default=%i\n"
  191.             "    -h .......... show this help\n"
  192.             , progname
  193.             , DEFAULT_N_ITER
  194.             );
  195. }
  196.  
  197. /*
  198.  * program entry point
  199.  */
  200. int main(int argc, char *argv[])
  201. {
  202.     uint64_t t1, t2, tdiff;
  203.     int opt;
  204.     const char* testname = NULL;
  205.     test_function_t testfunc = NULL;
  206.  
  207.     while ( -1 != (opt = getopt(argc, argv, "c:C:n:t:h")))
  208.     {
  209.         switch (opt)
  210.         {
  211.             case 'c': cpu1     = atoi(optarg);  break;
  212.             case 'C': cpu2     = atoi(optarg);  break;
  213.             case 'n': n_iter   = atoi(optarg);  break;
  214.             case 't': testname = optarg;        break;
  215.             case 'h': usage(argv[0]); exit(0);  break;
  216.             default : usage(argv[0]); exit(-1); break;
  217.         }
  218.     }
  219.  
  220.     // input checking
  221.     if (-1==cpu1 || -1==cpu2)
  222.     {
  223.         fprintf(stderr, "ERROR: cpu1 and/or cpu2 not set, use -h for help\n");
  224.         exit(1);
  225.     }
  226.     else if (NULL==testname || 0==strlen(testname))
  227.     {
  228.         fprintf(stderr, "ERROR: test not specified, use -h for help\n");
  229.         exit(1);
  230.     }
  231.  
  232.     printf( "RUNTIME PARAMS:\n"
  233.             "    n_iter ..... %d\n"
  234.             "    cpu1 ....... %d\n"
  235.             "    cpu2 ....... %d\n"
  236.             "    testname ... %s\n"
  237.             , n_iter
  238.             , cpu1
  239.             , cpu2
  240.             , testname
  241.             );
  242.  
  243.     // boilerplate initialization
  244.     pthread_mutex_init(&mutex, NULL);
  245.     pthread_attr_init(&attr);
  246.     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  247.  
  248.     shared_int = 0;
  249.  
  250.     if      (0==strcmp("lc", testname)) { testfunc = lock_contention_test;    }
  251.     else if (0==strcmp("cv", testname)) { testfunc = condition_variable_test; }
  252.     else
  253.     {
  254.         fprintf(stderr,
  255.                 "ERROR: invalid testname \"%s\", use -h for help\n",
  256.                 testname);
  257.         exit(1);
  258.     }
  259.  
  260.     t1 = timestamp();
  261.     testfunc();
  262.     t2 = timestamp();
  263.  
  264.     // cleanup
  265.     pthread_mutex_destroy(&mutex);
  266.     pthread_attr_destroy(&attr);
  267.  
  268.     tdiff = (t2 - t1);
  269.     printf( "runtime, microseconds ... %lu\n"
  270.             "runtime, seconds ........ %lf\n"
  271.             , tdiff
  272.             , (1.0*tdiff/USEC_PER_SEC)
  273.           );
  274.  
  275.     return 0;
  276. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement