linux/tools/perf/util/clockid.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3#include <subcmd/parse-options.h>
   4#include <stdio.h>
   5#include <time.h>
   6#include <strings.h>
   7#include <linux/time64.h>
   8#include "debug.h"
   9#include "clockid.h"
  10#include "record.h"
  11
  12struct clockid_map {
  13        const char *name;
  14        int clockid;
  15};
  16
  17#define CLOCKID_MAP(n, c)       \
  18        { .name = n, .clockid = (c), }
  19
  20#define CLOCKID_END     { .name = NULL, }
  21
  22
  23/*
  24 * Add the missing ones, we need to build on many distros...
  25 */
  26#ifndef CLOCK_MONOTONIC_RAW
  27#define CLOCK_MONOTONIC_RAW 4
  28#endif
  29#ifndef CLOCK_BOOTTIME
  30#define CLOCK_BOOTTIME 7
  31#endif
  32#ifndef CLOCK_TAI
  33#define CLOCK_TAI 11
  34#endif
  35
  36static const struct clockid_map clockids[] = {
  37        /* available for all events, NMI safe */
  38        CLOCKID_MAP("monotonic", CLOCK_MONOTONIC),
  39        CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW),
  40
  41        /* available for some events */
  42        CLOCKID_MAP("realtime", CLOCK_REALTIME),
  43        CLOCKID_MAP("boottime", CLOCK_BOOTTIME),
  44        CLOCKID_MAP("tai", CLOCK_TAI),
  45
  46        /* available for the lazy */
  47        CLOCKID_MAP("mono", CLOCK_MONOTONIC),
  48        CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW),
  49        CLOCKID_MAP("real", CLOCK_REALTIME),
  50        CLOCKID_MAP("boot", CLOCK_BOOTTIME),
  51
  52        CLOCKID_END,
  53};
  54
  55static int get_clockid_res(clockid_t clk_id, u64 *res_ns)
  56{
  57        struct timespec res;
  58
  59        *res_ns = 0;
  60        if (!clock_getres(clk_id, &res))
  61                *res_ns = res.tv_nsec + res.tv_sec * NSEC_PER_SEC;
  62        else
  63                pr_warning("WARNING: Failed to determine specified clock resolution.\n");
  64
  65        return 0;
  66}
  67
  68int parse_clockid(const struct option *opt, const char *str, int unset)
  69{
  70        struct record_opts *opts = (struct record_opts *)opt->value;
  71        const struct clockid_map *cm;
  72        const char *ostr = str;
  73
  74        if (unset) {
  75                opts->use_clockid = 0;
  76                return 0;
  77        }
  78
  79        /* no arg passed */
  80        if (!str)
  81                return 0;
  82
  83        /* no setting it twice */
  84        if (opts->use_clockid)
  85                return -1;
  86
  87        opts->use_clockid = true;
  88
  89        /* if its a number, we're done */
  90        if (sscanf(str, "%d", &opts->clockid) == 1)
  91                return get_clockid_res(opts->clockid, &opts->clockid_res_ns);
  92
  93        /* allow a "CLOCK_" prefix to the name */
  94        if (!strncasecmp(str, "CLOCK_", 6))
  95                str += 6;
  96
  97        for (cm = clockids; cm->name; cm++) {
  98                if (!strcasecmp(str, cm->name)) {
  99                        opts->clockid = cm->clockid;
 100                        return get_clockid_res(opts->clockid,
 101                                               &opts->clockid_res_ns);
 102                }
 103        }
 104
 105        opts->use_clockid = false;
 106        ui__warning("unknown clockid %s, check man page\n", ostr);
 107        return -1;
 108}
 109
 110const char *clockid_name(clockid_t clk_id)
 111{
 112        const struct clockid_map *cm;
 113
 114        for (cm = clockids; cm->name; cm++) {
 115                if (cm->clockid == clk_id)
 116                        return cm->name;
 117        }
 118        return "(not found)";
 119}
 120