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
19struct args {
20	unsigned int loops;
21	pthread_t th;
22	void *ret;
23};
24
25static 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
47static 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
57int main(int argc, char **argv)
58{
59	unsigned int i, len, thr;
60	struct args args[256];
61
62	if (argc < 3) {
63		printf("ERR: %s [numthreads] [numloops (millions)]\n", argv[0]);
64		exit(1);
65	}
66
67	thr = atoi(argv[1]);
68	if ((thr < 1) || (thr > 256)) {
69		printf("ERR: threads 1-256\n");
70		exit(1);
71	}
72	len = atoi(argv[2]);
73	if ((len < 1) || (len > 4000)) {
74		printf("ERR: max loops 4000 (millions)\n");
75		exit(1);
76	}
77	len *= 1000000;
78	for (i = 0; i < thr; i++) {
79		args[i].loops = len;
80		args[i].th = new_thr(thrfn, &(args[i]));
81	}
82	for (i = 0; i < thr; i++)
83		pthread_join(args[i].th, &(args[i].ret));
84	return 0;
85}
86