1 // Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "perf_serializer.h" 6 7 #include <stdint.h> 8 #include <stdio.h> 9 #include <sys/time.h> 10 11 #include <algorithm> // for std::copy 12 13 #include "base/logging.h" 14 15 #include "binary_data_utils.h" 16 #include "compat/proto.h" 17 #include "compat/string.h" 18 #include "kernel/perf_event.h" 19 #include "perf_data_structures.h" 20 #include "perf_data_utils.h" 21 #include "perf_parser.h" 22 #include "perf_reader.h" 23 24 namespace quipper { 25 26 PerfSerializer::PerfSerializer() {} 27 28 PerfSerializer::~PerfSerializer() {} 29 30 bool PerfSerializer::SerializePerfFileAttr( 31 const PerfFileAttr& perf_file_attr, 32 PerfDataProto_PerfFileAttr* perf_file_attr_proto) const { 33 if (!SerializePerfEventAttr(perf_file_attr.attr, 34 perf_file_attr_proto->mutable_attr())) { 35 return false; 36 } 37 38 for (size_t i = 0; i < perf_file_attr.ids.size(); i++) 39 perf_file_attr_proto->add_ids(perf_file_attr.ids[i]); 40 return true; 41 } 42 43 bool PerfSerializer::DeserializePerfFileAttr( 44 const PerfDataProto_PerfFileAttr& perf_file_attr_proto, 45 PerfFileAttr* perf_file_attr) const { 46 if (!DeserializePerfEventAttr(perf_file_attr_proto.attr(), 47 &perf_file_attr->attr)) { 48 return false; 49 } 50 51 for (int i = 0; i < perf_file_attr_proto.ids_size(); i++) 52 perf_file_attr->ids.push_back(perf_file_attr_proto.ids(i)); 53 return true; 54 } 55 56 bool PerfSerializer::SerializePerfEventAttr( 57 const perf_event_attr& perf_event_attr, 58 PerfDataProto_PerfEventAttr* perf_event_attr_proto) const { 59 #define S(x) perf_event_attr_proto->set_##x(perf_event_attr.x) 60 S(type); 61 S(size); 62 S(config); 63 if (perf_event_attr_proto->freq()) 64 S(sample_freq); 65 else 66 S(sample_period); 67 S(sample_type); 68 S(read_format); 69 S(disabled); 70 S(inherit); 71 S(pinned); 72 S(exclusive); 73 S(exclude_user); 74 S(exclude_kernel); 75 S(exclude_hv); 76 S(exclude_idle); 77 S(mmap); 78 S(comm); 79 S(freq); 80 S(inherit_stat); 81 S(enable_on_exec); 82 S(task); 83 S(watermark); 84 S(precise_ip); 85 S(mmap_data); 86 S(sample_id_all); 87 S(exclude_host); 88 S(exclude_guest); 89 S(exclude_callchain_kernel); 90 S(exclude_callchain_user); 91 S(mmap2); 92 S(comm_exec); 93 if (perf_event_attr_proto->watermark()) 94 S(wakeup_watermark); 95 else 96 S(wakeup_events); 97 S(bp_type); 98 S(bp_addr); 99 S(bp_len); 100 S(branch_sample_type); 101 S(sample_regs_user); 102 S(sample_stack_user); 103 #undef S 104 return true; 105 } 106 107 bool PerfSerializer::DeserializePerfEventAttr( 108 const PerfDataProto_PerfEventAttr& perf_event_attr_proto, 109 perf_event_attr* perf_event_attr) const { 110 memset(perf_event_attr, 0, sizeof(*perf_event_attr)); 111 #define S(x) perf_event_attr->x = perf_event_attr_proto.x() 112 S(type); 113 S(size); 114 S(config); 115 if (perf_event_attr->freq) 116 S(sample_freq); 117 else 118 S(sample_period); 119 S(sample_type); 120 S(read_format); 121 S(disabled); 122 S(inherit); 123 S(pinned); 124 S(exclusive); 125 S(exclude_user); 126 S(exclude_kernel); 127 S(exclude_hv); 128 S(exclude_idle); 129 S(mmap); 130 S(comm); 131 S(freq); 132 S(inherit_stat); 133 S(enable_on_exec); 134 S(task); 135 S(watermark); 136 S(precise_ip); 137 S(mmap_data); 138 S(sample_id_all); 139 S(exclude_host); 140 S(exclude_guest); 141 S(exclude_callchain_kernel); 142 S(exclude_callchain_user); 143 S(mmap2); 144 S(comm_exec); 145 if (perf_event_attr->watermark) 146 S(wakeup_watermark); 147 else 148 S(wakeup_events); 149 S(bp_type); 150 S(bp_addr); 151 S(bp_len); 152 S(branch_sample_type); 153 S(sample_regs_user); 154 S(sample_stack_user); 155 #undef S 156 return true; 157 } 158 159 bool PerfSerializer::SerializePerfEventType( 160 const PerfFileAttr& event_attr, 161 quipper::PerfDataProto_PerfEventType* event_type_proto) const { 162 event_type_proto->set_id(event_attr.attr.config); 163 event_type_proto->set_name(event_attr.name); 164 event_type_proto->set_name_md5_prefix(Md5Prefix(event_attr.name)); 165 return true; 166 } 167 168 bool PerfSerializer::DeserializePerfEventType( 169 const quipper::PerfDataProto_PerfEventType& event_type_proto, 170 PerfFileAttr* event_attr) const { 171 // Attr should have already been deserialized. 172 if (event_attr->attr.config != event_type_proto.id()) { 173 LOG(ERROR) << "Event type ID " << event_type_proto.id() 174 << " does not match attr.config " << event_attr->attr.config 175 << ". Not deserializing the event name!"; 176 return false; 177 } 178 event_attr->name = event_type_proto.name(); 179 return true; 180 } 181 182 bool PerfSerializer::SerializeEvent( 183 const malloced_unique_ptr<event_t>& event_ptr, 184 PerfDataProto_PerfEvent* event_proto) const { 185 const event_t& event = *event_ptr; 186 187 if (!SerializeEventHeader(event.header, event_proto->mutable_header())) 188 return false; 189 190 if (event.header.type >= PERF_RECORD_USER_TYPE_START) { 191 if (!SerializeUserEvent(event, event_proto)) { 192 return false; 193 } 194 } else if (!SerializeKernelEvent(event, event_proto)) { 195 return false; 196 } 197 198 event_proto->set_timestamp(GetTimeFromPerfEvent(*event_proto)); 199 return true; 200 } 201 202 bool PerfSerializer::SerializeKernelEvent( 203 const event_t& event, PerfDataProto_PerfEvent* event_proto) const { 204 switch (event.header.type) { 205 case PERF_RECORD_SAMPLE: 206 return SerializeSampleEvent(event, event_proto->mutable_sample_event()); 207 case PERF_RECORD_MMAP: 208 return SerializeMMapEvent(event, event_proto->mutable_mmap_event()); 209 case PERF_RECORD_MMAP2: 210 return SerializeMMap2Event(event, event_proto->mutable_mmap_event()); 211 case PERF_RECORD_COMM: 212 return SerializeCommEvent(event, event_proto->mutable_comm_event()); 213 case PERF_RECORD_EXIT: 214 return SerializeForkExitEvent(event, event_proto->mutable_exit_event()); 215 case PERF_RECORD_FORK: 216 return SerializeForkExitEvent(event, event_proto->mutable_fork_event()); 217 case PERF_RECORD_LOST: 218 return SerializeLostEvent(event, event_proto->mutable_lost_event()); 219 case PERF_RECORD_THROTTLE: 220 case PERF_RECORD_UNTHROTTLE: 221 return SerializeThrottleEvent(event, 222 event_proto->mutable_throttle_event()); 223 case PERF_RECORD_READ: 224 return SerializeReadEvent(event, event_proto->mutable_read_event()); 225 case PERF_RECORD_AUX: 226 return SerializeAuxEvent(event, event_proto->mutable_aux_event()); 227 default: 228 LOG(ERROR) << "Unknown event type: " << event.header.type; 229 } 230 return true; 231 } 232 233 bool PerfSerializer::SerializeUserEvent( 234 const event_t& event, PerfDataProto_PerfEvent* event_proto) const { 235 switch (event.header.type) { 236 case PERF_RECORD_AUXTRACE: 237 return SerializeAuxtraceEvent(event, 238 event_proto->mutable_auxtrace_event()); 239 default: 240 if (event.header.type >= PERF_RECORD_HEADER_MAX) { 241 LOG(ERROR) << "Unknown event type: " << event.header.type; 242 } 243 } 244 return true; 245 } 246 247 bool PerfSerializer::DeserializeEvent( 248 const PerfDataProto_PerfEvent& event_proto, 249 malloced_unique_ptr<event_t>* event_ptr) const { 250 event_ptr->reset(CallocMemoryForEvent(event_proto.header().size())); 251 event_t* event = event_ptr->get(); 252 253 if (!DeserializeEventHeader(event_proto.header(), &event->header)) 254 return false; 255 256 bool event_deserialized = false; 257 if (event_proto.header().type() >= PERF_RECORD_USER_TYPE_START) { 258 event_deserialized = DeserializeUserEvent(event_proto, event); 259 } else { 260 event_deserialized = DeserializeKernelEvent(event_proto, event); 261 } 262 263 if (!event_deserialized) { 264 LOG(ERROR) << "Could not deserialize event of type " 265 << event_proto.header().type(); 266 return false; 267 } 268 269 return true; 270 } 271 272 bool PerfSerializer::DeserializeKernelEvent( 273 const PerfDataProto_PerfEvent& event_proto, event_t* event) const { 274 switch (event_proto.header().type()) { 275 case PERF_RECORD_SAMPLE: 276 return DeserializeSampleEvent(event_proto.sample_event(), event); 277 case PERF_RECORD_MMAP: 278 return DeserializeMMapEvent(event_proto.mmap_event(), event); 279 case PERF_RECORD_MMAP2: 280 return DeserializeMMap2Event(event_proto.mmap_event(), event); 281 case PERF_RECORD_COMM: 282 return DeserializeCommEvent(event_proto.comm_event(), event); 283 case PERF_RECORD_EXIT: 284 return (event_proto.has_exit_event() && 285 DeserializeForkExitEvent(event_proto.exit_event(), event)) || 286 (event_proto.has_fork_event() && 287 DeserializeForkExitEvent(event_proto.fork_event(), event)); 288 // Some older protobufs use the |fork_event| field to store exit 289 // events. 290 case PERF_RECORD_FORK: 291 return DeserializeForkExitEvent(event_proto.fork_event(), event); 292 case PERF_RECORD_LOST: 293 return DeserializeLostEvent(event_proto.lost_event(), event); 294 case PERF_RECORD_THROTTLE: 295 case PERF_RECORD_UNTHROTTLE: 296 return DeserializeThrottleEvent(event_proto.throttle_event(), event); 297 case PERF_RECORD_READ: 298 return DeserializeReadEvent(event_proto.read_event(), event); 299 case PERF_RECORD_AUX: 300 return DeserializeAuxEvent(event_proto.aux_event(), event); 301 case PERF_RECORD_ITRACE_START: 302 case PERF_RECORD_LOST_SAMPLES: 303 case PERF_RECORD_SWITCH: 304 case PERF_RECORD_SWITCH_CPU_WIDE: 305 case PERF_RECORD_NAMESPACES: 306 LOG(ERROR) << "Event type: " << event_proto.header().type() 307 << ". Not yet supported."; 308 return true; 309 break; 310 } 311 return false; 312 } 313 314 bool PerfSerializer::DeserializeUserEvent( 315 const PerfDataProto_PerfEvent& event_proto, event_t* event) const { 316 switch (event_proto.header().type()) { 317 case PERF_RECORD_AUXTRACE: 318 return DeserializeAuxtraceEvent(event_proto.auxtrace_event(), event); 319 default: 320 // User type events are marked as deserialized because they don't 321 // have non-header data in perf.data proto. 322 if (event_proto.header().type() >= PERF_RECORD_HEADER_MAX) { 323 return false; 324 } 325 } 326 return true; 327 } 328 329 bool PerfSerializer::SerializeEventHeader( 330 const perf_event_header& header, 331 PerfDataProto_EventHeader* header_proto) const { 332 header_proto->set_type(header.type); 333 header_proto->set_misc(header.misc); 334 header_proto->set_size(header.size); 335 return true; 336 } 337 338 bool PerfSerializer::DeserializeEventHeader( 339 const PerfDataProto_EventHeader& header_proto, 340 perf_event_header* header) const { 341 header->type = header_proto.type(); 342 header->misc = header_proto.misc(); 343 header->size = header_proto.size(); 344 return true; 345 } 346 347 bool PerfSerializer::SerializeSampleEvent( 348 const event_t& event, PerfDataProto_SampleEvent* sample) const { 349 perf_sample sample_info; 350 uint64_t sample_type = 0; 351 if (!ReadPerfSampleInfoAndType(event, &sample_info, &sample_type)) 352 return false; 353 354 if (sample_type & PERF_SAMPLE_IP) sample->set_ip(sample_info.ip); 355 if (sample_type & PERF_SAMPLE_TID) { 356 sample->set_pid(sample_info.pid); 357 sample->set_tid(sample_info.tid); 358 } 359 if (sample_type & PERF_SAMPLE_TIME) 360 sample->set_sample_time_ns(sample_info.time); 361 if (sample_type & PERF_SAMPLE_ADDR) sample->set_addr(sample_info.addr); 362 if ((sample_type & PERF_SAMPLE_ID) || (sample_type & PERF_SAMPLE_IDENTIFIER)) 363 sample->set_id(sample_info.id); 364 if (sample_type & PERF_SAMPLE_STREAM_ID) 365 sample->set_stream_id(sample_info.stream_id); 366 if (sample_type & PERF_SAMPLE_CPU) sample->set_cpu(sample_info.cpu); 367 if (sample_type & PERF_SAMPLE_PERIOD) sample->set_period(sample_info.period); 368 if (sample_type & PERF_SAMPLE_RAW) sample->set_raw_size(sample_info.raw_size); 369 if (sample_type & PERF_SAMPLE_READ) { 370 const SampleInfoReader* reader = GetSampleInfoReaderForEvent(event); 371 if (reader) { 372 PerfDataProto_ReadInfo* read_info = sample->mutable_read_info(); 373 if (reader->event_attr().read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 374 read_info->set_time_enabled(sample_info.read.time_enabled); 375 if (reader->event_attr().read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 376 read_info->set_time_running(sample_info.read.time_running); 377 if (reader->event_attr().read_format & PERF_FORMAT_GROUP) { 378 for (size_t i = 0; i < sample_info.read.group.nr; i++) { 379 auto read_value = read_info->add_read_value(); 380 read_value->set_value(sample_info.read.group.values[i].value); 381 read_value->set_id(sample_info.read.group.values[i].id); 382 } 383 } else { 384 auto read_value = read_info->add_read_value(); 385 read_value->set_value(sample_info.read.one.value); 386 read_value->set_id(sample_info.read.one.id); 387 } 388 } 389 } 390 if (sample_type & PERF_SAMPLE_CALLCHAIN) { 391 sample->mutable_callchain()->Reserve(sample_info.callchain->nr); 392 for (size_t i = 0; i < sample_info.callchain->nr; ++i) 393 sample->add_callchain(sample_info.callchain->ips[i]); 394 } 395 if (sample_type & PERF_SAMPLE_BRANCH_STACK) { 396 for (size_t i = 0; i < sample_info.branch_stack->nr; ++i) { 397 sample->add_branch_stack(); 398 const struct branch_entry& entry = sample_info.branch_stack->entries[i]; 399 sample->mutable_branch_stack(i)->set_from_ip(entry.from); 400 sample->mutable_branch_stack(i)->set_to_ip(entry.to); 401 sample->mutable_branch_stack(i)->set_mispredicted(entry.flags.mispred); 402 } 403 } 404 405 if (sample_type & PERF_SAMPLE_WEIGHT) sample->set_weight(sample_info.weight); 406 if (sample_type & PERF_SAMPLE_DATA_SRC) 407 sample->set_data_src(sample_info.data_src); 408 if (sample_type & PERF_SAMPLE_TRANSACTION) 409 sample->set_transaction(sample_info.transaction); 410 411 return true; 412 } 413 414 bool PerfSerializer::DeserializeSampleEvent( 415 const PerfDataProto_SampleEvent& sample, event_t* event) const { 416 perf_sample sample_info; 417 if (sample.has_ip()) sample_info.ip = sample.ip(); 418 if (sample.has_pid()) { 419 CHECK(sample.has_tid()) << "Cannot have PID without TID."; 420 sample_info.pid = sample.pid(); 421 sample_info.tid = sample.tid(); 422 } 423 if (sample.has_sample_time_ns()) sample_info.time = sample.sample_time_ns(); 424 if (sample.has_addr()) sample_info.addr = sample.addr(); 425 if (sample.has_id()) sample_info.id = sample.id(); 426 if (sample.has_stream_id()) sample_info.stream_id = sample.stream_id(); 427 if (sample.has_cpu()) sample_info.cpu = sample.cpu(); 428 if (sample.has_period()) sample_info.period = sample.period(); 429 if (sample.has_read_info()) { 430 const SampleInfoReader* reader = GetSampleInfoReaderForEvent(*event); 431 if (reader) { 432 const PerfDataProto_ReadInfo& read_info = sample.read_info(); 433 if (reader->event_attr().read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 434 sample_info.read.time_enabled = read_info.time_enabled(); 435 if (reader->event_attr().read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 436 sample_info.read.time_running = read_info.time_running(); 437 if (reader->event_attr().read_format & PERF_FORMAT_GROUP) { 438 sample_info.read.group.nr = read_info.read_value_size(); 439 sample_info.read.group.values = 440 new sample_read_value[read_info.read_value_size()]; 441 for (size_t i = 0; i < sample_info.read.group.nr; i++) { 442 sample_info.read.group.values[i].value = 443 read_info.read_value(i).value(); 444 sample_info.read.group.values[i].id = read_info.read_value(i).id(); 445 } 446 } else if (read_info.read_value_size() == 1) { 447 sample_info.read.one.value = read_info.read_value(0).value(); 448 sample_info.read.one.id = read_info.read_value(0).id(); 449 } else { 450 LOG(ERROR) << "Expected read_value array size of 1 but got " 451 << read_info.read_value_size(); 452 } 453 } 454 } 455 if (sample.callchain_size() > 0) { 456 uint64_t callchain_size = sample.callchain_size(); 457 sample_info.callchain = reinterpret_cast<struct ip_callchain*>( 458 new uint64_t[callchain_size + 1]); 459 sample_info.callchain->nr = callchain_size; 460 for (size_t i = 0; i < callchain_size; ++i) 461 sample_info.callchain->ips[i] = sample.callchain(i); 462 } 463 if (sample.raw_size() > 0) { 464 sample_info.raw_size = sample.raw_size(); 465 sample_info.raw_data = new uint8_t[sample.raw_size()]; 466 memset(sample_info.raw_data, 0, sample.raw_size()); 467 } 468 if (sample.branch_stack_size() > 0) { 469 uint64_t branch_stack_size = sample.branch_stack_size(); 470 sample_info.branch_stack = reinterpret_cast<struct branch_stack*>( 471 new uint8_t[sizeof(uint64_t) + 472 branch_stack_size * sizeof(struct branch_entry)]); 473 sample_info.branch_stack->nr = branch_stack_size; 474 for (size_t i = 0; i < branch_stack_size; ++i) { 475 struct branch_entry& entry = sample_info.branch_stack->entries[i]; 476 memset(&entry, 0, sizeof(entry)); 477 entry.from = sample.branch_stack(i).from_ip(); 478 entry.to = sample.branch_stack(i).to_ip(); 479 entry.flags.mispred = sample.branch_stack(i).mispredicted(); 480 entry.flags.predicted = !entry.flags.mispred; 481 } 482 } 483 484 if (sample.has_weight()) sample_info.weight = sample.weight(); 485 if (sample.has_data_src()) sample_info.data_src = sample.data_src(); 486 if (sample.has_transaction()) sample_info.transaction = sample.transaction(); 487 488 const SampleInfoReader* writer = GetSampleInfoReaderForId(sample.id()); 489 CHECK(writer); 490 return writer->WritePerfSampleInfo(sample_info, event); 491 } 492 493 bool PerfSerializer::SerializeMMapEvent(const event_t& event, 494 PerfDataProto_MMapEvent* sample) const { 495 const struct mmap_event& mmap = event.mmap; 496 sample->set_pid(mmap.pid); 497 sample->set_tid(mmap.tid); 498 sample->set_start(mmap.start); 499 sample->set_len(mmap.len); 500 sample->set_pgoff(mmap.pgoff); 501 sample->set_filename(mmap.filename); 502 sample->set_filename_md5_prefix(Md5Prefix(mmap.filename)); 503 504 return SerializeSampleInfo(event, sample->mutable_sample_info()); 505 } 506 507 bool PerfSerializer::DeserializeMMapEvent(const PerfDataProto_MMapEvent& sample, 508 event_t* event) const { 509 struct mmap_event& mmap = event->mmap; 510 mmap.pid = sample.pid(); 511 mmap.tid = sample.tid(); 512 mmap.start = sample.start(); 513 mmap.len = sample.len(); 514 mmap.pgoff = sample.pgoff(); 515 snprintf(mmap.filename, PATH_MAX, "%s", sample.filename().c_str()); 516 517 return DeserializeSampleInfo(sample.sample_info(), event); 518 } 519 520 bool PerfSerializer::SerializeMMap2Event( 521 const event_t& event, PerfDataProto_MMapEvent* sample) const { 522 const struct mmap2_event& mmap = event.mmap2; 523 sample->set_pid(mmap.pid); 524 sample->set_tid(mmap.tid); 525 sample->set_start(mmap.start); 526 sample->set_len(mmap.len); 527 sample->set_pgoff(mmap.pgoff); 528 sample->set_maj(mmap.maj); 529 sample->set_min(mmap.min); 530 sample->set_ino(mmap.ino); 531 sample->set_ino_generation(mmap.ino_generation); 532 sample->set_prot(mmap.prot); 533 sample->set_flags(mmap.flags); 534 sample->set_filename(mmap.filename); 535 sample->set_filename_md5_prefix(Md5Prefix(mmap.filename)); 536 537 return SerializeSampleInfo(event, sample->mutable_sample_info()); 538 } 539 540 bool PerfSerializer::DeserializeMMap2Event( 541 const PerfDataProto_MMapEvent& sample, event_t* event) const { 542 struct mmap2_event& mmap = event->mmap2; 543 mmap.pid = sample.pid(); 544 mmap.tid = sample.tid(); 545 mmap.start = sample.start(); 546 mmap.len = sample.len(); 547 mmap.pgoff = sample.pgoff(); 548 mmap.maj = sample.maj(); 549 mmap.min = sample.min(); 550 mmap.ino = sample.ino(); 551 mmap.ino_generation = sample.ino_generation(); 552 mmap.prot = sample.prot(); 553 mmap.flags = sample.flags(); 554 snprintf(mmap.filename, PATH_MAX, "%s", sample.filename().c_str()); 555 556 return DeserializeSampleInfo(sample.sample_info(), event); 557 } 558 559 bool PerfSerializer::SerializeCommEvent(const event_t& event, 560 PerfDataProto_CommEvent* sample) const { 561 const struct comm_event& comm = event.comm; 562 sample->set_pid(comm.pid); 563 sample->set_tid(comm.tid); 564 sample->set_comm(comm.comm); 565 sample->set_comm_md5_prefix(Md5Prefix(comm.comm)); 566 567 return SerializeSampleInfo(event, sample->mutable_sample_info()); 568 } 569 570 bool PerfSerializer::DeserializeCommEvent(const PerfDataProto_CommEvent& sample, 571 event_t* event) const { 572 struct comm_event& comm = event->comm; 573 comm.pid = sample.pid(); 574 comm.tid = sample.tid(); 575 snprintf(comm.comm, sizeof(comm.comm), "%s", sample.comm().c_str()); 576 577 // Sometimes the command string will be modified. e.g. if the original comm 578 // string is not recoverable from the Md5sum prefix, then use the latter as a 579 // replacement comm string. However, if the original was < 8 bytes (fit into 580 // |sizeof(uint64_t)|), then the size is no longer correct. This section 581 // checks for the size difference and updates the size in the header. 582 const SampleInfoReader* reader = 583 GetSampleInfoReaderForId(sample.sample_info().id()); 584 CHECK(reader); 585 uint64_t sample_fields = SampleInfoReader::GetSampleFieldsForEventType( 586 comm.header.type, reader->event_attr().sample_type); 587 comm.header.size = SampleInfoReader::GetPerfSampleDataOffset(*event) + 588 GetNumBits(sample_fields) * sizeof(uint64_t); 589 590 return DeserializeSampleInfo(sample.sample_info(), event); 591 } 592 593 bool PerfSerializer::SerializeForkExitEvent( 594 const event_t& event, PerfDataProto_ForkEvent* sample) const { 595 const struct fork_event& fork = event.fork; 596 sample->set_pid(fork.pid); 597 sample->set_ppid(fork.ppid); 598 sample->set_tid(fork.tid); 599 sample->set_ptid(fork.ptid); 600 sample->set_fork_time_ns(fork.time); 601 602 return SerializeSampleInfo(event, sample->mutable_sample_info()); 603 } 604 605 bool PerfSerializer::DeserializeForkExitEvent( 606 const PerfDataProto_ForkEvent& sample, event_t* event) const { 607 struct fork_event& fork = event->fork; 608 fork.pid = sample.pid(); 609 fork.ppid = sample.ppid(); 610 fork.tid = sample.tid(); 611 fork.ptid = sample.ptid(); 612 fork.time = sample.fork_time_ns(); 613 614 return DeserializeSampleInfo(sample.sample_info(), event); 615 } 616 617 bool PerfSerializer::SerializeLostEvent(const event_t& event, 618 PerfDataProto_LostEvent* sample) const { 619 const struct lost_event& lost = event.lost; 620 sample->set_id(lost.id); 621 sample->set_lost(lost.lost); 622 623 return SerializeSampleInfo(event, sample->mutable_sample_info()); 624 } 625 626 bool PerfSerializer::DeserializeLostEvent(const PerfDataProto_LostEvent& sample, 627 event_t* event) const { 628 struct lost_event& lost = event->lost; 629 lost.id = sample.id(); 630 lost.lost = sample.lost(); 631 632 return DeserializeSampleInfo(sample.sample_info(), event); 633 } 634 635 bool PerfSerializer::SerializeThrottleEvent( 636 const event_t& event, PerfDataProto_ThrottleEvent* sample) const { 637 const struct throttle_event& throttle = event.throttle; 638 sample->set_time_ns(throttle.time); 639 sample->set_id(throttle.id); 640 sample->set_stream_id(throttle.stream_id); 641 642 return SerializeSampleInfo(event, sample->mutable_sample_info()); 643 } 644 645 bool PerfSerializer::DeserializeThrottleEvent( 646 const PerfDataProto_ThrottleEvent& sample, event_t* event) const { 647 struct throttle_event& throttle = event->throttle; 648 throttle.time = sample.time_ns(); 649 throttle.id = sample.id(); 650 throttle.stream_id = sample.stream_id(); 651 652 return DeserializeSampleInfo(sample.sample_info(), event); 653 } 654 655 bool PerfSerializer::SerializeReadEvent(const event_t& event, 656 PerfDataProto_ReadEvent* sample) const { 657 const struct read_event& read = event.read; 658 sample->set_pid(read.pid); 659 sample->set_tid(read.tid); 660 sample->set_value(read.value); 661 sample->set_time_enabled(read.time_enabled); 662 sample->set_time_running(read.time_running); 663 sample->set_id(read.id); 664 665 return true; 666 } 667 668 bool PerfSerializer::DeserializeReadEvent(const PerfDataProto_ReadEvent& sample, 669 event_t* event) const { 670 struct read_event& read = event->read; 671 read.pid = sample.pid(); 672 read.tid = sample.tid(); 673 read.value = sample.value(); 674 read.time_enabled = sample.time_enabled(); 675 read.time_running = sample.time_running(); 676 read.id = sample.id(); 677 678 return true; 679 } 680 681 bool PerfSerializer::SerializeAuxEvent(const event_t& event, 682 PerfDataProto_AuxEvent* sample) const { 683 const struct aux_event& aux = event.aux; 684 sample->set_aux_offset(aux.aux_offset); 685 sample->set_aux_size(aux.aux_size); 686 sample->set_is_truncated(aux.flags & PERF_AUX_FLAG_TRUNCATED ? true : false); 687 sample->set_is_overwrite(aux.flags & PERF_AUX_FLAG_OVERWRITE ? true : false); 688 sample->set_is_partial(aux.flags & PERF_AUX_FLAG_PARTIAL ? true : false); 689 if (aux.flags & ~(PERF_AUX_FLAG_TRUNCATED | PERF_AUX_FLAG_OVERWRITE | 690 PERF_AUX_FLAG_PARTIAL)) { 691 LOG(WARNING) << "Ignoring unknown PERF_RECORD_AUX flag: " << aux.flags; 692 } 693 694 return SerializeSampleInfo(event, sample->mutable_sample_info()); 695 } 696 697 bool PerfSerializer::DeserializeAuxEvent(const PerfDataProto_AuxEvent& sample, 698 event_t* event) const { 699 struct aux_event& aux = event->aux; 700 aux.aux_offset = sample.aux_offset(); 701 aux.aux_size = sample.aux_size(); 702 aux.flags |= sample.is_truncated() ? PERF_AUX_FLAG_TRUNCATED : 0; 703 aux.flags |= sample.is_overwrite() ? PERF_AUX_FLAG_OVERWRITE : 0; 704 aux.flags |= sample.is_partial() ? PERF_AUX_FLAG_PARTIAL : 0; 705 706 return DeserializeSampleInfo(sample.sample_info(), event); 707 } 708 709 bool PerfSerializer::SerializeSampleInfo( 710 const event_t& event, PerfDataProto_SampleInfo* sample) const { 711 if (!SampleIdAll()) return true; 712 713 perf_sample sample_info; 714 uint64_t sample_type = 0; 715 if (!ReadPerfSampleInfoAndType(event, &sample_info, &sample_type)) 716 return false; 717 718 if (sample_type & PERF_SAMPLE_TID) { 719 sample->set_pid(sample_info.pid); 720 sample->set_tid(sample_info.tid); 721 } 722 if (sample_type & PERF_SAMPLE_TIME) 723 sample->set_sample_time_ns(sample_info.time); 724 if ((sample_type & PERF_SAMPLE_ID) || (sample_type & PERF_SAMPLE_IDENTIFIER)) 725 sample->set_id(sample_info.id); 726 if (sample_type & PERF_SAMPLE_CPU) sample->set_cpu(sample_info.cpu); 727 if (sample_type & PERF_SAMPLE_STREAM_ID) 728 sample->set_stream_id(sample_info.stream_id); 729 return true; 730 } 731 732 bool PerfSerializer::DeserializeSampleInfo( 733 const PerfDataProto_SampleInfo& sample, event_t* event) const { 734 if (!SampleIdAll()) return true; 735 736 perf_sample sample_info; 737 if (sample.has_tid()) { 738 sample_info.pid = sample.pid(); 739 sample_info.tid = sample.tid(); 740 } 741 if (sample.has_sample_time_ns()) sample_info.time = sample.sample_time_ns(); 742 if (sample.has_id()) sample_info.id = sample.id(); 743 if (sample.has_cpu()) sample_info.cpu = sample.cpu(); 744 if (sample.has_stream_id()) sample_info.stream_id = sample.stream_id(); 745 746 const SampleInfoReader* writer = GetSampleInfoReaderForId(sample.id()); 747 CHECK(writer); 748 return writer->WritePerfSampleInfo(sample_info, event); 749 } 750 751 bool PerfSerializer::SerializeTracingMetadata(const std::vector<char>& from, 752 PerfDataProto* to) const { 753 if (from.empty()) { 754 return true; 755 } 756 PerfDataProto_PerfTracingMetadata* data = to->mutable_tracing_data(); 757 data->set_tracing_data(from.data(), from.size()); 758 data->set_tracing_data_md5_prefix(Md5Prefix(from)); 759 760 return true; 761 } 762 763 bool PerfSerializer::DeserializeTracingMetadata(const PerfDataProto& from, 764 std::vector<char>* to) const { 765 if (!from.has_tracing_data()) { 766 to->clear(); 767 return true; 768 } 769 770 const PerfDataProto_PerfTracingMetadata& data = from.tracing_data(); 771 to->assign(data.tracing_data().begin(), data.tracing_data().end()); 772 return true; 773 } 774 775 bool PerfSerializer::SerializeBuildIDEvent( 776 const malloced_unique_ptr<build_id_event>& from, 777 PerfDataProto_PerfBuildID* to) const { 778 to->set_misc(from->header.misc); 779 to->set_pid(from->pid); 780 to->set_filename(from->filename); 781 to->set_filename_md5_prefix(Md5Prefix(from->filename)); 782 783 // Trim out trailing zeroes from the build ID. 784 string build_id = RawDataToHexString(from->build_id, kBuildIDArraySize); 785 TrimZeroesFromBuildIDString(&build_id); 786 787 uint8_t build_id_bytes[kBuildIDArraySize]; 788 if (!HexStringToRawData(build_id, build_id_bytes, sizeof(build_id_bytes))) 789 return false; 790 791 // Used to convert build IDs (and possibly other hashes) between raw data 792 // format and as string of hex digits. 793 const int kHexCharsPerByte = 2; 794 to->set_build_id_hash(build_id_bytes, build_id.size() / kHexCharsPerByte); 795 796 return true; 797 } 798 799 bool PerfSerializer::DeserializeBuildIDEvent( 800 const PerfDataProto_PerfBuildID& from, 801 malloced_unique_ptr<build_id_event>* to) const { 802 const string& filename = from.filename(); 803 size_t size = sizeof(build_id_event) + GetUint64AlignedStringLength(filename); 804 805 malloced_unique_ptr<build_id_event>& event = *to; 806 event.reset(CallocMemoryForBuildID(size)); 807 event->header.type = PERF_RECORD_HEADER_BUILD_ID; 808 event->header.size = size; 809 event->header.misc = from.misc(); 810 event->pid = from.pid(); 811 memcpy(event->build_id, from.build_id_hash().c_str(), 812 from.build_id_hash().size()); 813 814 if (from.has_filename() && !filename.empty()) { 815 CHECK_GT( 816 snprintf(event->filename, filename.size() + 1, "%s", filename.c_str()), 817 0); 818 } 819 return true; 820 } 821 822 bool PerfSerializer::SerializeAuxtraceEvent( 823 const event_t& event, PerfDataProto_AuxtraceEvent* sample) const { 824 const struct auxtrace_event& auxtrace = event.auxtrace; 825 sample->set_size(auxtrace.size); 826 sample->set_offset(auxtrace.offset); 827 sample->set_reference(auxtrace.reference); 828 sample->set_idx(auxtrace.idx); 829 sample->set_tid(auxtrace.tid); 830 sample->set_cpu(auxtrace.cpu); 831 832 return true; 833 } 834 835 bool PerfSerializer::SerializeAuxtraceEventTraceData( 836 const std::vector<char>& from, PerfDataProto_AuxtraceEvent* to) const { 837 if (from.empty()) { 838 return true; 839 } 840 to->set_trace_data(from.data(), from.size()); 841 842 return true; 843 } 844 845 bool PerfSerializer::DeserializeAuxtraceEvent( 846 const PerfDataProto_AuxtraceEvent& sample, event_t* event) const { 847 struct auxtrace_event& auxtrace = event->auxtrace; 848 auxtrace.size = sample.size(); 849 auxtrace.offset = sample.offset(); 850 auxtrace.reference = sample.reference(); 851 auxtrace.idx = sample.idx(); 852 auxtrace.tid = sample.tid(); 853 auxtrace.cpu = sample.cpu(); 854 855 return true; 856 } 857 858 bool PerfSerializer::DeserializeAuxtraceEventTraceData( 859 const PerfDataProto_AuxtraceEvent& from, std::vector<char>* to) const { 860 to->assign(from.trace_data().begin(), from.trace_data().end()); 861 return true; 862 } 863 864 bool PerfSerializer::SerializeSingleUint32Metadata( 865 const PerfUint32Metadata& metadata, 866 PerfDataProto_PerfUint32Metadata* proto_metadata) const { 867 proto_metadata->set_type(metadata.type); 868 for (size_t i = 0; i < metadata.data.size(); ++i) 869 proto_metadata->add_data(metadata.data[i]); 870 return true; 871 } 872 873 bool PerfSerializer::DeserializeSingleUint32Metadata( 874 const PerfDataProto_PerfUint32Metadata& proto_metadata, 875 PerfUint32Metadata* metadata) const { 876 metadata->type = proto_metadata.type(); 877 for (int i = 0; i < proto_metadata.data_size(); ++i) 878 metadata->data.push_back(proto_metadata.data(i)); 879 return true; 880 } 881 882 bool PerfSerializer::SerializeSingleUint64Metadata( 883 const PerfUint64Metadata& metadata, 884 PerfDataProto_PerfUint64Metadata* proto_metadata) const { 885 proto_metadata->set_type(metadata.type); 886 for (size_t i = 0; i < metadata.data.size(); ++i) 887 proto_metadata->add_data(metadata.data[i]); 888 return true; 889 } 890 891 bool PerfSerializer::DeserializeSingleUint64Metadata( 892 const PerfDataProto_PerfUint64Metadata& proto_metadata, 893 PerfUint64Metadata* metadata) const { 894 metadata->type = proto_metadata.type(); 895 for (int i = 0; i < proto_metadata.data_size(); ++i) 896 metadata->data.push_back(proto_metadata.data(i)); 897 return true; 898 } 899 900 bool PerfSerializer::SerializeCPUTopologyMetadata( 901 const PerfCPUTopologyMetadata& metadata, 902 PerfDataProto_PerfCPUTopologyMetadata* proto_metadata) const { 903 for (const string& core_name : metadata.core_siblings) { 904 proto_metadata->add_core_siblings(core_name); 905 proto_metadata->add_core_siblings_md5_prefix(Md5Prefix(core_name)); 906 } 907 for (const string& thread_name : metadata.thread_siblings) { 908 proto_metadata->add_thread_siblings(thread_name); 909 proto_metadata->add_thread_siblings_md5_prefix(Md5Prefix(thread_name)); 910 } 911 return true; 912 } 913 914 bool PerfSerializer::DeserializeCPUTopologyMetadata( 915 const PerfDataProto_PerfCPUTopologyMetadata& proto_metadata, 916 PerfCPUTopologyMetadata* metadata) const { 917 metadata->core_siblings.clear(); 918 metadata->core_siblings.reserve(proto_metadata.core_siblings().size()); 919 std::copy(proto_metadata.core_siblings().begin(), 920 proto_metadata.core_siblings().end(), 921 std::back_inserter(metadata->core_siblings)); 922 923 metadata->thread_siblings.clear(); 924 metadata->thread_siblings.reserve(proto_metadata.thread_siblings().size()); 925 std::copy(proto_metadata.thread_siblings().begin(), 926 proto_metadata.thread_siblings().end(), 927 std::back_inserter(metadata->thread_siblings)); 928 return true; 929 } 930 931 bool PerfSerializer::SerializeNodeTopologyMetadata( 932 const PerfNodeTopologyMetadata& metadata, 933 PerfDataProto_PerfNodeTopologyMetadata* proto_metadata) const { 934 proto_metadata->set_id(metadata.id); 935 proto_metadata->set_total_memory(metadata.total_memory); 936 proto_metadata->set_free_memory(metadata.free_memory); 937 proto_metadata->set_cpu_list(metadata.cpu_list); 938 proto_metadata->set_cpu_list_md5_prefix(Md5Prefix(metadata.cpu_list)); 939 return true; 940 } 941 942 bool PerfSerializer::DeserializeNodeTopologyMetadata( 943 const PerfDataProto_PerfNodeTopologyMetadata& proto_metadata, 944 PerfNodeTopologyMetadata* metadata) const { 945 metadata->id = proto_metadata.id(); 946 metadata->total_memory = proto_metadata.total_memory(); 947 metadata->free_memory = proto_metadata.free_memory(); 948 metadata->cpu_list = proto_metadata.cpu_list(); 949 return true; 950 } 951 952 bool PerfSerializer::SerializePMUMappingsMetadata( 953 const PerfPMUMappingsMetadata& metadata, 954 PerfDataProto_PerfPMUMappingsMetadata* proto_metadata) const { 955 proto_metadata->set_type(metadata.type); 956 proto_metadata->set_name(metadata.name); 957 proto_metadata->set_name_md5_prefix(Md5Prefix(metadata.name)); 958 return true; 959 } 960 961 bool PerfSerializer::DeserializePMUMappingsMetadata( 962 const PerfDataProto_PerfPMUMappingsMetadata& proto_metadata, 963 PerfPMUMappingsMetadata* metadata) const { 964 metadata->type = proto_metadata.type(); 965 metadata->name = proto_metadata.name(); 966 return true; 967 } 968 969 bool PerfSerializer::SerializeGroupDescMetadata( 970 const PerfGroupDescMetadata& metadata, 971 PerfDataProto_PerfGroupDescMetadata* proto_metadata) const { 972 proto_metadata->set_name(metadata.name); 973 proto_metadata->set_name_md5_prefix(Md5Prefix(metadata.name)); 974 proto_metadata->set_leader_idx(metadata.leader_idx); 975 proto_metadata->set_num_members(metadata.num_members); 976 return true; 977 } 978 979 bool PerfSerializer::DeserializeGroupDescMetadata( 980 const PerfDataProto_PerfGroupDescMetadata& proto_metadata, 981 PerfGroupDescMetadata* metadata) const { 982 metadata->name = proto_metadata.name(); 983 metadata->leader_idx = proto_metadata.leader_idx(); 984 metadata->num_members = proto_metadata.num_members(); 985 return true; 986 } 987 988 // static 989 void PerfSerializer::SerializeParserStats(const PerfEventStats& stats, 990 PerfDataProto* perf_data_proto) { 991 PerfDataProto_PerfEventStats* stats_pb = perf_data_proto->mutable_stats(); 992 stats_pb->set_num_sample_events(stats.num_sample_events); 993 stats_pb->set_num_mmap_events(stats.num_mmap_events); 994 stats_pb->set_num_fork_events(stats.num_fork_events); 995 stats_pb->set_num_exit_events(stats.num_exit_events); 996 stats_pb->set_did_remap(stats.did_remap); 997 stats_pb->set_num_sample_events_mapped(stats.num_sample_events_mapped); 998 } 999 1000 // static 1001 void PerfSerializer::DeserializeParserStats( 1002 const PerfDataProto& perf_data_proto, PerfEventStats* stats) { 1003 const PerfDataProto_PerfEventStats& stats_pb = perf_data_proto.stats(); 1004 stats->num_sample_events = stats_pb.num_sample_events(); 1005 stats->num_mmap_events = stats_pb.num_mmap_events(); 1006 stats->num_fork_events = stats_pb.num_fork_events(); 1007 stats->num_exit_events = stats_pb.num_exit_events(); 1008 stats->did_remap = stats_pb.did_remap(); 1009 stats->num_sample_events_mapped = stats_pb.num_sample_events_mapped(); 1010 } 1011 1012 void PerfSerializer::CreateSampleInfoReader(const PerfFileAttr& attr, 1013 bool read_cross_endian) { 1014 for (const auto& id : 1015 (attr.ids.empty() ? std::initializer_list<u64>({0}) : attr.ids)) { 1016 sample_info_reader_map_[id].reset( 1017 new SampleInfoReader(attr.attr, read_cross_endian)); 1018 } 1019 UpdateEventIdPositions(attr.attr); 1020 } 1021 1022 void PerfSerializer::UpdateEventIdPositions( 1023 const struct perf_event_attr& attr) { 1024 const u64 sample_type = attr.sample_type; 1025 ssize_t new_sample_event_id_pos = EventIdPosition::NotPresent; 1026 ssize_t new_other_event_id_pos = EventIdPosition::NotPresent; 1027 if (sample_type & PERF_SAMPLE_IDENTIFIER) { 1028 new_sample_event_id_pos = 0; 1029 new_other_event_id_pos = 1; 1030 } else if (sample_type & PERF_SAMPLE_ID) { 1031 // Increment for IP, TID, TIME, ADDR 1032 new_sample_event_id_pos = 0; 1033 if (sample_type & PERF_SAMPLE_IP) new_sample_event_id_pos++; 1034 if (sample_type & PERF_SAMPLE_TID) new_sample_event_id_pos++; 1035 if (sample_type & PERF_SAMPLE_TIME) new_sample_event_id_pos++; 1036 if (sample_type & PERF_SAMPLE_ADDR) new_sample_event_id_pos++; 1037 1038 // Increment for CPU, STREAM_ID 1039 new_other_event_id_pos = 1; 1040 if (sample_type & PERF_SAMPLE_CPU) new_other_event_id_pos++; 1041 if (sample_type & PERF_SAMPLE_STREAM_ID) new_other_event_id_pos++; 1042 } 1043 1044 if (sample_event_id_pos_ == EventIdPosition::Uninitialized) { 1045 sample_event_id_pos_ = new_sample_event_id_pos; 1046 } else { 1047 CHECK_EQ(new_sample_event_id_pos, sample_event_id_pos_) 1048 << "Event ids must be in a consistent positition"; 1049 } 1050 if (other_event_id_pos_ == EventIdPosition::Uninitialized) { 1051 other_event_id_pos_ = new_other_event_id_pos; 1052 } else { 1053 CHECK_EQ(new_other_event_id_pos, other_event_id_pos_) 1054 << "Event ids must be in a consistent positition"; 1055 } 1056 } 1057 1058 bool PerfSerializer::SampleIdAll() const { 1059 if (sample_info_reader_map_.empty()) { 1060 return false; 1061 } 1062 return sample_info_reader_map_.begin()->second->event_attr().sample_id_all; 1063 } 1064 1065 const SampleInfoReader* PerfSerializer::GetSampleInfoReaderForEvent( 1066 const event_t& event) const { 1067 // Where is the event id? 1068 ssize_t event_id_pos = EventIdPosition::Uninitialized; 1069 if (event.header.type == PERF_RECORD_SAMPLE) { 1070 event_id_pos = sample_event_id_pos_; 1071 } else if (SampleIdAll()) { 1072 event_id_pos = other_event_id_pos_; 1073 } else { 1074 event_id_pos = EventIdPosition::NotPresent; 1075 } 1076 1077 // What is the event id? 1078 u64 event_id; 1079 switch (event_id_pos) { 1080 case EventIdPosition::Uninitialized: 1081 LOG(FATAL) << "Position of the event id was not initialized!"; 1082 return nullptr; 1083 case EventIdPosition::NotPresent: 1084 event_id = 0; 1085 break; 1086 default: 1087 if (event.header.type == PERF_RECORD_SAMPLE) { 1088 event_id = event.sample.array[event_id_pos]; 1089 } else { 1090 // Pretend this is a sample event--ie, an array of u64. Find the length 1091 // of the array. The sample id is at the end of the array, and 1092 // event_id_pos (aka other_event_id_pos_) counts from the end. 1093 size_t event_end_pos = 1094 (event.header.size - sizeof(event.header)) / sizeof(u64); 1095 event_id = event.sample.array[event_end_pos - event_id_pos]; 1096 } 1097 break; 1098 } 1099 return GetSampleInfoReaderForId(event_id); 1100 } 1101 1102 const SampleInfoReader* PerfSerializer::GetSampleInfoReaderForId( 1103 uint64_t id) const { 1104 if (id) { 1105 auto iter = sample_info_reader_map_.find(id); 1106 if (iter == sample_info_reader_map_.end()) return nullptr; 1107 return iter->second.get(); 1108 } 1109 1110 if (sample_info_reader_map_.empty()) return nullptr; 1111 return sample_info_reader_map_.begin()->second.get(); 1112 } 1113 1114 bool PerfSerializer::ReadPerfSampleInfoAndType(const event_t& event, 1115 perf_sample* sample_info, 1116 uint64_t* sample_type) const { 1117 const SampleInfoReader* reader = GetSampleInfoReaderForEvent(event); 1118 if (!reader) { 1119 LOG(ERROR) << "No SampleInfoReader available"; 1120 return false; 1121 } 1122 1123 if (!reader->ReadPerfSampleInfo(event, sample_info)) return false; 1124 *sample_type = reader->event_attr().sample_type; 1125 return true; 1126 } 1127 1128 } // namespace quipper 1129