/******************************************************************************
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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;
}