1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2015 The Qt Company Ltd 4 ** All rights reserved. 5 ** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us 6 ** 7 ** This file is part of the Qt Enterprise Perf Profiler Add-on. 8 ** 9 ** GNU General Public License Usage 10 ** This file may be used under the terms of the GNU General Public License 11 ** version 3 as published by the Free Software Foundation and appearing in 12 ** the file LICENSE.GPLv3 included in the packaging of this file. Please 13 ** review the following information to ensure the GNU General Public License 14 ** requirements will be met: https://www.gnu.org/licenses/gpl.html. 15 ** 16 ** If you have questions regarding the use of this file, please use 17 ** contact form at http://www.qt.io/contact-us 18 ** 19 ****************************************************************************/ 20 21 #pragma once 22 23 #include "perfattributes.h" 24 #include "perffeatures.h" 25 #include "perfheader.h" 26 27 #include <QIODevice> 28 29 #ifdef HAVE_ZSTD 30 #include <zstd.h> 31 32 constexpr bool CAN_DECOMPRESS_ZSTD = true; 33 #else 34 constexpr bool CAN_DECOMPRESS_ZSTD = false; 35 #endif 36 37 enum PerfEventType { 38 39 /* 40 * If perf_event_attr.sample_id_all is set then all event types will 41 * have the sample_type selected fields related to where/when 42 * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU, 43 * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed 44 * just after the perf_event_header and the fields already present for 45 * the existing fields, i.e. at the end of the payload. That way a newer 46 * perf.data file will be supported by older perf tools, with these new 47 * optional fields being ignored. 48 * 49 * struct sample_id { 50 * { u32 pid, tid; } && PERF_SAMPLE_TID 51 * { u64 time; } && PERF_SAMPLE_TIME 52 * { u64 id; } && PERF_SAMPLE_ID 53 * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID 54 * { u32 cpu, res; } && PERF_SAMPLE_CPU 55 * { u64 id; } && PERF_SAMPLE_IDENTIFIER 56 * } && perf_event_attr::sample_id_all 57 * 58 * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The 59 * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed 60 * relative to header.size. 61 */ 62 63 /* 64 * The MMAP events record the PROT_EXEC mappings so that we can 65 * correlate userspace IPs to code. They have the following structure: 66 * 67 * struct { 68 * struct perf_event_header header; 69 * 70 * u32 pid, tid; 71 * u64 addr; 72 * u64 len; 73 * u64 pgoff; 74 * char filename[]; 75 * struct sample_id sample_id; 76 * }; 77 */ 78 PERF_RECORD_MMAP = 1, 79 80 /* 81 * struct { 82 * struct perf_event_header header; 83 * u64 id; 84 * u64 lost; 85 * struct sample_id sample_id; 86 * }; 87 */ 88 PERF_RECORD_LOST = 2, 89 90 /* 91 * struct { 92 * struct perf_event_header header; 93 * 94 * u32 pid, tid; 95 * char comm[]; 96 * struct sample_id sample_id; 97 * }; 98 */ 99 PERF_RECORD_COMM = 3, 100 101 /* 102 * struct { 103 * struct perf_event_header header; 104 * u32 pid, ppid; 105 * u32 tid, ptid; 106 * u64 time; 107 * struct sample_id sample_id; 108 * }; 109 */ 110 PERF_RECORD_EXIT = 4, 111 112 /* 113 * struct { 114 * struct perf_event_header header; 115 * u64 time; 116 * u64 id; 117 * u64 stream_id; 118 * struct sample_id sample_id; 119 * }; 120 */ 121 PERF_RECORD_THROTTLE = 5, 122 PERF_RECORD_UNTHROTTLE = 6, 123 124 /* 125 * struct { 126 * struct perf_event_header header; 127 * u32 pid, ppid; 128 * u32 tid, ptid; 129 * u64 time; 130 * struct sample_id sample_id; 131 * }; 132 */ 133 PERF_RECORD_FORK = 7, 134 135 /* 136 * struct { 137 * struct perf_event_header header; 138 * u32 pid, tid; 139 * 140 * struct read_format values; 141 * struct sample_id sample_id; 142 * }; 143 */ 144 PERF_RECORD_READ = 8, 145 146 /* 147 * struct { 148 * struct perf_event_header header; 149 * 150 * # 151 * # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. 152 * # The advantage of PERF_SAMPLE_IDENTIFIER is that its position 153 * # is fixed relative to header. 154 * # 155 * 156 * { u64 id; } && PERF_SAMPLE_IDENTIFIER 157 * { u64 ip; } && PERF_SAMPLE_IP 158 * { u32 pid, tid; } && PERF_SAMPLE_TID 159 * { u64 time; } && PERF_SAMPLE_TIME 160 * { u64 addr; } && PERF_SAMPLE_ADDR 161 * { u64 id; } && PERF_SAMPLE_ID 162 * { u64 stream_id; } && PERF_SAMPLE_STREAM_ID 163 * { u32 cpu, res; } && PERF_SAMPLE_CPU 164 * { u64 period; } && PERF_SAMPLE_PERIOD 165 * 166 * { struct read_format values;} && PERF_SAMPLE_READ 167 * 168 * { u64 nr, 169 * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN 170 * 171 * # 172 * # The RAW record below is opaque data wrt the ABI 173 * # 174 * # That is, the ABI doesn't make any promises wrt to 175 * # the stability of its content, it may vary depending 176 * # on event, hardware, kernel version and phase of 177 * # the moon. 178 * # 179 * # In other words, PERF_SAMPLE_RAW contents are not an ABI. 180 * # 181 * 182 * { u32 size; 183 * char data[size];} && PERF_SAMPLE_RAW 184 * 185 * { u64 nr; 186 * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK 187 * 188 * { u64 abi; # enum perf_sample_regs_abi 189 * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER 190 * 191 * { u64 size; 192 * char data[size]; 193 * u64 dyn_size; } && PERF_SAMPLE_STACK_USER 194 * 195 * { u64 weight; } && PERF_SAMPLE_WEIGHT 196 * { u64 data_src; } && PERF_SAMPLE_DATA_SRC 197 * { u64 transaction; } && PERF_SAMPLE_TRANSACTION 198 * }; 199 */ 200 PERF_RECORD_SAMPLE = 9, 201 202 /* 203 * The MMAP2 records are an augmented version of MMAP, they add 204 * maj, min, ino numbers to be used to uniquely identify each mapping 205 * 206 * struct { 207 * struct perf_event_header header; 208 * 209 * u32 pid, tid; 210 * u64 addr; 211 * u64 len; 212 * u64 pgoff; 213 * u32 maj; 214 * u32 min; 215 * u64 ino; 216 * u64 ino_generation; 217 * u32 prot, flags; 218 * char filename[]; 219 * struct sample_id sample_id; 220 * }; 221 */ 222 PERF_RECORD_MMAP2 = 10, 223 224 /* 225 * Records a context switch in or out (flagged by 226 * PERF_RECORD_MISC_SWITCH_OUT). See also 227 * PERF_RECORD_SWITCH_CPU_WIDE. 228 * 229 * struct { 230 * struct perf_event_header header; 231 * struct sample_id sample_id; 232 * }; 233 */ 234 PERF_RECORD_SWITCH = 14, 235 236 /* 237 * CPU-wide version of PERF_RECORD_SWITCH with next_prev_pid and 238 * next_prev_tid that are the next (switching out) or previous 239 * (switching in) pid/tid. 240 * 241 * struct { 242 * struct perf_event_header header; 243 * u32 next_prev_pid; 244 * u32 next_prev_tid; 245 * struct sample_id sample_id; 246 * }; 247 */ 248 PERF_RECORD_SWITCH_CPU_WIDE = 15, 249 250 /* 251 * struct { 252 * struct perf_event_header header; 253 * u32 pid; 254 * u32 tid; 255 * u64 nr_namespaces; 256 * { u64 dev, inode; } [nr_namespaces]; 257 * struct sample_id sample_id; 258 * }; 259 */ 260 PERF_RECORD_NAMESPACES = 16, 261 262 /* 263 * Record ksymbol register/unregister events: 264 * 265 * struct { 266 * struct perf_event_header header; 267 * u64 addr; 268 * u32 len; 269 * u16 ksym_type; 270 * u16 flags; 271 * char name[]; 272 * struct sample_id sample_id; 273 * }; 274 */ 275 PERF_RECORD_KSYMBOL = 17, 276 277 /* 278 * Record bpf events: 279 * enum perf_bpf_event_type { 280 * PERF_BPF_EVENT_UNKNOWN = 0, 281 * PERF_BPF_EVENT_PROG_LOAD = 1, 282 * PERF_BPF_EVENT_PROG_UNLOAD = 2, 283 * }; 284 * 285 * struct { 286 * struct perf_event_header header; 287 * u16 type; 288 * u16 flags; 289 * u32 id; 290 * u8 tag[BPF_TAG_SIZE]; 291 * struct sample_id sample_id; 292 * }; 293 */ 294 PERF_RECORD_BPF_EVENT = 18, 295 296 /* 297 * struct { 298 * struct perf_event_header header; 299 * u64 id; 300 * char path[]; 301 * struct sample_id sample_id; 302 * }; 303 */ 304 PERF_RECORD_CGROUP = 19, 305 306 PERF_RECORD_MAX, /* non-ABI */ 307 308 PERF_RECORD_USER_TYPE_START = 64, 309 PERF_RECORD_HEADER_ATTR = 64, 310 PERF_RECORD_HEADER_EVENT_TYPE = 65, /* deprecated */ 311 PERF_RECORD_HEADER_TRACING_DATA = 66, 312 PERF_RECORD_HEADER_BUILD_ID = 67, 313 PERF_RECORD_FINISHED_ROUND = 68, 314 PERF_RECORD_ID_INDEX = 69, 315 PERF_RECORD_AUXTRACE_INFO = 70, 316 PERF_RECORD_AUXTRACE = 71, 317 PERF_RECORD_AUXTRACE_ERROR = 72, 318 PERF_RECORD_THREAD_MAP = 73, 319 PERF_RECORD_CPU_MAP = 74, 320 PERF_RECORD_STAT_CONFIG = 75, 321 PERF_RECORD_STAT = 76, 322 PERF_RECORD_STAT_ROUND = 77, 323 PERF_RECORD_EVENT_UPDATE = 78, 324 PERF_RECORD_TIME_CONV = 79, 325 PERF_RECORD_HEADER_FEATURE = 80, 326 PERF_RECORD_COMPRESSED = 81, 327 PERF_RECORD_HEADER_MAX 328 }; 329 330 enum PERF_RECORD_MISC { 331 PERF_RECORD_MISC_SWITCH_OUT = (1 << 13), 332 }; 333 334 class PerfRecordSample; 335 336 // Use first attribute for deciding if this is present, not the header! 337 // Why the first?!? idiots ... => encoded in sampleType via sampleIdAll 338 struct PerfSampleId { 339 PerfSampleId(quint64 sampleType = 0, bool sampleIdAll = false) : m_pid(0), m_tid(0), m_time(0), 340 m_id(0), m_streamId(0), m_cpu(0), m_res(0), 341 m_sampleType(sampleType 342 | (sampleIdAll ? static_cast<quint64>(PerfEventAttributes::SAMPLE_ID_ALL) : 0)) 343 {} 344 pidPerfSampleId345 qint32 pid() const { return m_pid; } tidPerfSampleId346 qint32 tid() const { return m_tid; } timePerfSampleId347 quint64 time() const { return m_time; } idPerfSampleId348 quint64 id() const { return m_id; } 349 quint16 fixedLength() const; sampleTypePerfSampleId350 quint64 sampleType() const { return m_sampleType; } cpuPerfSampleId351 quint32 cpu() const { return m_cpu; } 352 353 private: 354 qint32 m_pid; 355 qint32 m_tid; 356 quint64 m_time; 357 quint64 m_id; 358 quint64 m_streamId; 359 quint32 m_cpu; 360 quint32 m_res; 361 362 union { 363 quint64 m_ignoredDuplicateId; // In the file format this is the same as id above 364 quint64 m_sampleType; // As the id is ignored we can reuse the space for saving the flags 365 }; 366 367 friend QDataStream &operator>>(QDataStream &stream, PerfSampleId &sampleId); 368 friend QDataStream &operator>>(QDataStream &stream, PerfRecordSample &record); 369 }; 370 371 QDataStream &operator>>(QDataStream &stream, PerfSampleId &sampleId); 372 373 class PerfRecord { 374 public: pid()375 qint32 pid() const { return m_sampleId.pid(); } tid()376 qint32 tid() const { return m_sampleId.tid(); } time()377 quint64 time() const { return m_sampleId.time(); } id()378 quint64 id() const { return m_sampleId.id(); } cpu()379 quint32 cpu() const { return m_sampleId.cpu(); } size()380 quint16 size() const { return m_header.size; } misc()381 quint16 misc() const { return m_header.misc; } type()382 quint64 type() const { return m_sampleId.sampleType(); } 383 384 protected: 385 PerfRecord(const PerfEventHeader *header, quint64 sampleType, bool sampleIdAll); 386 PerfEventHeader m_header; 387 PerfSampleId m_sampleId; 388 fixedLength()389 quint16 fixedLength() const { return m_header.fixedLength() + m_sampleId.fixedLength(); } 390 }; 391 392 class PerfRecordMmap2; 393 class PerfRecordMmap : public PerfRecord { 394 public: 395 PerfRecordMmap(PerfEventHeader *header = nullptr, quint64 sampleType = 0, 396 bool sampleIdAll = false); 397 398 // The pids and tids in the sampleId are always 0 in this case. Go figure ... pid()399 qint32 pid() const { return m_pid; } tid()400 qint32 tid() const { return m_tid; } 401 addr()402 quint64 addr() const { return m_addr; } len()403 quint64 len() const { return m_len; } pgoff()404 quint64 pgoff() const { return m_pgoff; } filename()405 const QByteArray &filename() const { return m_filename; } 406 407 protected: 408 QDataStream &readNumbers(QDataStream &stream); 409 QDataStream &readFilename(QDataStream &stream, quint16 filenameLength); 410 QDataStream &readSampleId(QDataStream &stream); 411 quint16 fixedLength() const; 412 413 private: 414 qint32 m_pid; 415 qint32 m_tid; 416 quint64 m_addr; 417 quint64 m_len; 418 quint64 m_pgoff; 419 QByteArray m_filename; 420 421 friend QDataStream &operator>>(QDataStream &stream, PerfRecordMmap &record); 422 friend QDataStream &operator>>(QDataStream &stream, PerfRecordMmap2 &record); 423 }; 424 425 QDataStream &operator>>(QDataStream &stream, PerfRecordMmap &record); 426 427 class PerfRecordMmap2 : public PerfRecordMmap 428 { 429 public: 430 PerfRecordMmap2(PerfEventHeader *header = nullptr, quint64 sampleType = 0, 431 bool sampleIdAll = false); 432 prot()433 quint32 prot() const { return m_prot; } 434 435 protected: 436 QDataStream &readNumbers(QDataStream &stream); 437 438 private: 439 quint32 m_maj; 440 quint32 m_min; 441 quint64 m_ino; 442 quint64 m_ino_generation; 443 quint32 m_prot; 444 quint32 m_flags; 445 446 quint16 fixedLength() const; 447 448 friend QDataStream &operator>>(QDataStream &stream, PerfRecordMmap2 &record); 449 }; 450 451 QDataStream &operator>>(QDataStream &stream, PerfRecordMmap2 &record); 452 453 class PerfRecordLost : public PerfRecord { 454 public: 455 PerfRecordLost(PerfEventHeader *header = nullptr, quint64 sampleType = 0, 456 bool sampleIdAll = false); 457 lost()458 quint64 lost() const { return m_lost; } 459 private: 460 quint64 m_id; 461 quint64 m_lost; 462 463 friend QDataStream &operator>>(QDataStream &stream, PerfRecordLost &record); 464 }; 465 466 QDataStream &operator>>(QDataStream &stream, PerfRecordLost &record); 467 468 class PerfRecordComm : public PerfRecord { 469 public: 470 PerfRecordComm(PerfEventHeader *header = nullptr, quint64 sampleType = 0, 471 bool sampleIdAll = false); comm()472 const QByteArray &comm() const { return m_comm; } 473 474 // The pids and tids in the sampleId are always 0 in this case. Go figure ... pid()475 qint32 pid() const { return m_pid; } tid()476 qint32 tid() const { return m_tid; } 477 478 private: 479 qint32 m_pid; 480 qint32 m_tid; 481 QByteArray m_comm; 482 fixedLength()483 quint16 fixedLength() const { return PerfRecord::fixedLength() + sizeof(m_pid) + sizeof(m_tid); } 484 485 friend QDataStream &operator>>(QDataStream &stream, PerfRecordComm &record); 486 }; 487 488 QDataStream &operator>>(QDataStream &stream, PerfRecordComm &record); 489 490 class PerfRecordSample : public PerfRecord { 491 public: 492 PerfRecordSample(const PerfEventHeader *header = nullptr, 493 const PerfEventAttributes *attributes = nullptr); registerAbi()494 quint64 registerAbi() const { return m_registerAbi; } 495 quint64 registerValue(int reg) const; ip()496 quint64 ip() const { return m_ip; } userStack()497 const QByteArray &userStack() const { return m_userStack; } callchain()498 const QList<quint64> &callchain() const { return m_callchain; } period()499 quint64 period() const { return m_period; } weight()500 quint64 weight() const { return m_weight; } rawData()501 const QByteArray &rawData() const { return m_rawData; } 502 503 struct ReadFormat { 504 quint64 value; 505 quint64 id; 506 }; 507 readFormats()508 QList<ReadFormat> readFormats() const { return m_readFormats; } 509 510 struct BranchFlags { 511 quint64 mispred: 1; 512 quint64 predicted: 1; 513 quint64 in_tx: 1; 514 quint64 abort: 1; 515 quint64 cycles: 16; 516 quint64 type: 4; 517 quint64 reserved: 40; 518 }; 519 520 struct BranchEntry { 521 quint64 from; 522 quint64 to; 523 BranchFlags flags; 524 }; branchStack()525 const QList<BranchEntry> &branchStack() const { return m_branchStack; } 526 527 private: 528 529 quint64 m_readFormat; 530 quint64 m_registerMask; 531 532 quint64 m_ip; 533 quint64 m_addr; 534 quint64 m_period; 535 quint64 m_timeEnabled; 536 quint64 m_timeRunning; 537 538 quint64 m_registerAbi; 539 quint64 m_weight; 540 quint64 m_dataSrc; 541 quint64 m_transaction; 542 543 QList<ReadFormat> m_readFormats; 544 QList<quint64> m_callchain; 545 QByteArray m_rawData; 546 QList<BranchEntry> m_branchStack; 547 QList<quint64> m_registers; 548 QByteArray m_userStack; 549 550 friend QDataStream &operator>>(QDataStream &stream, PerfRecordSample &record); 551 }; 552 553 QDataStream &operator>>(QDataStream &stream, PerfRecordSample &record); 554 555 class PerfRecordAttr : public PerfRecord 556 { 557 public: 558 PerfRecordAttr(const PerfEventHeader *header = nullptr, quint64 sampleType = 0, 559 bool sampleIdAll = false); 560 561 PerfRecordAttr(const PerfEventAttributes &attributes, const QList<quint64> &ids); 562 attr()563 const PerfEventAttributes &attr() const { return m_attr; } ids()564 const QList<quint64> &ids() const { return m_ids; } 565 566 private: 567 PerfEventAttributes m_attr; 568 QList<quint64> m_ids; 569 570 friend QDataStream &operator>>(QDataStream &stream, PerfRecordAttr &record); 571 }; 572 573 QDataStream &operator>>(QDataStream &stream, PerfRecordAttr &record); 574 575 class PerfRecordFork : public PerfRecord 576 { 577 public: 578 PerfRecordFork(PerfEventHeader *header = nullptr, quint64 sampleType = 0, 579 bool sampleIdAll = false); childTid()580 qint32 childTid() const { return m_tid; } childPid()581 qint32 childPid() const { return m_pid; } parentTid()582 qint32 parentTid() const { return m_ptid; } parentPid()583 qint32 parentPid() const { return m_ppid; } 584 private: 585 qint32 m_pid, m_ppid; 586 qint32 m_tid, m_ptid; 587 quint64 m_time; 588 589 friend QDataStream &operator>>(QDataStream &stream, PerfRecordFork &record); 590 }; 591 592 QDataStream &operator>>(QDataStream &stream, PerfRecordFork &record); 593 594 typedef PerfRecordFork PerfRecordExit; 595 596 class PerfRecordContextSwitch : public PerfRecord 597 { 598 public: 599 PerfRecordContextSwitch(PerfEventHeader *header = 0, quint64 sampleType = 0, 600 bool sampleIdAll = false); 601 602 private: 603 friend QDataStream &operator>>(QDataStream &stream, PerfRecordContextSwitch &record); 604 }; 605 606 QDataStream &operator>>(QDataStream &stream, PerfRecordContextSwitch &record); 607 608 class PerfRecordContextSwitchCpuWide : public PerfRecordContextSwitch 609 { 610 public: 611 PerfRecordContextSwitchCpuWide(PerfEventHeader *header = 0, quint64 sampleType = 0, 612 bool sampleIdAll = false); 613 nextPrevPid()614 qint32 nextPrevPid() const { return m_nextPrevPid; } nextPrevTid()615 qint32 nextPrevTid() const { return m_nextPrevTid; } 616 617 private: 618 qint32 m_nextPrevPid; 619 qint32 m_nextPrevTid; 620 friend QDataStream &operator>>(QDataStream &stream, PerfRecordContextSwitchCpuWide &record); 621 }; 622 623 QDataStream &operator>>(QDataStream &stream, PerfRecordContextSwitchCpuWide &record); 624 625 class PerfUnwind; 626 class PerfData : public QObject 627 { 628 Q_OBJECT 629 public: 630 PerfData(PerfUnwind *destination, const PerfHeader *header, PerfAttributes *attributes); 631 ~PerfData(); 632 void setSource(QIODevice *source); 633 634 bool setCompressed(const PerfCompressed &compressed); 635 636 public slots: 637 void read(); 638 void finishReading(); 639 640 signals: 641 void finished(); 642 void error(); 643 644 private: 645 646 enum ReadStatus { 647 Rerun, 648 SignalError, 649 SignalFinished 650 }; 651 652 QIODevice *m_source; 653 PerfUnwind *m_destination; 654 655 const PerfHeader *m_header; 656 PerfAttributes *m_attributes; 657 PerfEventHeader m_eventHeader; 658 PerfTracingData m_tracingData; 659 PerfCompressed m_compressed; 660 QByteArray m_decompressBuffer; 661 QByteArray m_compressedBuffer; 662 int m_remaininingDecompressedDataSize = 0; 663 #ifdef HAVE_ZSTD 664 ZSTD_DStream *m_zstdDstream = nullptr; 665 #endif 666 667 ReadStatus processEvents(QDataStream &stream); 668 ReadStatus doRead(); 669 }; 670