| /****************************************************************************** |
| * |
| * Copyright © International Business Machines Corp., 2007, 2008 |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| * the GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| * NAME |
| * tc-2.c |
| * |
| * DESCRIPTION |
| * Check if clock_gettime is working properly. |
| * This test creates NUMSLEEP threads that just sleep and NUMWORK threads |
| * that spend time on the CPU. It then reads the thread cpu clocks of all |
| * these threads and compares the sum of thread cpu clocks with the process |
| * cpu clock value. The test expects that: |
| * the cpu clock of every sleeping thread shows close to zero value. |
| * sum of cpu clocks of all threads is comparable with the process cpu clock. |
| * |
| * |
| * USAGE: |
| * Use run_auto.sh script in current directory to build and run test. |
| * |
| * AUTHOR |
| * Sripathi Kodi <sripathik@in.ibm.com> |
| * |
| * HISTORY |
| * 2007-Apr-04: Initial version by Sripathi Kodi <sripathik@in.ibm.com> |
| * |
| *****************************************************************************/ |
| |
| #include <stdio.h> |
| #include <pthread.h> |
| #include <time.h> |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <librttest.h> |
| |
| #define NS_PER_SEC 1000000000 |
| #define THRESHOLD 0.5 /* 500 milliseconds */ |
| #define NUMSLEEP 5 |
| #define NUMWORK 2 |
| |
| struct timespec sleepts[NUMSLEEP]; |
| struct timespec workts[NUMWORK]; |
| |
| void usage(void) |
| { |
| rt_help(); |
| printf("thread_clock specific options:\n"); |
| } |
| |
| int parse_args(int c, char *v) |
| { |
| int handled = 1; |
| switch (c) { |
| case 'h': |
| usage(); |
| exit(0); |
| default: |
| handled = 0; |
| break; |
| } |
| return handled; |
| } |
| |
| /* Just spend some time on the CPU */ |
| void work(void) |
| { |
| unsigned int i=0; |
| for (i=0; i<2147483600; i++) { |
| if ((i == i+1) || (i == i-1)) |
| printf("Hey!\n"); |
| } |
| } |
| |
| void *workerthread(void *arg) |
| { |
| struct thread* pthr = (struct thread* )arg; |
| int tid =(int)(long)pthr->arg; |
| struct timespec *ts = &workts[tid]; |
| |
| #ifdef DEBUG |
| printf("Worker thread %d working\n", tid); |
| #endif |
| work(); |
| |
| if ((clock_gettime (CLOCK_THREAD_CPUTIME_ID, ts)) < 0) { |
| perror("clock_gettime: CLOCK_THREAD_CPUTIME_ID: "); |
| exit(1); |
| } |
| |
| #ifdef DEBUG |
| printf("workerthread %d: AFTER WORK: tv_sec = %ld, tv_nsec = %ld\n", tid, ts->tv_sec, ts->tv_nsec); |
| #endif |
| return NULL; |
| } |
| |
| void *sleeperthread(void *arg) |
| { |
| struct thread* pthr = (struct thread* )arg; |
| int tid = (int)(long)pthr->arg; |
| struct timespec *ts = &sleepts[tid]; |
| |
| #ifdef DEBUG |
| printf("Sleeper thread %d sleeping\n", tid); |
| #endif |
| |
| sleep(5); |
| |
| if ((clock_gettime (CLOCK_THREAD_CPUTIME_ID, ts)) < 0) { |
| perror("clock_gettime: CLOCK_THREAD_CPUTIME_ID: "); |
| exit(1); |
| } |
| |
| #ifdef DEBUG |
| printf("sleeperthread %d: AFTER SLEEP: tv_sec = %ld, tv_nsec = %ld\n", tid, ts->tv_sec, ts->tv_nsec); |
| #endif |
| return NULL; |
| } |
| |
| int checkresult(float proctime) |
| { |
| int i, retval = 0; |
| float diff, threadstime=0; |
| for (i=0; i<NUMSLEEP; i++) { |
| /* Sleeping thread should not accumulate more than 1 second of CPU time */ |
| if (sleepts[i].tv_sec > 0) { |
| printf("Sleeper thread %d time is %f, should have been close to zero. FAIL\n", |
| i, sleepts[i].tv_sec + ((float)sleepts[i].tv_nsec/NS_PER_SEC)); |
| retval = 1; |
| } |
| threadstime += sleepts[i].tv_sec + ((float)sleepts[i].tv_nsec/NS_PER_SEC); |
| } |
| if (retval) |
| return retval; |
| |
| for (i=0; i<NUMWORK; i++) { |
| threadstime += workts[i].tv_sec + ((float)workts[i].tv_nsec/NS_PER_SEC); |
| } |
| diff = proctime - threadstime; |
| if (diff < 0) diff = -diff; |
| printf("Process: %.4f s\n", proctime); |
| printf("Threads: %.4f s\n", threadstime); |
| printf("Delta: %.4f s\n", diff); |
| /* Difference between the sum of thread times and process time |
| * should not be more than pass_criteria */ |
| printf("\nCriteria: Delta < %.4f s\n", pass_criteria); |
| printf("Result: "); |
| if (diff > pass_criteria) { |
| printf("FAIL\n"); |
| retval = 1; |
| } |
| else { |
| printf("PASS\n"); |
| } |
| return retval; |
| } |
| |
| int main(int argc,char* argv[]) |
| { |
| int i, retval = 0; |
| struct timespec myts; |
| setup(); |
| |
| pass_criteria = THRESHOLD; |
| rt_init("ht:",parse_args,argc,argv); |
| |
| /* Start sleeper threads */ |
| for (i=0; i<NUMSLEEP; i++) { |
| if ((create_other_thread (sleeperthread, (void *)(intptr_t)i)) < 0) { |
| exit(1); |
| } |
| } |
| printf("\n%d sleeper threads created\n", NUMSLEEP); |
| |
| /* Start worker threads */ |
| for (i=0; i<NUMWORK; i++) { |
| if ((create_other_thread (workerthread, (void *)(intptr_t)i)) < 0) { |
| exit(1); |
| } |
| } |
| printf("\n%d worker threads created\n", NUMWORK); |
| |
| printf("\nPlease wait...\n\n"); |
| |
| join_threads(); |
| /* Get the process cpu clock value */ |
| if ((clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &myts)) < 0) { |
| perror("clock_gettime: CLOCK_PROCESS_CPUTIME_ID: "); |
| exit(1); |
| } |
| retval = checkresult(myts.tv_sec + ((float)myts.tv_nsec/NS_PER_SEC)); |
| return retval; |
| } |