/* Copyright (C) 2021 Free Software Foundation, Inc. Contributed by Oracle. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #include #include #include #include #include "gp-defs.h" #include "gp-time.h" /* =============================================================== */ /* * Below this are the get_clock_rate() and get_ncpus() for all architectures */ static int clock_rate = 0; static int ncpus = 0; static char msgbuf[1024]; int get_clock_rate (void) { /* Linux version -- read /proc/cpuinfo * Note the parsing is different on intel-Linux and sparc-Linux */ FILE *fp = fopen ("/proc/cpuinfo", "r"); if (fp != NULL) { char temp[1024]; while (fgets (temp, sizeof (temp), fp) != NULL) { #if ARCH(SPARC) /* cpu count for SPARC linux -- read from /proc/cpuinfo */ if (strncmp (temp, "ncpus active", 12) == 0) { char *val = strchr (temp, ':'); ncpus = val ? atol (val + 1) : 0; } #endif /* ARCH(SPARC) */ if (clock_rate == 0) { /* pick the first line that gives a CPU clock rate */ #if ARCH(SPARC) long long clk; if (strncmp (temp, "Cpu0ClkTck", 10) == 0) { char *val = strchr (temp, ':'); clk = val ? strtoll (val + 1, NULL, 16) : 0; clock_rate = (int) (clk / 1000000); } #else if (strncmp (temp, "cpu MHz", 7) == 0) { char *val = strchr (temp, ':'); clock_rate = val ? atoi (val + 1) : 0; } #endif /* ARCH() */ } /* did we get a clock rate? */ if (clock_rate != 0) { #if ARCH(SPARC) /* since we got a cpu count, we can break from the look */ break; #endif /* ARCH(SPARC) */ } #if ARCH(Intel) /* On intel-Linux, count cpus based on "cpu MHz" lines */ if (strncmp (temp, "cpu MHz", 7) == 0) ncpus++; #endif /* ARCH(Intel) */ } fclose (fp); } if (clock_rate != 0) sprintf (msgbuf, "Clock rate = %d MHz (from reading /proc/cpuinfo) %d CPUs\n", clock_rate, ncpus); /* did we get a clock rate? */ if (clock_rate == 0) { clock_rate = 1000; sprintf (msgbuf, "Clock rate = %d MHz (set by default) %d CPUs\n", clock_rate, ncpus); } return clock_rate; } int get_ncpus (void) { if (clock_rate == 0) get_clock_rate (); return ncpus; } /* gethrvtime -- generic solution, getting user time from * clock_gettime(CLOCK_THREAD_CPUTIME_ID,..), and reformatting. * need -lrt to compile.*/ hrtime_t gethrvtime () { struct timespec tp; hrtime_t rc = 0; int r = clock_gettime (CLOCK_THREAD_CPUTIME_ID, &tp); if (r == 0) rc = ((hrtime_t) tp.tv_sec) * 1000000000 + (hrtime_t) tp.tv_nsec; return rc; } /* * CLOCK_MONOTONIC * Clock that cannot be set and represents monotonic time since some * unspecified starting point. */ hrtime_t gethrtime (void) { struct timespec tp; hrtime_t rc = 0; /* * For er_kernel on Linux, we want to match how DTrace gets its timestamps. * This is CLOCK_MONOTONIC_RAW. It might be changing to CLOCK_MONOTONIC. * For now, we change to "RAW" and can change back if DTrace changes. * * The two can be different. Check the clock_gettime() man page. * CLOCK_MONOTONIC_RAW is Linux-specific and introduced in 2.6.28. * It is impervious to NTP or adjtime adjustments. * * We must match the timer used in perfan/libcollector/src/gethrtime.c. * * There is no issue on Solaris, where gethrtime() is provided by the kernel * and used by DTrace. */ int r = clock_gettime (CLOCK_MONOTONIC_RAW, &tp); if (r == 0) rc = ((hrtime_t) tp.tv_sec) * 1000000000 + (hrtime_t) tp.tv_nsec; return rc; }