Commit fda562fd authored by oli's avatar oli

Clean code and add back max clock resolution measure

parent 931eb065
...@@ -3,3 +3,6 @@ ...@@ -3,3 +3,6 @@
simple-server/build/main simple-server/build/main
simple-client/build/main simple-client/build/main
latency-measure/build/main latency-measure/build/main
latency-measure/build/main
clock-res/build/clockres
clock-res/build/clockres_arm
...@@ -33,6 +33,6 @@ run: $(PROG) ...@@ -33,6 +33,6 @@ run: $(PROG)
./$^ ./$^
clean: clean:
$(RM) $(OBJS) $(PROG) $(subst .c,.d,$(SRCS)) $(RM) $(OBJS) $(PROG) $(ARM_PROG) $(subst .c,.d,$(SRCS))
.PHONY: clean FORCE .PHONY: clean FORCE
#include <errno.h> #include <errno.h>
#include <error.h> #include <error.h>
#include <inttypes.h>
#include <pthread.h> #include <pthread.h>
#include <sched.h> #include <sched.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include <stdint.h>
#include <inttypes.h>
#define CLOCK_ID CLOCK_MONOTONIC #define CLOCK_ID CLOCK_MONOTONIC
#define NSEC_PER_SEC INT64_C(1000000000) #define NSEC_PER_SEC INT64_C(1000000000)
typedef struct thread_stat { typedef struct thread_stat {
int nb_cycles; int nb_cycles;
int64_t max_res; uint64_t max_res;
int64_t min_res; uint64_t min_res;
} thread_stat_t; } thread_stat_t;
typedef struct thread_param { typedef struct thread_param {
int priority; int priority;
int max_cycles; int max_cycles;
int64_t interval; uint64_t interval;
thread_stat_t stat; thread_stat_t stat;
} thread_param_t; } thread_param_t;
...@@ -30,168 +30,124 @@ typedef struct main_param { ...@@ -30,168 +30,124 @@ typedef struct main_param {
int refresh_rate; int refresh_rate;
} main_param_t; } main_param_t;
static inline int64_t calcdiff_ns(struct timespec t1, struct timespec t2) static void process_options(int argc, char *argv[], thread_param_t * param, main_param_t * main_param);
{
int64_t diff;
diff = NSEC_PER_SEC * (int64_t)((int) t1.tv_sec - (int) t2.tv_sec);
diff += ((int) t1.tv_nsec - (int) t2.tv_nsec);
return diff;
}
static inline int64_t max(int64_t a, int64_t b) { return a > b ? a : b; }
static inline int64_t min(int64_t a, int64_t b) { return a < b ? a : b; }
// Code from cyclictest
void compute_resolution() {
int clock;
uint64_t diff;
int k;
uint64_t min_non_zero_diff = UINT64_MAX;
struct timespec now;
struct timespec prev;
struct timespec *time;
int times;
clock = CLOCK_ID;
/*
* Calculate how many calls to clock_gettime are needed.
* Then call it that many times.
* Goal is to collect timestamps for ~ 0.001 sec.
* This will reliably capture resolution <= 500 usec.
*/
times = 1000;
clock_gettime(clock, &prev);
for (k = 0; k < times; k++) {
clock_gettime(clock, &now);
}
diff = calcdiff_ns(now, prev);
if (diff == 0) {
/*
* No clock rollover occurred.
* Use the default value for times.
*/
times = -1;
} else {
int call_time;
call_time = diff / times; /* duration 1 call */
times = NSEC_PER_SEC / call_time; /* calls per second */
times /= 1000; /* calls per msec */
if (times < 1000) times = 1000;
}
/* sanity check */
if ((times <= 0) || (times > 100000)) times = 100000;
time = calloc(times, sizeof(*time));
for (k = 0; k < times; k++) { static inline uint64_t calcdiff_ns(struct timespec t1, struct timespec t2);
clock_gettime(clock, &time[k]); static inline uint64_t max(uint64_t a, uint64_t b);
} static inline uint64_t min(uint64_t a, uint64_t b);
prev = time[0];
for (k = 1; k < times; k++) {
diff = calcdiff_ns(time[k], prev);
prev = time[k];
if (diff && (diff < min_non_zero_diff)) {
min_non_zero_diff = diff;
}
}
free(time);
printf("measured clock resolution approximately: %llu nsec\n",
(unsigned long long)min_non_zero_diff);
}
// Real-time thread // Real-time thread
// Sends packets at a regular intervall
static void *timerthread(void *p) { static void *timerthread(void *p) {
struct timespec previous, current;
struct sched_param priority; struct sched_param priority;
uint64_t diff;
thread_param_t *param = (thread_param_t *)p; thread_param_t * param = (thread_param_t *)p;
thread_stat_t *stat = &param->stat; thread_stat_t * stat = &param->stat;
priority.sched_priority = param->priority; priority.sched_priority = param->priority;
int err = sched_setscheduler(0, SCHED_FIFO, &priority); if (sched_setscheduler(0, SCHED_FIFO, &priority))
error(EXIT_FAILURE, errno, "Couldn't set priority");
if (err) error(EXIT_FAILURE, errno, "Couldn't set priority");
stat->max_res = 0; stat->max_res = 0;
stat->min_res = 1000000; stat->min_res = UINT64_MAX;
for (stat->nb_cycles = 0;; stat->nb_cycles++) { for(stat->nb_cycles = 0;; stat->nb_cycles++) {
if (param->max_cycles)
if (stat->nb_cycles >= param->max_cycles) break;
compute_resolution(); if(param->max_cycles && (stat->nb_cycles >= param->max_cycles))
break;
usleep(param->interval); clock_gettime(CLOCK_ID, &previous);
} clock_gettime(CLOCK_ID, &current);
printf("Done\n"); diff = calcdiff_ns(current, previous);
return NULL; stat->max_res = max(stat->max_res, diff);
} stat->min_res = min(stat->min_res, diff);
static void process_options(int argc, char *argv[], thread_param_t *param, usleep(param->interval);
main_param_t *main_param) {
for (;;) {
int c = getopt(argc, argv, "l:p:i:r:");
if (c == -1) break;
switch (c) {
case 'p':
param->priority = atoi(optarg);
break;
case 'l':
param->max_cycles = atoi(optarg);
break;
case 'i':
param->interval = atoi(optarg);
break;
case 'r':
main_param->refresh_rate = atoi(optarg);
break;
default:
exit(EXIT_FAILURE);
break;
}
} }
}
return NULL;
}
// Main thread, has non-real time priority // Main thread, has non-real time priority
// Handles the IO and creates real time threads // Handles the IO and creates real time threads
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
pthread_t thread; pthread_t thread;
thread_param_t param; thread_param_t param;
main_param_t main_param; main_param_t main_param;
int err;
// Default values // Default values
param.interval = 100; param.interval= 1000;
param.max_cycles = 100000; param.max_cycles = 100000;
param.priority = 99; param.priority = 99;
main_param.refresh_rate = 10000; main_param.refresh_rate = 10000;
process_options(argc, argv, &param, &main_param); process_options(argc, argv, &param, &main_param);
usleep(10000); usleep(10000);
err = pthread_create(&thread, NULL, timerthread, (void *)&param); if(pthread_create(&thread, NULL, timerthread, (void *)&param))
error(EXIT_FAILURE, errno, "Couldn't create thread");
if (err) error(EXIT_FAILURE, errno, "Couldn't create thread");
for (;;) { for (;;) {
usleep(main_param.refresh_rate); usleep(main_param.refresh_rate);
if (param.max_cycles == param.stat.nb_cycles) break; printf("Maximum res: %" PRIu64 "ns (%d)", (param.stat.max_res), param.stat.nb_cycles);
printf(", minimum res: %" PRIu64 "ns (%d)\n", (param.stat.min_res), param.stat.nb_cycles);
if( param.max_cycles == param.stat.nb_cycles )
break;
} }
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
static void process_options(int argc, char *argv[], thread_param_t * param, main_param_t * main_param) {
for(;;) {
int c = getopt(argc, argv, "l:p:i:r:");
if(c == -1)
break;
switch(c) {
case 'p':
param->priority = atoi(optarg);
break;
case 'l':
param->max_cycles = atoi(optarg);
break;
case 'i':
param->interval = atoi(optarg);
break;
case 'r':
main_param->refresh_rate = atoi(optarg);
break;
default:
exit(EXIT_FAILURE);
break;
}
}
}
static inline uint64_t calcdiff_ns(struct timespec t1, struct timespec t2)
{
uint64_t diff;
diff = NSEC_PER_SEC * (uint64_t)((int) t1.tv_sec - (int) t2.tv_sec);
diff += ((int) t1.tv_nsec - (int) t2.tv_nsec);
return diff;
}
static inline uint64_t max(uint64_t a, uint64_t b) {
return a > b ? a : b;
}
static inline uint64_t min(uint64_t a, uint64_t b) {
return a < b ? a : b;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment