• 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_tsc.c
21  *
22  * DESCRIPTION
23  *     This test mimics an async event handler in a real-time JVM
24  *     An async event server thread is created that goes to sleep waiting
25  *     to be woken up to do some work.
26  *
27  *     A user thread is created that simulates the firing of an event by
28  *     signalling the async handler thread to do some work.
29  *
30  * USAGE:
31  *     Use run_auto.sh script in current directory to build and run test.
32  *
33  * AUTHOR
34  *      Darren Hart <dvhltc@us.ibm.com>
35  *
36  * HISTORY
37  *    2006-Oct-20: Initial version by Darren Hart <dvhltc@us.ibm.com>
38  *
39  *      This line has to be added to avoid a stupid CVS problem
40  *****************************************************************************/
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <math.h>
45 #include <stdint.h>
46 #include <pthread.h>
47 #include <librttest.h>
48 #include <libstats.h>
49 #include <libtsc.h>
50 
51 #define HANDLER_PRIO 98
52 #define SIGNAL_PRIO 99
53 #define ITERATIONS 10000000
54 #define HIST_BUCKETS 100
55 #define PASS_US 100
56 
57 nsec_t start;
58 nsec_t end;
59 unsigned long long tsc_period;	/* in picoseconds */
60 int over_20 = 0;
61 int over_25 = 0;
62 int over_30 = 0;
63 
64 #define CHILD_START   0
65 #define CHILD_WAIT    1
66 #define CHILD_HANDLED 2
67 #define CHILD_QUIT    3
68 atomic_t step;
69 
70 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
71 pthread_mutex_t mutex;
72 
usage(void)73 void usage(void)
74 {
75 	rt_help();
76 	printf("async_handler_tsc specific options:\n");
77 }
78 
parse_args(int c,char * v)79 int parse_args(int c, char *v)
80 {
81 
82 	int handled = 1;
83 	switch (c) {
84 	case 'h':
85 		usage();
86 		exit(0);
87 	default:
88 		handled = 0;
89 		break;
90 	}
91 	return handled;
92 }
93 
94 /* calculate the tsc period */
tsc_period_ps(void)95 unsigned long long tsc_period_ps(void)
96 {
97 	nsec_t ns_start;
98 	nsec_t ns_end;
99 	unsigned long long tsc_start, tsc_end;
100 
101 	rdtscll(tsc_start);
102 	ns_start = rt_gettime();
103 	sleep(1);
104 	rdtscll(tsc_end);
105 	ns_end = rt_gettime();
106 
107 	return (1000 * (ns_end - ns_start)) / tsc_minus(tsc_start, tsc_end);
108 }
109 
handler_thread(void * arg)110 void *handler_thread(void *arg)
111 {
112 	while (atomic_get(&step) != CHILD_QUIT) {
113 		pthread_mutex_lock(&mutex);
114 		atomic_set(CHILD_WAIT, &step);
115 		if (pthread_cond_wait(&cond, &mutex) != 0) {
116 			perror("pthead_cond_wait");
117 			break;
118 		}
119 		rdtscll(end);
120 		atomic_set(CHILD_HANDLED, &step);
121 		pthread_mutex_unlock(&mutex);
122 		while (atomic_get(&step) == CHILD_HANDLED)
123 			usleep(10);
124 	}
125 	printf("handler thread exiting\n");
126 	return NULL;
127 }
128 
signal_thread(void * arg)129 void *signal_thread(void *arg)
130 {
131 	int i;
132 	long delta, max, min;
133 	stats_container_t dat;
134 	stats_container_t hist;
135 	stats_record_t rec;
136 
137 	stats_container_init(&dat, ITERATIONS);
138 	stats_container_init(&hist, HIST_BUCKETS);
139 
140 	min = max = 0;
141 	for (i = 0; i < ITERATIONS; i++) {
142 		/* wait for child to wait on cond, then signal the event */
143 		while (atomic_get(&step) != CHILD_WAIT)
144 			usleep(10);
145 		pthread_mutex_lock(&mutex);
146 		rdtscll(start);
147 		if (pthread_cond_signal(&cond) != 0) {
148 			perror("pthread_cond_signal");
149 			atomic_set(CHILD_QUIT, &step);
150 			break;
151 		}
152 		pthread_mutex_unlock(&mutex);
153 
154 		/* wait for the event handler to schedule */
155 		while (atomic_get(&step) != CHILD_HANDLED)
156 			usleep(10);
157 		delta = (long)(tsc_period * (end - start) / 1000000);
158 		if (delta > 30) {
159 			over_30++;
160 		} else if (delta > 25) {
161 			over_25++;
162 		} else if (delta > 20) {
163 			over_20++;
164 		}
165 		rec.x = i;
166 		rec.y = delta;
167 		stats_container_append(&dat, rec);
168 		if (i == 0)
169 			min = max = delta;
170 		else {
171 			min = MIN(min, delta);
172 			max = MAX(max, delta);
173 		}
174 		atomic_set((i == ITERATIONS - 1) ? CHILD_QUIT : CHILD_START,
175 			   &step);
176 	}
177 	printf("recording statistics...\n");
178 	printf("Minimum: %ld\n", min);
179 	printf("Maximum: %ld\n", max);
180 	printf("Average: %f\n", stats_avg(&dat));
181 	printf("Standard Deviation: %f\n", stats_stddev(&dat));
182 	stats_hist(&hist, &dat);
183 	stats_container_save("samples",
184 			     "Asynchronous Event Handling Latency (TSC) Scatter Plot",
185 			     "Iteration", "Latency (us)", &dat, "points");
186 	stats_container_save("hist",
187 			     "Asynchronous Event Handling Latency (TSC) Histogram",
188 			     "Latency (us)", "Samples", &hist, "steps");
189 	printf("signal thread exiting\n");
190 
191 	return NULL;
192 }
193 
main(int argc,char * argv[])194 int main(int argc, char *argv[])
195 {
196 	int signal_id, handler_id;
197 
198 #ifdef TSC_UNSUPPORTED
199 	printf("Error: test cannot be executed on an arch wihout TSC.\n");
200 	return ENOTSUP;
201 #endif
202 	setup();
203 
204 	rt_init("h", parse_args, argc, argv);
205 
206 	printf("-------------------------------\n");
207 	printf("Asynchronous Event Handling Latency\n");
208 	printf("-------------------------------\n\n");
209 	printf("Running %d iterations\n", ITERATIONS);
210 	printf("Calculating tsc period...");
211 	fflush(stdout);
212 	tsc_period = tsc_period_ps();
213 	printf("%llu ps\n", tsc_period);
214 
215 	init_pi_mutex(&mutex);
216 
217 	atomic_set(CHILD_START, &step);
218 	handler_id =
219 	    create_fifo_thread(handler_thread, NULL, HANDLER_PRIO);
220 	signal_id = create_fifo_thread(signal_thread, NULL, SIGNAL_PRIO);
221 
222 	join_threads();
223 
224 	printf("%d samples over 20 us latency\n", over_20);
225 	printf("%d samples over 25 us latency\n", over_25);
226 	printf("%d samples over 30 us latency\n", over_30);
227 
228 	return 0;
229 }
230