@@ -260,10 +260,25 @@ static const uint64_t IN_TX = 1ULL << 32;
260260static const uint64_t IN_TXCP = 1ULL << 33 ;
261261
262262static int64_t read_counter (ScopedFd& fd) {
263- int64_t val;
264- ssize_t nread = read (fd, &val, sizeof (val));
265- DEBUG_ASSERT (nread == sizeof (val));
266- return val;
263+ struct read_format {
264+ int64_t value;
265+ int64_t time_enabled;
266+ int64_t time_running;
267+ } data;
268+ errno = 0 ;
269+ ssize_t nread = read (fd, &data, sizeof (data));
270+ if (nread < 0 ) {
271+ FATAL () << " Failed to read counter" ;
272+ }
273+ DEBUG_ASSERT (nread == sizeof (data));
274+ if (data.time_enabled != data.time_running ) {
275+ FATAL ()
276+ << " \n Counter was multiplexed to a ratio of "
277+ << (data.time_running * 1.0 / data.time_enabled )
278+ << " .\n Check that other software is not using performance counters on\n "
279+ " this CPU." ;
280+ }
281+ return data.value ;
267282}
268283
269284static ScopedFd start_counter (pid_t tid, int group_fd,
@@ -272,11 +287,14 @@ static ScopedFd start_counter(pid_t tid, int group_fd,
272287 if (disabled_txcp) {
273288 *disabled_txcp = false ;
274289 }
290+ struct perf_event_attr tmp_attr = *attr;
291+ // Needed to detect when the kernel is multiplexing counters.
292+ tmp_attr.read_format =
293+ PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
275294 int fd = syscall (__NR_perf_event_open, attr, tid, -1 , group_fd, 0 );
276295 if (0 > fd && errno == EINVAL && attr->type == PERF_TYPE_RAW &&
277296 (attr->config & IN_TXCP)) {
278297 // The kernel might not support IN_TXCP, so try again without it.
279- struct perf_event_attr tmp_attr = *attr;
280298 tmp_attr.config &= ~IN_TXCP;
281299 fd = syscall (__NR_perf_event_open, &tmp_attr, tid, -1 , group_fd, 0 );
282300 if (fd >= 0 ) {
0 commit comments