Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
B
brpc
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
brpc
Commits
28ed8fd4
Unverified
Commit
28ed8fd4
authored
Sep 29, 2018
by
Ge Jun
Committed by
GitHub
Sep 29, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #497 from PeterRK/bug-fix
fix read_invariant_cpu_frequency
parents
8ac2d8d9
aed68f46
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
139 additions
and
43 deletions
+139
-43
time.cpp
src/butil/time.cpp
+132
-38
time.h
src/butil/time.h
+7
-5
No files found.
src/butil/time.cpp
View file @
28ed8fd4
...
...
@@ -25,6 +25,7 @@
#endif
#include <string.h> // memmem
#undef _GNU_SOURCE
#include <ctype.h>
#include "butil/time.h"
...
...
@@ -81,8 +82,7 @@ int64_t monotonic_time_ns() {
namespace
detail
{
// read_cpu_frequency() is modified from source code of glibc.
int64_t
read_cpu_frequency
(
bool
*
invariant_tsc
)
{
static
int64_t
read_cpu_current_frequency
(
char
*
buf
,
ssize_t
n
)
{
/* We read the information from the /proc filesystem. It contains at
least one line like
cpu MHz : 497.840237
...
...
@@ -90,54 +90,148 @@ int64_t read_cpu_frequency(bool* invariant_tsc) {
cpu MHz : 497.841
We search for this line and convert the number in an integer. */
int64_t
result
=
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
;
}
}
return
result
;
}
#if defined(__x86_64__) || defined(__i386__)
#if defined(__pic__) && defined(__i386__)
static
void
__cpuid
(
uint32_t
reg
[
4
],
uint32_t
code
)
{
__asm__
volatile
(
"mov %%ebx, %%edi
\n
"
"cpuid
\n
"
"xchg %%edi, %%ebx
\n
"
:
"=a"
(
reg
[
0
]),
"=D"
(
reg
[
1
]),
"=c"
(
reg
[
2
]),
"=d"
(
reg
[
3
])
:
"a"
(
code
)
);
}
#else
static
void
__cpuid
(
uint32_t
reg
[
4
],
uint32_t
code
)
{
__asm__
volatile
(
"cpuid
\n\t
"
:
"=a"
(
reg
[
0
]),
"=b"
(
reg
[
1
]),
"=c"
(
reg
[
2
]),
"=d"
(
reg
[
3
])
:
"a"
(
code
)
);
}
#endif
#endif
static
int64_t
read_cpu_frequency_by_cpuid
()
{
int64_t
result
=
0
;
#if defined(__x86_64__) || defined(__i386__)
uint32_t
reg
[
4
];
__cpuid
(
reg
,
0
);
if
(
reg
[
0
]
>=
0x16
&&
reg
[
1
]
==
0x756e6547
&&
reg
[
2
]
==
0x6c65746e
&&
reg
[
3
]
==
0x49656e69
)
{
//Intel CPU only
__cpuid
(
reg
,
0x16
);
return
static_cast
<
uint64_t
>
(
reg
[
0
])
*
1000000UL
;
}
#endif
return
result
;
}
static
int64_t
read_cpu_frequency_from_brand_string
()
{
int64_t
result
=
0
;
#if defined(__x86_64__) || defined(__i386__)
union
{
char
brand
[
48
];
uint32_t
reg
[
12
];
}
buf
;
__cpuid
(
buf
.
reg
,
0x80000000
);
if
(
buf
.
reg
[
0
]
<
0x80000004
)
{
return
0
;
}
__cpuid
(
buf
.
reg
,
0x80000002
);
__cpuid
(
buf
.
reg
+
4
,
0x80000003
);
__cpuid
(
buf
.
reg
+
8
,
0x80000004
);
//Get something like: Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHz
char
*
end
=
buf
.
brand
+
sizeof
(
buf
.
brand
);
char
*
p
=
buf
.
brand
;
while
(
p
!=
end
&&
*
p
!=
'@'
)
{
if
(
*
p
++
==
'\n'
)
{
return
0
;
}
}
while
(
p
!=
end
&&
!
isdigit
(
*
p
))
{
p
++
;
}
//expect x.xxGhz
//FSB may be 0.10GHz or 0.133...GHz
if
(
end
-
p
<
7
||
p
[
1
]
!=
'.'
||
!
isdigit
(
p
[
2
])
||
!
isdigit
(
p
[
3
])
||
p
[
4
]
!=
'G'
)
{
return
0
;
}
result
=
(
p
[
0
]
-
'0'
)
*
10
+
(
p
[
2
]
-
'0'
);
int64_t
last
=
p
[
3
]
-
'0'
;
if
(
last
==
7
)
{
last
=
6
;
}
for
(
int
i
=
0
;
i
<
8
;
i
++
)
{
result
=
result
*
10
+
last
;
}
#endif
return
result
;
}
// read_cpu_frequency() is modified from source code of glibc.
int64_t
read_cpu_frequency
(
bool
*
invariant_tsc
)
{
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
;
close
(
fd
);
if
(
n
<=
0
)
{
return
0
;
}
/* Search for the beginning of the string. */
while
(
mhz
<
endp
&&
(
*
mhz
<
'0'
||
*
mhz
>
'9'
)
&&
*
mhz
!=
'\n'
)
{
++
mhz
;
if
(
invariant_tsc
)
{
char
*
flags_pos
=
static_cast
<
char
*>
(
memmem
(
buf
,
n
,
"flags"
,
5
));
if
(
flags_pos
&&
memmem
(
flags_pos
,
buf
+
n
-
flags_pos
,
"constant_tsc"
,
12
)
&&
memmem
(
flags_pos
,
buf
+
n
-
flags_pos
,
"nonstop_tsc"
,
11
))
{
int64_t
result
=
read_cpu_frequency_by_cpuid
();
if
(
result
<=
0
)
{
result
=
read_cpu_frequency_from_brand_string
();
}
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
;
if
(
result
>
0
)
{
*
invariant_tsc
=
true
;
return
result
;
}
/* 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
));
}
//current frequency is usually not invariant
*
invariant_tsc
=
false
;
}
close
(
fd
);
return
result
;
return
read_cpu_current_frequency
(
buf
,
n
);
}
// Return value must be >= 0
...
...
src/butil/time.h
View file @
28ed8fd4
...
...
@@ -236,13 +236,15 @@ extern int64_t invariant_cpu_freq;
// note: Inlining shortens time cost per-call for 15ns in a loop of many
// calls to this function.
inline
int64_t
cpuwide_time_ns
()
{
if
(
detail
::
invariant_cpu_freq
>
0
)
{
int64_t
cpu_freq
=
detail
::
invariant_cpu_freq
;
if
(
cpu_freq
>
0
)
{
const
uint64_t
tsc
=
detail
::
clock_cycles
();
const
uint64_t
sec
=
tsc
/
detail
::
invariant_cpu_freq
;
//Try to avoid overflow
const
uint64_t
sec
=
tsc
/
cpu_freq
;
const
uint64_t
remain
=
tsc
%
cpu_freq
;
// TODO: should be OK until CPU's frequency exceeds 16GHz.
return
(
tsc
-
sec
*
detail
::
invariant_cpu_freq
)
*
1000000000L
/
detail
::
invariant_cpu_freq
+
sec
*
1000000000L
;
}
else
if
(
!
detail
::
invariant_cpu_freq
)
{
return
remain
*
1000000000L
/
cpu_freq
+
sec
*
1000000000L
;
}
else
if
(
!
cpu_freq
)
{
// Lack of necessary features, return system-wide monotonic time instead.
return
monotonic_time_ns
();
}
else
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment