18c2ecf20Sopenharmony_ci/* threadtest.c 28c2ecf20Sopenharmony_ci * by: john stultz (johnstul@us.ibm.com) 38c2ecf20Sopenharmony_ci * (C) Copyright IBM 2004, 2005, 2006, 2012 48c2ecf20Sopenharmony_ci * Licensed under the GPLv2 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * To build: 78c2ecf20Sopenharmony_ci * $ gcc threadtest.c -o threadtest -lrt 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This program is free software: you can redistribute it and/or modify 108c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 118c2ecf20Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or 128c2ecf20Sopenharmony_ci * (at your option) any later version. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, 158c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 168c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 178c2ecf20Sopenharmony_ci * GNU General Public License for more details. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci#include <stdio.h> 208c2ecf20Sopenharmony_ci#include <unistd.h> 218c2ecf20Sopenharmony_ci#include <stdlib.h> 228c2ecf20Sopenharmony_ci#include <sys/time.h> 238c2ecf20Sopenharmony_ci#include <pthread.h> 248c2ecf20Sopenharmony_ci#include "../kselftest.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* serializes shared list access */ 278c2ecf20Sopenharmony_cipthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER; 288c2ecf20Sopenharmony_ci/* serializes console output */ 298c2ecf20Sopenharmony_cipthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define MAX_THREADS 128 338c2ecf20Sopenharmony_ci#define LISTSIZE 128 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ciint done = 0; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistruct timespec global_list[LISTSIZE]; 388c2ecf20Sopenharmony_ciint listcount = 0; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_civoid checklist(struct timespec *list, int size) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci int i, j; 448c2ecf20Sopenharmony_ci struct timespec *a, *b; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* scan the list */ 478c2ecf20Sopenharmony_ci for (i = 0; i < size-1; i++) { 488c2ecf20Sopenharmony_ci a = &list[i]; 498c2ecf20Sopenharmony_ci b = &list[i+1]; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* look for any time inconsistencies */ 528c2ecf20Sopenharmony_ci if ((b->tv_sec <= a->tv_sec) && 538c2ecf20Sopenharmony_ci (b->tv_nsec < a->tv_nsec)) { 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* flag other threads */ 568c2ecf20Sopenharmony_ci done = 1; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci /*serialize printing to avoid junky output*/ 598c2ecf20Sopenharmony_ci pthread_mutex_lock(&print_lock); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* dump the list */ 628c2ecf20Sopenharmony_ci printf("\n"); 638c2ecf20Sopenharmony_ci for (j = 0; j < size; j++) { 648c2ecf20Sopenharmony_ci if (j == i) 658c2ecf20Sopenharmony_ci printf("---------------\n"); 668c2ecf20Sopenharmony_ci printf("%lu:%lu\n", list[j].tv_sec, list[j].tv_nsec); 678c2ecf20Sopenharmony_ci if (j == i+1) 688c2ecf20Sopenharmony_ci printf("---------------\n"); 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci printf("[FAILED]\n"); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci pthread_mutex_unlock(&print_lock); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* The shared thread shares a global list 788c2ecf20Sopenharmony_ci * that each thread fills while holding the lock. 798c2ecf20Sopenharmony_ci * This stresses clock syncronization across cpus. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_civoid *shared_thread(void *arg) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci while (!done) { 848c2ecf20Sopenharmony_ci /* protect the list */ 858c2ecf20Sopenharmony_ci pthread_mutex_lock(&list_lock); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* see if we're ready to check the list */ 888c2ecf20Sopenharmony_ci if (listcount >= LISTSIZE) { 898c2ecf20Sopenharmony_ci checklist(global_list, LISTSIZE); 908c2ecf20Sopenharmony_ci listcount = 0; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &global_list[listcount++]); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci pthread_mutex_unlock(&list_lock); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci return NULL; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* Each independent thread fills in its own 1018c2ecf20Sopenharmony_ci * list. This stresses clock_gettime() lock contention. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_civoid *independent_thread(void *arg) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct timespec my_list[LISTSIZE]; 1068c2ecf20Sopenharmony_ci int count; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci while (!done) { 1098c2ecf20Sopenharmony_ci /* fill the list */ 1108c2ecf20Sopenharmony_ci for (count = 0; count < LISTSIZE; count++) 1118c2ecf20Sopenharmony_ci clock_gettime(CLOCK_MONOTONIC, &my_list[count]); 1128c2ecf20Sopenharmony_ci checklist(my_list, LISTSIZE); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci return NULL; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#define DEFAULT_THREAD_COUNT 8 1188c2ecf20Sopenharmony_ci#define DEFAULT_RUNTIME 30 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ciint main(int argc, char **argv) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci int thread_count, i; 1238c2ecf20Sopenharmony_ci time_t start, now, runtime; 1248c2ecf20Sopenharmony_ci char buf[255]; 1258c2ecf20Sopenharmony_ci pthread_t pth[MAX_THREADS]; 1268c2ecf20Sopenharmony_ci int opt; 1278c2ecf20Sopenharmony_ci void *tret; 1288c2ecf20Sopenharmony_ci int ret = 0; 1298c2ecf20Sopenharmony_ci void *(*thread)(void *) = shared_thread; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci thread_count = DEFAULT_THREAD_COUNT; 1328c2ecf20Sopenharmony_ci runtime = DEFAULT_RUNTIME; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* Process arguments */ 1358c2ecf20Sopenharmony_ci while ((opt = getopt(argc, argv, "t:n:i")) != -1) { 1368c2ecf20Sopenharmony_ci switch (opt) { 1378c2ecf20Sopenharmony_ci case 't': 1388c2ecf20Sopenharmony_ci runtime = atoi(optarg); 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci case 'n': 1418c2ecf20Sopenharmony_ci thread_count = atoi(optarg); 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci case 'i': 1448c2ecf20Sopenharmony_ci thread = independent_thread; 1458c2ecf20Sopenharmony_ci printf("using independent threads\n"); 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci default: 1488c2ecf20Sopenharmony_ci printf("Usage: %s [-t <secs>] [-n <numthreads>] [-i]\n", argv[0]); 1498c2ecf20Sopenharmony_ci printf(" -t: time to run\n"); 1508c2ecf20Sopenharmony_ci printf(" -n: number of threads\n"); 1518c2ecf20Sopenharmony_ci printf(" -i: use independent threads\n"); 1528c2ecf20Sopenharmony_ci return -1; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (thread_count > MAX_THREADS) 1578c2ecf20Sopenharmony_ci thread_count = MAX_THREADS; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci setbuf(stdout, NULL); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci start = time(0); 1638c2ecf20Sopenharmony_ci strftime(buf, 255, "%a, %d %b %Y %T %z", localtime(&start)); 1648c2ecf20Sopenharmony_ci printf("%s\n", buf); 1658c2ecf20Sopenharmony_ci printf("Testing consistency with %i threads for %ld seconds: ", thread_count, runtime); 1668c2ecf20Sopenharmony_ci fflush(stdout); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* spawn */ 1698c2ecf20Sopenharmony_ci for (i = 0; i < thread_count; i++) 1708c2ecf20Sopenharmony_ci pthread_create(&pth[i], 0, thread, 0); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci while (time(&now) < start + runtime) { 1738c2ecf20Sopenharmony_ci sleep(1); 1748c2ecf20Sopenharmony_ci if (done) { 1758c2ecf20Sopenharmony_ci ret = 1; 1768c2ecf20Sopenharmony_ci strftime(buf, 255, "%a, %d %b %Y %T %z", localtime(&now)); 1778c2ecf20Sopenharmony_ci printf("%s\n", buf); 1788c2ecf20Sopenharmony_ci goto out; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci printf("[OK]\n"); 1828c2ecf20Sopenharmony_ci done = 1; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ciout: 1858c2ecf20Sopenharmony_ci /* wait */ 1868c2ecf20Sopenharmony_ci for (i = 0; i < thread_count; i++) 1878c2ecf20Sopenharmony_ci pthread_join(pth[i], &tret); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* die */ 1908c2ecf20Sopenharmony_ci if (ret) 1918c2ecf20Sopenharmony_ci ksft_exit_fail(); 1928c2ecf20Sopenharmony_ci return ksft_exit_pass(); 1938c2ecf20Sopenharmony_ci} 194