Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * snb_slow_demo.c
- *
- * - simple program to demonstrate specific cases where Sandy Bridge is
- * dramatically slower than Westmere:
- * (1) pthread mutex contention
- * (2) pthread condition variable signaling
- *
- * - compile with gcc as follows:
- * gcc -Wall -g -O2 snb_slow_demo.c -o snb_slow_demo -lpthread
- *
- * - tested on the following hardware:
- * Dell PowerEdge R620, E5-2690
- * HP dl360pg8, E5-2690
- * Dell PowerEdge R610, X5550
- * Dell PowerEdge R610, X5690
- */
- #define _GNU_SOURCE
- #include <pthread.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdint.h>
- #include <sys/time.h>
- #define DEFAULT_N_ITER (50000000)
- #define USEC_PER_SEC (1000000UL)
- #define TIMEVAL_TO_UINT64(tv) \
- ( (uint64_t)tv.tv_sec*(uint64_t)USEC_PER_SEC + (uint64_t)tv.tv_usec );
- /*
- * flatten struct timeval fields into one 64-bit unsigned integer
- */
- uint64_t timestamp()
- {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return TIMEVAL_TO_UINT64(tv);
- }
- /*
- * globals/types
- */
- static pthread_cond_t condvar;
- static pthread_mutex_t mutex;
- static pthread_attr_t attr;
- static pthread_t thread;
- static int64_t shared_int;
- static cpu_set_t cpuset;
- static int n_iter = DEFAULT_N_ITER;
- static int cpu1 = -1;
- static int cpu2 = -1;
- typedef int (*test_function_t)();
- /*
- * threaded function for lock contention test
- */
- void* lock_contention_thread(void *vptr)
- {
- int i;
- for (i=0; i<n_iter; i++)
- {
- pthread_mutex_lock(&mutex);
- shared_int--;
- //printf("DEBUG: shared_int: %ld\n", shared_int);
- pthread_mutex_unlock(&mutex);
- }
- return NULL;
- }
- /*
- * main thread for lock contention test
- * - two threads fighting over incrementing/decrementing an int
- */
- int lock_contention_test()
- {
- int rc, i;
- // create thread
- pthread_create(&thread, &attr, lock_contention_thread, NULL);
- // pin this (main) thread to cpu1
- CPU_ZERO(&cpuset);
- CPU_SET(cpu1, &cpuset);
- rc = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
- if (0 != rc) { fprintf(stderr, "ERROR: pthread_setaffinity_np()\n"); }
- // pin child thread to cpu2
- CPU_ZERO(&cpuset);
- CPU_SET(cpu2, &cpuset);
- rc = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
- if (0 != rc) { fprintf(stderr, "ERROR: pthread_setaffinity_np()\n"); }
- // do stuff
- for (i=0; i<n_iter; i++)
- {
- pthread_mutex_lock(&mutex);
- shared_int++;
- //printf("DEBUG: shared_int: %ld\n", shared_int);
- pthread_mutex_unlock(&mutex);
- }
- // wait for thread to finish
- pthread_join(thread, NULL);
- return 0;
- }
- /*
- * threaded function for condition variable test
- * - this thread always wants to transition from 1 to 0
- */
- void* condition_variable_thread(void *vptr)
- {
- int i;
- for (i=0; i<n_iter; i++)
- {
- pthread_mutex_lock(&mutex);
- if (1!=shared_int) { pthread_cond_wait(&condvar, &mutex); }
- shared_int--;
- //printf("DEBUG: shared_int: %ld\n", shared_int);
- pthread_cond_signal(&condvar);
- pthread_mutex_unlock(&mutex);
- }
- return NULL;
- }
- /*
- * main thread for condition variable test
- * - two threads "politely" incrementing and decrementing a shared integer by
- * communicating through a condition variable
- * - this thread always wants to transition from 0 to 1
- */
- int condition_variable_test()
- {
- int rc, i;
- pthread_cond_init(&condvar, NULL);
- // create thread
- pthread_create(&thread, &attr, condition_variable_thread, NULL);
- // pin this (main) thread to cpu1
- CPU_ZERO(&cpuset);
- CPU_SET(cpu1, &cpuset);
- rc = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
- if (0 != rc) { fprintf(stderr, "ERROR: pthread_setaffinity_np()\n"); }
- // pin child thread to cpu2
- CPU_ZERO(&cpuset);
- CPU_SET(cpu2, &cpuset);
- rc = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
- if (0 != rc) { fprintf(stderr, "ERROR: pthread_setaffinity_np()\n"); }
- for (i=0; i<n_iter; i++)
- {
- pthread_mutex_lock(&mutex);
- if (0!=shared_int) { pthread_cond_wait(&condvar, &mutex); }
- shared_int++;
- //printf("DEBUG: shared_int: %ld\n", shared_int);
- pthread_cond_signal(&condvar);
- pthread_mutex_unlock(&mutex);
- }
- // wait for thread to finish
- pthread_join(thread, NULL);
- pthread_cond_destroy(&condvar);
- return 0;
- }
- /*
- * handy helper function
- */
- void usage(const char* progname)
- {
- fprintf(stderr,
- "Usage: %s <-t test> <-c cpu1> <-C cpu2> [opts]\n"
- "ARGUMENTS:\n"
- " -c cpu1 ..... set CPU #1 for pinning main thread\n"
- " -C cpu2 ..... set CPU #2 for pinning child thread\n"
- " -t test ..... run specified test; options are:\n"
- " lc .... mutex lock contention\n"
- " cv .... condition variable\n"
- "OPTIONS:\n"
- " -n N ........ set number of iterations, default=%i\n"
- " -h .......... show this help\n"
- , progname
- , DEFAULT_N_ITER
- );
- }
- /*
- * program entry point
- */
- int main(int argc, char *argv[])
- {
- uint64_t t1, t2, tdiff;
- int opt;
- const char* testname = NULL;
- test_function_t testfunc = NULL;
- while ( -1 != (opt = getopt(argc, argv, "c:C:n:t:h")))
- {
- switch (opt)
- {
- case 'c': cpu1 = atoi(optarg); break;
- case 'C': cpu2 = atoi(optarg); break;
- case 'n': n_iter = atoi(optarg); break;
- case 't': testname = optarg; break;
- case 'h': usage(argv[0]); exit(0); break;
- default : usage(argv[0]); exit(-1); break;
- }
- }
- // input checking
- if (-1==cpu1 || -1==cpu2)
- {
- fprintf(stderr, "ERROR: cpu1 and/or cpu2 not set, use -h for help\n");
- exit(1);
- }
- else if (NULL==testname || 0==strlen(testname))
- {
- fprintf(stderr, "ERROR: test not specified, use -h for help\n");
- exit(1);
- }
- printf( "RUNTIME PARAMS:\n"
- " n_iter ..... %d\n"
- " cpu1 ....... %d\n"
- " cpu2 ....... %d\n"
- " testname ... %s\n"
- , n_iter
- , cpu1
- , cpu2
- , testname
- );
- // boilerplate initialization
- pthread_mutex_init(&mutex, NULL);
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
- shared_int = 0;
- if (0==strcmp("lc", testname)) { testfunc = lock_contention_test; }
- else if (0==strcmp("cv", testname)) { testfunc = condition_variable_test; }
- else
- {
- fprintf(stderr,
- "ERROR: invalid testname \"%s\", use -h for help\n",
- testname);
- exit(1);
- }
- t1 = timestamp();
- testfunc();
- t2 = timestamp();
- // cleanup
- pthread_mutex_destroy(&mutex);
- pthread_attr_destroy(&attr);
- tdiff = (t2 - t1);
- printf( "runtime, microseconds ... %lu\n"
- "runtime, seconds ........ %lf\n"
- , tdiff
- , (1.0*tdiff/USEC_PER_SEC)
- );
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement