| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- #include <sys/event.h>
- #include <sys/time.h>
- #include <stdio.h>
- #include <sched.h>
- #include <err.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <getopt.h>
- #include <signal.h>
- #include <stdbool.h>
- static int verbose;
- const struct sched_param param = {.sched_priority = 15};
- static struct option longopts[] = {
- { "period", required_argument, NULL, 'p' },
- { "verbose", no_argument , &verbose, 1 },
- { NULL, 0, NULL, 0 }
- };
- void fd_close(int *fd) {
- close(*fd);
- *fd = -1;
- }
- #define _smartfd __attribute((cleanup(fd_close)))
- void file_close(FILE **fd) {
- fclose(*fd);
- *fd = NULL;
- }
- #define _smartfile __attribute((cleanup(file_close)))
- __attribute__((noreturn))static int usage(void)
- {
- fputs("kq_timer [--verbose] [--period ms]\n", stderr);
- exit (EXIT_SUCCESS);
- }
- __attribute__((const)) static double diff_ms(const struct timespec * restrict time1, const struct timespec * restrict time0)
- {
- return (double)(time1->tv_sec - time0->tv_sec) * 1000.0
- + (double)(time1->tv_nsec - time0->tv_nsec) / 1000000.0;
- }
- static void sig_handler(int sig)
- {
- signal(SIGINT, SIG_DFL);
- }
- int main(int argc, char *argv[])
- {
- struct kevent change; /* event we want to monitor */
- struct kevent event; /* event that was triggered */
- _smartfd int kq;
- int nev; /* handlers */
- int ch; /* opt long */
- int period = 1000; /* Default to 1 sec. */
- size_t counter = 0;
- size_t total = 0;
- _smartfile FILE *fd = NULL;
- char template[64];
- int rc = EXIT_FAILURE;
- struct timespec t0 = { 0, 0};
- while ((ch = getopt_long(argc, argv, "hvp:", longopts, NULL)) != -1) {
- switch (ch) {
- case 'v':
- verbose = 1;
- break;
- case 'p':
- period = atoi(optarg);
- break;
- case 0:
- /* long option */
- break;
- default:
- usage();
- }
- }
- argc -= optind;
- argv += optind;
- if (*argv)
- usage();
- /* create a new kernel event queue */
- if ((kq = kqueue()) == -1)
- err(EXIT_FAILURE, "kqueue() failure");
- /* initalise kevent structure */
- EV_SET(&change, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, NOTE_MSECONDS, 1, 0);
- /* Dummy file to store measurements */
- strncpy(template, "/tmp/timer.XXXXXX", sizeof template);
- if (mkstemp(template) == -1) {
- warn("mkstemp() failure");
- return EXIT_FAILURE;
- }
- fd = fopen(template, "w");
- if (fd == NULL) {
- warn("fopen() failure");
- return EXIT_FAILURE;
- }
- printf("Log file: %s\n", template);
- /* process priority */
- if (-1 == sched_setscheduler(0, SCHED_RR, ¶m)) {
- warn("set scheduler() failure");
- }
- signal(SIGINT, sig_handler);
- while (true) {
- nev = kevent(kq, &change, 1, &event, 1, NULL);
- if (nev < 0) {
- if (errno != EINTR)
- warn("kevent wait:");
- /* interrupted */
- break;
- }
- if (nev > 0) {
- /* measurements */
- struct timespec t1;
- clock_gettime(CLOCK_MONOTONIC, &t1);
- if (!(t0.tv_sec == 0 && t0.tv_nsec == 0)) {
- fprintf(fd, "%06.3f\n", diff_ms(&t1, &t0));
- ++total;
- }
- t0 = t1;
- if (event.flags & EV_ERROR) {
- fprintf(stderr, "EV_ERROR: %s\n", strerror((int)event.data));
- rc = EXIT_FAILURE;
- break;
- }
- /* verbose mode */
- ++counter;
- if (counter == period) {
- if (verbose) {
- fputs(".", stdout);
- fflush(stdout);
- }
- counter = 0;
- }
- }
- }
- rc = EXIT_SUCCESS;
- fprintf(stdout, "\n%zu entries stored.\n", total);
- fprintf(stdout, "%zu cycles counted.\n", counter);
- return rc;
- }
|