|
rpm-build |
2ca94e |
/**
|
|
rpm-build |
2ca94e |
* hiccup.c
|
|
rpm-build |
2ca94e |
* Written by Michael Barker and released to the public domain,
|
|
rpm-build |
2ca94e |
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
|
|
rpm-build |
2ca94e |
*/
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
#include <stdint.h>
|
|
rpm-build |
2ca94e |
#include <stdbool.h>
|
|
rpm-build |
2ca94e |
#include <stdio.h>
|
|
rpm-build |
2ca94e |
#include <pthread.h>
|
|
rpm-build |
2ca94e |
#include <sys/timerfd.h>
|
|
rpm-build |
2ca94e |
#include <poll.h>
|
|
rpm-build |
2ca94e |
#include <string.h>
|
|
rpm-build |
2ca94e |
#include <signal.h>
|
|
rpm-build |
2ca94e |
#include <ctype.h>
|
|
rpm-build |
2ca94e |
#include <stdio.h>
|
|
rpm-build |
2ca94e |
#include <stdlib.h>
|
|
rpm-build |
2ca94e |
#include <unistd.h>
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
#include <hdr_histogram.h>
|
|
rpm-build |
2ca94e |
#include <hdr_histogram_log.h>
|
|
rpm-build |
2ca94e |
#include <hdr_interval_recorder.h>
|
|
rpm-build |
2ca94e |
#include <hdr_time.h>
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
static int64_t diff(struct timespec t0, struct timespec t1)
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
int64_t delta_us = 0;
|
|
rpm-build |
2ca94e |
delta_us = (t1.tv_sec - t0.tv_sec) * 1000000;
|
|
rpm-build |
2ca94e |
delta_us += (t1.tv_nsec - t0.tv_nsec) / 1000;
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
return delta_us;
|
|
rpm-build |
2ca94e |
}
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
static void* record_hiccups(void* thread_context)
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
struct pollfd fd;
|
|
rpm-build |
2ca94e |
struct timespec t0;
|
|
rpm-build |
2ca94e |
struct timespec t1;
|
|
rpm-build |
2ca94e |
struct itimerspec timeout;
|
|
rpm-build |
2ca94e |
struct hdr_interval_recorder* r = thread_context;
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
memset(&fd, 0, sizeof(struct pollfd));
|
|
rpm-build |
2ca94e |
memset(&timeout, 0, sizeof(struct itimerspec));
|
|
rpm-build |
2ca94e |
memset(&t0, 0, sizeof(struct timespec));
|
|
rpm-build |
2ca94e |
memset(&t1, 0, sizeof(struct timespec));
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
fd.fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
|
|
rpm-build |
2ca94e |
fd.events = POLLIN|POLLPRI|POLLRDHUP;
|
|
rpm-build |
2ca94e |
fd.revents = 0;
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
#pragma clang diagnostic push
|
|
rpm-build |
2ca94e |
#pragma clang diagnostic ignored "-Wmissing-noreturn"
|
|
rpm-build |
2ca94e |
while (true)
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
int64_t delta_us;
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
timeout.it_value.tv_sec = 0;
|
|
rpm-build |
2ca94e |
timeout.it_value.tv_nsec = 1000000;
|
|
rpm-build |
2ca94e |
timerfd_settime(fd.fd, 0, &timeout, NULL);
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
hdr_gettime(&t0;;
|
|
rpm-build |
2ca94e |
poll(&fd, 1, -1);
|
|
rpm-build |
2ca94e |
hdr_gettime(&t1;;
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
delta_us = diff(t0, t1) - 1000;
|
|
rpm-build |
2ca94e |
delta_us = delta_us < 0 ? 0 : delta_us;
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
hdr_interval_recorder_record_value(r, delta_us);
|
|
rpm-build |
2ca94e |
}
|
|
rpm-build |
2ca94e |
#pragma clang diagnostic pop
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
pthread_exit(NULL);
|
|
rpm-build |
2ca94e |
}
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
struct config_t
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
unsigned int interval;
|
|
rpm-build |
2ca94e |
const char* filename;
|
|
rpm-build |
2ca94e |
};
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
const char* USAGE =
|
|
rpm-build |
2ca94e |
"hiccup [-i <interval>] [-f <filename>]\n"
|
|
rpm-build |
2ca94e |
" interval: <number> Time in seconds between samples (default 1).\n"
|
|
rpm-build |
2ca94e |
" filename: <string> Name of the file to log to (default stdout).\n";
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
static int handle_opts(int argc, char** argv, struct config_t* config)
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
int c;
|
|
rpm-build |
2ca94e |
unsigned int interval = 1;
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
while ((c = getopt(argc, argv, "i:f:")) != -1)
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
switch (c)
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
case 'h':
|
|
rpm-build |
2ca94e |
return 0;
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
case 'i':
|
|
rpm-build |
2ca94e |
interval = (unsigned int) strtoul(optarg, NULL, 10);
|
|
rpm-build |
2ca94e |
if (interval < 1)
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
return 0;
|
|
rpm-build |
2ca94e |
}
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
break;
|
|
rpm-build |
2ca94e |
case 'f':
|
|
rpm-build |
2ca94e |
config->filename = optarg;
|
|
rpm-build |
2ca94e |
break;
|
|
rpm-build |
2ca94e |
default:
|
|
rpm-build |
2ca94e |
return 0;
|
|
rpm-build |
2ca94e |
}
|
|
rpm-build |
2ca94e |
}
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
config->interval = interval < 1 ? 1 : interval;
|
|
rpm-build |
2ca94e |
return 1;
|
|
rpm-build |
2ca94e |
}
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
int main(int argc, char** argv)
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
struct timespec timestamp;
|
|
rpm-build |
2ca94e |
struct timespec start_timestamp;
|
|
rpm-build |
2ca94e |
struct timespec end_timestamp;
|
|
rpm-build |
2ca94e |
struct hdr_interval_recorder recorder;
|
|
rpm-build |
2ca94e |
struct hdr_log_writer log_writer;
|
|
rpm-build |
2ca94e |
struct config_t config;
|
|
rpm-build |
2ca94e |
struct hdr_histogram* inactive = NULL;
|
|
rpm-build |
2ca94e |
pthread_t recording_thread;
|
|
rpm-build |
2ca94e |
FILE* output = stdout;
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
memset(&config, 0, sizeof(struct config_t));
|
|
rpm-build |
2ca94e |
if (!handle_opts(argc, argv, &config))
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
printf("%s", USAGE);
|
|
rpm-build |
2ca94e |
return 0;
|
|
rpm-build |
2ca94e |
}
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
if (config.filename)
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
output = fopen(config.filename, "a+");
|
|
rpm-build |
2ca94e |
if (!output)
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
fprintf(
|
|
rpm-build |
2ca94e |
stderr, "Failed to open/create file: %s, %s",
|
|
rpm-build |
2ca94e |
config.filename, strerror(errno));
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
return -1;
|
|
rpm-build |
2ca94e |
}
|
|
rpm-build |
2ca94e |
}
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
if (0 != hdr_interval_recorder_init_all(&recorder, 1, INT64_C(24) * 60 * 60 * 1000000, 3))
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
fprintf(stderr, "%s\n", "Failed to init phaser");
|
|
rpm-build |
2ca94e |
return -1;
|
|
rpm-build |
2ca94e |
}
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
if (pthread_create(&recording_thread, NULL, record_hiccups, &recorder))
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
fprintf(stderr, "%s\n", "Failed to create thread");
|
|
rpm-build |
2ca94e |
return -1;
|
|
rpm-build |
2ca94e |
}
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
hdr_gettime(&start_timestamp);
|
|
rpm-build |
2ca94e |
hdr_getnow(×tamp);
|
|
rpm-build |
2ca94e |
hdr_log_writer_init(&log_writer);
|
|
rpm-build |
2ca94e |
hdr_log_write_header(&log_writer, output, "foobar", ×tamp);
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
#pragma clang diagnostic push
|
|
rpm-build |
2ca94e |
#pragma clang diagnostic ignored "-Wmissing-noreturn"
|
|
rpm-build |
2ca94e |
while (true)
|
|
rpm-build |
2ca94e |
{
|
|
rpm-build |
2ca94e |
sleep(config.interval);
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
inactive = hdr_interval_recorder_sample_and_recycle(&recorder, inactive);
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
hdr_gettime(&end_timestamp);
|
|
rpm-build |
2ca94e |
timestamp = start_timestamp;
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
hdr_gettime(&start_timestamp);
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
hdr_log_write(&log_writer, output, ×tamp, &end_timestamp, inactive);
|
|
rpm-build |
2ca94e |
fflush(output);
|
|
rpm-build |
2ca94e |
}
|
|
rpm-build |
2ca94e |
#pragma clang diagnostic pop
|
|
rpm-build |
2ca94e |
|
|
rpm-build |
2ca94e |
pthread_exit(NULL);
|
|
rpm-build |
2ca94e |
}
|