1/* Copyright (C) 2021 Free Software Foundation, Inc. 2 Contributed by Oracle. 3 4 This file is part of GNU Binutils. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, 51 Franklin Street - Fifth Floor, Boston, 19 MA 02110-1301, USA. */ 20 21#include "config.h" 22#include <time.h> 23#include <unistd.h> 24#include <string.h> 25#include <stdio.h> 26#include <stdlib.h> 27#include <sys/resource.h> 28 29#include "gp-defs.h" 30#include "gp-time.h" 31 32/* =============================================================== */ 33/* 34 * Below this are the get_clock_rate() and get_ncpus() for all architectures 35 */ 36 37static int clock_rate = 0; 38static int ncpus = 0; 39static char msgbuf[1024]; 40 41int 42get_clock_rate (void) 43{ 44 /* Linux version -- read /proc/cpuinfo 45 * Note the parsing is different on intel-Linux and sparc-Linux 46 */ 47 FILE *fp = fopen ("/proc/cpuinfo", "r"); 48 if (fp != NULL) 49 { 50 51 char temp[1024]; 52 while (fgets (temp, sizeof (temp), fp) != NULL) 53 { 54#if ARCH(SPARC) 55 /* cpu count for SPARC linux -- read from /proc/cpuinfo */ 56 if (strncmp (temp, "ncpus active", 12) == 0) 57 { 58 char *val = strchr (temp, ':'); 59 ncpus = val ? atol (val + 1) : 0; 60 } 61#endif /* ARCH(SPARC) */ 62 63 if (clock_rate == 0) 64 { 65 /* pick the first line that gives a CPU clock rate */ 66#if ARCH(SPARC) 67 long long clk; 68 if (strncmp (temp, "Cpu0ClkTck", 10) == 0) 69 { 70 char *val = strchr (temp, ':'); 71 clk = val ? strtoll (val + 1, NULL, 16) : 0; 72 clock_rate = (int) (clk / 1000000); 73 } 74#else 75 if (strncmp (temp, "cpu MHz", 7) == 0) 76 { 77 char *val = strchr (temp, ':'); 78 clock_rate = val ? atoi (val + 1) : 0; 79 } 80#endif /* ARCH() */ 81 } 82 83 /* did we get a clock rate? */ 84 if (clock_rate != 0) 85 { 86#if ARCH(SPARC) 87 /* since we got a cpu count, we can break from the look */ 88 break; 89#endif /* ARCH(SPARC) */ 90 } 91#if ARCH(Intel) 92 /* On intel-Linux, count cpus based on "cpu MHz" lines */ 93 if (strncmp (temp, "cpu MHz", 7) == 0) 94 ncpus++; 95#endif /* ARCH(Intel) */ 96 } 97 fclose (fp); 98 } 99 100 if (clock_rate != 0) 101 sprintf (msgbuf, 102 "Clock rate = %d MHz (from reading /proc/cpuinfo) %d CPUs\n", 103 clock_rate, ncpus); 104 105 /* did we get a clock rate? */ 106 if (clock_rate == 0) 107 { 108 clock_rate = 1000; 109 sprintf (msgbuf, "Clock rate = %d MHz (set by default) %d CPUs\n", 110 clock_rate, ncpus); 111 } 112 return clock_rate; 113} 114 115int 116get_ncpus (void) 117{ 118 if (clock_rate == 0) 119 get_clock_rate (); 120 return ncpus; 121} 122 123/* gethrvtime -- generic solution, getting user time from 124 * clock_gettime(CLOCK_THREAD_CPUTIME_ID,..), and reformatting. 125 * need -lrt to compile.*/ 126hrtime_t 127gethrvtime () 128{ 129 struct timespec tp; 130 hrtime_t rc = 0; 131 int r = clock_gettime (CLOCK_THREAD_CPUTIME_ID, &tp); 132 if (r == 0) 133 rc = ((hrtime_t) tp.tv_sec) * 1000000000 + (hrtime_t) tp.tv_nsec; 134 return rc; 135} 136 137/* 138 * CLOCK_MONOTONIC 139 * Clock that cannot be set and represents monotonic time since some 140 * unspecified starting point. 141 */ 142hrtime_t 143gethrtime (void) 144{ 145 struct timespec tp; 146 hrtime_t rc = 0; 147 148 /* 149 * For er_kernel on Linux, we want to match how DTrace gets its timestamps. 150 * This is CLOCK_MONOTONIC_RAW. It might be changing to CLOCK_MONOTONIC. 151 * For now, we change to "RAW" and can change back if DTrace changes. 152 * 153 * The two can be different. Check the clock_gettime() man page. 154 * CLOCK_MONOTONIC_RAW is Linux-specific and introduced in 2.6.28. 155 * It is impervious to NTP or adjtime adjustments. 156 * 157 * We must match the timer used in perfan/libcollector/src/gethrtime.c. 158 * 159 * There is no issue on Solaris, where gethrtime() is provided by the kernel 160 * and used by DTrace. 161 */ 162#ifdef CLOCK_MONOTONIC_RAW 163 int r = clock_gettime (CLOCK_MONOTONIC_RAW, &tp); 164#else 165 int r = clock_gettime (CLOCK_MONOTONIC, &tp); 166#endif 167 if (r == 0) 168 rc = ((hrtime_t) tp.tv_sec) * 1000000000 + (hrtime_t) tp.tv_nsec; 169 return rc; 170} 171