1/****************************************************************************** 2 * 3 * Copyright © International Business Machines Corp., 2007, 2008 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 * 19 * NAME 20 * tc-2.c 21 * 22 * DESCRIPTION 23 * Check if clock_gettime is working properly. 24 * This test creates NUMSLEEP threads that just sleep and NUMWORK threads 25 * that spend time on the CPU. It then reads the thread cpu clocks of all 26 * these threads and compares the sum of thread cpu clocks with the process 27 * cpu clock value. The test expects that: 28 * the cpu clock of every sleeping thread shows close to zero value. 29 * sum of cpu clocks of all threads is comparable with the process cpu clock. 30 * 31 * 32 * USAGE: 33 * Use run_auto.sh script in current directory to build and run test. 34 * 35 * AUTHOR 36 * Sripathi Kodi <sripathik@in.ibm.com> 37 * 38 * HISTORY 39 * 2007-Apr-04: Initial version by Sripathi Kodi <sripathik@in.ibm.com> 40 * 41 *****************************************************************************/ 42 43#include <stdio.h> 44#include <pthread.h> 45#include <time.h> 46#include <errno.h> 47#include <stdlib.h> 48#include <unistd.h> 49#include <librttest.h> 50 51#define NS_PER_SEC 1000000000 52#define THRESHOLD 0.5 /* 500 milliseconds */ 53#define NUMSLEEP 5 54#define NUMWORK 2 55 56struct timespec sleepts[NUMSLEEP]; 57struct timespec workts[NUMWORK]; 58 59void usage(void) 60{ 61 rt_help(); 62 printf("thread_clock specific options:\n"); 63} 64 65int parse_args(int c, char *v) 66{ 67 int handled = 1; 68 switch (c) { 69 case 'h': 70 usage(); 71 exit(0); 72 default: 73 handled = 0; 74 break; 75 } 76 return handled; 77} 78 79/* Just spend some time on the CPU */ 80void work(void) 81{ 82 unsigned int i = 0; 83 for (i = 0; i < 2147483600; i++) { 84 if ((i == i + 1) || (i == i - 1)) 85 printf("Hey!\n"); 86 } 87} 88 89void *workerthread(void *arg) 90{ 91 struct thread *pthr = (struct thread *)arg; 92 int tid = (int)(long)pthr->arg; 93 struct timespec *ts = &workts[tid]; 94 95#ifdef DEBUG 96 printf("Worker thread %d working\n", tid); 97#endif 98 work(); 99 100 if ((clock_gettime(CLOCK_THREAD_CPUTIME_ID, ts)) < 0) { 101 perror("clock_gettime: CLOCK_THREAD_CPUTIME_ID: "); 102 exit(1); 103 } 104#ifdef DEBUG 105 printf("workerthread %d: AFTER WORK: tv_sec = %ld, tv_nsec = %ld\n", 106 tid, ts->tv_sec, ts->tv_nsec); 107#endif 108 return NULL; 109} 110 111void *sleeperthread(void *arg) 112{ 113 struct thread *pthr = (struct thread *)arg; 114 int tid = (int)(long)pthr->arg; 115 struct timespec *ts = &sleepts[tid]; 116 117#ifdef DEBUG 118 printf("Sleeper thread %d sleeping\n", tid); 119#endif 120 121 sleep(5); 122 123 if ((clock_gettime(CLOCK_THREAD_CPUTIME_ID, ts)) < 0) { 124 perror("clock_gettime: CLOCK_THREAD_CPUTIME_ID: "); 125 exit(1); 126 } 127#ifdef DEBUG 128 printf("sleeperthread %d: AFTER SLEEP: tv_sec = %ld, tv_nsec = %ld\n", 129 tid, ts->tv_sec, ts->tv_nsec); 130#endif 131 return NULL; 132} 133 134int checkresult(float proctime) 135{ 136 int i, retval = 0; 137 float diff, threadstime = 0; 138 for (i = 0; i < NUMSLEEP; i++) { 139 /* Sleeping thread should not accumulate more than 1 second of CPU time */ 140 if (sleepts[i].tv_sec > 0) { 141 printf 142 ("Sleeper thread %d time is %f, should have been close to zero. FAIL\n", 143 i, 144 sleepts[i].tv_sec + 145 ((float)sleepts[i].tv_nsec / NS_PER_SEC)); 146 retval = 1; 147 } 148 threadstime += 149 sleepts[i].tv_sec + 150 ((float)sleepts[i].tv_nsec / NS_PER_SEC); 151 } 152 if (retval) 153 return retval; 154 155 for (i = 0; i < NUMWORK; i++) { 156 threadstime += 157 workts[i].tv_sec + ((float)workts[i].tv_nsec / NS_PER_SEC); 158 } 159 diff = proctime - threadstime; 160 if (diff < 0) 161 diff = -diff; 162 printf("Process: %.4f s\n", proctime); 163 printf("Threads: %.4f s\n", threadstime); 164 printf("Delta: %.4f s\n", diff); 165 /* Difference between the sum of thread times and process time 166 * should not be more than pass_criteria */ 167 printf("\nCriteria: Delta < %.4f s\n", pass_criteria); 168 printf("Result: "); 169 if (diff > pass_criteria) { 170 printf("FAIL\n"); 171 retval = 1; 172 } else { 173 printf("PASS\n"); 174 } 175 return retval; 176} 177 178int main(int argc, char *argv[]) 179{ 180 int i, retval = 0; 181 struct timespec myts; 182 setup(); 183 184 pass_criteria = THRESHOLD; 185 rt_init("ht:", parse_args, argc, argv); 186 187 /* Start sleeper threads */ 188 for (i = 0; i < NUMSLEEP; i++) { 189 if ((create_other_thread(sleeperthread, (void *)(intptr_t) i)) < 190 0) { 191 exit(1); 192 } 193 } 194 printf("\n%d sleeper threads created\n", NUMSLEEP); 195 196 /* Start worker threads */ 197 for (i = 0; i < NUMWORK; i++) { 198 if ((create_other_thread(workerthread, (void *)(intptr_t) i)) < 199 0) { 200 exit(1); 201 } 202 } 203 printf("\n%d worker threads created\n", NUMWORK); 204 205 printf("\nPlease wait...\n\n"); 206 207 join_threads(); 208 /* Get the process cpu clock value */ 209 if ((clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &myts)) < 0) { 210 perror("clock_gettime: CLOCK_PROCESS_CPUTIME_ID: "); 211 exit(1); 212 } 213 retval = checkresult(myts.tv_sec + ((float)myts.tv_nsec / NS_PER_SEC)); 214 return retval; 215} 216