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