• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
52 static nsec_t start;
53 static nsec_t end;
54 static int iterations = 0;
55 
56 #define CHILD_START   0
57 #define CHILD_WAIT    1
58 #define CHILD_HANDLED 2
59 #define CHILD_QUIT    3
60 atomic_t step;
61 
62 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
63 pthread_mutex_t mutex;
64 
65 static int ret = 0;
66 
usage(void)67 void 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 
parse_args(int c,char * v)75 int 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 
handler_thread(void * arg)93 void *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 
signal_thread(void * arg)113 void *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 
main(int argc,char * argv[])174 int 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