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