1f08c3bdfSopenharmony_ci
2f08c3bdfSopenharmony_ci/******************************************************************************
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * Copyright (C) 2007-2009 Steven Rostedt <srostedt@redhat.com>
5f08c3bdfSopenharmony_ci *
6f08c3bdfSopenharmony_ci * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7f08c3bdfSopenharmony_ci *
8f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or modify
9f08c3bdfSopenharmony_ci * it under the terms of the GNU General Public License as published by
10f08c3bdfSopenharmony_ci * the Free Software Foundation; version 2 of the License (not later!)
11f08c3bdfSopenharmony_ci *
12f08c3bdfSopenharmony_ci * This program is distributed in the hope that it will be useful,
13f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15f08c3bdfSopenharmony_ci * GNU General Public License for more details.
16f08c3bdfSopenharmony_ci *
17f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License
18f08c3bdfSopenharmony_ci * along with this program; if not, write to the Free Software
19f08c3bdfSopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20f08c3bdfSopenharmony_ci *
21f08c3bdfSopenharmony_ci * NAME
22f08c3bdfSopenharmony_ci *      rt-migrate-test.c
23f08c3bdfSopenharmony_ci *
24f08c3bdfSopenharmony_ci * DESCRIPTION
25f08c3bdfSopenharmony_ci *	This test makes sure that all the high prio tasks that are in the
26f08c3bdfSopenharmony_ci *	running state are actually running on a CPU if it can.
27f08c3bdfSopenharmony_ci ** Steps:
28f08c3bdfSopenharmony_ci *	- Creates N+1 threads with lower real time priorities.
29f08c3bdfSopenharmony_ci *	  Where N is the number of CPUs in the system.
30f08c3bdfSopenharmony_ci *	- If the thread is high priority, and if a CPU is available, the
31f08c3bdfSopenharmony_ci *	  thread runs on that CPU.
32f08c3bdfSopenharmony_ci *	- The thread records the start time and the number of ticks in the run
33f08c3bdfSopenharmony_ci *	  interval.
34f08c3bdfSopenharmony_ci *	- The output indicates if lower prio task is quicker than higher
35f08c3bdfSopenharmony_ci *	  priority task.
36f08c3bdfSopenharmony_ci *
37f08c3bdfSopenharmony_ci * USAGE:
38f08c3bdfSopenharmony_ci *	Use run_auto.sh in the current directory to build and run the test.
39f08c3bdfSopenharmony_ci *
40f08c3bdfSopenharmony_ci * AUTHOR
41f08c3bdfSopenharmony_ci *      Steven Rostedt <srostedt@redhat.com>
42f08c3bdfSopenharmony_ci *
43f08c3bdfSopenharmony_ci * HISTORY
44f08c3bdfSopenharmony_ci *      30 July, 2009: Initial version by Steven Rostedt
45f08c3bdfSopenharmony_ci *      11 Aug, 2009: Converted the coding style to the one used by the realtime
46f08c3bdfSopenharmony_ci *		    testcases by Kiran Prakash
47f08c3bdfSopenharmony_ci *
48f08c3bdfSopenharmony_ci */
49f08c3bdfSopenharmony_ci#ifndef _GNU_SOURCE
50f08c3bdfSopenharmony_ci#define _GNU_SOURCE
51f08c3bdfSopenharmony_ci#endif
52f08c3bdfSopenharmony_ci#include <stdio.h>
53f08c3bdfSopenharmony_ci#include <stdlib.h>
54f08c3bdfSopenharmony_ci#include <string.h>
55f08c3bdfSopenharmony_ci#include <getopt.h>
56f08c3bdfSopenharmony_ci#include <stdarg.h>
57f08c3bdfSopenharmony_ci#include <unistd.h>
58f08c3bdfSopenharmony_ci#include <ctype.h>
59f08c3bdfSopenharmony_ci#include <time.h>
60f08c3bdfSopenharmony_ci#include <sys/types.h>
61f08c3bdfSopenharmony_ci#include <sys/stat.h>
62f08c3bdfSopenharmony_ci#include <fcntl.h>
63f08c3bdfSopenharmony_ci#include <signal.h>
64f08c3bdfSopenharmony_ci#include <sys/time.h>
65f08c3bdfSopenharmony_ci#include <linux/unistd.h>
66f08c3bdfSopenharmony_ci#include <sys/syscall.h>
67f08c3bdfSopenharmony_ci#include <errno.h>
68f08c3bdfSopenharmony_ci#include <sched.h>
69f08c3bdfSopenharmony_ci#include <pthread.h>
70f08c3bdfSopenharmony_ci#include <librttest.h>
71f08c3bdfSopenharmony_ci#include <libstats.h>
72f08c3bdfSopenharmony_ci
73f08c3bdfSopenharmony_ci#define gettid() syscall(__NR_gettid)
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_ci#define VERSION_STRING "V 0.4LTP"
76f08c3bdfSopenharmony_ci
77f08c3bdfSopenharmony_ciint nr_tasks;
78f08c3bdfSopenharmony_ciint lfd;
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_ciint numcpus;
81f08c3bdfSopenharmony_cistatic int mark_fd = -1;
82f08c3bdfSopenharmony_cistatic __thread char buff[BUFSIZ + 1];
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_cistatic void setup_ftrace_marker(void)
85f08c3bdfSopenharmony_ci{
86f08c3bdfSopenharmony_ci	struct stat st;
87f08c3bdfSopenharmony_ci	char *files[] = {
88f08c3bdfSopenharmony_ci		"/sys/kernel/debug/tracing/trace_marker",
89f08c3bdfSopenharmony_ci		"/debug/tracing/trace_marker",
90f08c3bdfSopenharmony_ci		"/debugfs/tracing/trace_marker",
91f08c3bdfSopenharmony_ci	};
92f08c3bdfSopenharmony_ci	int ret;
93f08c3bdfSopenharmony_ci	int i;
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_ci	for (i = 0; i < (sizeof(files) / sizeof(char *)); i++) {
96f08c3bdfSopenharmony_ci		ret = stat(files[i], &st);
97f08c3bdfSopenharmony_ci		if (ret >= 0)
98f08c3bdfSopenharmony_ci			goto found;
99f08c3bdfSopenharmony_ci	}
100f08c3bdfSopenharmony_ci	/* todo, check mounts system */
101f08c3bdfSopenharmony_ci	return;
102f08c3bdfSopenharmony_cifound:
103f08c3bdfSopenharmony_ci	mark_fd = open(files[i], O_WRONLY);
104f08c3bdfSopenharmony_ci}
105f08c3bdfSopenharmony_ci
106f08c3bdfSopenharmony_cistatic void ftrace_write(const char *fmt, ...)
107f08c3bdfSopenharmony_ci{
108f08c3bdfSopenharmony_ci	va_list ap;
109f08c3bdfSopenharmony_ci	int n;
110f08c3bdfSopenharmony_ci
111f08c3bdfSopenharmony_ci	if (mark_fd < 0)
112f08c3bdfSopenharmony_ci		return;
113f08c3bdfSopenharmony_ci
114f08c3bdfSopenharmony_ci	va_start(ap, fmt);
115f08c3bdfSopenharmony_ci	n = vsnprintf(buff, BUFSIZ, fmt, ap);
116f08c3bdfSopenharmony_ci	va_end(ap);
117f08c3bdfSopenharmony_ci
118f08c3bdfSopenharmony_ci	/*
119f08c3bdfSopenharmony_ci	 * This doesn't return any valid vs invalid exit codes, so printing out
120f08c3bdfSopenharmony_ci	 * a perror to warn the end-user of an issue is sufficient.
121f08c3bdfSopenharmony_ci	 */
122f08c3bdfSopenharmony_ci	if (write(mark_fd, buff, n) < 0) {
123f08c3bdfSopenharmony_ci		perror("write");
124f08c3bdfSopenharmony_ci	}
125f08c3bdfSopenharmony_ci}
126f08c3bdfSopenharmony_ci
127f08c3bdfSopenharmony_ci#define INTERVAL 100ULL * NS_PER_MS
128f08c3bdfSopenharmony_ci#define RUN_INTERVAL 20ULL * NS_PER_MS
129f08c3bdfSopenharmony_ci#define NR_RUNS 50
130f08c3bdfSopenharmony_ci#define PRIO_START 2
131f08c3bdfSopenharmony_ci/* 1 millisec off */
132f08c3bdfSopenharmony_ci#define MAX_ERR  1000 * NS_PER_US
133f08c3bdfSopenharmony_ci
134f08c3bdfSopenharmony_ci#define PROGRESS_CHARS 70
135f08c3bdfSopenharmony_ci
136f08c3bdfSopenharmony_cistatic unsigned long long interval = INTERVAL;
137f08c3bdfSopenharmony_cistatic unsigned long long run_interval = RUN_INTERVAL;
138f08c3bdfSopenharmony_cistatic unsigned long long max_err = MAX_ERR;
139f08c3bdfSopenharmony_cistatic int nr_runs = NR_RUNS;
140f08c3bdfSopenharmony_cistatic int prio_start = PRIO_START;
141f08c3bdfSopenharmony_cistatic int check = 1;
142f08c3bdfSopenharmony_cistatic int stop;
143f08c3bdfSopenharmony_ci
144f08c3bdfSopenharmony_cistatic unsigned long long now;
145f08c3bdfSopenharmony_ci
146f08c3bdfSopenharmony_cistatic int done;
147f08c3bdfSopenharmony_cistatic int loop;
148f08c3bdfSopenharmony_ci
149f08c3bdfSopenharmony_cistatic pthread_barrier_t start_barrier;
150f08c3bdfSopenharmony_cistatic pthread_barrier_t end_barrier;
151f08c3bdfSopenharmony_cistats_container_t *intervals;
152f08c3bdfSopenharmony_cistats_container_t *intervals_length;
153f08c3bdfSopenharmony_cistats_container_t *intervals_loops;
154f08c3bdfSopenharmony_cistatic long *thread_pids;
155f08c3bdfSopenharmony_ci
156f08c3bdfSopenharmony_cistatic void print_progress_bar(int percent)
157f08c3bdfSopenharmony_ci{
158f08c3bdfSopenharmony_ci	int i;
159f08c3bdfSopenharmony_ci	int p;
160f08c3bdfSopenharmony_ci
161f08c3bdfSopenharmony_ci	if (percent > 100)
162f08c3bdfSopenharmony_ci		percent = 100;
163f08c3bdfSopenharmony_ci
164f08c3bdfSopenharmony_ci	/* Use stderr, so we don't capture it */
165f08c3bdfSopenharmony_ci	putc('\r', stderr);
166f08c3bdfSopenharmony_ci	putc('|', stderr);
167f08c3bdfSopenharmony_ci	for (i = 0; i < PROGRESS_CHARS; i++)
168f08c3bdfSopenharmony_ci		putc(' ', stderr);
169f08c3bdfSopenharmony_ci	putc('|', stderr);
170f08c3bdfSopenharmony_ci	putc('\r', stderr);
171f08c3bdfSopenharmony_ci	putc('|', stderr);
172f08c3bdfSopenharmony_ci
173f08c3bdfSopenharmony_ci	p = PROGRESS_CHARS * percent / 100;
174f08c3bdfSopenharmony_ci
175f08c3bdfSopenharmony_ci	for (i = 0; i < p; i++)
176f08c3bdfSopenharmony_ci		putc('-', stderr);
177f08c3bdfSopenharmony_ci
178f08c3bdfSopenharmony_ci	fflush(stderr);
179f08c3bdfSopenharmony_ci}
180f08c3bdfSopenharmony_ci
181f08c3bdfSopenharmony_cistatic void usage()
182f08c3bdfSopenharmony_ci{
183f08c3bdfSopenharmony_ci	rt_help();
184f08c3bdfSopenharmony_ci	printf("Usage:\n"
185f08c3bdfSopenharmony_ci	       "-a priority Priority of the threads"
186f08c3bdfSopenharmony_ci	       "-r time     Run time (ms) to busy loop the threads (20)\n"
187f08c3bdfSopenharmony_ci	       "-t time     Sleep time (ms) between intervals (100)\n"
188f08c3bdfSopenharmony_ci	       "-e time     Max allowed error (microsecs)\n"
189f08c3bdfSopenharmony_ci	       "-l loops    Number of iterations to run (50)\n");
190f08c3bdfSopenharmony_ci}
191f08c3bdfSopenharmony_ci
192f08c3bdfSopenharmony_ci/*
193f08c3bdfSopenharmony_ciint rt_init(const char *options, int (*parse_arg)(int option, char *value),
194f08c3bdfSopenharmony_ci	    int argc, char *argv[]);
195f08c3bdfSopenharmony_ci */
196f08c3bdfSopenharmony_cistatic int parse_args(int c, char *v)
197f08c3bdfSopenharmony_ci{
198f08c3bdfSopenharmony_ci	int handled = 1;
199f08c3bdfSopenharmony_ci	switch (c) {
200f08c3bdfSopenharmony_ci	case 'a':
201f08c3bdfSopenharmony_ci		prio_start = atoi(v);
202f08c3bdfSopenharmony_ci		break;
203f08c3bdfSopenharmony_ci	case 'r':
204f08c3bdfSopenharmony_ci		run_interval = atoi(v);
205f08c3bdfSopenharmony_ci		break;
206f08c3bdfSopenharmony_ci	case 't':
207f08c3bdfSopenharmony_ci		interval = atoi(v);
208f08c3bdfSopenharmony_ci		break;
209f08c3bdfSopenharmony_ci	case 'l':
210f08c3bdfSopenharmony_ci		nr_runs = atoi(v);
211f08c3bdfSopenharmony_ci		break;
212f08c3bdfSopenharmony_ci	case 'e':
213f08c3bdfSopenharmony_ci		max_err = atoi(v) * NS_PER_US;
214f08c3bdfSopenharmony_ci		break;
215f08c3bdfSopenharmony_ci	case '?':
216f08c3bdfSopenharmony_ci	case 'h':
217f08c3bdfSopenharmony_ci		usage();
218f08c3bdfSopenharmony_ci		handled = 0;
219f08c3bdfSopenharmony_ci	}
220f08c3bdfSopenharmony_ci	return handled;
221f08c3bdfSopenharmony_ci}
222f08c3bdfSopenharmony_ci
223f08c3bdfSopenharmony_cistatic void record_time(int id, unsigned long long time, unsigned long l)
224f08c3bdfSopenharmony_ci{
225f08c3bdfSopenharmony_ci	unsigned long long ltime;
226f08c3bdfSopenharmony_ci	stats_record_t rec;
227f08c3bdfSopenharmony_ci	if (loop >= nr_runs)
228f08c3bdfSopenharmony_ci		return;
229f08c3bdfSopenharmony_ci	time -= now;
230f08c3bdfSopenharmony_ci	ltime = rt_gettime() / NS_PER_US;
231f08c3bdfSopenharmony_ci	ltime -= now;
232f08c3bdfSopenharmony_ci	rec.x = loop;
233f08c3bdfSopenharmony_ci	rec.y = time;
234f08c3bdfSopenharmony_ci	stats_container_append(&intervals[id], rec);
235f08c3bdfSopenharmony_ci	rec.x = loop;
236f08c3bdfSopenharmony_ci	rec.y = ltime;
237f08c3bdfSopenharmony_ci	stats_container_append(&intervals_length[id], rec);
238f08c3bdfSopenharmony_ci	rec.x = loop;
239f08c3bdfSopenharmony_ci	rec.y = l;
240f08c3bdfSopenharmony_ci	stats_container_append(&intervals_loops[id], rec);
241f08c3bdfSopenharmony_ci}
242f08c3bdfSopenharmony_ci
243f08c3bdfSopenharmony_cistatic void print_results(void)
244f08c3bdfSopenharmony_ci{
245f08c3bdfSopenharmony_ci	int i;
246f08c3bdfSopenharmony_ci	int t;
247f08c3bdfSopenharmony_ci	unsigned long long tasks_max[nr_tasks];
248f08c3bdfSopenharmony_ci	unsigned long long tasks_min[nr_tasks];
249f08c3bdfSopenharmony_ci	unsigned long long tasks_avg[nr_tasks];
250f08c3bdfSopenharmony_ci
251f08c3bdfSopenharmony_ci	memset(tasks_max, 0, sizeof(tasks_max[0]) * nr_tasks);
252f08c3bdfSopenharmony_ci	memset(tasks_min, 0xff, sizeof(tasks_min[0]) * nr_tasks);
253f08c3bdfSopenharmony_ci	memset(tasks_avg, 0, sizeof(tasks_avg[0]) * nr_tasks);
254f08c3bdfSopenharmony_ci
255f08c3bdfSopenharmony_ci	printf("Iter: ");
256f08c3bdfSopenharmony_ci	for (t = 0; t < nr_tasks; t++)
257f08c3bdfSopenharmony_ci		printf("%6d  ", t);
258f08c3bdfSopenharmony_ci	printf("\n");
259f08c3bdfSopenharmony_ci
260f08c3bdfSopenharmony_ci	for (t = 0; t < nr_tasks; t++) {
261f08c3bdfSopenharmony_ci		tasks_max[t] = stats_max(&intervals[t]);
262f08c3bdfSopenharmony_ci		tasks_min[t] = stats_min(&intervals[t]);
263f08c3bdfSopenharmony_ci		tasks_avg[t] = stats_avg(&intervals[t]);
264f08c3bdfSopenharmony_ci	}
265f08c3bdfSopenharmony_ci	for (i = 0; i < nr_runs; i++) {
266f08c3bdfSopenharmony_ci		printf("%4d:   ", i);
267f08c3bdfSopenharmony_ci		for (t = 0; t < nr_tasks; t++)
268f08c3bdfSopenharmony_ci			printf("%6ld  ", intervals[t].records[i].y);
269f08c3bdfSopenharmony_ci
270f08c3bdfSopenharmony_ci		printf("\n");
271f08c3bdfSopenharmony_ci		printf(" len:   ");
272f08c3bdfSopenharmony_ci		for (t = 0; t < nr_tasks; t++)
273f08c3bdfSopenharmony_ci			printf("%6ld  ", intervals_length[t].records[i].y);
274f08c3bdfSopenharmony_ci
275f08c3bdfSopenharmony_ci		printf("\n");
276f08c3bdfSopenharmony_ci		printf(" loops: ");
277f08c3bdfSopenharmony_ci		for (t = 0; t < nr_tasks; t++)
278f08c3bdfSopenharmony_ci			printf("%6ld  ", intervals_loops[t].records[i].y);
279f08c3bdfSopenharmony_ci
280f08c3bdfSopenharmony_ci		printf("\n");
281f08c3bdfSopenharmony_ci		printf("\n");
282f08c3bdfSopenharmony_ci	}
283f08c3bdfSopenharmony_ci
284f08c3bdfSopenharmony_ci	printf("Parent pid: %d\n", getpid());
285f08c3bdfSopenharmony_ci
286f08c3bdfSopenharmony_ci	for (t = 0; t < nr_tasks; t++) {
287f08c3bdfSopenharmony_ci		printf(" Task %d (prio %d) (pid %ld):\n", t, t + prio_start,
288f08c3bdfSopenharmony_ci		       thread_pids[t]);
289f08c3bdfSopenharmony_ci		printf("   Max: %lld us\n", tasks_max[t]);
290f08c3bdfSopenharmony_ci		printf("   Min: %lld us\n", tasks_min[t]);
291f08c3bdfSopenharmony_ci		printf("   Tot: %lld us\n", tasks_avg[t] * nr_runs);
292f08c3bdfSopenharmony_ci		printf("   Avg: %lld us\n", tasks_avg[t]);
293f08c3bdfSopenharmony_ci		printf("\n");
294f08c3bdfSopenharmony_ci	}
295f08c3bdfSopenharmony_ci
296f08c3bdfSopenharmony_ci	printf(" Result: %s\n", (check < 0) ? "FAIL" : "PASS");
297f08c3bdfSopenharmony_ci}
298f08c3bdfSopenharmony_ci
299f08c3bdfSopenharmony_cistatic unsigned long busy_loop(unsigned long long start_time)
300f08c3bdfSopenharmony_ci{
301f08c3bdfSopenharmony_ci	unsigned long long time;
302f08c3bdfSopenharmony_ci	unsigned long l = 0;
303f08c3bdfSopenharmony_ci
304f08c3bdfSopenharmony_ci	do {
305f08c3bdfSopenharmony_ci		l++;
306f08c3bdfSopenharmony_ci		time = rt_gettime();
307f08c3bdfSopenharmony_ci	} while ((time - start_time) < RUN_INTERVAL);
308f08c3bdfSopenharmony_ci
309f08c3bdfSopenharmony_ci	return l;
310f08c3bdfSopenharmony_ci}
311f08c3bdfSopenharmony_ci
312f08c3bdfSopenharmony_civoid *start_task(void *data)
313f08c3bdfSopenharmony_ci{
314f08c3bdfSopenharmony_ci	struct thread *thr = (struct thread *)data;
315f08c3bdfSopenharmony_ci	long id = (long)thr->arg;
316f08c3bdfSopenharmony_ci	thread_pids[id] = gettid();
317f08c3bdfSopenharmony_ci	unsigned long long start_time;
318f08c3bdfSopenharmony_ci	int ret;
319f08c3bdfSopenharmony_ci	int high = 0;
320f08c3bdfSopenharmony_ci	cpu_set_t cpumask;
321f08c3bdfSopenharmony_ci	cpu_set_t save_cpumask;
322f08c3bdfSopenharmony_ci	int cpu = 0;
323f08c3bdfSopenharmony_ci	unsigned long l;
324f08c3bdfSopenharmony_ci	long pid;
325f08c3bdfSopenharmony_ci
326f08c3bdfSopenharmony_ci	ret = sched_getaffinity(0, sizeof(save_cpumask), &save_cpumask);
327f08c3bdfSopenharmony_ci	if (ret < 0)
328f08c3bdfSopenharmony_ci		debug(DBG_ERR, "sched_getaffinity failed: %s\n", strerror(ret));
329f08c3bdfSopenharmony_ci
330f08c3bdfSopenharmony_ci	pid = gettid();
331f08c3bdfSopenharmony_ci
332f08c3bdfSopenharmony_ci	/* Check if we are the highest prio task */
333f08c3bdfSopenharmony_ci	if (id == nr_tasks - 1)
334f08c3bdfSopenharmony_ci		high = 1;
335f08c3bdfSopenharmony_ci
336f08c3bdfSopenharmony_ci	while (!done) {
337f08c3bdfSopenharmony_ci		if (high) {
338f08c3bdfSopenharmony_ci			/* rotate around the CPUS */
339f08c3bdfSopenharmony_ci			if (!CPU_ISSET(cpu, &save_cpumask))
340f08c3bdfSopenharmony_ci				cpu = 0;
341f08c3bdfSopenharmony_ci			CPU_ZERO(&cpumask);
342f08c3bdfSopenharmony_ci			CPU_SET(cpu, &cpumask);
343f08c3bdfSopenharmony_ci			cpu++;
344f08c3bdfSopenharmony_ci			sched_setaffinity(0, sizeof(cpumask), &cpumask);
345f08c3bdfSopenharmony_ci		}
346f08c3bdfSopenharmony_ci		pthread_barrier_wait(&start_barrier);
347f08c3bdfSopenharmony_ci		start_time = rt_gettime();
348f08c3bdfSopenharmony_ci		ftrace_write("Thread %d: started %lld diff %lld\n",
349f08c3bdfSopenharmony_ci			     pid, start_time, start_time - now);
350f08c3bdfSopenharmony_ci		l = busy_loop(start_time);
351f08c3bdfSopenharmony_ci		record_time(id, start_time / NS_PER_US, l);
352f08c3bdfSopenharmony_ci		pthread_barrier_wait(&end_barrier);
353f08c3bdfSopenharmony_ci	}
354f08c3bdfSopenharmony_ci
355f08c3bdfSopenharmony_ci	return (void *)pid;
356f08c3bdfSopenharmony_ci}
357f08c3bdfSopenharmony_ci
358f08c3bdfSopenharmony_cistatic int check_times(int l)
359f08c3bdfSopenharmony_ci{
360f08c3bdfSopenharmony_ci	int i;
361f08c3bdfSopenharmony_ci	unsigned long long last;
362f08c3bdfSopenharmony_ci	unsigned long long last_loops;
363f08c3bdfSopenharmony_ci	unsigned long long last_length;
364f08c3bdfSopenharmony_ci
365f08c3bdfSopenharmony_ci	for (i = 0; i < nr_tasks; i++) {
366f08c3bdfSopenharmony_ci		if (i && last < intervals[i].records[l].y &&
367f08c3bdfSopenharmony_ci		    ((intervals[i].records[l].y - last) > max_err)) {
368f08c3bdfSopenharmony_ci			/*
369f08c3bdfSopenharmony_ci			 * May be a false positive.
370f08c3bdfSopenharmony_ci			 * Make sure that we did more loops
371f08c3bdfSopenharmony_ci			 * our start is before the end
372f08c3bdfSopenharmony_ci			 * and the end should be tested.
373f08c3bdfSopenharmony_ci			 */
374f08c3bdfSopenharmony_ci			if (intervals_loops[i].records[l].y < last_loops ||
375f08c3bdfSopenharmony_ci			    intervals[i].records[l].y > last_length ||
376f08c3bdfSopenharmony_ci			    (intervals_length[i].records[l].y > last_length &&
377f08c3bdfSopenharmony_ci			     intervals_length[i].records[l].y - last_length >
378f08c3bdfSopenharmony_ci			     max_err)) {
379f08c3bdfSopenharmony_ci				check = -1;
380f08c3bdfSopenharmony_ci				return 1;
381f08c3bdfSopenharmony_ci			}
382f08c3bdfSopenharmony_ci		}
383f08c3bdfSopenharmony_ci		last = intervals[i].records[l].y;
384f08c3bdfSopenharmony_ci		last_loops = intervals_loops[i].records[l].y;
385f08c3bdfSopenharmony_ci		last_length = intervals_length[i].records[l].y;
386f08c3bdfSopenharmony_ci	}
387f08c3bdfSopenharmony_ci	return 0;
388f08c3bdfSopenharmony_ci}
389f08c3bdfSopenharmony_ci
390f08c3bdfSopenharmony_cistatic void stop_log(int sig)
391f08c3bdfSopenharmony_ci{
392f08c3bdfSopenharmony_ci	stop = 1;
393f08c3bdfSopenharmony_ci}
394f08c3bdfSopenharmony_ci
395f08c3bdfSopenharmony_ciint main(int argc, char **argv)
396f08c3bdfSopenharmony_ci{
397f08c3bdfSopenharmony_ci	int *threads;
398f08c3bdfSopenharmony_ci	long i;
399f08c3bdfSopenharmony_ci	int ret;
400f08c3bdfSopenharmony_ci	struct timespec intv;
401f08c3bdfSopenharmony_ci	struct sched_param param;
402f08c3bdfSopenharmony_ci
403f08c3bdfSopenharmony_ci	rt_init("a:r:t:e:l:h:", parse_args, argc, argv);
404f08c3bdfSopenharmony_ci	signal(SIGINT, stop_log);
405f08c3bdfSopenharmony_ci
406f08c3bdfSopenharmony_ci	if (argc >= (optind + 1))
407f08c3bdfSopenharmony_ci		nr_tasks = atoi(argv[optind]);
408f08c3bdfSopenharmony_ci	else {
409f08c3bdfSopenharmony_ci		numcpus = sysconf(_SC_NPROCESSORS_ONLN);
410f08c3bdfSopenharmony_ci		nr_tasks = numcpus + 1;
411f08c3bdfSopenharmony_ci	}
412f08c3bdfSopenharmony_ci
413f08c3bdfSopenharmony_ci	intervals = malloc(sizeof(stats_container_t) * nr_tasks);
414f08c3bdfSopenharmony_ci	if (!intervals)
415f08c3bdfSopenharmony_ci		debug(DBG_ERR, "malloc failed\n");
416f08c3bdfSopenharmony_ci	memset(intervals, 0, sizeof(stats_container_t) * nr_tasks);
417f08c3bdfSopenharmony_ci
418f08c3bdfSopenharmony_ci	intervals_length = malloc(sizeof(stats_container_t) * nr_tasks);
419f08c3bdfSopenharmony_ci	if (!intervals_length)
420f08c3bdfSopenharmony_ci		debug(DBG_ERR, "malloc failed\n");
421f08c3bdfSopenharmony_ci	memset(intervals_length, 0, sizeof(stats_container_t) * nr_tasks);
422f08c3bdfSopenharmony_ci
423f08c3bdfSopenharmony_ci	if (!intervals_loops)
424f08c3bdfSopenharmony_ci		debug(DBG_ERR, "malloc failed\n");
425f08c3bdfSopenharmony_ci	intervals_loops = malloc(sizeof(stats_container_t) * nr_tasks);
426f08c3bdfSopenharmony_ci	memset(intervals_loops, 0, sizeof(stats_container_t) * nr_tasks);
427f08c3bdfSopenharmony_ci
428f08c3bdfSopenharmony_ci	threads = malloc(sizeof(*threads) * nr_tasks);
429f08c3bdfSopenharmony_ci	if (!threads)
430f08c3bdfSopenharmony_ci		debug(DBG_ERR, "malloc failed\n");
431f08c3bdfSopenharmony_ci	memset(threads, 0, sizeof(*threads) * nr_tasks);
432f08c3bdfSopenharmony_ci
433f08c3bdfSopenharmony_ci	ret = pthread_barrier_init(&start_barrier, NULL, nr_tasks + 1);
434f08c3bdfSopenharmony_ci	ret = pthread_barrier_init(&end_barrier, NULL, nr_tasks + 1);
435f08c3bdfSopenharmony_ci	if (ret < 0)
436f08c3bdfSopenharmony_ci		debug(DBG_ERR, "pthread_barrier_init failed: %s\n",
437f08c3bdfSopenharmony_ci		      strerror(ret));
438f08c3bdfSopenharmony_ci
439f08c3bdfSopenharmony_ci	for (i = 0; i < nr_tasks; i++) {
440f08c3bdfSopenharmony_ci		stats_container_init(&intervals[i], nr_runs);
441f08c3bdfSopenharmony_ci		stats_container_init(&intervals_length[i], nr_runs);
442f08c3bdfSopenharmony_ci		stats_container_init(&intervals_loops[i], nr_runs);
443f08c3bdfSopenharmony_ci	}
444f08c3bdfSopenharmony_ci
445f08c3bdfSopenharmony_ci	thread_pids = malloc(sizeof(long) * nr_tasks);
446f08c3bdfSopenharmony_ci	if (!thread_pids)
447f08c3bdfSopenharmony_ci		debug(DBG_ERR, "malloc thread_pids failed\n");
448f08c3bdfSopenharmony_ci
449f08c3bdfSopenharmony_ci	for (i = 0; i < nr_tasks; i++) {
450f08c3bdfSopenharmony_ci		threads[i] = create_fifo_thread(start_task, (void *)i,
451f08c3bdfSopenharmony_ci						prio_start + i);
452f08c3bdfSopenharmony_ci	}
453f08c3bdfSopenharmony_ci
454f08c3bdfSopenharmony_ci	/*
455f08c3bdfSopenharmony_ci	 * Progress bar uses stderr to let users see it when
456f08c3bdfSopenharmony_ci	 * redirecting output. So we convert stderr to use line
457f08c3bdfSopenharmony_ci	 * buffering so the progress bar doesn't flicker.
458f08c3bdfSopenharmony_ci	 */
459f08c3bdfSopenharmony_ci	setlinebuf(stderr);
460f08c3bdfSopenharmony_ci
461f08c3bdfSopenharmony_ci	/* up our prio above all tasks */
462f08c3bdfSopenharmony_ci	memset(&param, 0, sizeof(param));
463f08c3bdfSopenharmony_ci	param.sched_priority = nr_tasks + prio_start;
464f08c3bdfSopenharmony_ci	if (sched_setscheduler(0, SCHED_FIFO, &param))
465f08c3bdfSopenharmony_ci		debug(DBG_WARN, "Warning, can't set priority of main thread!\n");
466f08c3bdfSopenharmony_ci	intv.tv_sec = INTERVAL / NS_PER_SEC;
467f08c3bdfSopenharmony_ci	intv.tv_nsec = INTERVAL % (1 * NS_PER_SEC);
468f08c3bdfSopenharmony_ci
469f08c3bdfSopenharmony_ci	print_progress_bar(0);
470f08c3bdfSopenharmony_ci
471f08c3bdfSopenharmony_ci	setup_ftrace_marker();
472f08c3bdfSopenharmony_ci
473f08c3bdfSopenharmony_ci	for (loop = 0; loop < nr_runs; loop++) {
474f08c3bdfSopenharmony_ci		unsigned long long end;
475f08c3bdfSopenharmony_ci
476f08c3bdfSopenharmony_ci		now = rt_gettime() / NS_PER_US;
477f08c3bdfSopenharmony_ci
478f08c3bdfSopenharmony_ci		ftrace_write("Loop %d now=%lld\n", loop, now);
479f08c3bdfSopenharmony_ci
480f08c3bdfSopenharmony_ci		pthread_barrier_wait(&start_barrier);
481f08c3bdfSopenharmony_ci
482f08c3bdfSopenharmony_ci		ftrace_write("All running!!!\n");
483f08c3bdfSopenharmony_ci
484f08c3bdfSopenharmony_ci		rt_nanosleep(intv.tv_nsec);
485f08c3bdfSopenharmony_ci		print_progress_bar((loop * 100) / nr_runs);
486f08c3bdfSopenharmony_ci
487f08c3bdfSopenharmony_ci		end = rt_gettime() / NS_PER_US;
488f08c3bdfSopenharmony_ci		ftrace_write("Loop %d end now=%lld diff=%lld\n",
489f08c3bdfSopenharmony_ci			     loop, end, end - now);
490f08c3bdfSopenharmony_ci		ret = pthread_barrier_wait(&end_barrier);
491f08c3bdfSopenharmony_ci
492f08c3bdfSopenharmony_ci		if (stop || (check && check_times(loop))) {
493f08c3bdfSopenharmony_ci			loop++;
494f08c3bdfSopenharmony_ci			nr_runs = loop;
495f08c3bdfSopenharmony_ci			break;
496f08c3bdfSopenharmony_ci		}
497f08c3bdfSopenharmony_ci	}
498f08c3bdfSopenharmony_ci	putc('\n', stderr);
499f08c3bdfSopenharmony_ci
500f08c3bdfSopenharmony_ci	pthread_barrier_wait(&start_barrier);
501f08c3bdfSopenharmony_ci	done = 1;
502f08c3bdfSopenharmony_ci	pthread_barrier_wait(&end_barrier);
503f08c3bdfSopenharmony_ci
504f08c3bdfSopenharmony_ci	join_threads();
505f08c3bdfSopenharmony_ci	print_results();
506f08c3bdfSopenharmony_ci
507f08c3bdfSopenharmony_ci	if (stop) {
508f08c3bdfSopenharmony_ci		/*
509f08c3bdfSopenharmony_ci		 * We use this test in bash while loops
510f08c3bdfSopenharmony_ci		 * So if we hit Ctrl-C then let the while
511f08c3bdfSopenharmony_ci		 * loop know to break.
512f08c3bdfSopenharmony_ci		 */
513f08c3bdfSopenharmony_ci		if (check < 0)
514f08c3bdfSopenharmony_ci			exit(-1);
515f08c3bdfSopenharmony_ci		else
516f08c3bdfSopenharmony_ci			exit(1);
517f08c3bdfSopenharmony_ci	}
518f08c3bdfSopenharmony_ci
519f08c3bdfSopenharmony_ci	if (check < 0)
520f08c3bdfSopenharmony_ci		exit(-1);
521f08c3bdfSopenharmony_ci	else
522f08c3bdfSopenharmony_ci		exit(0);
523f08c3bdfSopenharmony_ci}
524