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