diff --git a/src/perf_event_record.cpp b/src/perf_event_record.cpp index d8af5fd5e59db608c12e7efa662b086650444332..60826ca72223aa3428b5d896170fbe9518a2e4bd 100644 --- a/src/perf_event_record.cpp +++ b/src/perf_event_record.cpp @@ -16,6 +16,8 @@ #include "perf_event_record.h" #include +#include +#include #include "utilities.h" @@ -24,6 +26,11 @@ using namespace std; namespace OHOS { namespace Developtools { namespace HiPerf { +struct SampleTypeHandler { + uint64_t type; + void (*handler)(const PerfRecordSample&, int); +}; + std::unique_ptr GetPerfEventRecord(const int type, uint8_t *p, const perf_event_attr &attr) { @@ -31,41 +38,45 @@ std::unique_ptr GetPerfEventRecord(const int type, uint8_t *p, uint8_t *data = p; // check kernel - switch (type) { - case PERF_RECORD_SAMPLE: - return std::make_unique(data, attr); - case PERF_RECORD_MMAP: - return std::make_unique(data); - case PERF_RECORD_MMAP2: - return std::make_unique(data); - case PERF_RECORD_LOST: - return std::make_unique(data); - case PERF_RECORD_COMM: - return std::make_unique(data); - case PERF_RECORD_EXIT: - return std::make_unique(data); - case PERF_RECORD_THROTTLE: - return std::make_unique(data); - case PERF_RECORD_UNTHROTTLE: - return std::make_unique(data); - case PERF_RECORD_FORK: - return std::make_unique(data); - case PERF_RECORD_READ: - return std::make_unique(data); - case PERF_RECORD_AUX: - return std::make_unique(data); - case PERF_RECORD_ITRACE_START: - return std::make_unique(data); - case PERF_RECORD_LOST_SAMPLES: - return std::make_unique(data); - case PERF_RECORD_SWITCH: - return std::make_unique(data); - case PERF_RECORD_SWITCH_CPU_WIDE: - return std::make_unique(data); - default: - HLOGE("unknown record type %d\n", type); - return nullptr; - } + static std::unordered_map(uint8_t*, const perf_event_attr&)>> + record_map{ + {PERF_RECORD_SAMPLE, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data, attr); }}, + {PERF_RECORD_MMAP, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }}, + {PERF_RECORD_MMAP2, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }}, + {PERF_RECORD_LOST, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }}, + {PERF_RECORD_COMM, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }}, + {PERF_RECORD_EXIT, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }}, + {PERF_RECORD_THROTTLE, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }}, + {PERF_RECORD_UNTHROTTLE, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }}, + {PERF_RECORD_FORK, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }}, + {PERF_RECORD_READ, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }}, + {PERF_RECORD_AUX, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }}, + {PERF_RECORD_ITRACE_START, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }}, + {PERF_RECORD_LOST_SAMPLES, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }}, + {PERF_RECORD_SWITCH, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }}, + {PERF_RECORD_SWITCH_CPU_WIDE, + [](uint8_t* data, const perf_event_attr& attr) { return std::make_unique(data); }} + }; + auto it = record_map.find(type); + if (it != record_map.end()) { + return it->second(data, attr); + } + HLOGE("unknown record type %dn", type); + return nullptr; } template @@ -348,85 +359,126 @@ bool PerfRecordSample::GetBinary(std::vector &buf) const return true; } -void PerfRecordSample::DumpData(int indent) const +void handleSampleId(const PerfRecordSample& sample, int indent) { - PrintIndent(indent, "sample_type: 0x%" PRIx64 "\n", sampleType_); + PrintIndent(indent, "ID %" PRIu64 "\n", static_cast(sample.data_.sample_id)); +} - // dump record according sampleType - if (sampleType_ & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) { - PrintIndent(indent, "ID %" PRIu64 "\n", static_cast(data_.sample_id)); - } - if (sampleType_ & PERF_SAMPLE_IP) { - PrintIndent(indent, "ip %llx\n", data_.ip); - } - if (sampleType_ & PERF_SAMPLE_TID) { - PrintIndent(indent, "pid %u, tid %u\n", data_.pid, data_.tid); - } - if (sampleType_ & PERF_SAMPLE_TIME) { - PrintIndent(indent, "time %llu\n", data_.time); - } - if (sampleType_ & PERF_SAMPLE_ADDR) { - PrintIndent(indent, "addr %p\n", reinterpret_cast(data_.addr)); - } - if (sampleType_ & PERF_SAMPLE_STREAM_ID) { - PrintIndent(indent, "stream_id %" PRIu64 "\n", static_cast(data_.stream_id)); - } - if (sampleType_ & PERF_SAMPLE_CPU) { - PrintIndent(indent, "cpu %u, res %u\n", data_.cpu, data_.res); - } - if (sampleType_ & PERF_SAMPLE_PERIOD) { - PrintIndent(indent, "period %" PRIu64 "\n", static_cast(data_.period)); - } - if (sampleType_ & PERF_SAMPLE_CALLCHAIN) { - bool userContext = false; - PrintIndent(indent, "callchain nr=%lld\n", data_.nr); - for (uint64_t i = 0; i < data_.nr; ++i) { - std::string_view supplement = ""; - if ((sampleType_ & PERF_SAMPLE_STACK_USER) == 0 || data_.ips[i] != PERF_CONTEXT_USER) { - PrintIndent(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data()); - continue; - } - // is PERF_SAMPLE_STACK_USER type and is PERF_CONTEXT_USER - if (!userContext) { - userContext = true; - supplement = " "; - } else { - supplement = " "; - } - PrintIndent(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data()); +void handleSampleIp(const PerfRecordSample& sample, int indent) +{ + PrintIndent(indent, "ip %llx\n", sample.data_.ip); +} + +void handleSampleTid(const PerfRecordSample& sample, int indent) +{ + PrintIndent(indent, "pid %u, tid %u\n", sample.data_.pid, sample.data_.tid); +} + +void handleSampleTime(const PerfRecordSample& sample, int indent) +{ + PrintIndent(indent, "time %llu\n", sample.data_.time); +} + +void handleSampleAddr(const PerfRecordSample& sample, int indent) +{ + PrintIndent(indent, "addr %p\n", reinterpret_cast(sample.data_.addr)); +} + +void handleSampleStreamId(const PerfRecordSample& sample, int indent) +{ + PrintIndent(indent, "stream_id %" PRIu64 "\n", static_cast(sample.data_.stream_id)); +} + +void handleSampleCpu(const PerfRecordSample& sample, int indent) +{ + PrintIndent(indent, "cpu %u, res %u\n", sample.data_.cpu, sample.data_.res); +} + +void handleSamplePeriod(const PerfRecordSample& sample, int indent) +{ + PrintIndent(indent, "period %" PRIu64 "\n", static_cast(sample.data_.period)); +} + +void handleSampleCallchain(const PerfRecordSample& sample, int indent) +{ + bool userContext = false; + PrintIndent(indent, "callchain nr=%lld\n", sample.data_.nr); + for (uint64_t i = 0; i < sample.data_.nr; ++i) { + std::string_view supplement = ""; + if ((sample.sampleType_ & PERF_SAMPLE_STACK_USER) == 0 || sample.data_.ips[i] != PERF_CONTEXT_USER) { + PrintIndent(indent + 1, "0x%llx%s\n", sample.data_.ips[i], supplement.data()); + continue; } - } - if (sampleType_ & PERF_SAMPLE_RAW) { - PrintIndent(indent, "raw size=%u\n", data_.raw_size); - const uint32_t *data = reinterpret_cast(data_.raw_data); - size_t size = data_.raw_size / sizeof(uint32_t); - for (size_t i = 0; i < size; ++i) { - PrintIndent(indent + 1, "0x%08x (%x)\n", data[i], data[i]); + // is PERF_SAMPLE_STACK_USER type and is PERF_CONTEXT_USER + if (!userContext) { + userContext = true; + supplement = " "; + } else { + supplement = " "; } + PrintIndent(indent + 1, "0x%llx%s\n", sample.data_.ips[i], supplement.data()); } - if (sampleType_ & PERF_SAMPLE_BRANCH_STACK) { - PrintIndent(indent, "branch_stack nr=%lld\n", data_.bnr); - for (uint64_t i = 0; i < data_.bnr; ++i) { - auto &item = data_.lbr[i]; - PrintIndent(indent + 1, "from 0x%llx, to 0x%llx %s%s\n", item.from, item.to, - item.mispred ? "mispred" : "", item.predicted ? "predicted" : ""); - } +} + +void handleSampleRaw(const PerfRecordSample& sample, int indent) +{ + PrintIndent(indent, "raw size=%u\n", sample.data_.raw_size); + const uint32_t *data = reinterpret_cast(sample.data_.raw_data); + size_t size = sample.data_.raw_size / sizeof(uint32_t); + for (size_t i = 0; i < size; ++i) { + PrintIndent(indent + 1, "0x%08x (%x)\n", data[i], data[i]); } - if (sampleType_ & PERF_SAMPLE_REGS_USER) { - PrintIndent(indent, "user regs: abi=%lld, reg_nr=%lld\n", data_.user_abi, data_.reg_nr); - for (uint64_t i = 0; i < data_.reg_nr; ++i) { - PrintIndent(indent + 1, "0x%llx\n", data_.user_regs[i]); - } +} + +void handleSampleBranchStack(const PerfRecordSample& sample, int indent) +{ + PrintIndent(indent, "branch_stack nr=%lld\n", sample.data_.bnr); + for (uint64_t i = 0; i < sample.data_.bnr; ++i) { + auto &item = sample.data_.lbr[i]; + PrintIndent(indent + 1, "from 0x%llx, to 0x%llx %s%s\n", item.from, item.to, + item.mispred ? "mispred" : "", item.predicted ? "predicted" : ""); } - if (sampleType_ & PERF_SAMPLE_SERVER_PID) { - PrintIndent(indent, "server nr=%lld\n", data_.server_nr); - for (uint64_t i = 0; i < data_.server_nr; ++i) { - PrintIndent(indent + 1, "pid: %llu\n", data_.server_pids[i]); - } +} + +void handleSampleRegsUser(const PerfRecordSample& sample, int indent) +{ + PrintIndent(indent, "user regs: abi=%lld, reg_nr=%lld\n", sample.data_.user_abi, sample.data_.reg_nr); + for (uint64_t i = 0; i < sample.data_.reg_nr; ++i) { + PrintIndent(indent + 1, "0x%llx\n", sample.data_.user_regs[i]); + } +} + +void handleSampleServerPid(const PerfRecordSample& sample, int indent) +{ + PrintIndent(indent, "server nr=%lld\n", sample.data_.server_nr); + for (uint64_t i = 0; i < sample.data_.server_nr; ++i) { + PrintIndent(indent + 1, "pid: %llu\n", sample.data_.server_pids[i]); } - if (sampleType_ & PERF_SAMPLE_STACK_USER) { - PrintIndent(indent, "user stack: size %llu dyn_size %lld\n", data_.stack_size, - data_.dyn_size); +} + +void handleSampleStackUser(const PerfRecordSample& sample, int indent) +{ + PrintIndent(indent, "user stack: size %llu dyn_size %lld\n", sample.data_.stack_size, sample.data_.dyn_size); +} + +void PerfRecordSample::DumpData(int indent) const +{ + SampleTypeHandler handlers[] = { + {PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER, handleSampleId}, {PERF_SAMPLE_IP, handleSampleIp}, + {PERF_SAMPLE_TID, handleSampleTid}, {PERF_SAMPLE_TIME, handleSampleTime}, + {PERF_SAMPLE_ADDR, handleSampleAddr}, {PERF_SAMPLE_STREAM_ID, handleSampleStreamId}, + {PERF_SAMPLE_CPU, handleSampleCpu}, {PERF_SAMPLE_PERIOD, handleSamplePeriod}, + {PERF_SAMPLE_CALLCHAIN, handleSampleCallchain}, {PERF_SAMPLE_RAW, handleSampleRaw}, + {PERF_SAMPLE_BRANCH_STACK, handleSampleBranchStack}, {PERF_SAMPLE_REGS_USER, handleSampleRegsUser}, + {PERF_SAMPLE_SERVER_PID, handleSampleServerPid}, {PERF_SAMPLE_STACK_USER, handleSampleStackUser}, + }; + int handlersLength = sizeof(handlers) / sizeof(handlers[0]); + + PrintIndent(indent, "sample_type: 0x%" PRIx64 "\n", sampleType_); + for (int i = 0; i < handlersLength; i++) { + if (sampleType_ & handlers[i].type) { + handlers[i].handler(*this, indent); + } } } diff --git a/src/subcommand_stat.cpp b/src/subcommand_stat.cpp index ebd77215d8df7aa8c51ae4e1e1d7c2927a904975..08a66cbe3718ec6bba7c389984ee8d7ef855c46c 100644 --- a/src/subcommand_stat.cpp +++ b/src/subcommand_stat.cpp @@ -358,35 +358,33 @@ void SubCommandStat::FormatComments(const std::unique_ptr if (reportSum->commentSum == 0) { return; } - if (reportSum->configName == "sw-task-clock") { - commentStr = StringPrintf("%lf cpus used", reportSum->commentSum); - return; - } - if (reportSum->configName == "hw-cpu-cycles") { - commentStr = StringPrintf("%lf GHz", reportSum->commentSum); - return; - } - if (reportSum->configName == "hw-instructions") { - commentStr = StringPrintf("%lf cycles per instruction", reportSum->commentSum); - return; - } - if (reportSum->configName == "hw-branch-misses") { - commentStr = StringPrintf("%lf miss rate", reportSum->commentSum); - return; - } - if (reportSum->commentSum > 1e9) { - commentStr = StringPrintf("%.3lf G/sec", reportSum->commentSum / 1e9); - return; - } - if (reportSum->commentSum > 1e6) { - commentStr = StringPrintf("%.3lf M/sec", reportSum->commentSum / 1e6); + std::unordered_map configMap = { + {"sw-task-clock", "%lf cpus used"}, + {"hw-cpu-cycles", "%lf GHz"}, + {"hw-instructions", "%lf cycles per instruction"}, + {"hw-branch-misses", "%lf miss rate"} + }; + + auto types = configMap.find(reportSum->configName); + if (types != configMap.end()) { + commentStr = StringPrintf(types->second.c_str(), reportSum->commentSum); return; } - if (reportSum->commentSum > 1e3) { - commentStr = StringPrintf("%.3lf K/sec", reportSum->commentSum / 1e3); - return; + + std::vector> unitMap = { + {1e9, "%.3lf G/sec"}, + {1e6, "%.3lf M/sec"}, + {1e3, "%.3lf K/sec"} + }; + + for (auto &itor : unitMap) { + if (reportSum->commentSum > itor.first) { + commentStr = StringPrintf(itor.second.c_str(), reportSum->commentSum / itor.first); + return; + } } + commentStr = StringPrintf("%.3lf /sec", reportSum->commentSum); }