Skip to content

Instantly share code, notes, and snippets.

@bschlinker
Last active November 14, 2018 07:25
Show Gist options
  • Save bschlinker/7428815 to your computer and use it in GitHub Desktop.
Save bschlinker/7428815 to your computer and use it in GitHub Desktop.
System Timer Granularity Analyzer for C
// System Timer Granularity Analysis
// Developed by: Brandon C. Schlinker (Inbound5 / Develop5)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <signal.h>
#include <sched.h>
#include <unistd.h>
#include <sys/timerfd.h>
#include <sys/prctl.h>
#define __STDC_FORMAT_MACROS
// generate statistics on Ctrl+C / SIG_INT
int terminate;
void handle_sigint (int signum)
{
terminate = 1;
}
// perform timer accuracy analysis
int main(int argc, char *argv[])
{
// make sure we have a sufficient # of arguments
if(argc < 3) {
printf("%s: [INTERVAL_IN_NANOSECONDS] [MAX_NUMBER_OF_QUEUED_EVENTS] \n", argv[0]);
return(-1);
}
// grab user parameters
int nanosecondInterval = atoi(argv[1]);
int maximumNumOfQueuedEventsTolerated = atoi(argv[2]);
// set real-time priority
struct sched_param schedparm;
memset(&schedparm, 0, sizeof(schedparm));
schedparm.sched_priority = 99; // highest rt priority
sched_setscheduler(0, SCHED_FIFO, &schedparm);
// set timer slack equal to 1 nanosecond
prctl(PR_SET_TIMERSLACK, 1);
// timer setup
int timerfd = timerfd_create(CLOCK_MONOTONIC,0);
struct itimerspec timspec;
bzero(&timspec, sizeof(timspec));
timspec.it_interval.tv_sec = 0;
timspec.it_interval.tv_nsec = nanosecondInterval;
timspec.it_value.tv_sec = 0;
timspec.it_value.tv_nsec = 1;
timerfd_settime(timerfd, 0, &timspec, 0);
// statistics tracking
int * eventQueueLength = malloc(sizeof(uint64_t) * maximumNumOfQueuedEventsTolerated);
uint64_t totalInstancesOfMissedEvents = 0;
uint64_t totalNumOfMissedEvents = 0;
uint64_t eventsQueued = 0;
uint64_t eventsProceessed = 0;
// termination tracking
terminate = 0;
signal (SIGINT, handle_sigint);
// poll the timerfd, if we missed an expiration, increment
while( read (timerfd, &eventsQueued, sizeof(eventsQueued) )){
if(terminate == 1) { break; }
else if(eventsQueued > maximumNumOfQueuedEventsTolerated) { break; }
else if(eventsQueued > 1)
{
totalInstancesOfMissedEvents++;
totalNumOfMissedEvents+=(eventsQueued - 1); // -1 as the current read isn't an expiration tolerated
eventQueueLength[eventsQueued - 1]++;
}
else { eventsProceessed++; }
}
// calculate baseline statistics
uint64_t totalNumOfEvents = eventsProceessed + totalNumOfMissedEvents;
float percentMissingEvents = ((float)totalNumOfMissedEvents / (float)totalNumOfEvents) * 100;
// calculate mean and median queue length when event(s) missed
float averageNumOfMissedEventsPerFailureInstance = 0;
uint64_t medianNumOfMissedEventsPerFailureInstance = 0;
{
int i = 1;
for(i = 1; i < maximumNumOfQueuedEventsTolerated; i++)
{
medianNumOfMissedEventsPerFailureInstance+= (eventQueueLength[i]);
if(medianNumOfMissedEventsPerFailureInstance >= (totalInstancesOfMissedEvents / 2)) // rounds median up
{
medianNumOfMissedEventsPerFailureInstance = i;
break;
}
}
}
averageNumOfMissedEventsPerFailureInstance = ((float)totalNumOfMissedEvents / (float)totalInstancesOfMissedEvents);
// print statistics
printf("\n\nStatistics:\n");
printf("latest number of missed events = %" PRIu64 " | (limit = %d per instance or program quits)\n", (eventsQueued - 1), maximumNumOfQueuedEventsTolerated);
printf("total number of missed events = %" PRIu64 "\n", totalNumOfMissedEvents);
printf("total instances of missed events = %" PRIu64 "\n", totalInstancesOfMissedEvents);
printf("(one instance can be associated with multiple missed events)\n");
printf("total number of on-time events = %" PRIu64 "\n", eventsProceessed);
printf("total number of events = %" PRIu64 "\n", totalNumOfEvents);
printf("%f %% of readings were not processed (late)\n", percentMissingEvents);
printf("average number of missed events per instance of missed events = %f\n", averageNumOfMissedEventsPerFailureInstance);
printf("median number of missed events per instance of missed events = %" PRIu64 "\n", medianNumOfMissedEventsPerFailureInstance);
// dump the array
free(eventQueueLength);
// return success
return(0);
}
@PuneetPatwari
Copy link

Hi
Can you briefly explain the working of this program? I am looking for a scheduler that will help to schedule some jobs every 1 ms with utmost accuracy. Do you have any idea how to approach that problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment