--- /dev/null
+/* depend: */
+/* cflags: */
+/* linker: mstime.o stat.o -lpthread -lm */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "mstime.h"
+#include "stat.h"
+
+/* static variables */
+
+char *progname = NULL;
+char *version = "1.1";
+
+int nb_measurements = 1000;
+int do_stat = 0;
+int hist_bin = 10;
+char *output = NULL;
+
+/* global variables */
+
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+int shared_flag = 0;
+mstime_t timestamp1, timestamp2;
+int try = 0;
+
+void *mutex_giver_task (__attribute__((unused)) void *arg)
+{
+ while (try < nb_measurements) {
+ pthread_mutex_lock (&mutex);
+ shared_flag = 1;
+ timestamp1 = sys_timestamp ();
+ pthread_mutex_unlock (&mutex);
+ }
+ pthread_exit(NULL);
+}
+
+void *mutex_taker_task (__attribute__((unused)) void *arg)
+{
+ mstime_t *deltas = (mstime_t *) calloc (nb_measurements, sizeof (mstime_t));
+ assert (deltas);
+
+ while (try < nb_measurements) {
+ pthread_mutex_lock (&mutex);
+ if (shared_flag) {
+ timestamp2 = sys_timestamp ();
+ deltas[try++] = timestamp2 - timestamp1;
+ shared_flag = 0;
+ }
+ pthread_mutex_unlock(&mutex);
+ }
+
+ if (output) {
+ FILE *fd = fopen (output, "w");
+ assert (fd);
+ for (int i = 0; i < nb_measurements; i++) {
+ fprintf (fd, "%ld\n", deltas[i]);
+ }
+ fclose (fd);
+ }
+
+ if (do_stat) {
+ compute_statistics (deltas, nb_measurements, hist_bin);
+ }
+
+ free (deltas);
+
+ pthread_exit(NULL);
+}
+
+/* usage function */
+
+int usage (int ret)
+{
+ FILE *fd = ret ? stderr : stdout;
+ fprintf (fd, "usage: %s [-b int] [-h] [-n int] [-o file] [-s]\n", progname);
+ fprintf (fd, " -b: nb bins for histogram (%d)\n", hist_bin);
+ fprintf (fd, " -h: help message\n");
+ fprintf (fd, " -n: nb measurements (%d)\n", nb_measurements);
+ fprintf (fd, " -o: output raw data (%s)\n", (output) ? output : "none");
+ fprintf (fd, " -s: display statistics (%s)\n", (do_stat) ? "yes" : "no");
+ fprintf (fd, "%s version %s\n", progname, version);
+
+ return ret;
+}
+
+/* main function */
+
+int main (int argc, char *argv[])
+{
+
+ /* get basename */
+
+ char *pt = progname = argv[0];
+ while (*pt) {
+ if ((*pt == '/') || (*pt == '\\')) {
+ progname = pt + 1;
+ }
+ pt++;
+ }
+
+ /* process arguments */
+
+ while (argc-- > 1) {
+ char *arg = *(++argv);
+ if (arg[0] != '-') {
+ fprintf (stderr, "%s: invalid option -- %s\n", progname, arg);
+ return usage (1);
+ }
+ char c = arg[1];
+ switch (c) {
+ case 'b':
+ arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
+ if (arg == NULL) {
+ fprintf (stderr, "%s: no number of bins specified\n", progname);
+ return usage (1);
+ }
+ hist_bin = atoi (arg);
+ break;
+ case 'n':
+ arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
+ if (arg == NULL) {
+ fprintf (stderr, "%s: no number of measurements specified\n", progname);
+ return usage (1);
+ }
+ nb_measurements = atoi (arg);
+ break;
+ case 'o':
+ arg = (arg[2]) ? arg + 2 : (--argc > 0) ? *(++argv) : NULL;
+ if (arg == NULL) {
+ fprintf (stderr, "%s: no output file specified\n", progname);
+ return usage (1);
+ }
+ output = arg;
+ break;
+ case 's':
+ do_stat = 1;
+ break;
+ case 'v':
+ printf ("version: %s\n", version);
+ break;
+ case 'h':
+ default:
+ return usage (c != 'h');
+ }
+ }
+
+ /* main process */
+
+ pthread_t giver_thread, taker_thread;
+ pthread_attr_t attr;
+ struct sched_param param;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
+ param.sched_priority = sched_get_priority_max(SCHED_FIFO);
+ pthread_attr_setschedparam(&attr, ¶m);
+ pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+
+ shared_flag = 1;
+
+ if (pthread_create (&giver_thread, &attr, mutex_giver_task, NULL) != 0) {
+ fprintf (stderr, "error on pthread_create for giver_task\n");
+ return 1;
+ }
+
+ if (pthread_create (&taker_thread, &attr, mutex_taker_task, NULL) != 0) {
+ fprintf (stderr, "error on pthread_create for taker_task\n");
+ return 1;
+ }
+
+ pthread_join (giver_thread, NULL);
+ pthread_join (taker_thread, NULL);
+
+ pthread_mutex_destroy(&mutex);
+
+ return 0;
+}
--- /dev/null
+/* Statistic module */
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "mstime.h"
+
+#include "stat.h"
+
+void compute_statistics (mstime_t *points, int nb, int bins)
+{
+
+ /* compute average, minimum and maximum */
+
+ double avg = 0;
+ double min = points[1];
+ double max = points[1];
+
+ for (int i = 1; i < nb; i++) {
+ double pt = points[i];
+ avg += pt;
+ if (pt < min) {
+ min = pt;
+ }
+ if (pt > max) {
+ max = pt;
+ }
+ }
+ avg = avg / (nb - 1);
+
+ printf ("Minimum = %.2lf\n", min);
+ printf ("Average = %.2lf\n", avg);
+ printf ("Maximum = %.2lf\n", max);
+
+ /* standard deviation */
+
+ double std = 0;
+
+ for (int i = 0; i < nb; i++) {
+ std += (points[i] - avg) * (points[i] - avg);
+ }
+ std = sqrt (std / (nb - 1));
+
+ /* compute median, 25 percentile and 75 percentile */
+
+ for (int j = 1; j < nb - 1; j++) {
+ int change_done = 0;
+ for (int i = 1; i < nb - 1; i++) {
+ if (points[i + 1] < points[i]) {
+ mstime_t tmp = points[i];
+ points[i] = points[i + 1];
+ points[i + 1] = tmp;
+ change_done = 1;
+ }
+ }
+ if (!change_done) {
+ break;
+ }
+ }
+ double p25 = points[nb / 4];
+ if ((nb % 4 == 0) && (nb >= 4)) {
+ p25 = (p25 + points[nb / 4 - 1]) / 2;
+ }
+ double med = points[nb / 2];
+ if (nb % 2 == 0) {
+ med = (med + points[nb / 2 - 1]) / 2;
+ }
+ double p75 = points[(3 * nb) / 4];
+ if (((3 * nb) % 4 == 0) && (nb >= 4)) {
+ p75 = (p75 + points[(3 * nb) / 4 - 1]) / 2;
+ }
+
+ printf ("25th %% = %.2lf\n", p25);
+ printf ("Median = %.2lf\n", med);
+ printf ("75th %% = %.2lf\n", p75);
+
+ /* compute histogram */
+
+ int *hist = (int *) calloc (bins, sizeof (int));
+ assert (hist);
+
+ double gap = (max - min) / bins;
+ for (int i = 0; i < nb; i++) {
+ hist[(int)((points[i] - min) / gap)]++;
+ }
+
+ printf ("Histogram\n");
+ for (int i = 0; i < bins - 1; i++) {
+ printf (" [%.2lf - %.2lf] = %d\n", min + i * gap, min + (i + 1) * gap, hist[i]);
+ }
+ printf (" [%.2lf - %.2lf] = %d\n", min + (bins - 1) * gap, max, hist[bins - 1]);
+
+ free (hist);
+
+}