Monitoring execution times
QNX OS includes some special CPU-time clocks that you can use to monitor the execution times for processes and threads.
This mechanism is implemented following the POSIX Execution Time Monitoring
option,
which defines special clock IDs that represent the execution time of a thread or a process:
To obtain: | Call: | Specifying: | Classification |
---|---|---|---|
A process CPU-time clock ID | clock_getcpuclockid() | A process ID, or 0 to get the clock ID for the calling process | POSIX |
A thread CPU-time clock ID | pthread_getcpuclockid() | A thread ID in the calling process | POSIX |
Either of the above | ClockId() | A process ID and a thread ID | QNX OS |
A process has permission to get the CPU-time clock ID of any process.
To get the execution time for the process or thread, call clock_gettime() or ClockTime(), passing a process or thread CPU-time clock ID. POSIX also defines the following, which you can use instead of calling clock_getcpuclockid() or pthread_getcpuclockid():
- CLOCK_PROCESS_CPUTIME_ID
- The CPU-time clock ID for the calling process.
- CLOCK_THREAD_CPUTIME_ID
- The CPU-time clock ID for the calling thread.
The OS calculates the execution times on every clock tick and whenever an active thread is preempted.
int process_clock_id, ret;
struct timespec process_time;
ret = clock_getcpuclockid (0, &process_clock_id);
if (ret != 0) {
perror ("clock_getcpuid()");
return (EXIT_FAILURE);
}
printf ("Process clock ID: %d\n", process_clock_id);
ret = clock_gettime (process_clock_id, &process_time);
if (ret != 0) {
perror ("clock_gettime()");
return (EXIT_FAILURE);
}
printf ("Process clock: %ld sec, %ld nsec\n", process_time.tv_sec,
process_time.tv_nsec);
int process_clock_id, ret;
struct timespec process_time;
ret = clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &process_time);
if (ret != 0) {
perror ("clock_gettime()");
return (EXIT_FAILURE);
}
printf ("Process clock: %ld sec, %ld nsec\n", process_time.tv_sec,
process_time.tv_nsec);
Timers using a thread CPU-time clock
You can arrange to be notified when a thread uses more than a given amount of CPU time. You can't currently do this for a process.
Setting up this type of notification involves creating a timer with a thread CPU-time clock ID:
- Get a thread CPU-time clock ID, as described above.
- Set up a sigevent that specifies how you want to be notified.
- Call
timer_create(),
passing to it the thread CPU-time clock ID and the sigevent.
Note:
- At any moment, only one timer can be using a thread's CPU-time clock ID. If there's already a timer for the given thread CPU-time clock ID, timer_create() gives an error of EAGAIN.
- If you try to create a timer for a process CPU-time clock, timer_create() gives an error of EINVAL.
- Set up the appropriate data structure (e.g., an itimerspec), specifying the execution time as the timeout.
- Call timer_settime(), passing to it the timer ID and the timeout.
struct sigevent event;
timer_t timer_id;
struct itimerspec cpu_usage;
/* Set up the method of notification. */
SIGEV_SIGNAL_INIT( &event, SIGALRM );
signal( SIGALRM, sig_handler );
/* Create a timer. */
if ( timer_create( CLOCK_THREAD_CPUTIME_ID, &event, &timer_id ) ) {
perror( "timer_create" );
return EXIT_FAILURE;
}
/* Set up the amount of CPU time and then set the timer. */
cpu_usage.it_value.tv_sec = 0;
cpu_usage.it_value.tv_nsec = nsec;
cpu_usage.it_interval.tv_sec = 0;
cpu_usage.it_interval.tv_nsec = period_nsec;
if ( timer_settime( timer_id, 0, &cpu_usage, NULL ) ) {
perror( "timer_settime" );
exit(EXIT_FAILURE);
}
/* If the thread exceeds the specified CPU time, we'll get a SIGALRM,
and our sig_handler() function will be called. */
The accuracy of this mechanism depends on the clock period; if the thread exceeds the given execution time, the actual amount of time used is at least the amount you specified but less than the same amount plus the clock period.
CPU time billing for threads
- Thread context switching time is billed partly to the preempted thread and partly to the preempter thread.
- Interrupts are billed to the thread that gets interrupted. This includes normal hardware interrupts and
system
interrupts such as the system timer tick and interrupts.