xref: /openbmc/linux/tools/perf/util/clockid.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
16953beb4SJiri Olsa // SPDX-License-Identifier: GPL-2.0
26953beb4SJiri Olsa 
36953beb4SJiri Olsa #include <subcmd/parse-options.h>
46953beb4SJiri Olsa #include <stdio.h>
56953beb4SJiri Olsa #include <time.h>
66953beb4SJiri Olsa #include <strings.h>
76953beb4SJiri Olsa #include <linux/time64.h>
86953beb4SJiri Olsa #include "debug.h"
96953beb4SJiri Olsa #include "clockid.h"
106953beb4SJiri Olsa #include "record.h"
116953beb4SJiri Olsa 
126953beb4SJiri Olsa struct clockid_map {
136953beb4SJiri Olsa 	const char *name;
146953beb4SJiri Olsa 	int clockid;
156953beb4SJiri Olsa };
166953beb4SJiri Olsa 
176953beb4SJiri Olsa #define CLOCKID_MAP(n, c)	\
186953beb4SJiri Olsa 	{ .name = n, .clockid = (c), }
196953beb4SJiri Olsa 
206953beb4SJiri Olsa #define CLOCKID_END	{ .name = NULL, }
216953beb4SJiri Olsa 
226953beb4SJiri Olsa 
236953beb4SJiri Olsa /*
246953beb4SJiri Olsa  * Add the missing ones, we need to build on many distros...
256953beb4SJiri Olsa  */
266953beb4SJiri Olsa #ifndef CLOCK_MONOTONIC_RAW
276953beb4SJiri Olsa #define CLOCK_MONOTONIC_RAW 4
286953beb4SJiri Olsa #endif
296953beb4SJiri Olsa #ifndef CLOCK_BOOTTIME
306953beb4SJiri Olsa #define CLOCK_BOOTTIME 7
316953beb4SJiri Olsa #endif
326953beb4SJiri Olsa #ifndef CLOCK_TAI
336953beb4SJiri Olsa #define CLOCK_TAI 11
346953beb4SJiri Olsa #endif
356953beb4SJiri Olsa 
366953beb4SJiri Olsa static const struct clockid_map clockids[] = {
376953beb4SJiri Olsa 	/* available for all events, NMI safe */
386953beb4SJiri Olsa 	CLOCKID_MAP("monotonic", CLOCK_MONOTONIC),
396953beb4SJiri Olsa 	CLOCKID_MAP("monotonic_raw", CLOCK_MONOTONIC_RAW),
406953beb4SJiri Olsa 
416953beb4SJiri Olsa 	/* available for some events */
426953beb4SJiri Olsa 	CLOCKID_MAP("realtime", CLOCK_REALTIME),
436953beb4SJiri Olsa 	CLOCKID_MAP("boottime", CLOCK_BOOTTIME),
446953beb4SJiri Olsa 	CLOCKID_MAP("tai", CLOCK_TAI),
456953beb4SJiri Olsa 
466953beb4SJiri Olsa 	/* available for the lazy */
476953beb4SJiri Olsa 	CLOCKID_MAP("mono", CLOCK_MONOTONIC),
486953beb4SJiri Olsa 	CLOCKID_MAP("raw", CLOCK_MONOTONIC_RAW),
496953beb4SJiri Olsa 	CLOCKID_MAP("real", CLOCK_REALTIME),
506953beb4SJiri Olsa 	CLOCKID_MAP("boot", CLOCK_BOOTTIME),
516953beb4SJiri Olsa 
526953beb4SJiri Olsa 	CLOCKID_END,
536953beb4SJiri Olsa };
546953beb4SJiri Olsa 
get_clockid_res(clockid_t clk_id,u64 * res_ns)556953beb4SJiri Olsa static int get_clockid_res(clockid_t clk_id, u64 *res_ns)
566953beb4SJiri Olsa {
576953beb4SJiri Olsa 	struct timespec res;
586953beb4SJiri Olsa 
596953beb4SJiri Olsa 	*res_ns = 0;
606953beb4SJiri Olsa 	if (!clock_getres(clk_id, &res))
616953beb4SJiri Olsa 		*res_ns = res.tv_nsec + res.tv_sec * NSEC_PER_SEC;
626953beb4SJiri Olsa 	else
636953beb4SJiri Olsa 		pr_warning("WARNING: Failed to determine specified clock resolution.\n");
646953beb4SJiri Olsa 
656953beb4SJiri Olsa 	return 0;
666953beb4SJiri Olsa }
676953beb4SJiri Olsa 
parse_clockid(const struct option * opt,const char * str,int unset)686953beb4SJiri Olsa int parse_clockid(const struct option *opt, const char *str, int unset)
696953beb4SJiri Olsa {
706953beb4SJiri Olsa 	struct record_opts *opts = (struct record_opts *)opt->value;
716953beb4SJiri Olsa 	const struct clockid_map *cm;
726953beb4SJiri Olsa 	const char *ostr = str;
736953beb4SJiri Olsa 
746953beb4SJiri Olsa 	if (unset) {
756953beb4SJiri Olsa 		opts->use_clockid = 0;
766953beb4SJiri Olsa 		return 0;
776953beb4SJiri Olsa 	}
786953beb4SJiri Olsa 
796953beb4SJiri Olsa 	/* no arg passed */
806953beb4SJiri Olsa 	if (!str)
816953beb4SJiri Olsa 		return 0;
826953beb4SJiri Olsa 
836953beb4SJiri Olsa 	/* no setting it twice */
846953beb4SJiri Olsa 	if (opts->use_clockid)
856953beb4SJiri Olsa 		return -1;
866953beb4SJiri Olsa 
876953beb4SJiri Olsa 	opts->use_clockid = true;
886953beb4SJiri Olsa 
896953beb4SJiri Olsa 	/* if its a number, we're done */
906953beb4SJiri Olsa 	if (sscanf(str, "%d", &opts->clockid) == 1)
916953beb4SJiri Olsa 		return get_clockid_res(opts->clockid, &opts->clockid_res_ns);
926953beb4SJiri Olsa 
936953beb4SJiri Olsa 	/* allow a "CLOCK_" prefix to the name */
946953beb4SJiri Olsa 	if (!strncasecmp(str, "CLOCK_", 6))
956953beb4SJiri Olsa 		str += 6;
966953beb4SJiri Olsa 
976953beb4SJiri Olsa 	for (cm = clockids; cm->name; cm++) {
986953beb4SJiri Olsa 		if (!strcasecmp(str, cm->name)) {
996953beb4SJiri Olsa 			opts->clockid = cm->clockid;
1006953beb4SJiri Olsa 			return get_clockid_res(opts->clockid,
1016953beb4SJiri Olsa 					       &opts->clockid_res_ns);
1026953beb4SJiri Olsa 		}
1036953beb4SJiri Olsa 	}
1046953beb4SJiri Olsa 
1056953beb4SJiri Olsa 	opts->use_clockid = false;
1066953beb4SJiri Olsa 	ui__warning("unknown clockid %s, check man page\n", ostr);
1076953beb4SJiri Olsa 	return -1;
1086953beb4SJiri Olsa }
109*cc3365bbSJiri Olsa 
clockid_name(clockid_t clk_id)110*cc3365bbSJiri Olsa const char *clockid_name(clockid_t clk_id)
111*cc3365bbSJiri Olsa {
112*cc3365bbSJiri Olsa 	const struct clockid_map *cm;
113*cc3365bbSJiri Olsa 
114*cc3365bbSJiri Olsa 	for (cm = clockids; cm->name; cm++) {
115*cc3365bbSJiri Olsa 		if (cm->clockid == clk_id)
116*cc3365bbSJiri Olsa 			return cm->name;
117*cc3365bbSJiri Olsa 	}
118*cc3365bbSJiri Olsa 	return "(not found)";
119*cc3365bbSJiri Olsa }
120