| #include <stdbool.h> |
| #include <linux/kernel.h> |
| #include <linux/types.h> |
| #include <linux/bitops.h> |
| #include <linux/log2.h> |
| #include <linux/zalloc.h> |
| |
| #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; |
| } |