1 // SPDX-License-Identifier: GPL-2.0
2 // Carsten Haitzler <carsten.haitzler@arm.com>, 2021
3 
4 // define this for gettid()
5 #define _GNU_SOURCE
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <pthread.h>
12 #include <sys/syscall.h>
13 #ifndef SYS_gettid
14 // gettid is 178 on arm64
15 # define SYS_gettid 178
16 #endif
17 #define gettid() syscall(SYS_gettid)
18 
19 struct args {
20 	unsigned int loops;
21 	pthread_t th;
22 	void *ret;
23 };
24 
25 static void *thrfn(void *arg)
26 {
27 	struct args *a = arg;
28 	int i = 0, len = a->loops;
29 
30 	if (getenv("SHOW_TID")) {
31 		unsigned long long tid = gettid();
32 
33 		printf("%llu\n", tid);
34 	}
35 	asm volatile(
36 		"loop:\n"
37 		"add %[i], %[i], #1\n"
38 		"cmp %[i], %[len]\n"
39 		"blt loop\n"
40 		: /* out */
41 		: /* in */ [i] "r" (i), [len] "r" (len)
42 		: /* clobber */
43 	);
44 	return (void *)(long)i;
45 }
46 
47 static pthread_t new_thr(void *(*fn) (void *arg), void *arg)
48 {
49 	pthread_t t;
50 	pthread_attr_t attr;
51 
52 	pthread_attr_init(&attr);
53 	pthread_create(&t, &attr, fn, arg);
54 	return t;
55 }
56 
57 int main(int argc, char **argv)
58 {
59 	unsigned int i, len, thr;
60 	pthread_t threads[256];
61 	struct args args[256];
62 
63 	if (argc < 3) {
64 		printf("ERR: %s [numthreads] [numloops (millions)]\n", argv[0]);
65 		exit(1);
66 	}
67 
68 	thr = atoi(argv[1]);
69 	if ((thr < 1) || (thr > 256)) {
70 		printf("ERR: threads 1-256\n");
71 		exit(1);
72 	}
73 	len = atoi(argv[2]);
74 	if ((len < 1) || (len > 4000)) {
75 		printf("ERR: max loops 4000 (millions)\n");
76 		exit(1);
77 	}
78 	len *= 1000000;
79 	for (i = 0; i < thr; i++) {
80 		args[i].loops = len;
81 		args[i].th = new_thr(thrfn, &(args[i]));
82 	}
83 	for (i = 0; i < thr; i++)
84 		pthread_join(args[i].th, &(args[i].ret));
85 	return 0;
86 }
87