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
thrfn(void * arg)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
new_thr(void * (* fn)(void * arg),void * arg)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
main(int argc,char ** argv)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