#include #include #include #include #include #include #include #include #include // The different type of sleep that are supported enum sleep_type { SLEEP_TYPE_NONE, SLEEP_TYPE_SELECT, SLEEP_TYPE_POLL, SLEEP_TYPE_USLEEP, SLEEP_TYPE_YIELD, }; // Function type for doing work with a sleep typedef long long *(*work_func)(const int sleep_time, const int num_iterations, const int work_size); // Information passed to the thread struct thread_info { int sleep_time; int num_iterations; int work_size; work_func func; }; // In order to make SLEEP_TYPE a run-time parameter function pointers are used. // The function pointer could have been to the sleep function being used, but // then that would mean an extra function call inside of the "work loop" and I // wanted to keep the measurements as tight as possible and the extra work being // done to be as small/controlled as possible so instead the work is declared as // a seriees of macros that are called in all of the sleep functions. The code // is a bit uglier this way, but I believe it results in a more accurate test. // Fill in a buffer with random numbers (taken from latt.c by Jens Axboe ) #define DECLARE_WORK() \ int *buf; \ int pseed; \ int inum, bnum; \ struct timeval before, after; \ long long *diff; \ buf = calloc(work_size, sizeof(int)); \ diff = malloc(sizeof(long long)); \ gettimeofday(&before, NULL) #define DO_WORK(SLEEP_FUNC) \ for (inum=0; inumfunc)(tinfo->sleep_time, tinfo->num_iterations, tinfo->work_size); } int main(int argc, char **argv) { if (argc <= 6) { printf("Usage: %s \n", argv[0]); printf(" outer_iterations: Number of iterations for each thread (used to calculate statistics)\n"); printf(" inner_iterations: Number of work/sleep cycles performed in each thread (used to improve consistency/observability))\n"); printf(" work_size: Number of array elements (in kb) that are filled with psuedo-random numbers\n"); printf(" num_threads: Number of threads to spawn and perform work/sleep cycles in\n"); printf(" sleep_type: 0=none 1=select 2=poll 3=usleep 4=yield\n"); return -1; } struct thread_info tinfo; int outer_iterations; int sleep_type; int s, inum, tnum, num_threads; pthread_attr_t attr; pthread_t *threads; long long *res; long long *times; // Get the parameters tinfo.sleep_time = atoi(argv[1]); outer_iterations = atoi(argv[2]); tinfo.num_iterations = atoi(argv[3]); tinfo.work_size = atoi(argv[4]) * 1024; num_threads = atoi(argv[5]); sleep_type = atoi(argv[6]); switch (sleep_type) { case SLEEP_TYPE_NONE: tinfo.func = &do_work_nosleep; break; case SLEEP_TYPE_SELECT: tinfo.func = &do_work_select; break; case SLEEP_TYPE_POLL: tinfo.func = &do_work_poll; break; case SLEEP_TYPE_USLEEP: tinfo.func = &do_work_usleep; break; case SLEEP_TYPE_YIELD: tinfo.func = &do_work_yield; break; default: printf("Invalid sleep type: %d\n", sleep_type); return -7; } // Initialize the thread creation attributes s = pthread_attr_init(&attr); if (s != 0) { printf("Error initializing thread attributes\n"); return -2; } // Allocate the memory to track the threads threads = calloc(num_threads, sizeof(pthread_t)); times = calloc(num_threads, sizeof(unsigned long long)); if (threads == NULL) { printf("Error allocating memory to track threads\n"); return -3; } // Calculate the statistics of the processing float min_time = FLT_MAX; float max_time = -FLT_MAX; float avg_time = 0; float prev_avg_time = 0; float stddev_time = 0; // Perform the requested number of outer iterations for (inum=0; inum max_time) max_time = times[tnum]; avg_time += (times[tnum] - avg_time) / (float)(tnum + 1); stddev_time += (times[tnum] - prev_avg_time) * (times[tnum] - avg_time); prev_avg_time = avg_time; } } // Finish the calculation of the standard deviation stddev_time = sqrtf(stddev_time / ((outer_iterations * num_threads) - 1)); // Print out the statistics of the times printf("time_per_iteration: min: %.1f us avg: %.1f us max: %.1f us stddev: %.1f us\n", min_time / tinfo.num_iterations, avg_time / tinfo.num_iterations, max_time / tinfo.num_iterations, stddev_time / tinfo.num_iterations); // Clean up the allocated threads free(threads); return 0; }