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 (at) in.ibm.com> 37 * 38 * HISTORY 39 * 2007-Apr-04: Initial version by Sripathi Kodi <sripathik (at) 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 56 struct timespec sleepts[NUMSLEEP]; 57 struct timespec workts[NUMWORK]; 58 59 void usage(void) 60 { 61 rt_help(); 62 printf("thread_clock specific options:\n"); 63 } 64 65 int 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 */ 80 void 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 89 void *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 111 void *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 134 int 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 178 int 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