blob: 1197f622529a185e67fc7131a6007857b730802d [file] [log] [blame]
/*
* tscalibrate.c: Calibrate the get_timestamp() function
*
* This test produces output similar to the following:
*
* duration: 100 maxlatency: 5 nsamples: 24 min: 0.416666 max: 0.416674 avg: 0.41667 (ns per timestamp unit)
*
* 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, you can access it online at
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright (c) 2023 Paul E. McKenney, Meta Platforms Inc.
*/
#include "../api.h"
#include <time.h>
#include <stdarg.h>
#include <stdbool.h>
struct sample {
long long s_cgtdur;
long long s_tsdur;
};
/*
* Test variables.
*/
static int duration = 100;
static int maxlatency = 5;
static int nsamples = 24;
// Collect one timestamp.
bool ts1read(struct sample *sp)
{
long long cgt1;
long long cgt2;
cgt1 = get_microseconds();
sp->s_tsdur = get_timestamp();
cgt2 = get_microseconds();
if (cgt2 < cgt1 || cgt2 - cgt1 > maxlatency)
return false;
sp->s_cgtdur = (cgt1 + cgt2) / 2ULL;
return true;
}
// Collect one timestamp calibration sample.
void ts1sample(struct sample *sp)
{
int i = 0;
struct sample s1;
struct sample s2;
for (;;) {
BUG_ON(++i > 10);
if (!ts1read(&s1))
continue;
poll(NULL, 0, duration);
if (ts1read(&s2))
break;
}
sp->s_cgtdur = s2.s_cgtdur - s1.s_cgtdur;
sp->s_tsdur = s2.s_tsdur - s1.s_tsdur;
}
// Collect timestamp calibration samples.
void tscollectsamples(struct sample *sp)
{
int i;
for (i = 0; i < nsamples; i++)
ts1sample(&sp[i]);
}
// Collect the samples, compute the statistics, and print the results.
void tscalibrate(void)
{
double avg_cgt;
double avg_ts;
double cur;
int i;
double max;
double min;
struct sample *sp = calloc(nsamples, sizeof(*sp));
struct sample sum = {};
BUG_ON(!sp);
tscollectsamples(sp);
sum = sp[0];
min = sp[0].s_cgtdur * 1000. / (double)sp[0].s_tsdur;
max = sp[0].s_cgtdur * 1000. / (double)sp[0].s_tsdur;
for (i = 1; i < nsamples; i++) {
sum.s_cgtdur += sp[i].s_cgtdur;
sum.s_tsdur += sp[i].s_tsdur;
cur = sp[i].s_cgtdur * 1000. / (double)sp[i].s_tsdur;
if (cur < min)
min = cur;
if (cur > max)
max = cur;
}
avg_cgt = sum.s_cgtdur / (double)nsamples;
avg_ts = sum.s_tsdur / (double)nsamples;
printf("duration: %d maxlatency: %d nsamples: %d min: %g max: %g avg: %g (ns per timestamp unit)\n",
duration, maxlatency, nsamples, min, max, avg_cgt * 1000. / avg_ts);
}
/*
* Mainprogram.
*/
void usage(char *progname, const char *format, ...)
{
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
fprintf(stderr, "Usage: %s\n", progname);
fprintf(stderr, "\t --duration\n");
fprintf(stderr, "\t\tDuration of run in milliseconds (default 100).\n");
fprintf(stderr, "\t --maxlatency\n");
fprintf(stderr, "\t\tMaximum timestamp latency (default 5us).\n");
fprintf(stderr, "\t --nsamples\n");
fprintf(stderr, "\t\tNumber of samples (default 24).\n");
exit(EXIT_FAILURE);
}
int main(int argc, char *argv[])
{
int i = 1;
while (i < argc) {
if (strcmp(argv[i], "--duration") == 0) {
duration = atoi(argv[++i]);
if (duration <= 0)
usage(argv[0], "%s: --duration argument must be positive.\n", argv[i]);
++i;
} else if (strcmp(argv[i], "--maxlatency") == 0) {
maxlatency = atoi(argv[++i]);
if (maxlatency <= 0)
usage(argv[0], "%s: --maxlatency argument must be positive.\n", argv[i]);
++i;
} else if (strcmp(argv[i], "--nsamples") == 0) {
nsamples = atoi(argv[++i]);
if (nsamples <= 1)
usage(argv[0], "%s: --nsamples argument must be positive.\n", argv[i]);
++i;
} else {
usage(argv[0], "Unrecognized argument: %s\n", argv[i]);
}
}
tscalibrate();
return 0;
}