linux-stable/tools/perf/util/session.h
Ian Rogers 89d64e7273 perf inject: Overhaul handling of pipe files
Previously inject->is_pipe was set if the input or output were a
pipe. Determining the input was a pipe had to be done prior to
starting the session and opening the file. This was done by comparing
the input file name with '-' but it fails if the pipe file is written
to disk.

Opening a pipe file from disk will correctly set perf_data.is_pipe, but
this is too late for 'perf inject' and results in a broken file. A
workaround is 'cat pipe_perf|perf inject -i - ...'.

This change removes inject->is_pipe and changes the dependent
conditions to use the is_pipe flag on the input
(inject->session->data) and output files (inject->output). This
ensures the is_pipe condition reflects things like the header being
read.

The change removes the use of perf file header repiping, that is
writing the file header out while reading it in. The case of input
pipe and output file cannot repipe as the attributes for the file are
unknown. To resolve this, write the file header when writing to disk
and as the attributes may be unknown, write them after the data.

Update sessions repipe variable to be trace_event_repipe as those are
the only events now impacted by it. Update __perf_session__new as the
repipe_fd no longer needs passing. Fully removing repipe from session
header reading will be done in a later change.

Committer testing:

  root@number:~# perf record -e syscalls:sys_enter_*sleep/max-stack=4/ -o - sleep 0.01 | perf report -i -
  # To display the perf.data header info, please use --header/--header-only options.
  #
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.050 MB - ]
  #
  # Total Lost Samples: 0
  #
  # Samples: 1  of event 'syscalls:sys_enter_clock_nanosleep'
  # Event count (approx.): 1
  #
  # Overhead  Command  Shared Object  Symbol
  # ........  .......  .............  ...............................
  #
     100.00%  sleep    libc.so.6      [.] clock_nanosleep@GLIBC_2.2.5
              |
              ---__libc_start_main@@GLIBC_2.34
                 __libc_start_call_main
                 0x562fc2560a9f
                 clock_nanosleep@GLIBC_2.2.5

  #
  # (Tip: Create an archive with symtabs to analyse on other machine: perf archive)
  #
  root@number:~# perf record -e syscalls:sys_enter_*sleep/max-stack=4/ -o - sleep 0.01 > pipe.data
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.050 MB - ]
  root@number:~# perf report --stdio -i pipe.data
  # To display the perf.data header info, please use --header/--header-only options.
  #
  #
  # Total Lost Samples: 0
  #
  # Samples: 1  of event 'syscalls:sys_enter_clock_nanosleep'
  # Event count (approx.): 1
  #
  # Overhead  Command  Shared Object  Symbol
  # ........  .......  .............  ...............................
  #
     100.00%  sleep    libc.so.6      [.] clock_nanosleep@GLIBC_2.2.5
              |
              ---__libc_start_main@@GLIBC_2.34
                 __libc_start_call_main
                 0x55f775975a9f
                 clock_nanosleep@GLIBC_2.2.5

  #
  # (Tip: To set sampling period of individual events use perf record -e cpu/cpu-cycles,period=100001/,cpu/branches,period=10001/ ...)
  #
  root@number:~#

Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Nick Terrell <terrelln@fb.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Yanteng Si <siyanteng@loongson.cn>
Cc: Yicong Yang <yangyicong@hisilicon.com>
Link: https://lore.kernel.org/r/20240829150154.37929-7-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2024-08-30 09:23:51 -03:00

211 lines
6.7 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __PERF_SESSION_H
#define __PERF_SESSION_H
#include "trace-event.h"
#include "event.h"
#include "header.h"
#include "machine.h"
#include "data.h"
#include "ordered-events.h"
#include "util/compress.h"
#include <linux/kernel.h>
#include <linux/rbtree.h>
#include <linux/perf_event.h>
struct ip_callchain;
struct symbol;
struct thread;
struct auxtrace;
struct itrace_synth_opts;
struct decomp_data {
struct decomp *decomp;
struct decomp *decomp_last;
struct zstd_data *zstd_decomp;
};
/**
* struct perf_session- A Perf session holds the main state when the program is
* working with live perf events or reading data from an input file.
*
* The rough organization of a perf_session is:
* ```
* +--------------+ +-----------+ +------------+
* | Session |1..* ----->| Machine |1..* ----->| Thread |
* +--------------+ +-----------+ +------------+
* ```
*/
struct perf_session {
/**
* @header: The read version of a perf_file_header, or captures global
* information from a live session.
*/
struct perf_header header;
/** @machines: Machines within the session a host and 0 or more guests. */
struct machines machines;
/** @evlist: List of evsels/events of the session. */
struct evlist *evlist;
/** @auxtrace: callbacks to allow AUX area data decoding. */
const struct auxtrace *auxtrace;
/** @itrace_synth_opts: AUX area tracing synthesis options. */
struct itrace_synth_opts *itrace_synth_opts;
/** @auxtrace_index: index of AUX area tracing events within a perf.data file. */
struct list_head auxtrace_index;
#ifdef HAVE_LIBTRACEEVENT
/** @tevent: handles for libtraceevent and plugins. */
struct trace_event tevent;
#endif
/** @time_conv: Holds contents of last PERF_RECORD_TIME_CONV event. */
struct perf_record_time_conv time_conv;
/** @trace_event_repipe: When set causes read trace events to be written to stdout. */
bool trace_event_repipe;
/**
* @one_mmap: The reader will use a single mmap by default. There may be
* multiple data files in particular for aux events. If this is true
* then the single big mmap for the data file can be assumed.
*/
bool one_mmap;
/** @one_mmap_addr: Address of initial perf data file reader mmap. */
void *one_mmap_addr;
/** @one_mmap_offset: File offset in perf.data file when mapped. */
u64 one_mmap_offset;
/** @ordered_events: Used to turn unordered events into ordered ones. */
struct ordered_events ordered_events;
/** @data: Optional perf data file being read from. */
struct perf_data *data;
/** @tool: callbacks for event handling. */
const struct perf_tool *tool;
/**
* @bytes_transferred: Used by perf record to count written bytes before
* compression.
*/
u64 bytes_transferred;
/**
* @bytes_compressed: Used by perf record to count written bytes after
* compression.
*/
u64 bytes_compressed;
/** @zstd_data: Owner of global compression state, buffers, etc. */
struct zstd_data zstd_data;
struct decomp_data decomp_data;
struct decomp_data *active_decomp;
};
struct decomp {
struct decomp *next;
u64 file_pos;
const char *file_path;
size_t mmap_len;
u64 head;
size_t size;
char data[];
};
struct perf_tool;
struct perf_session *__perf_session__new(struct perf_data *data,
struct perf_tool *tool,
bool trace_event_repipe);
static inline struct perf_session *perf_session__new(struct perf_data *data,
struct perf_tool *tool)
{
return __perf_session__new(data, tool, /*trace_event_repipe=*/false);
}
void perf_session__delete(struct perf_session *session);
void perf_event_header__bswap(struct perf_event_header *hdr);
int perf_session__peek_event(struct perf_session *session, off_t file_offset,
void *buf, size_t buf_sz,
union perf_event **event_ptr,
struct perf_sample *sample);
typedef int (*peek_events_cb_t)(struct perf_session *session,
union perf_event *event, u64 offset,
void *data);
int perf_session__peek_events(struct perf_session *session, u64 offset,
u64 size, peek_events_cb_t cb, void *data);
int perf_session__process_events(struct perf_session *session);
int perf_session__queue_event(struct perf_session *s, union perf_event *event,
u64 timestamp, u64 file_offset, const char *file_path);
int perf_session__resolve_callchain(struct perf_session *session,
struct evsel *evsel,
struct thread *thread,
struct ip_callchain *chain,
struct symbol **parent);
bool perf_session__has_traces(struct perf_session *session, const char *msg);
void perf_event__attr_swap(struct perf_event_attr *attr);
int perf_session__create_kernel_maps(struct perf_session *session);
void perf_session__set_id_hdr_size(struct perf_session *session);
static inline
struct machine *perf_session__find_machine(struct perf_session *session, pid_t pid)
{
return machines__find(&session->machines, pid);
}
static inline
struct machine *perf_session__findnew_machine(struct perf_session *session, pid_t pid)
{
return machines__findnew(&session->machines, pid);
}
struct thread *perf_session__findnew(struct perf_session *session, pid_t pid);
int perf_session__register_idle_thread(struct perf_session *session);
size_t perf_session__fprintf(struct perf_session *session, FILE *fp);
size_t perf_session__fprintf_dsos(struct perf_session *session, FILE *fp);
size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp,
bool (fn)(struct dso *dso, int parm), int parm);
size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
void perf_session__dump_kmaps(struct perf_session *session);
struct evsel *perf_session__find_first_evtype(struct perf_session *session,
unsigned int type);
int perf_session__cpu_bitmap(struct perf_session *session,
const char *cpu_list, unsigned long *cpu_bitmap);
void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full);
struct evsel_str_handler;
#define perf_session__set_tracepoints_handlers(session, array) \
__evlist__set_tracepoints_handlers(session->evlist, array, ARRAY_SIZE(array))
extern volatile int session_done;
#define session_done() READ_ONCE(session_done)
int perf_session__deliver_synth_event(struct perf_session *session,
union perf_event *event,
struct perf_sample *sample);
int perf_session__deliver_synth_attr_event(struct perf_session *session,
const struct perf_event_attr *attr,
u64 id);
int perf_session__dsos_hit_all(struct perf_session *session);
int perf_event__process_id_index(struct perf_session *session,
union perf_event *event);
int perf_event__process_finished_round(const struct perf_tool *tool,
union perf_event *event,
struct ordered_events *oe);
#endif /* __PERF_SESSION_H */