blob: fc74160e921aeb76842ce4628d2c9dc8e355da53 [file] [log] [blame]
/* -*- Mode: C++; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
#ifndef RR_PERF_COUNTERS_H_
#define RR_PERF_COUNTERS_H_
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <signal.h>
#include <stdint.h>
#include <sys/types.h>
#include "ScopedFd.h"
#include "Ticks.h"
struct perf_event_attr;
namespace rr {
class Task;
enum TicksSemantics {
TICKS_RETIRED_CONDITIONAL_BRANCHES,
TICKS_TAKEN_BRANCHES,
};
/**
* A class encapsulating the performance counters we use to monitor
* each task during recording and replay.
*
* Normally we monitor a single kind of event that we use as a proxy
* for progress, which we call "ticks". Currently this is the count of retired
* conditional branches. We support dispatching a signal when the counter
* reaches a particular value.
*
* When extra_perf_counters_enabled() returns true, we monitor additional
* counters of interest.
*/
class PerfCounters {
public:
/**
* Create performance counters monitoring the given task.
* When enable is false, we always report 0 and don't do any interrupts.
*/
PerfCounters(pid_t tid, int cpu_binding, TicksSemantics ticks_semantics,
bool enable);
~PerfCounters() { stop(); }
void set_tid(pid_t tid);
/**
* Reset all counter values to 0 and program the counters to send
* TIME_SLICE_SIGNAL when 'ticks_period' tick events have elapsed. (In reality
* the hardware triggers its interrupt some time after that. We also allow
* the interrupt to fire early.)
* This must be called while the task is stopped, and it must be called
* before the task is allowed to run again.
* `ticks_period` of zero means don't interrupt at all.
*/
void reset(Ticks ticks_period);
template <typename Arch>
void reset_arch_extras();
/**
* Close the perfcounter fds. They will be automatically reopened if/when
* reset is called again.
*/
void stop();
/**
* Suspend counting until the next reset. This may or may not actually stop
* the performance counters, depending on whether or not this is required
* for correctness on this kernel version.
*/
void stop_counting();
/**
* Return the number of ticks we need for an emulated branch.
*/
static Ticks ticks_for_unconditional_indirect_branch(Task*);
/**
* Return the number of ticks we need for an emulated direct branch.
*/
static Ticks ticks_for_unconditional_direct_branch(Task*);
/**
* Return the number of ticks we need for a direct call.
*/
static Ticks ticks_for_direct_call(Task*);
/**
* Whether PMU on core i is supported.
*/
static bool support_cpu(int cpu);
/**
* Read the current value of the ticks counter.
* `t` is used for debugging purposes.
*/
Ticks read_ticks(Task* t);
/**
* Returns what ticks mean for these counters.
*/
TicksSemantics ticks_semantics() const { return ticks_semantics_; }
/**
* Return the fd we last used to generate the ticks-counter signal.
*/
int ticks_interrupt_fd() const { return fd_ticks_interrupt.get(); }
/* This choice is fairly arbitrary; linux doesn't use SIGSTKFLT so we
* hope that tracees don't either. */
enum { TIME_SLICE_SIGNAL = SIGSTKFLT };
static bool is_rr_ticks_attr(const perf_event_attr& attr);
static bool supports_ticks_semantics(TicksSemantics ticks_semantics);
static TicksSemantics default_ticks_semantics();
/**
* When an interrupt is requested, at most this many ticks may elapse before
* the interrupt is delivered.
*/
uint32_t skid_size();
/**
* Use a separate skid_size for recording since we seem to see more skid
* in practice during recording, in particular during the
* async_signal_syscalls tests
*/
uint32_t recording_skid_size() { return skid_size() * 5; }
private:
// Only valid while 'counting' is true
Ticks counting_period;
pid_t tid;
int pmu_index;
// We use separate fds for counting ticks and for generating interrupts. The
// former ignores ticks in aborted transactions, and does not support
// sample_period; the latter does not ignore ticks in aborted transactions,
// but does support sample_period.
ScopedFd fd_ticks_measure;
ScopedFd fd_minus_ticks_measure;
ScopedFd fd_ticks_interrupt;
ScopedFd fd_useless_counter;
// x86(_64) specific counter to support recording HLE
ScopedFd fd_ticks_in_transaction;
// aarch64 specific counter to detect use of ll/sc instructions
ScopedFd fd_strex_counter;
TicksSemantics ticks_semantics_;
bool enable;
bool started;
bool counting;
};
} // namespace rr
#endif /* RR_PERF_COUNTERS_H_ */