1/****************************************************************************** 2 * 3 * Copyright © International Business Machines Corp., 2006, 2008 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 * 19 * NAME 20 * async_handler.c 21 * 22 * DESCRIPTION 23 * Measure the latency involved in asynchronous event handlers. 24 * Specifically it measures the latency of the pthread_cond_signal 25 * call until the signalled thread is scheduled. 26 * 27 * USAGE: 28 * Use run_auto.sh script in current directory to build and run test. 29 * 30 * AUTHOR 31 * Darren Hart <dvhltc@us.ibm.com> 32 * 33 * HISTORY 34 * 2006-Oct-20: Initial version by Darren Hart <dvhltc@us.ibm.com> 35 * 36 * This line has to be added to avoid a stupid CVS problem 37 *****************************************************************************/ 38 39#include <stdio.h> 40#include <stdlib.h> 41#include <math.h> 42#include <librttest.h> 43#include <libstats.h> 44#include <getopt.h> 45 46#define SIGNAL_PRIO 89 47#define HANDLER_PRIO 89 48#define DEFAULT_ITERATIONS 1000000 /* about 1 minute @ 2GHz */ 49#define HIST_BUCKETS 100 50#define PASS_US 100 51 52static nsec_t start; 53static nsec_t end; 54static int iterations = 0; 55 56#define CHILD_START 0 57#define CHILD_WAIT 1 58#define CHILD_HANDLED 2 59#define CHILD_QUIT 3 60atomic_t step; 61 62pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 63pthread_mutex_t mutex; 64 65static int ret = 0; 66 67void usage(void) 68{ 69 rt_help(); 70 printf("async_handler specific options:\n"); 71 printf 72 (" -iITERATIONS number of iterations to calculate the average over\n"); 73} 74 75int parse_args(int c, char *v) 76{ 77 78 int handled = 1; 79 switch (c) { 80 case 'h': 81 usage(); 82 exit(0); 83 case 'i': 84 iterations = atoi(v); 85 break; 86 default: 87 handled = 0; 88 break; 89 } 90 return handled; 91} 92 93void *handler_thread(void *arg) 94{ 95 96 while (atomic_get(&step) != CHILD_QUIT) { 97 pthread_mutex_lock(&mutex); 98 atomic_set(CHILD_WAIT, &step); 99 if (pthread_cond_wait(&cond, &mutex) != 0) { 100 perror("pthead_cond_wait"); 101 break; 102 } 103 end = rt_gettime(); 104 atomic_set(CHILD_HANDLED, &step); 105 pthread_mutex_unlock(&mutex); 106 while (atomic_get(&step) == CHILD_HANDLED) 107 usleep(10); 108 } 109 printf("handler thread exiting\n"); 110 return 0; 111} 112 113void *signal_thread(void *arg) 114{ 115 116 int i; 117 long delta, max, min; 118 stats_container_t dat; 119 stats_container_t hist; 120 stats_record_t rec; 121 122 stats_container_init(&dat, iterations); 123 stats_container_init(&hist, HIST_BUCKETS); 124 125 min = max = 0; 126 for (i = 0; i < iterations; i++) { 127 /* wait for child to wait on cond, then signal the event */ 128 while (atomic_get(&step) != CHILD_WAIT) 129 usleep(10); 130 pthread_mutex_lock(&mutex); 131 start = rt_gettime(); 132 if (pthread_cond_signal(&cond) != 0) { 133 perror("pthread_cond_signal"); 134 atomic_set(CHILD_QUIT, &step); 135 break; 136 } 137 pthread_mutex_unlock(&mutex); 138 139 /* wait for the event handler to schedule */ 140 while (atomic_get(&step) != CHILD_HANDLED) 141 usleep(10); 142 delta = (long)((end - start) / NS_PER_US); 143 if (delta > pass_criteria) 144 ret = 1; 145 rec.x = i; 146 rec.y = delta; 147 stats_container_append(&dat, rec); 148 if (i == 0) 149 min = max = delta; 150 else { 151 min = MIN(min, delta); 152 max = MAX(max, delta); 153 } 154 atomic_set((i == iterations - 1) ? CHILD_QUIT : CHILD_START, 155 &step); 156 } 157 printf("recording statistics...\n"); 158 printf("Min: %ld us\n", min); 159 printf("Max: %ld us\n", max); 160 printf("Avg: %.4f us\n", stats_avg(&dat)); 161 printf("StdDev: %.4f us\n", stats_stddev(&dat)); 162 stats_hist(&hist, &dat); 163 stats_container_save("samples", 164 "Asynchronous Event Handling Latency Scatter Plot", 165 "Iteration", "Latency (us)", &dat, "points"); 166 stats_container_save("hist", 167 "Asynchronous Event Handling Latency Histogram", 168 "Latency (us)", "Samples", &hist, "steps"); 169 printf("signal thread exiting\n"); 170 171 return NULL; 172} 173 174int main(int argc, char *argv[]) 175{ 176 int signal_id, handler_id; 177 setup(); 178 179 printf("\n-----------------------------------\n"); 180 printf("Asynchronous Event Handling Latency\n"); 181 printf("-----------------------------------\n\n"); 182 183 pass_criteria = PASS_US; 184 rt_init("i:h", parse_args, argc, argv); 185 186 init_pi_mutex(&mutex); 187 188 atomic_set(CHILD_START, &step); 189 190 if (iterations == 0) 191 iterations = DEFAULT_ITERATIONS; 192 printf("Running %d iterations\n", iterations); 193 194 handler_id = 195 create_fifo_thread(handler_thread, NULL, HANDLER_PRIO); 196 signal_id = create_fifo_thread(signal_thread, NULL, SIGNAL_PRIO); 197 198 join_threads(); 199 200 printf("\nCriteria: latencies < %d\n", (int)pass_criteria); 201 printf("Result: %s\n", ret ? "FAIL" : "PASS"); 202 203 return ret; 204} 205