blob: 57e875436552237290b207fc927141ebcbf75a5b [file] [log] [blame]
/**
* @file pe_profiling/operf_counter.h
* C++ class definition that abstracts the user-to-kernel interface
* for using Linux Performance Events Subsystem.
*
* @remark Copyright 2011 OProfile authors
* @remark Read the file COPYING
*
* Created on: Dec 7, 2011
* @author Maynard Johnson
* (C) Copyright IBM Corp. 2011
*
* Modified by Maynard Johnson <maynardj@us.ibm.com>
* (C) Copyright IBM Corporation 2012
*
*/
#ifndef OPERF_COUNTER_H_
#define OPERF_COUNTER_H_
#include <sys/mman.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <stdint.h>
#include <poll.h>
#include <string>
#include <vector>
#include <map>
#include <stdexcept>
#include <limits.h>
#include <istream>
#include <fstream>
#include "operf_event.h"
#include "op_cpu_type.h"
#include "operf_utils.h"
extern char * start_time_human_readable;
class operf_record;
#define OP_BASIC_SAMPLE_FORMAT (PERF_SAMPLE_ID | PERF_SAMPLE_IP \
| PERF_SAMPLE_TID)
static inline int
op_perf_event_open(struct perf_event_attr * attr,
pid_t pid, int cpu, int group_fd,
unsigned long flags)
{
return syscall(__NR_perf_event_open, attr, pid, cpu,
group_fd, flags);
}
#define OP_PERF_HANDLED_ERROR -101
class operf_counter {
public:
operf_counter(operf_event_t & evt, bool enable_on_exec, bool callgraph,
bool separate_by_cpu, bool inherit, int event_number);
~operf_counter();
int perf_event_open(pid_t pid, int cpu, operf_record * pr);
const struct perf_event_attr * the_attr(void) const { return &attr; }
int get_fd(void) const { return fd; }
int get_id(void) const { return id; }
int get_evt_num(void) const { return evt_num; }
const std::string get_event_name(void) const { return event_name; }
private:
struct perf_event_attr attr;
int fd;
int id;
int evt_num;
std::string event_name;
};
class operf_record {
public:
/* For system-wide profiling, set sys_wide=true, the_pid=-1, and pid_running=false.
* For single app profiling, set sys_wide=false, the_pid=<processID-to-profile>,
* and pid_running=true if profiling an already active process; otherwise false.
*/
operf_record(int output_fd, bool sys_wide, pid_t the_pid, bool pid_running,
std::vector<operf_event_t> & evts, OP_perf_utils::vmlinux_info_t vi,
bool callgraph, bool separate_by_cpu, bool output_fd_is_file);
~operf_record();
void recordPerfData(void);
int out_fd(void) const { return output_fd; }
void add_to_total(int n) { total_bytes_recorded += n; }
void add_process(struct comm_event proc) { procs.push_back(proc); }
unsigned int get_total_bytes_recorded(void) const { return total_bytes_recorded; }
void register_perf_event_id(unsigned counter, u64 id, perf_event_attr evt_attr);
bool get_valid(void) { return valid; }
private:
void create(std::string outfile, std::vector<operf_event_t> & evts);
void setup(void);
int prepareToRecord(void);
int _prepare_to_record_one_fd(int idx, int fd);
void record_process_info(void);
void write_op_header_info(void);
int _write_header_to_file(void);
int _write_header_to_pipe(void);
int output_fd;
bool write_to_file;
// Array of size 'num_cpus_used_for_perf_event_open * num_pids * num_events'
struct pollfd * poll_data;
std::vector<struct mmap_data> samples_array;
int num_cpus;
pid_t pid_to_profile;
/* When doing --pid or --system-wide profiling, we'll obtain process information
* for all processes to be profiled (including forked/cloned processes) and store
* that information in a collection of type 'comm_event'. We'll use this collection
* for synthesizing PERF_RECORD_COMM events into the profile data stream.
*/
std::vector<struct comm_event> procs;
bool pid_started;
bool system_wide;
bool callgraph;
bool separate_cpu;
std::vector<operf_counter> perfCounters;
unsigned int total_bytes_recorded;
int poll_count;
struct OP_header opHeader;
std::vector<operf_event_t> evts;
bool valid;
std::string vmlinux_file;
u64 kernel_start, kernel_end;
};
class operf_read {
public:
operf_read(void) : sample_data_fd(-1), inputFname(""), cpu_type(CPU_NO_GOOD) { valid = syswide = false;}
void init(int sample_data_pipe_fd, std::string input_filename, std::string samples_dir, op_cpu cputype,
std::vector<operf_event_t> & evts, bool systemwide);
~operf_read();
int readPerfHeader(void);
unsigned int convertPerfData(void);
bool is_valid(void) {return valid; }
int get_eventnum_by_perf_event_id(u64 id) const;
inline const operf_event_t * get_event_by_counter(u32 counter) { return &evts[counter]; }
private:
int sample_data_fd;
std::string inputFname;
std::string sampledir;
std::ifstream istrm;
struct OP_header opHeader;
std::vector<operf_event_t> evts;
bool valid;
bool syswide;
op_cpu cpu_type;
int _read_header_info_with_ifstream(void);
int _read_perf_header_from_file(void);
int _read_perf_header_from_pipe(void);
};
#endif /* OPERF_COUNTER_H_ */