use bitflags::*;
#[derive(Debug)]
pub struct ThreadId {
pub pid: i32,
pub tid: i32
}
#[derive(Debug)]
pub struct Cpu {
pub cpu: u32,
pub res: u32
}
#[derive(Debug)]
pub struct SampleId {
pub ptid: ThreadId,
pub time: u64,
pub id: u64,
pub stream_id: u64,
pub cpu: Cpu,
pub identifier: u64
}
#[derive(Debug)]
pub struct Event {
pub header: EventHeader,
pub data: EventData,
}
#[derive(Debug)]
pub enum EventData {
MMAP(MMAPRecord),
Lost(LostRecord),
Comm(CommRecord),
Exit(ExitRecord),
Throttle(ThrottleRecord),
Unthrottle(UnthrottleRecord),
Fork(ForkRecord),
Sample(SampleRecord),
MMAP2(MMAP2Record),
BuildId(BuildIdRecord),
None,
}
#[derive(Debug)]
pub struct EventHeader {
pub event_type: EventType,
pub misc: u16,
pub size: u16,
}
impl EventHeader {
pub fn size(&self) -> usize {
self.size as usize
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum EventType {
Mmap,
Lost,
Comm,
Exit,
Throttle,
Unthrottle,
Fork,
Read,
Sample,
Mmap2,
BuildId,
FinishedRound,
Unknown(u32)
}
impl EventType {
pub fn new(event_type: u32) -> EventType {
match event_type {
1 => EventType::Mmap,
2 => EventType::Lost,
3 => EventType::Comm,
4 => EventType::Exit,
5 => EventType::Throttle,
6 => EventType::Unthrottle,
7 => EventType::Fork,
8 => EventType::Read,
9 => EventType::Sample,
10 => EventType::Mmap2,
67 => EventType::BuildId,
68 => EventType::FinishedRound,
_ => EventType::Unknown(event_type)
}
}
pub fn is_unknown(&self) -> bool {
match *self {
EventType::Unknown(_) => true,
_ => false
}
}
}
#[derive(Debug)]
pub struct ForkRecord {
pub pid: u32,
pub ppid: u32,
pub tid: u32,
pub ptid: u32,
pub time: u64,
}
#[derive(Debug)]
pub struct ExitRecord {
pub pid: u32,
pub ppid: u32,
pub tid: u32,
pub ptid: u32,
pub time: u64
}
#[derive(Debug)]
pub struct ThrottleRecord {
pub time: u64,
pub id: u64,
pub stream_id: u64
}
#[derive(Debug)]
pub struct UnthrottleRecord {
pub time: u64,
pub id: u64,
pub stream_id: u64
}
#[derive(Debug)]
pub struct MMAPRecord {
pub pid: i32,
pub tid: u32,
pub addr: u64,
pub len: u64,
pub pgoff: u64,
pub filename: String
}
#[derive(Debug)]
pub struct MMAP2Record {
pub ptid: ThreadId,
pub addr: u64,
pub len: u64,
pub pgoff: u64,
pub maj: u32,
pub min: u32,
pub ino: u64,
pub ino_generation: u64,
pub prot: u32,
pub flags: u32,
pub filename: String,
}
#[derive(Default, Debug)]
pub struct ReadFormat {
pub time_enabled: Option<u64>,
pub time_running: Option<u64>,
pub values: Vec<(u64, Option<u64>)>
}
#[derive(Debug)]
pub struct ReadRecord {
pub pid: u32,
pub tid: u32,
pub value: ReadFormat,
}
#[derive(Debug)]
pub struct BranchEntry {
pub from: u64,
pub to: u64,
pub flags: u64,
}
#[derive(Debug)]
pub struct SampleRecord {
pub sample_id: Option<u64>,
pub ip: Option<u64>,
pub ptid: Option<ThreadId>,
pub time: Option<u64>,
pub addr: Option<u64>,
pub id: Option<u64>,
pub stream_id: Option<u64>,
pub cpu: Option<Cpu>,
pub period: Option<u64>,
pub v: Option<ReadFormat>,
pub ips: Option<Vec<u64>>,
pub raw: Option<Vec<u8>>,
pub lbr: Option<Vec<BranchEntry>>,
pub abi_user: Option<u64>,
pub regs_user: Option<Vec<u64>>,
pub user_stack: Option<Vec<u8>>,
pub dyn_size: Option<u64>,
pub weight: Option<u64>,
pub data_src: Option<u64>,
pub transaction: Option<u64>,
pub abi: Option<u64>,
pub regs_intr: Option<Vec<u64>>
}
#[derive(Debug)]
pub struct CommRecord {
pub ptid: ThreadId,
pub comm: String,
}
#[derive(Debug)]
pub struct LostRecord {
}
#[derive(Debug)]
pub struct BuildIdRecord {
pub pid: i32,
pub build_id: Vec<u8>,
pub filename: String,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum HeaderFlag {
NrCpus,
Arch,
Version,
OsRelease,
Hostname,
BuildId,
TracingData,
BranchStack,
NumaTopology,
CpuTopology,
EventDesc,
CmdLine,
TotalMem,
CpuId,
CpuDesc,
GroupDesc,
PmuMappings
}
#[derive(Debug)]
pub struct HeaderFlags {
pub nrcpus: bool,
pub arch: bool,
pub version: bool,
pub osrelease: bool,
pub hostname: bool,
pub build_id: bool,
pub tracing_data: bool,
pub branch_stack: bool,
pub numa_topology: bool,
pub cpu_topology: bool,
pub event_desc: bool,
pub cmdline: bool,
pub total_mem: bool,
pub cpuid: bool,
pub cpudesc: bool,
pub group_desc: bool,
pub pmu_mappings: bool,
}
impl HeaderFlags {
pub fn collect(&self) -> Vec<HeaderFlag> {
let mut flags = Vec::with_capacity(17);
if self.tracing_data {
flags.push(HeaderFlag::TracingData);
}
if self.build_id {
flags.push(HeaderFlag::BuildId);
}
if self.hostname {
flags.push(HeaderFlag::Hostname);
}
if self.osrelease {
flags.push(HeaderFlag::OsRelease);
}
if self.version {
flags.push(HeaderFlag::Version);
}
if self.arch {
flags.push(HeaderFlag::Arch);
}
if self.nrcpus {
flags.push(HeaderFlag::NrCpus);
}
if self.cpudesc {
flags.push(HeaderFlag::CpuDesc);
}
if self.cpuid {
flags.push(HeaderFlag::CpuId);
}
if self.total_mem {
flags.push(HeaderFlag::TotalMem);
}
if self.cmdline {
flags.push(HeaderFlag::CmdLine);
}
if self.event_desc {
flags.push(HeaderFlag::EventDesc);
}
if self.cpu_topology {
flags.push(HeaderFlag::CpuTopology);
}
if self.numa_topology {
flags.push(HeaderFlag::NumaTopology);
}
if self.branch_stack {
flags.push(HeaderFlag::BranchStack);
}
if self.pmu_mappings {
flags.push(HeaderFlag::PmuMappings);
}
if self.group_desc {
flags.push(HeaderFlag::GroupDesc);
}
flags
}
}
#[derive(Debug)]
pub struct PerfFileHeader {
pub size: u64,
pub attr_size: u64,
pub attrs: PerfFileSection,
pub data: PerfFileSection,
pub event_types: PerfFileSection,
pub flags: HeaderFlags,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct EventAttr {
pub attr_type: u32,
pub size: u32,
pub config: u64,
pub sample_period_freq: u64,
pub sample_type: SampleFormatFlags,
pub read_format: ReadFormatFlags,
pub settings: EventAttrFlags,
pub wakeup_events_watermark: u32,
pub bp_type: u32,
pub config1_or_bp_addr: u64,
pub config2_or_bp_len: u64,
pub branch_sample_type: u64,
pub sample_regs_user: u64,
pub sample_stack_user: u32,
pub clock_id: i32,
pub sample_regs_intr: u64,
pub aux_watermark: u32,
pub reserved: u32
}
impl EventAttr {
pub fn attr_type(&self) -> EventAttrType {
EventAttrType::new(self.attr_type)
}
}
impl Default for EventAttr {
fn default() -> EventAttr {
use std::mem;
unsafe { mem::zeroed::<EventAttr>() }
}
}
#[derive(Debug)]
pub enum EventAttrType {
Hardware,
Software,
TracePoint,
HwCache,
Raw,
Breakpoint,
Unknown(u32)
}
impl EventAttrType {
pub fn new(attr_type: u32) -> EventAttrType {
match attr_type {
0 => EventAttrType::Hardware,
1 => EventAttrType::Software,
2 => EventAttrType::TracePoint,
3 => EventAttrType::HwCache,
4 => EventAttrType::Raw,
5 => EventAttrType::Breakpoint,
_ => EventAttrType::Unknown(attr_type)
}
}
}
bitflags!{
pub struct ReadFormatFlags: u64 {
const FORMAT_TOTAL_TIME_ENABLED = 1 << 0;
const FORMAT_TOTAL_TIME_RUNNING = 1 << 1;
const FORMAT_ID = 1 << 2;
const FORMAT_GROUP = 1 << 3;
}
}
impl ReadFormatFlags {
pub fn has_total_time_enabled(&self) -> bool {
self.contains(ReadFormatFlags::FORMAT_TOTAL_TIME_ENABLED)
}
pub fn has_total_time_running(&self) -> bool {
self.contains(ReadFormatFlags::FORMAT_TOTAL_TIME_RUNNING)
}
pub fn has_id(&self) -> bool {
self.contains(ReadFormatFlags::FORMAT_ID)
}
pub fn has_group(&self) -> bool {
self.contains(ReadFormatFlags::FORMAT_GROUP)
}
}
bitflags!{
pub struct SampleFormatFlags: u64 {
const PERF_SAMPLE_IP = 1 << 0;
const PERF_SAMPLE_TID = 1 << 1;
const PERF_SAMPLE_TIME = 1 << 2;
const PERF_SAMPLE_ADDR = 1 << 3;
const PERF_SAMPLE_READ = 1 << 4;
const PERF_SAMPLE_CALLCHAIN = 1 << 5;
const PERF_SAMPLE_ID = 1 << 6;
const PERF_SAMPLE_CPU = 1 << 7;
const PERF_SAMPLE_PERIOD = 1 << 8;
const PERF_SAMPLE_STREAM_ID = 1 << 9;
const PERF_SAMPLE_RAW = 1 << 10;
const PERF_SAMPLE_BRANCH_STACK = 1 << 11;
const PERF_SAMPLE_REGS_USER = 1 << 12;
const PERF_SAMPLE_STACK_USER = 1 << 13;
const PERF_SAMPLE_WEIGHT = 1 << 14;
const PERF_SAMPLE_DATA_SRC = 1 << 15;
const PERF_SAMPLE_IDENTIFIER = 1 << 16;
const PERF_SAMPLE_TRANSACTION = 1 << 17;
const PERF_SAMPLE_REGS_INTR = 1 << 18;
}
}
impl SampleFormatFlags {
pub fn has_ip(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_IP)
}
pub fn has_tid(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_TID)
}
pub fn has_time(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_TIME)
}
pub fn has_addr(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_ADDR)
}
pub fn has_read(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_READ)
}
pub fn has_callchain(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_CALLCHAIN)
}
pub fn has_sample_id(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_ID)
}
pub fn has_cpu(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_CPU)
}
pub fn has_period(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_PERIOD)
}
pub fn has_stream_id(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_STREAM_ID)
}
pub fn has_raw(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_RAW)
}
pub fn has_branch_stack(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_BRANCH_STACK)
}
pub fn has_regs_user(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_REGS_USER)
}
pub fn has_stack_user(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_STACK_USER)
}
pub fn has_weight(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_WEIGHT)
}
pub fn has_data_src(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_DATA_SRC)
}
pub fn has_identifier(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_IDENTIFIER)
}
pub fn has_transaction(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_TRANSACTION)
}
pub fn has_regs_intr(&self) -> bool {
self.contains(SampleFormatFlags::PERF_SAMPLE_REGS_INTR)
}
}
bitflags! {
pub struct EventAttrFlags: u64 {
const EVENT_ATTR_DISABLED = 1 << 0;
const EVENT_ATTR_INHERIT = 1 << 1;
const EVENT_ATTR_PINNED = 1 << 2;
const EVENT_ATTR_EXCLUSIVE = 1 << 3;
const EVENT_ATTR_EXCLUDE_USER = 1 << 4;
const EVENT_ATTR_EXCLUDE_KERNEL = 1 << 5;
const EVENT_ATTR_EXCLUDE_HV = 1 << 6;
const EVENT_ATTR_EXCLUDE_IDLE = 1 << 7;
const EVENT_ATTR_MMAP = 1 << 8;
const EVENT_ATTR_COMM = 1 << 9;
const EVENT_ATTR_FREQ = 1 << 10;
const EVENT_ATTR_INHERIT_STAT = 1 << 11;
const EVENT_ATTR_ENABLE_ON_EXEC = 1 << 12;
const EVENT_ATTR_TASK = 1 << 13;
const EVENT_ATTR_WATERMARK = 1 << 14;
const EVENT_ATTR_SAMPLE_IP_ARBITRARY_SKID = 0 << 15;
const EVENT_ATTR_SAMPLE_IP_CONSTANT_SKID = 1 << 15;
const EVENT_ATTR_SAMPLE_IP_REQ_ZERO_SKID = 2 << 15;
const EVENT_ATTR_SAMPLE_IP_ZERO_SKID = 3 << 15;
const EVENT_ATTR_MMAP_DATA = 1 << 17;
const EVENT_ATTR_SAMPLE_ID_ALL = 1 << 18;
const EVENT_ATTR_EXCLUDE_HOST = 1 << 19;
const EVENT_ATTR_EXCLUDE_GUEST = 1 << 20;
const EVENT_ATTR_EXCLUDE_CALLCHAIN_KERNEL = 1 << 21;
const EVENT_ATTR_EXCLUDE_CALLCHAIN_USER = 1 << 22;
const EVENT_ATTR_MMAP2 = 1 << 23;
}
}
#[derive(Debug, Clone, Copy)]
pub struct PerfFileSection {
pub offset: u64,
pub size: u64
}
impl PerfFileSection {
pub fn start(&self) -> usize {
self.offset as usize
}
pub fn end(&self) -> usize {
(self.offset + self.size) as usize
}
}
#[derive(Debug)]
pub struct NrCpus {
pub online: u32,
pub available: u32
}
#[derive(Debug)]
pub struct EventDesc {
pub attr: EventAttr,
pub event_string: String,
pub ids: Vec<u64>
}
#[derive(Debug)]
pub struct CpuTopology {
pub cores: Vec<String>,
pub threads: Vec<String>
}
#[derive(Debug)]
pub struct NumaNode {
pub node_nr: u32,
pub mem_total: u64,
pub mem_free: u64,
pub cpus: String
}
#[derive(Debug)]
pub struct PmuMapping {
pub pmu_type: u32,
pub pmu_name: String
}
#[derive(Debug)]
pub struct GroupDesc {
pub string: String,
pub leader_idx: u32,
pub nr_members: u32
}