1 // SPDX-License-Identifier: GPL-2.0 2 #include "data.h" 3 #include "debug.h" 4 #include "event.h" 5 #include "header.h" 6 #include "session.h" 7 #include "stat.h" 8 #include "tool.h" 9 #include "tsc.h" 10 #include <linux/compiler.h> 11 #include <sys/mman.h> 12 #include <stddef.h> 13 #include <unistd.h> 14 15 #ifdef HAVE_ZSTD_SUPPORT 16 static int perf_session__process_compressed_event(struct perf_session *session, 17 union perf_event *event, u64 file_offset, 18 const char *file_path) 19 { 20 void *src; 21 size_t decomp_size, src_size; 22 u64 decomp_last_rem = 0; 23 size_t mmap_len, decomp_len = perf_session__env(session)->comp_mmap_len; 24 struct decomp *decomp, *decomp_last = session->active_decomp->decomp_last; 25 26 if (decomp_last) { 27 decomp_last_rem = decomp_last->size - decomp_last->head; 28 decomp_len += decomp_last_rem; 29 } 30 31 mmap_len = sizeof(struct decomp) + decomp_len; 32 decomp = mmap(NULL, mmap_len, PROT_READ|PROT_WRITE, 33 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 34 if (decomp == MAP_FAILED) { 35 pr_err("Couldn't allocate memory for decompression\n"); 36 return -1; 37 } 38 39 decomp->file_pos = file_offset; 40 decomp->file_path = file_path; 41 decomp->mmap_len = mmap_len; 42 decomp->head = 0; 43 44 if (decomp_last_rem) { 45 memcpy(decomp->data, &(decomp_last->data[decomp_last->head]), decomp_last_rem); 46 decomp->size = decomp_last_rem; 47 } 48 49 if (event->header.type == PERF_RECORD_COMPRESSED) { 50 src = (void *)event + sizeof(struct perf_record_compressed); 51 src_size = event->pack.header.size - sizeof(struct perf_record_compressed); 52 } else if (event->header.type == PERF_RECORD_COMPRESSED2) { 53 src = (void *)event + sizeof(struct perf_record_compressed2); 54 src_size = event->pack2.data_size; 55 } else { 56 return -1; 57 } 58 59 decomp_size = zstd_decompress_stream(session->active_decomp->zstd_decomp, src, src_size, 60 &(decomp->data[decomp_last_rem]), decomp_len - decomp_last_rem); 61 if (!decomp_size) { 62 munmap(decomp, mmap_len); 63 pr_err("Couldn't decompress data\n"); 64 return -1; 65 } 66 67 decomp->size += decomp_size; 68 69 if (session->active_decomp->decomp == NULL) 70 session->active_decomp->decomp = decomp; 71 else 72 session->active_decomp->decomp_last->next = decomp; 73 74 session->active_decomp->decomp_last = decomp; 75 76 pr_debug("decomp (B): %zd to %zd\n", src_size, decomp_size); 77 78 return 0; 79 } 80 #endif 81 82 static int process_event_synth_tracing_data_stub(struct perf_session *session 83 __maybe_unused, 84 union perf_event *event 85 __maybe_unused) 86 { 87 dump_printf(": unhandled!\n"); 88 return 0; 89 } 90 91 static int process_event_synth_attr_stub(const struct perf_tool *tool __maybe_unused, 92 union perf_event *event __maybe_unused, 93 struct evlist **pevlist 94 __maybe_unused) 95 { 96 dump_printf(": unhandled!\n"); 97 return 0; 98 } 99 100 static int process_event_synth_event_update_stub(const struct perf_tool *tool __maybe_unused, 101 union perf_event *event __maybe_unused, 102 struct evlist **pevlist 103 __maybe_unused) 104 { 105 if (dump_trace) 106 perf_event__fprintf_event_update(event, stdout); 107 108 dump_printf(": unhandled!\n"); 109 return 0; 110 } 111 112 int process_event_sample_stub(const struct perf_tool *tool __maybe_unused, 113 union perf_event *event __maybe_unused, 114 struct perf_sample *sample __maybe_unused, 115 struct evsel *evsel __maybe_unused, 116 struct machine *machine __maybe_unused) 117 { 118 dump_printf(": unhandled!\n"); 119 return 0; 120 } 121 122 static int process_event_stub(const struct perf_tool *tool __maybe_unused, 123 union perf_event *event __maybe_unused, 124 struct perf_sample *sample __maybe_unused, 125 struct machine *machine __maybe_unused) 126 { 127 dump_printf(": unhandled!\n"); 128 return 0; 129 } 130 131 static int process_finished_round_stub(const struct perf_tool *tool __maybe_unused, 132 union perf_event *event __maybe_unused, 133 struct ordered_events *oe __maybe_unused) 134 { 135 dump_printf(": unhandled!\n"); 136 return 0; 137 } 138 139 static int skipn(int fd, off_t n) 140 { 141 char buf[4096]; 142 ssize_t ret; 143 144 while (n > 0) { 145 ret = read(fd, buf, min(n, (off_t)sizeof(buf))); 146 if (ret <= 0) 147 return ret; 148 n -= ret; 149 } 150 151 return 0; 152 } 153 154 static s64 process_event_auxtrace_stub(struct perf_session *session __maybe_unused, 155 union perf_event *event) 156 { 157 dump_printf(": unhandled!\n"); 158 if (perf_data__is_pipe(session->data)) 159 skipn(perf_data__fd(session->data), event->auxtrace.size); 160 return event->auxtrace.size; 161 } 162 163 static int process_event_op2_stub(struct perf_session *session __maybe_unused, 164 union perf_event *event __maybe_unused) 165 { 166 dump_printf(": unhandled!\n"); 167 return 0; 168 } 169 170 171 static 172 int process_event_thread_map_stub(struct perf_session *session __maybe_unused, 173 union perf_event *event __maybe_unused) 174 { 175 if (dump_trace) 176 perf_event__fprintf_thread_map(event, stdout); 177 178 dump_printf(": unhandled!\n"); 179 return 0; 180 } 181 182 static 183 int process_event_cpu_map_stub(struct perf_session *session __maybe_unused, 184 union perf_event *event __maybe_unused) 185 { 186 if (dump_trace) 187 perf_event__fprintf_cpu_map(event, stdout); 188 189 dump_printf(": unhandled!\n"); 190 return 0; 191 } 192 193 static 194 int process_event_stat_config_stub(struct perf_session *session __maybe_unused, 195 union perf_event *event __maybe_unused) 196 { 197 if (dump_trace) 198 perf_event__fprintf_stat_config(event, stdout); 199 200 dump_printf(": unhandled!\n"); 201 return 0; 202 } 203 204 static int process_stat_stub(struct perf_session *perf_session __maybe_unused, 205 union perf_event *event) 206 { 207 if (dump_trace) 208 perf_event__fprintf_stat(event, stdout); 209 210 dump_printf(": unhandled!\n"); 211 return 0; 212 } 213 214 static int process_stat_round_stub(struct perf_session *perf_session __maybe_unused, 215 union perf_event *event) 216 { 217 if (dump_trace) 218 perf_event__fprintf_stat_round(event, stdout); 219 220 dump_printf(": unhandled!\n"); 221 return 0; 222 } 223 224 static int process_event_time_conv_stub(struct perf_session *perf_session __maybe_unused, 225 union perf_event *event) 226 { 227 if (dump_trace) 228 perf_event__fprintf_time_conv(event, stdout); 229 230 dump_printf(": unhandled!\n"); 231 return 0; 232 } 233 234 static int perf_session__process_compressed_event_stub(struct perf_session *session __maybe_unused, 235 union perf_event *event __maybe_unused, 236 u64 file_offset __maybe_unused, 237 const char *file_path __maybe_unused) 238 { 239 dump_printf(": unhandled!\n"); 240 return 0; 241 } 242 243 static int perf_event__process_bpf_metadata_stub(struct perf_session *perf_session __maybe_unused, 244 union perf_event *event) 245 { 246 if (dump_trace) 247 perf_event__fprintf_bpf_metadata(event, stdout); 248 249 dump_printf(": unhandled!\n"); 250 return 0; 251 } 252 253 void perf_tool__init(struct perf_tool *tool, bool ordered_events) 254 { 255 tool->ordered_events = ordered_events; 256 tool->ordering_requires_timestamps = false; 257 tool->namespace_events = false; 258 tool->cgroup_events = false; 259 tool->no_warn = false; 260 tool->show_feat_hdr = SHOW_FEAT_NO_HEADER; 261 262 tool->sample = process_event_sample_stub; 263 tool->mmap = process_event_stub; 264 tool->mmap2 = process_event_stub; 265 tool->comm = process_event_stub; 266 tool->namespaces = process_event_stub; 267 tool->cgroup = process_event_stub; 268 tool->fork = process_event_stub; 269 tool->exit = process_event_stub; 270 tool->lost = perf_event__process_lost; 271 tool->lost_samples = perf_event__process_lost_samples; 272 tool->aux = perf_event__process_aux; 273 tool->itrace_start = perf_event__process_itrace_start; 274 tool->context_switch = perf_event__process_switch; 275 tool->ksymbol = perf_event__process_ksymbol; 276 tool->bpf = perf_event__process_bpf; 277 tool->text_poke = perf_event__process_text_poke; 278 tool->aux_output_hw_id = perf_event__process_aux_output_hw_id; 279 tool->read = process_event_sample_stub; 280 tool->throttle = process_event_stub; 281 tool->unthrottle = process_event_stub; 282 tool->attr = process_event_synth_attr_stub; 283 tool->event_update = process_event_synth_event_update_stub; 284 tool->tracing_data = process_event_synth_tracing_data_stub; 285 tool->build_id = process_event_op2_stub; 286 287 if (ordered_events) 288 tool->finished_round = perf_event__process_finished_round; 289 else 290 tool->finished_round = process_finished_round_stub; 291 292 tool->id_index = process_event_op2_stub; 293 tool->auxtrace_info = process_event_op2_stub; 294 tool->auxtrace = process_event_auxtrace_stub; 295 tool->auxtrace_error = process_event_op2_stub; 296 tool->thread_map = process_event_thread_map_stub; 297 tool->cpu_map = process_event_cpu_map_stub; 298 tool->stat_config = process_event_stat_config_stub; 299 tool->stat = process_stat_stub; 300 tool->stat_round = process_stat_round_stub; 301 tool->time_conv = process_event_time_conv_stub; 302 tool->feature = process_event_op2_stub; 303 #ifdef HAVE_ZSTD_SUPPORT 304 tool->compressed = perf_session__process_compressed_event; 305 #else 306 tool->compressed = perf_session__process_compressed_event_stub; 307 #endif 308 tool->finished_init = process_event_op2_stub; 309 tool->bpf_metadata = perf_event__process_bpf_metadata_stub; 310 } 311 312 bool perf_tool__compressed_is_stub(const struct perf_tool *tool) 313 { 314 return tool->compressed == perf_session__process_compressed_event_stub; 315 } 316