Commit e4168e88 authored by gejun's avatar gejun

Remove fast_realtime* & monotonic_time and cpuwide_time is callable before…

Remove fast_realtime* & monotonic_time and cpuwide_time is callable before main() & remove CLOCK_MONOTONIC_RAW related code
parent 345e31e1
......@@ -31,47 +31,17 @@
namespace butil {
clockid_t get_monotonic_clockid() {
// http://lxr.free-electrons.com/source/include/uapi/linux/time.h#L44
const clockid_t MY_CLOCK_MONOTONIC_RAW = 4;
timespec ts;
if (0 == syscall(SYS_clock_gettime, MY_CLOCK_MONOTONIC_RAW, &ts)) {
return MY_CLOCK_MONOTONIC_RAW;
}
return CLOCK_MONOTONIC;
}
extern const clockid_t monotonic_clockid = get_monotonic_clockid();
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;
syscall(SYS_clock_gettime, monotonic_clockid, &now);
clock_gettime(CLOCK_MONOTONIC, &now);
return now.tv_sec * 1000000000L + now.tv_nsec;
}
/*
read_cpu_frequency() is modified from source code of glibc.
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
uint64_t read_cpu_frequency(bool* invariant_tsc) {
// 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
......@@ -84,7 +54,7 @@ uint64_t read_cpu_frequency(bool* invariant_tsc) {
return 0;
}
uint64_t result = 0;
int64_t result = 0;
char buf[4096]; // should be enough
const ssize_t n = read(fd, buf, sizeof(buf));
if (n > 0) {
......@@ -129,15 +99,16 @@ uint64_t read_cpu_frequency(bool* invariant_tsc) {
return result;
}
uint64_t read_invariant_cpu_frequency() {
// Return value must be >= 0
int64_t read_invariant_cpu_frequency() {
bool invariant_tsc = false;
const uint64_t freq = read_cpu_frequency(&invariant_tsc);
return (invariant_tsc ? freq : 0);
const int64_t freq = read_cpu_frequency(&invariant_tsc);
if (!invariant_tsc || freq < 0) {
return 0;
}
return freq;
}
extern const uint64_t invariant_cpu_freq = read_invariant_cpu_frequency();
__thread int64_t tls_realtime_ns = 0;
__thread int64_t tls_cpuwidetime_ns = 0;
int64_t invariant_cpu_freq = -1;
} // namespace butil
......@@ -17,8 +17,8 @@
// Measuring time
#ifndef BAIDU_BASE_TIME_H
#define BAIDU_BASE_TIME_H
#ifndef BAIDU_BUTIL_TIME_H
#define BAIDU_BUTIL_TIME_H
#include <time.h> // timespec, clock_gettime
#include <sys/time.h> // timeval, gettimeofday
......@@ -184,7 +184,6 @@ inline timeval seconds_to_timeval(int64_t s) {
// ---------------------------------------------------------------
// Get system-wide monotonic time.
// Cost ~85ns on 2.6.32_1-12-0-0, Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
// ---------------------------------------------------------------
extern int64_t monotonic_time_ns();
......@@ -217,20 +216,30 @@ inline uint64_t clock_cycles() {
// Get cpu-wide (wall-) time.
// Cost ~9ns on Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
// ---------------------------------------------------------------
// note: Inlining shortens time cost per-call for 15ns in a loop of many
// calls to this function.
inline int64_t cpuwide_time_ns() {
extern const uint64_t invariant_cpu_freq; // will be non-zero iff:
extern int64_t read_invariant_cpu_frequency();
// Be positive iff:
// 1 Intel x86_64 CPU (multiple cores) supporting constant_tsc and
// nonstop_tsc(check flags in /proc/cpuinfo)
extern int64_t invariant_cpu_freq;
if (invariant_cpu_freq) {
if (invariant_cpu_freq > 0) {
const uint64_t tsc = detail::clock_cycles();
const uint64_t sec = tsc / invariant_cpu_freq;
// TODO: should be OK until CPU's frequency exceeds 16GHz.
return (tsc - sec * invariant_cpu_freq) * 1000000000L /
invariant_cpu_freq + sec * 1000000000L;
} else if (!invariant_cpu_freq) {
// Lack of necessary features, return system-wide monotonic time instead.
return monotonic_time_ns();
} else {
// Use a thread-unsafe method(OK to us) to initialize the freq
// to save a "if" test comparing to using a local static variable
invariant_cpu_freq = read_invariant_cpu_frequency();
return cpuwide_time_ns();
}
// Lack of necessary features, return system-wide monotonic time instead.
return monotonic_time_ns();
}
inline int64_t cpuwide_time_us() {
......@@ -337,60 +346,6 @@ private:
int64_t _start;
};
// NOTE: Don't call fast_realtime*! they're still experimental.
inline int64_t fast_realtime_ns() {
extern const uint64_t invariant_cpu_freq;
extern __thread int64_t tls_cpuwidetime_ns;
extern __thread int64_t tls_realtime_ns;
if (invariant_cpu_freq) {
// 1 Intel x86_64 CPU (multiple cores) supporting constant_tsc and
// nonstop_tsc(check flags in /proc/cpuinfo)
const uint64_t tsc = detail::clock_cycles();
const uint64_t sec = tsc / invariant_cpu_freq;
// TODO: should be OK until CPU's frequency exceeds 16GHz.
const int64_t diff = (tsc - sec * invariant_cpu_freq) * 1000000000L /
invariant_cpu_freq + sec * 1000000000L - tls_cpuwidetime_ns;
if (__builtin_expect(diff < 10000000, 1)) {
return diff + tls_realtime_ns;
}
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
tls_cpuwidetime_ns += diff;
tls_realtime_ns = timespec_to_nanoseconds(ts);
return tls_realtime_ns;
}
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return timespec_to_nanoseconds(ts);
}
inline int fast_realtime(timespec* ts) {
extern const uint64_t invariant_cpu_freq;
extern __thread int64_t tls_cpuwidetime_ns;
extern __thread int64_t tls_realtime_ns;
if (invariant_cpu_freq) {
const uint64_t tsc = detail::clock_cycles();
const uint64_t sec = tsc / invariant_cpu_freq;
// TODO: should be OK until CPU's frequency exceeds 16GHz.
const int64_t diff = (tsc - sec * invariant_cpu_freq) * 1000000000L /
invariant_cpu_freq + sec * 1000000000L - tls_cpuwidetime_ns;
if (__builtin_expect(diff < 10000000, 1)) {
const int64_t now = diff + tls_realtime_ns;
ts->tv_sec = now / 1000000000L;
ts->tv_nsec = now - ts->tv_sec * 1000000000L;
return 0;
}
const int rc = clock_gettime(CLOCK_REALTIME, ts);
tls_cpuwidetime_ns += diff;
tls_realtime_ns = timespec_to_nanoseconds(*ts);
return rc;
}
return clock_gettime(CLOCK_REALTIME, ts);
}
} // namespace butil
#endif // BAIDU_BASE_TIME_H
#endif // BAIDU_BUTIL_TIME_H
......@@ -9,20 +9,8 @@
#include "butil/macros.h"
#include "butil/logging.h"
namespace butil {
extern const clockid_t monotonic_clockid;
extern const uint64_t invariant_cpu_freq;
}
namespace {
TEST(BaiduTimeTest, cpuwide_time) {
const long t1 = butil::cpuwide_time_us();
usleep(10000);
const long t2 = butil::cpuwide_time_us();
printf("elp=%luus freq=%lu\n", t2-t1, butil::invariant_cpu_freq);
}
TEST(BaiduTimeTest, diff_between_gettimeofday_and_REALTIME) {
long t1 = butil::gettimeofday_us();
timespec time;
......@@ -46,20 +34,6 @@ const char* clock_desc[] = {
"CLOCK_TAI" //11
};
TEST(BaiduTimeTest, fast_realtime) {
for (size_t i = 0; i < 10; ++i) {
long t1 = butil::gettimeofday_us();
timespec time;
clock_gettime(CLOCK_REALTIME, &time);
long t2 = butil::timespec_to_microseconds(time);
butil::fast_realtime(&time);
long t3 = butil::timespec_to_microseconds(time);
long t4 = butil::fast_realtime_ns() / 1000L;
LOG(INFO) << "t1=" << t1 << " t2=" << t2 << " t3=" << t3 << " t4=" << t4;
usleep(7000);
}
}
TEST(BaiduTimeTest, cost_of_timer) {
printf("sizeof(time_t)=%lu\n", sizeof(time_t));
......@@ -90,25 +64,24 @@ TEST(BaiduTimeTest, cost_of_timer) {
t1.start();
for (size_t i = 0; i < N; ++i) {
s += butil::fast_realtime_ns();
s += butil::gettimeofday_us();
}
t1.stop();
printf("fast_realtime_ns takes %luns\n", t1.n_elapsed() / N);
printf("gettimeofday_us takes %luns\n", t1.n_elapsed() / N);
t1.start();
for (size_t i = 0; i < N; ++i) {
s += butil::gettimeofday_us();
time(NULL);
}
t1.stop();
printf("gettimeofday_us takes %luns\n", t1.n_elapsed() / N);
printf("time(NULL) takes %luns\n", t1.n_elapsed() / N);
t1.start();
for (size_t i = 0; i < N; ++i) {
timespec ts2;
butil::fast_realtime(&ts2);
s += butil::monotonic_time_ns();
}
t1.stop();
printf("fast_realtime takes %luns\n", t1.n_elapsed() / N);
printf("monotonic_time_ns takes %luns\n", t1.n_elapsed() / N);
for (size_t i = 0; i < arraysize(clock_desc); ++i) {
if (0 == syscall(SYS_clock_gettime, (clockid_t)i, &ts)) {
......@@ -130,13 +103,6 @@ TEST(BaiduTimeTest, cost_of_timer) {
clock_desc[i], t1.n_elapsed() / N);
}
}
t1.start();
for (size_t i = 0; i < N; ++i) {
time(NULL);
}
t1.stop();
printf("time(NULL) takes %luns\n", t1.n_elapsed() / N);
}
TEST(BaiduTimeTest, timespec) {
......@@ -209,7 +175,8 @@ TEST(BaiduTimeTest, every_many_us) {
const long start_time = butil::gettimeofday_ms();
while (1) {
if (every_10ms) {
printf("enter this branch at %lums\n", butil::gettimeofday_ms() - start_time);
printf("enter this branch at %lums\n",
butil::gettimeofday_ms() - start_time);
if (++i >= 10) {
break;
}
......@@ -217,13 +184,6 @@ TEST(BaiduTimeTest, every_many_us) {
}
}
TEST(BaiduTimeTest, monotonic_time) {
const long t1 = butil::monotonic_time_ms();
usleep(10000L);
const long t2 = butil::monotonic_time_ms();
printf("clockid=%d %lums\n", butil::monotonic_clockid, t2-t1);
}
TEST(BaiduTimeTest, timer_auto_start) {
butil::Timer t(butil::Timer::STARTED);
usleep(100);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment