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 *      sched_jitter.c
21f08c3bdfSopenharmony_ci *
22f08c3bdfSopenharmony_ci * DESCRIPTION
23f08c3bdfSopenharmony_ci *      This test measures scheduling jitter w/ realtime processes.
24f08c3bdfSopenharmony_ci *
25f08c3bdfSopenharmony_ci *      It spawns a realtime thread that repeatedly times how long it takes to
26f08c3bdfSopenharmony_ci *      do a fixed amount of work. It then prints out the maximum jitter seen
27f08c3bdfSopenharmony_ci *      (longest execution time - the shortest execution time).
28f08c3bdfSopenharmony_ci *      It also spawns off a realtime thread of higher priority that simply
29f08c3bdfSopenharmony_ci *      wakes up and goes back to sleep. This tries to measure how much overhead
30f08c3bdfSopenharmony_ci *      the scheduler adds in switching quickly to another task and back.
31f08c3bdfSopenharmony_ci *
32f08c3bdfSopenharmony_ci * USAGE:
33f08c3bdfSopenharmony_ci *      Use run_auto.sh script in current directory to build and run test.
34f08c3bdfSopenharmony_ci *
35f08c3bdfSopenharmony_ci * AUTHOR
36f08c3bdfSopenharmony_ci *      John Stultz <johnstul@us.ibm.com>
37f08c3bdfSopenharmony_ci *
38f08c3bdfSopenharmony_ci * HISTORY
39f08c3bdfSopenharmony_ci *      2006-May-05: Initial version by John Stultz <johnstul@us.ibm.com>
40f08c3bdfSopenharmony_ci *      2007-July-18: Support to gather stats by Ankita Garg <ankita@in.ibm.com>
41f08c3bdfSopenharmony_ci *
42f08c3bdfSopenharmony_ci *      This line has to be added to avoid a stupid CVS problem
43f08c3bdfSopenharmony_ci *****************************************************************************/
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_ci#include <stdio.h>
46f08c3bdfSopenharmony_ci#include <time.h>
47f08c3bdfSopenharmony_ci#include <pthread.h>
48f08c3bdfSopenharmony_ci#include <sched.h>
49f08c3bdfSopenharmony_ci#include <unistd.h>
50f08c3bdfSopenharmony_ci#include <libstats.h>
51f08c3bdfSopenharmony_ci#include <librttest.h>
52f08c3bdfSopenharmony_ci
53f08c3bdfSopenharmony_ci#define NUMRUNS 1000
54f08c3bdfSopenharmony_ci#define NUMLOOPS 1000000
55f08c3bdfSopenharmony_ci#define NSEC_PER_SEC 1000000000
56f08c3bdfSopenharmony_ci#define WORKLEN 64
57f08c3bdfSopenharmony_ci#define ISLEEP 50000
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_ciint array[WORKLEN];
60f08c3bdfSopenharmony_ci
61f08c3bdfSopenharmony_civolatile int flag;		/*let interrupter know we're done */
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_civoid usage(void)
64f08c3bdfSopenharmony_ci{
65f08c3bdfSopenharmony_ci	rt_help();
66f08c3bdfSopenharmony_ci	printf("sched_jitter specific options:\n");
67f08c3bdfSopenharmony_ci}
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ciint parse_args(int c, char *v)
70f08c3bdfSopenharmony_ci{
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_ci	int handled = 1;
73f08c3bdfSopenharmony_ci	switch (c) {
74f08c3bdfSopenharmony_ci	case 'h':
75f08c3bdfSopenharmony_ci		usage();
76f08c3bdfSopenharmony_ci		exit(0);
77f08c3bdfSopenharmony_ci	default:
78f08c3bdfSopenharmony_ci		handled = 0;
79f08c3bdfSopenharmony_ci		break;
80f08c3bdfSopenharmony_ci	}
81f08c3bdfSopenharmony_ci	return handled;
82f08c3bdfSopenharmony_ci}
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_ciunsigned long long ts_sub(struct timespec a, struct timespec b)
85f08c3bdfSopenharmony_ci{
86f08c3bdfSopenharmony_ci	unsigned long long first, second;
87f08c3bdfSopenharmony_ci
88f08c3bdfSopenharmony_ci	first = (unsigned long long)a.tv_sec * NSEC_PER_SEC + a.tv_nsec;
89f08c3bdfSopenharmony_ci	second = (unsigned long long)b.tv_sec * NSEC_PER_SEC + b.tv_nsec;
90f08c3bdfSopenharmony_ci	return first - second;
91f08c3bdfSopenharmony_ci}
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_civoid print_unit(unsigned long long val)
94f08c3bdfSopenharmony_ci{
95f08c3bdfSopenharmony_ci	if (val > 1000000)
96f08c3bdfSopenharmony_ci		printf("%f ms\n", (float)(val) / 1000000);
97f08c3bdfSopenharmony_ci	else if (val > 1000)
98f08c3bdfSopenharmony_ci		printf("%f us\n", (float)(val) / 1000);
99f08c3bdfSopenharmony_ci	else
100f08c3bdfSopenharmony_ci		printf("%f ns\n", (float)val);
101f08c3bdfSopenharmony_ci
102f08c3bdfSopenharmony_ci}
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_civoid do_work(int runs)
105f08c3bdfSopenharmony_ci{
106f08c3bdfSopenharmony_ci	int i, j;
107f08c3bdfSopenharmony_ci	for (i = 0; i < runs; i++) {
108f08c3bdfSopenharmony_ci		for (j = 0; j < WORKLEN - 1; j++)
109f08c3bdfSopenharmony_ci			array[j] = array[j] + array[j + 1];
110f08c3bdfSopenharmony_ci		for (j = 0; j < WORKLEN - 1; j++)
111f08c3bdfSopenharmony_ci			array[j] = array[j] - array[j + 1];
112f08c3bdfSopenharmony_ci	}
113f08c3bdfSopenharmony_ci}
114f08c3bdfSopenharmony_ci
115f08c3bdfSopenharmony_civoid *thread_worker(void *arg)
116f08c3bdfSopenharmony_ci{
117f08c3bdfSopenharmony_ci	struct timespec start, stop;
118f08c3bdfSopenharmony_ci	int i;
119f08c3bdfSopenharmony_ci	unsigned long long delta;
120f08c3bdfSopenharmony_ci	unsigned long long min = -1, max = 0;
121f08c3bdfSopenharmony_ci
122f08c3bdfSopenharmony_ci	stats_container_t dat;
123f08c3bdfSopenharmony_ci	stats_record_t rec;
124f08c3bdfSopenharmony_ci
125f08c3bdfSopenharmony_ci	stats_container_init(&dat, NUMRUNS);
126f08c3bdfSopenharmony_ci
127f08c3bdfSopenharmony_ci	for (i = 0; i < NUMRUNS; i++) {
128f08c3bdfSopenharmony_ci
129f08c3bdfSopenharmony_ci		do_work(1);	/* warm cache */
130f08c3bdfSopenharmony_ci
131f08c3bdfSopenharmony_ci		/* do test */
132f08c3bdfSopenharmony_ci		clock_gettime(CLOCK_MONOTONIC, &start);
133f08c3bdfSopenharmony_ci		do_work(NUMLOOPS);
134f08c3bdfSopenharmony_ci		clock_gettime(CLOCK_MONOTONIC, &stop);
135f08c3bdfSopenharmony_ci
136f08c3bdfSopenharmony_ci		/* calc delta, min and max */
137f08c3bdfSopenharmony_ci		delta = ts_sub(stop, start);
138f08c3bdfSopenharmony_ci		if (delta < min)
139f08c3bdfSopenharmony_ci			min = delta;
140f08c3bdfSopenharmony_ci		if (delta > max)
141f08c3bdfSopenharmony_ci			max = delta;
142f08c3bdfSopenharmony_ci		rec.x = i;
143f08c3bdfSopenharmony_ci		rec.y = delta;
144f08c3bdfSopenharmony_ci		stats_container_append(&dat, rec);
145f08c3bdfSopenharmony_ci
146f08c3bdfSopenharmony_ci		printf("delta: %llu ns\n", delta);
147f08c3bdfSopenharmony_ci		usleep(1);	/* let other things happen */
148f08c3bdfSopenharmony_ci	}
149f08c3bdfSopenharmony_ci
150f08c3bdfSopenharmony_ci	printf("max jitter: ");
151f08c3bdfSopenharmony_ci	print_unit(max - min);
152f08c3bdfSopenharmony_ci	stats_container_save("samples", "Scheduling Jitter Scatter Plot",
153f08c3bdfSopenharmony_ci			     "Iteration", "Delay (ns)", &dat, "points");
154f08c3bdfSopenharmony_ci	return NULL;
155f08c3bdfSopenharmony_ci}
156f08c3bdfSopenharmony_ci
157f08c3bdfSopenharmony_civoid *thread_interrupter(void *arg)
158f08c3bdfSopenharmony_ci{
159f08c3bdfSopenharmony_ci	while (!flag)
160f08c3bdfSopenharmony_ci		usleep(ISLEEP);
161f08c3bdfSopenharmony_ci	return NULL;
162f08c3bdfSopenharmony_ci}
163f08c3bdfSopenharmony_ci
164f08c3bdfSopenharmony_ciint main(int argc, char *argv[])
165f08c3bdfSopenharmony_ci{
166f08c3bdfSopenharmony_ci	int worker, interrupter;
167f08c3bdfSopenharmony_ci
168f08c3bdfSopenharmony_ci	setup();
169f08c3bdfSopenharmony_ci
170f08c3bdfSopenharmony_ci	rt_init("h", parse_args, argc, argv);
171f08c3bdfSopenharmony_ci
172f08c3bdfSopenharmony_ci	interrupter = create_fifo_thread(thread_interrupter, NULL, 80);
173f08c3bdfSopenharmony_ci	sleep(1);
174f08c3bdfSopenharmony_ci	worker = create_fifo_thread(thread_worker, NULL, 10);
175f08c3bdfSopenharmony_ci
176f08c3bdfSopenharmony_ci	join_thread(worker);
177f08c3bdfSopenharmony_ci	flag = 1;
178f08c3bdfSopenharmony_ci	join_thread(interrupter);
179f08c3bdfSopenharmony_ci
180f08c3bdfSopenharmony_ci	return 0;
181f08c3bdfSopenharmony_ci}
182