// Copyright (c) 2010 Baidu, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Author: Ge,Jun (gejun@baidu.com) // Date: Fri Aug 29 15:01:15 CST 2014 #include <unistd.h> // close #include <sys/types.h> // open #include <sys/stat.h> // ^ #include <fcntl.h> // ^ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include <string.h> // memmem #undef _GNU_SOURCE #include "butil/time.h" namespace butil { int64_t monotonic_time_ns() { // MONOTONIC_RAW is slower than MONOTONIC in linux 2.6.32, trying to // use the RAW version does not make sense anymore. // NOTE: Not inline to keep ABI-compatible with previous versions. timespec now; #ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time clock_serv_t cclock; mach_timespec_t mts; host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); now.tv_sec = mts.tv_sec; now.tv_nsec = mts.tv_nsec; #else clock_gettime(CLOCK_MONOTONIC, &now); #endif return now.tv_sec * 1000000000L + now.tv_nsec; } namespace detail { // read_cpu_frequency() is modified from source code of glibc. int64_t read_cpu_frequency(bool* invariant_tsc) { /* We read the information from the /proc filesystem. It contains at least one line like cpu MHz : 497.840237 or also cpu MHz : 497.841 We search for this line and convert the number in an integer. */ const int fd = open("/proc/cpuinfo", O_RDONLY); if (fd < 0) { return 0; } int64_t result = 0; char buf[4096]; // should be enough const ssize_t n = read(fd, buf, sizeof(buf)); if (n > 0) { char *mhz = static_cast<char*>(memmem(buf, n, "cpu MHz", 7)); if (mhz != NULL) { char *endp = buf + n; int seen_decpoint = 0; int ndigits = 0; /* Search for the beginning of the string. */ while (mhz < endp && (*mhz < '0' || *mhz > '9') && *mhz != '\n') { ++mhz; } while (mhz < endp && *mhz != '\n') { if (*mhz >= '0' && *mhz <= '9') { result *= 10; result += *mhz - '0'; if (seen_decpoint) ++ndigits; } else if (*mhz == '.') { seen_decpoint = 1; } ++mhz; } /* Compensate for missing digits at the end. */ while (ndigits++ < 6) { result *= 10; } } if (invariant_tsc) { char* flags_pos = static_cast<char*>(memmem(buf, n, "flags", 5)); *invariant_tsc = (flags_pos && memmem(flags_pos, buf + n - flags_pos, "constant_tsc", 12) && memmem(flags_pos, buf + n - flags_pos, "nonstop_tsc", 11)); } } close (fd); return result; } // Return value must be >= 0 int64_t read_invariant_cpu_frequency() { bool invariant_tsc = false; const int64_t freq = read_cpu_frequency(&invariant_tsc); if (!invariant_tsc || freq < 0) { return 0; } return freq; } int64_t invariant_cpu_freq = -1; } // namespace detail } // namespace butil