#include #include #include #include #include #include "../../util/evlist.h" #include "../../util/auxtrace.h" #include "../../util/evsel.h" #define PERF_EVENT_CPUM_SF 0xB0000 /* Event: Basic-sampling */ #define PERF_EVENT_CPUM_SF_DIAG 0xBD000 /* Event: Combined-sampling */ #define DEFAULT_AUX_PAGES 128 #define DEFAULT_FREQ 4000 static void cpumsf_free(struct auxtrace_record *itr) { free(itr); } static size_t cpumsf_info_priv_size(struct auxtrace_record *itr __maybe_unused, struct perf_evlist *evlist __maybe_unused) { return 0; } static int cpumsf_info_fill(struct auxtrace_record *itr __maybe_unused, struct perf_session *session __maybe_unused, struct auxtrace_info_event *auxtrace_info __maybe_unused, size_t priv_size __maybe_unused) { auxtrace_info->type = PERF_AUXTRACE_S390_CPUMSF; return 0; } static unsigned long cpumsf_reference(struct auxtrace_record *itr __maybe_unused) { return 0; } static int cpumsf_recording_options(struct auxtrace_record *ar __maybe_unused, struct perf_evlist *evlist __maybe_unused, struct record_opts *opts) { unsigned int factor = 1; unsigned int pages; opts->full_auxtrace = true; /* * The AUX buffer size should be set properly to avoid * overflow of samples if it is not set explicitly. * DEFAULT_AUX_PAGES is an proper size when sampling frequency * is DEFAULT_FREQ. It is expected to hold about 1/2 second * of sampling data. The size used for AUX buffer will scale * according to the specified frequency and DEFAULT_FREQ. */ if (!opts->auxtrace_mmap_pages) { if (opts->user_freq != UINT_MAX) factor = (opts->user_freq + DEFAULT_FREQ - 1) / DEFAULT_FREQ; pages = DEFAULT_AUX_PAGES * factor; opts->auxtrace_mmap_pages = roundup_pow_of_two(pages); } return 0; } static int cpumsf_parse_snapshot_options(struct auxtrace_record *itr __maybe_unused, struct record_opts *opts __maybe_unused, const char *str __maybe_unused) { return 0; } /* * auxtrace_record__init is called when perf record * check if the event really need auxtrace */ struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist, int *err) { struct auxtrace_record *aux; struct perf_evsel *pos; int diagnose = 0; *err = 0; if (evlist->nr_entries == 0) return NULL; evlist__for_each_entry(evlist, pos) { if (pos->attr.config == PERF_EVENT_CPUM_SF_DIAG) { diagnose = 1; break; } } if (!diagnose) return NULL; /* sampling in diagnose mode. alloc aux buffer */ aux = zalloc(sizeof(*aux)); if (aux == NULL) { *err = -ENOMEM; return NULL; } aux->parse_snapshot_options = cpumsf_parse_snapshot_options; aux->recording_options = cpumsf_recording_options; aux->info_priv_size = cpumsf_info_priv_size; aux->info_fill = cpumsf_info_fill; aux->free = cpumsf_free; aux->reference = cpumsf_reference; return aux; }