PageRenderTime 57ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/src/PerfCounters.cc

https://github.com/mozilla/rr
C++ | 658 lines | 517 code | 67 blank | 74 comment | 100 complexity | 560a4b61b2cc3a37bbcfa5345f56afa0 MD5 | raw file
  1. /* -*- Mode: C++; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
  2. #include "PerfCounters.h"
  3. #include <err.h>
  4. #include <fcntl.h>
  5. #include <linux/perf_event.h>
  6. #include <poll.h>
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <sys/ioctl.h>
  11. #include <sys/syscall.h>
  12. #include <sys/types.h>
  13. #include <unistd.h>
  14. #include <algorithm>
  15. #include <string>
  16. #include "Flags.h"
  17. #include "Session.h"
  18. #include "Task.h"
  19. #include "core.h"
  20. #include "kernel_metadata.h"
  21. #include "log.h"
  22. #include "util.h"
  23. using namespace std;
  24. namespace rr {
  25. #define PERF_COUNT_RR 0x72727272L
  26. static bool attributes_initialized;
  27. // At some point we might support multiple kinds of ticks for the same CPU arch.
  28. // At that point this will need to become more complicated.
  29. static struct perf_event_attr ticks_attr;
  30. static struct perf_event_attr minus_ticks_attr;
  31. static struct perf_event_attr cycles_attr;
  32. static struct perf_event_attr hw_interrupts_attr;
  33. static struct perf_event_attr llsc_fail_attr;
  34. static uint32_t pmu_flags;
  35. static uint32_t skid_size;
  36. static bool has_ioc_period_bug;
  37. static bool only_one_counter;
  38. static bool activate_useless_counter;
  39. /*
  40. * Find out the cpu model using the cpuid instruction.
  41. * Full list of CPUIDs at http://sandpile.org/x86/cpuid.htm
  42. * Another list at
  43. * http://software.intel.com/en-us/articles/intel-architecture-and-processor-identification-with-cpuid-model-and-family-numbers
  44. */
  45. enum CpuMicroarch {
  46. UnknownCpu,
  47. FirstIntel,
  48. IntelMerom = FirstIntel,
  49. IntelPenryn,
  50. IntelNehalem,
  51. IntelWestmere,
  52. IntelSandyBridge,
  53. IntelIvyBridge,
  54. IntelHaswell,
  55. IntelBroadwell,
  56. IntelSkylake,
  57. IntelSilvermont,
  58. IntelGoldmont,
  59. IntelKabylake,
  60. IntelCometlake,
  61. IntelIcelake,
  62. IntelTigerlake,
  63. IntelRocketlake,
  64. IntelAlderlake,
  65. LastIntel = IntelAlderlake,
  66. FirstAMD,
  67. AMDF15R30 = FirstAMD,
  68. AMDZen,
  69. LastAMD = AMDZen,
  70. FirstARM,
  71. ARMNeoverseN1 = FirstARM,
  72. LastARM = ARMNeoverseN1,
  73. };
  74. /*
  75. * Set if this CPU supports ticks counting retired conditional branches.
  76. */
  77. #define PMU_TICKS_RCB (1<<0)
  78. /*
  79. * Some CPUs turn off the whole PMU when there are no remaining events
  80. * scheduled (perhaps as a power consumption optimization). This can be a
  81. * very expensive operation, and is thus best avoided. For cpus, where this
  82. * is a problem, we keep a cycles counter (which corresponds to one of the
  83. * fixed function counters, so we don't use up a programmable PMC) that we
  84. * don't otherwise use, but keeps the PMU active, greatly increasing
  85. * performance.
  86. */
  87. #define PMU_BENEFITS_FROM_USELESS_COUNTER (1<<1)
  88. /*
  89. * Set if this CPU supports ticks counting all taken branches
  90. * (excluding interrupts, far branches, and rets).
  91. */
  92. #define PMU_TICKS_TAKEN_BRANCHES (1<<3)
  93. struct PmuConfig {
  94. CpuMicroarch uarch;
  95. const char* name;
  96. unsigned rcb_cntr_event;
  97. unsigned minus_ticks_cntr_event;
  98. unsigned hw_intr_cntr_event;
  99. unsigned llsc_cntr_event;
  100. uint32_t skid_size;
  101. uint32_t flags;
  102. };
  103. // XXX please only edit this if you really know what you're doing.
  104. // event = 0x5101c4:
  105. // - 51 = generic PMU
  106. // - 01 = umask for event BR_INST_RETIRED.CONDITIONAL
  107. // - c4 = eventsel for event BR_INST_RETIRED.CONDITIONAL
  108. // event = 0x5301cb:
  109. // - 51 = generic PMU
  110. // - 01 = umask for event HW_INTERRUPTS.RECEIVED
  111. // - cb = eventsel for event HW_INTERRUPTS.RECEIVED
  112. // See Intel 64 and IA32 Architectures Performance Monitoring Events.
  113. // See check_events from libpfm4.
  114. static const PmuConfig pmu_configs[] = {
  115. { IntelAlderlake, "Intel Alderlake", 0x5111c4, 0, 0, 0, 100, PMU_TICKS_RCB },
  116. { IntelRocketlake, "Intel Rocketlake", 0x5111c4, 0, 0, 0, 100, PMU_TICKS_RCB },
  117. { IntelTigerlake, "Intel Tigerlake", 0x5111c4, 0, 0, 0, 100, PMU_TICKS_RCB },
  118. { IntelIcelake, "Intel Icelake", 0x5111c4, 0, 0, 0, 100, PMU_TICKS_RCB },
  119. { IntelCometlake, "Intel Cometlake", 0x5101c4, 0, 0x5301cb, 0, 100, PMU_TICKS_RCB },
  120. { IntelKabylake, "Intel Kabylake", 0x5101c4, 0, 0x5301cb, 0, 100, PMU_TICKS_RCB },
  121. { IntelSilvermont, "Intel Silvermont", 0x517ec4, 0, 0x5301cb, 0, 100, PMU_TICKS_RCB },
  122. { IntelGoldmont, "Intel Goldmont", 0x517ec4, 0, 0x5301cb, 0, 100, PMU_TICKS_RCB },
  123. { IntelSkylake, "Intel Skylake", 0x5101c4, 0, 0x5301cb, 0, 100, PMU_TICKS_RCB },
  124. { IntelBroadwell, "Intel Broadwell", 0x5101c4, 0, 0x5301cb, 0, 100, PMU_TICKS_RCB },
  125. { IntelHaswell, "Intel Haswell", 0x5101c4, 0, 0x5301cb, 0, 100, PMU_TICKS_RCB },
  126. { IntelIvyBridge, "Intel Ivy Bridge", 0x5101c4, 0, 0x5301cb, 0, 100, PMU_TICKS_RCB },
  127. { IntelSandyBridge, "Intel Sandy Bridge", 0x5101c4, 0, 0x5301cb, 0, 100, PMU_TICKS_RCB },
  128. { IntelNehalem, "Intel Nehalem", 0x5101c4, 0, 0x50011d, 0, 100, PMU_TICKS_RCB },
  129. { IntelWestmere, "Intel Westmere", 0x5101c4, 0, 0x50011d, 0, 100, PMU_TICKS_RCB },
  130. { IntelPenryn, "Intel Penryn", 0, 0, 0, 0, 100, 0 },
  131. { IntelMerom, "Intel Merom", 0, 0, 0, 0, 100, 0 },
  132. { AMDF15R30, "AMD Family 15h Revision 30h", 0xc4, 0xc6, 0, 0, 250, PMU_TICKS_TAKEN_BRANCHES },
  133. // 0xd1 == RETIRED_CONDITIONAL_BRANCH_INSTRUCTIONS - Number of retired conditional branch instructions
  134. // 0x2c == INTERRUPT_TAKEN - Counts the number of interrupts taken
  135. // Both counters are available on Zen, Zen+ and Zen2.
  136. { AMDZen, "AMD Zen", 0x5100d1, 0, 0x51002c, 0, 10000, PMU_TICKS_RCB },
  137. // 0x21 == BR_RETIRED - Architecturally retired taken branches
  138. // 0x6F == STREX_SPEC - Speculatively executed strex instructions
  139. { ARMNeoverseN1, "ARM Neoverse N1", 0x21, 0, 0, 0x6F, 1000, PMU_TICKS_TAKEN_BRANCHES }
  140. };
  141. #define RR_SKID_MAX 10000
  142. static string lowercase(const string& s) {
  143. string c = s;
  144. transform(c.begin(), c.end(), c.begin(), ::tolower);
  145. return c;
  146. }
  147. static void init_perf_event_attr(struct perf_event_attr* attr,
  148. perf_type_id type, unsigned config) {
  149. memset(attr, 0, sizeof(*attr));
  150. attr->type = type;
  151. attr->size = sizeof(*attr);
  152. attr->config = config;
  153. // rr requires that its events count userspace tracee code
  154. // only.
  155. attr->exclude_kernel = 1;
  156. attr->exclude_guest = 1;
  157. }
  158. static const uint64_t IN_TX = 1ULL << 32;
  159. static const uint64_t IN_TXCP = 1ULL << 33;
  160. static int64_t read_counter(ScopedFd& fd) {
  161. int64_t val;
  162. ssize_t nread = read(fd, &val, sizeof(val));
  163. DEBUG_ASSERT(nread == sizeof(val));
  164. return val;
  165. }
  166. static ScopedFd start_counter(pid_t tid, int group_fd,
  167. struct perf_event_attr* attr,
  168. bool* disabled_txcp = nullptr) {
  169. if (disabled_txcp) {
  170. *disabled_txcp = false;
  171. }
  172. attr->pinned = group_fd == -1;
  173. int fd = syscall(__NR_perf_event_open, attr, tid, -1, group_fd, PERF_FLAG_FD_CLOEXEC);
  174. if (0 >= fd && errno == EINVAL && attr->type == PERF_TYPE_RAW &&
  175. (attr->config & IN_TXCP)) {
  176. // The kernel might not support IN_TXCP, so try again without it.
  177. struct perf_event_attr tmp_attr = *attr;
  178. tmp_attr.config &= ~IN_TXCP;
  179. fd = syscall(__NR_perf_event_open, &tmp_attr, tid, -1, group_fd, PERF_FLAG_FD_CLOEXEC);
  180. if (fd >= 0) {
  181. if (disabled_txcp) {
  182. *disabled_txcp = true;
  183. }
  184. LOG(warn) << "kernel does not support IN_TXCP";
  185. if ((cpuid(CPUID_GETEXTENDEDFEATURES, 0).ebx & HLE_FEATURE_FLAG) &&
  186. !Flags::get().suppress_environment_warnings) {
  187. fprintf(stderr,
  188. "Your CPU supports Hardware Lock Elision but your kernel does\n"
  189. "not support setting the IN_TXCP PMU flag. Record and replay\n"
  190. "of code that uses HLE will fail unless you update your\n"
  191. "kernel.\n");
  192. }
  193. }
  194. }
  195. if (0 >= fd) {
  196. if (errno == EACCES) {
  197. CLEAN_FATAL() << "Permission denied to use 'perf_event_open'; are hardware perf events "
  198. "available? See https://github.com/rr-debugger/rr/wiki/Will-rr-work-on-my-system";
  199. }
  200. if (errno == ENOENT) {
  201. CLEAN_FATAL() << "Unable to open performance counter with 'perf_event_open'; "
  202. "are hardware perf events available? See https://github.com/rr-debugger/rr/wiki/Will-rr-work-on-my-system";
  203. }
  204. FATAL() << "Failed to initialize counter";
  205. }
  206. return fd;
  207. }
  208. static void check_for_ioc_period_bug() {
  209. // Start a cycles counter
  210. struct perf_event_attr attr = rr::ticks_attr;
  211. attr.sample_period = 0xffffffff;
  212. attr.exclude_kernel = 1;
  213. ScopedFd bug_fd = start_counter(0, -1, &attr);
  214. uint64_t new_period = 1;
  215. if (ioctl(bug_fd, PERF_EVENT_IOC_PERIOD, &new_period)) {
  216. FATAL() << "ioctl(PERF_EVENT_IOC_PERIOD) failed";
  217. }
  218. struct pollfd poll_bug_fd = {.fd = bug_fd, .events = POLL_IN, .revents = 0 };
  219. poll(&poll_bug_fd, 1, 0);
  220. has_ioc_period_bug = poll_bug_fd.revents == 0;
  221. LOG(debug) << "has_ioc_period_bug=" << has_ioc_period_bug;
  222. }
  223. static const int NUM_BRANCHES = 500;
  224. volatile uint32_t accumulator_sink = 0;
  225. static void do_branches() {
  226. // Do NUM_BRANCHES conditional branches that can't be optimized out.
  227. // 'accumulator' is always odd and can't be zero
  228. uint32_t accumulator = uint32_t(rand()) * 2 + 1;
  229. for (int i = 0; i < NUM_BRANCHES && accumulator; ++i) {
  230. accumulator = ((accumulator * 7) + 2) & 0xffffff;
  231. }
  232. // Use 'accumulator' so it can't be optimized out.
  233. accumulator_sink = accumulator;
  234. }
  235. // Architecture specific detection code
  236. #if defined(__i386__) || defined(__x86_64__)
  237. #include "PerfCounters_x86.h"
  238. #elif defined(__aarch64__)
  239. #include "PerfCounters_aarch64.h"
  240. #else
  241. #error Must define microarchitecture detection code for this architecture
  242. #endif
  243. static void check_working_counters() {
  244. struct perf_event_attr attr = rr::ticks_attr;
  245. attr.sample_period = 0;
  246. struct perf_event_attr attr2 = rr::cycles_attr;
  247. attr.sample_period = 0;
  248. ScopedFd fd = start_counter(0, -1, &attr);
  249. ScopedFd fd2 = start_counter(0, -1, &attr2);
  250. do_branches();
  251. int64_t events = read_counter(fd);
  252. int64_t events2 = read_counter(fd2);
  253. if (events < NUM_BRANCHES) {
  254. char config[100];
  255. sprintf(config, "%llx", (long long)ticks_attr.config);
  256. FATAL()
  257. << "\nGot " << events << " branch events, expected at least "
  258. << NUM_BRANCHES
  259. << ".\n"
  260. "\nThe hardware performance counter seems to not be working. Check\n"
  261. "that hardware performance counters are working by running\n"
  262. " perf stat -e r"
  263. << config
  264. << " true\n"
  265. "and checking that it reports a nonzero number of events.\n"
  266. "If performance counters seem to be working with 'perf', file an\n"
  267. "rr issue, otherwise check your hardware/OS/VM configuration. Also\n"
  268. "check that other software is not using performance counters on\n"
  269. "this CPU.";
  270. }
  271. only_one_counter = events2 == 0;
  272. LOG(debug) << "only_one_counter=" << only_one_counter;
  273. if (only_one_counter) {
  274. arch_check_restricted_counter();
  275. }
  276. }
  277. static void check_for_bugs(CpuMicroarch uarch) {
  278. if (running_under_rr()) {
  279. // Under rr we emulate idealized performance counters, so we can assume
  280. // none of the bugs apply.
  281. return;
  282. }
  283. check_for_ioc_period_bug();
  284. check_working_counters();
  285. check_for_arch_bugs(uarch);
  286. }
  287. static CpuMicroarch get_cpu_microarch() {
  288. string forced_uarch = lowercase(Flags::get().forced_uarch);
  289. if (!forced_uarch.empty()) {
  290. for (size_t i = 0; i < array_length(pmu_configs); ++i) {
  291. const PmuConfig& pmu = pmu_configs[i];
  292. string name = lowercase(pmu.name);
  293. if (name.npos != name.find(forced_uarch)) {
  294. LOG(info) << "Using forced uarch " << pmu.name;
  295. return pmu.uarch;
  296. }
  297. }
  298. CLEAN_FATAL() << "Forced uarch " << Flags::get().forced_uarch
  299. << " isn't known.";
  300. }
  301. return compute_cpu_microarch();
  302. }
  303. static void init_attributes() {
  304. if (attributes_initialized) {
  305. return;
  306. }
  307. attributes_initialized = true;
  308. CpuMicroarch uarch = get_cpu_microarch();
  309. const PmuConfig* pmu = nullptr;
  310. for (size_t i = 0; i < array_length(pmu_configs); ++i) {
  311. if (uarch == pmu_configs[i].uarch) {
  312. pmu = &pmu_configs[i];
  313. break;
  314. }
  315. }
  316. DEBUG_ASSERT(pmu);
  317. if (!(pmu->flags & (PMU_TICKS_RCB | PMU_TICKS_TAKEN_BRANCHES))) {
  318. FATAL() << "Microarchitecture `" << pmu->name << "' currently unsupported.";
  319. }
  320. if (running_under_rr()) {
  321. init_perf_event_attr(&ticks_attr, PERF_TYPE_HARDWARE, PERF_COUNT_RR);
  322. skid_size = RR_SKID_MAX;
  323. pmu_flags = pmu->flags & (PMU_TICKS_RCB | PMU_TICKS_TAKEN_BRANCHES);
  324. } else {
  325. skid_size = pmu->skid_size;
  326. pmu_flags = pmu->flags;
  327. init_perf_event_attr(&ticks_attr, PERF_TYPE_RAW, pmu->rcb_cntr_event);
  328. if (pmu->minus_ticks_cntr_event != 0) {
  329. init_perf_event_attr(&minus_ticks_attr, PERF_TYPE_RAW,
  330. pmu->minus_ticks_cntr_event);
  331. }
  332. init_perf_event_attr(&cycles_attr, PERF_TYPE_HARDWARE,
  333. PERF_COUNT_HW_CPU_CYCLES);
  334. init_perf_event_attr(&hw_interrupts_attr, PERF_TYPE_RAW,
  335. pmu->hw_intr_cntr_event);
  336. init_perf_event_attr(&llsc_fail_attr, PERF_TYPE_RAW,
  337. pmu->llsc_cntr_event);
  338. // libpfm encodes the event with this bit set, so we'll do the
  339. // same thing. Unclear if necessary.
  340. hw_interrupts_attr.exclude_hv = 1;
  341. check_for_bugs(uarch);
  342. /*
  343. * For maintainability, and since it doesn't impact performance when not
  344. * needed, we always activate this. If it ever turns out to be a problem,
  345. * this can be set to pmu->flags & PMU_BENEFITS_FROM_USELESS_COUNTER,
  346. * instead.
  347. *
  348. * We also disable this counter when running under rr. Even though it's the
  349. * same event for the same task as the outer rr, the linux kernel does not
  350. * coalesce them and tries to schedule the new one on a general purpose PMC.
  351. * On CPUs with only 2 general PMCs (e.g. KNL), we'd run out.
  352. */
  353. activate_useless_counter = has_ioc_period_bug && !running_under_rr();
  354. }
  355. }
  356. bool PerfCounters::is_rr_ticks_attr(const perf_event_attr& attr) {
  357. return attr.type == PERF_TYPE_HARDWARE && attr.config == PERF_COUNT_RR;
  358. }
  359. bool PerfCounters::supports_ticks_semantics(TicksSemantics ticks_semantics) {
  360. init_attributes();
  361. switch (ticks_semantics) {
  362. case TICKS_RETIRED_CONDITIONAL_BRANCHES:
  363. return (pmu_flags & PMU_TICKS_RCB) != 0;
  364. case TICKS_TAKEN_BRANCHES:
  365. return (pmu_flags & PMU_TICKS_TAKEN_BRANCHES) != 0;
  366. default:
  367. FATAL() << "Unknown ticks_semantics " << ticks_semantics;
  368. return false;
  369. }
  370. }
  371. TicksSemantics PerfCounters::default_ticks_semantics() {
  372. init_attributes();
  373. if (pmu_flags & PMU_TICKS_TAKEN_BRANCHES) {
  374. return TICKS_TAKEN_BRANCHES;
  375. }
  376. if (pmu_flags & PMU_TICKS_RCB) {
  377. return TICKS_RETIRED_CONDITIONAL_BRANCHES;
  378. }
  379. FATAL() << "Unsupported architecture";
  380. return TICKS_TAKEN_BRANCHES;
  381. }
  382. uint32_t PerfCounters::skid_size() {
  383. init_attributes();
  384. return rr::skid_size;
  385. }
  386. PerfCounters::PerfCounters(pid_t tid, TicksSemantics ticks_semantics)
  387. : tid(tid), ticks_semantics_(ticks_semantics), started(false), counting(false) {
  388. if (!supports_ticks_semantics(ticks_semantics)) {
  389. FATAL() << "Ticks semantics " << ticks_semantics << " not supported";
  390. }
  391. }
  392. static void make_counter_async(ScopedFd& fd, int signal) {
  393. if (fcntl(fd, F_SETFL, O_ASYNC) || fcntl(fd, F_SETSIG, signal)) {
  394. FATAL() << "Failed to make ticks counter ASYNC with sig"
  395. << signal_name(signal);
  396. }
  397. }
  398. void PerfCounters::reset(Ticks ticks_period) {
  399. DEBUG_ASSERT(ticks_period >= 0);
  400. if (ticks_period == 0 && !always_recreate_counters()) {
  401. // We can't switch a counter between sampling and non-sampling via
  402. // PERF_EVENT_IOC_PERIOD so just turn 0 into a very big number.
  403. ticks_period = uint64_t(1) << 60;
  404. }
  405. if (!started) {
  406. LOG(debug) << "Recreating counters with period " << ticks_period;
  407. struct perf_event_attr attr = rr::ticks_attr;
  408. struct perf_event_attr minus_attr = rr::minus_ticks_attr;
  409. attr.sample_period = ticks_period;
  410. fd_ticks_interrupt = start_counter(tid, -1, &attr);
  411. if (minus_attr.config != 0) {
  412. fd_minus_ticks_measure = start_counter(tid, fd_ticks_interrupt, &minus_attr);
  413. }
  414. if (!only_one_counter && !running_under_rr()) {
  415. reset_arch_extras<NativeArch>();
  416. }
  417. if (activate_useless_counter && !fd_useless_counter.is_open()) {
  418. // N.B.: This is deliberately not in the same group as the other counters
  419. // since we want to keep it scheduled at all times.
  420. fd_useless_counter = start_counter(tid, -1, &cycles_attr);
  421. }
  422. struct f_owner_ex own;
  423. own.type = F_OWNER_TID;
  424. own.pid = tid;
  425. if (fcntl(fd_ticks_interrupt, F_SETOWN_EX, &own)) {
  426. FATAL() << "Failed to SETOWN_EX ticks event fd";
  427. }
  428. make_counter_async(fd_ticks_interrupt, PerfCounters::TIME_SLICE_SIGNAL);
  429. } else {
  430. LOG(debug) << "Resetting counters with period " << ticks_period;
  431. if (ioctl(fd_ticks_interrupt, PERF_EVENT_IOC_RESET, 0)) {
  432. FATAL() << "ioctl(PERF_EVENT_IOC_RESET) failed";
  433. }
  434. if (ioctl(fd_ticks_interrupt, PERF_EVENT_IOC_PERIOD, &ticks_period)) {
  435. FATAL() << "ioctl(PERF_EVENT_IOC_PERIOD) failed with period "
  436. << ticks_period;
  437. }
  438. if (ioctl(fd_ticks_interrupt, PERF_EVENT_IOC_ENABLE, 0)) {
  439. FATAL() << "ioctl(PERF_EVENT_IOC_ENABLE) failed";
  440. }
  441. if (fd_minus_ticks_measure.is_open()) {
  442. if (ioctl(fd_minus_ticks_measure, PERF_EVENT_IOC_RESET, 0)) {
  443. FATAL() << "ioctl(PERF_EVENT_IOC_RESET) failed";
  444. }
  445. if (ioctl(fd_minus_ticks_measure, PERF_EVENT_IOC_ENABLE, 0)) {
  446. FATAL() << "ioctl(PERF_EVENT_IOC_ENABLE) failed";
  447. }
  448. }
  449. if (fd_ticks_measure.is_open()) {
  450. if (ioctl(fd_ticks_measure, PERF_EVENT_IOC_RESET, 0)) {
  451. FATAL() << "ioctl(PERF_EVENT_IOC_RESET) failed";
  452. }
  453. if (ioctl(fd_ticks_measure, PERF_EVENT_IOC_ENABLE, 0)) {
  454. FATAL() << "ioctl(PERF_EVENT_IOC_ENABLE) failed";
  455. }
  456. }
  457. if (fd_ticks_in_transaction.is_open()) {
  458. if (ioctl(fd_ticks_in_transaction, PERF_EVENT_IOC_RESET, 0)) {
  459. FATAL() << "ioctl(PERF_EVENT_IOC_RESET) failed";
  460. }
  461. if (ioctl(fd_ticks_in_transaction, PERF_EVENT_IOC_ENABLE, 0)) {
  462. FATAL() << "ioctl(PERF_EVENT_IOC_ENABLE) failed";
  463. }
  464. }
  465. }
  466. started = true;
  467. counting = true;
  468. counting_period = ticks_period;
  469. }
  470. void PerfCounters::set_tid(pid_t tid) {
  471. stop();
  472. this->tid = tid;
  473. }
  474. void PerfCounters::stop() {
  475. if (!started) {
  476. return;
  477. }
  478. started = false;
  479. fd_ticks_interrupt.close();
  480. fd_ticks_measure.close();
  481. fd_minus_ticks_measure.close();
  482. fd_useless_counter.close();
  483. fd_ticks_in_transaction.close();
  484. }
  485. void PerfCounters::stop_counting() {
  486. if (!counting) {
  487. return;
  488. }
  489. counting = false;
  490. if (always_recreate_counters()) {
  491. stop();
  492. } else {
  493. ioctl(fd_ticks_interrupt, PERF_EVENT_IOC_DISABLE, 0);
  494. if (fd_minus_ticks_measure.is_open()) {
  495. ioctl(fd_minus_ticks_measure, PERF_EVENT_IOC_DISABLE, 0);
  496. }
  497. if (fd_ticks_measure.is_open()) {
  498. ioctl(fd_ticks_measure, PERF_EVENT_IOC_DISABLE, 0);
  499. }
  500. if (fd_ticks_in_transaction.is_open()) {
  501. ioctl(fd_ticks_in_transaction, PERF_EVENT_IOC_DISABLE, 0);
  502. }
  503. }
  504. }
  505. Ticks PerfCounters::ticks_for_unconditional_indirect_branch(Task*) {
  506. return (pmu_flags & PMU_TICKS_TAKEN_BRANCHES) ? 1 : 0;
  507. }
  508. Ticks PerfCounters::ticks_for_direct_call(Task*) {
  509. return (pmu_flags & PMU_TICKS_TAKEN_BRANCHES) ? 1 : 0;
  510. }
  511. Ticks PerfCounters::read_ticks(Task* t) {
  512. if (!started || !counting) {
  513. return 0;
  514. }
  515. if (fd_ticks_in_transaction.is_open()) {
  516. uint64_t transaction_ticks = read_counter(fd_ticks_in_transaction);
  517. if (transaction_ticks > 0) {
  518. LOG(debug) << transaction_ticks << " IN_TX ticks detected";
  519. if (!Flags::get().force_things) {
  520. ASSERT(t, false)
  521. << transaction_ticks
  522. << " IN_TX ticks detected while HLE not supported due to KVM PMU\n"
  523. "virtualization bug. See "
  524. "http://marc.info/?l=linux-kernel&m=148582794808419&w=2\n"
  525. "Aborting. Retry with -F to override, but it will probably\n"
  526. "fail.";
  527. }
  528. }
  529. }
  530. if (fd_strex_counter.is_open()) {
  531. uint64_t strex_count = read_counter(fd_strex_counter);
  532. if (strex_count > 0) {
  533. LOG(debug) << strex_count << " strex detected";
  534. if (!Flags::get().force_things) {
  535. CLEAN_FATAL()
  536. << strex_count
  537. << " (speculatively) executed strex instructions detected. \n"
  538. "On aarch64, rr only supports applications making use of LSE\n"
  539. "atomics rather than legacy LL/SC-based atomics.\n"
  540. "Aborting. Retry with -F to override, but replaying such\n"
  541. "a recording will probably fail.";
  542. }
  543. }
  544. }
  545. uint64_t adjusted_counting_period =
  546. counting_period +
  547. (t->session().is_recording() ? recording_skid_size() : skid_size());
  548. uint64_t interrupt_val = read_counter(fd_ticks_interrupt);
  549. if (!fd_ticks_measure.is_open()) {
  550. if (fd_minus_ticks_measure.is_open()) {
  551. uint64_t minus_measure_val = read_counter(fd_minus_ticks_measure);
  552. interrupt_val -= minus_measure_val;
  553. }
  554. if (t->session().is_recording()) {
  555. if (counting_period && interrupt_val > adjusted_counting_period) {
  556. LOG(warn) << "Recorded ticks of " << interrupt_val
  557. << " overshot requested ticks target by " << interrupt_val - counting_period
  558. << " ticks.\n"
  559. "On AMD systems this is known to occur occasionally for unknown reasons.\n"
  560. "Recording should continue normally. Please report any unexpected rr failures\n"
  561. "received after this warning, any conditions that reliably reproduce it,\n"
  562. "or sightings of this warning on non-AMD systems.";
  563. }
  564. } else {
  565. ASSERT(t, !counting_period || interrupt_val <= adjusted_counting_period)
  566. << "Detected " << interrupt_val << " ticks, expected no more than "
  567. << adjusted_counting_period;
  568. }
  569. return interrupt_val;
  570. }
  571. uint64_t measure_val = read_counter(fd_ticks_measure);
  572. if (measure_val > interrupt_val) {
  573. // There is some kind of kernel or hardware bug that means we sometimes
  574. // see more events with IN_TXCP set than without. These are clearly
  575. // spurious events :-(. For now, work around it by returning the
  576. // interrupt_val. That will work if HLE hasn't been used in this interval.
  577. // Note that interrupt_val > measure_val is valid behavior (when HLE is
  578. // being used).
  579. LOG(debug) << "Measured too many ticks; measure=" << measure_val
  580. << ", interrupt=" << interrupt_val;
  581. ASSERT(t, !counting_period || interrupt_val <= adjusted_counting_period)
  582. << "Detected " << interrupt_val << " ticks, expected no more than "
  583. << adjusted_counting_period;
  584. return interrupt_val;
  585. }
  586. ASSERT(t, !counting_period || measure_val <= adjusted_counting_period)
  587. << "Detected " << measure_val << " ticks, expected no more than "
  588. << adjusted_counting_period;
  589. return measure_val;
  590. }
  591. } // namespace rr