Commit | Line | Data |
---|---|---|
6953beb4 JO |
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 | ||
12 | struct 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 | ||
36 | static 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 | ||
55 | static 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 | ||
68 | int 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 | } | |
cc3365bb JO |
109 | |
110 | const 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 | } |