diff --git a/example/pmu_perfdata.cpp b/example/pmu_perfdata.cpp index 53e026b20b6b4b29cd59bef70d52c57ef0c3c94a..a20e38ffa0db2c79ccd0402619250960fc80ed62 100644 --- a/example/pmu_perfdata.cpp +++ b/example/pmu_perfdata.cpp @@ -34,6 +34,8 @@ atomic toRead(false); bool running = true; PmuFile file = NULL; int lastErr = SUCCESS; +bool verbose = false; +int64_t startTs = 0; struct Param { vector events; @@ -53,6 +55,13 @@ int64_t GetTime() .count(); } +void Ts(const string msg) +{ + if (verbose) { + cout << "[" << GetTime() - startTs << "]" << msg << "\n"; + } +} + void Split(const string &eventStr, vector &events) { stringstream ss(eventStr); @@ -102,6 +111,8 @@ static Param ParseArgs(int argc, char** argv) } else if (strcmp(argv[i], "-I") == 0 && i+1 < argc) { param.interval = atoi(argv[i+1]); ++i; + } else if (strcmp(argv[i], "-v") == 0) { + verbose = true; } else { PrintHelp(); exit(0); @@ -147,8 +158,10 @@ void AsyncReadAndWrite() continue; } + Ts("to read samples"); PmuData *data = nullptr; int len = PmuRead(pd, &data); + Ts("read samples"); if (len < 0) { lastErr = Perrorno(); continue; @@ -157,6 +170,7 @@ void AsyncReadAndWrite() lastErr = Perrorno(); continue; } + Ts("write data"); toRead.store(false, memory_order_release); } } @@ -199,8 +213,8 @@ int Collect(const Param ¶m) return Perrorno(); } PmuEnable(pd); + Ts("pmu open"); for (int i = 0; i < param.duration; ++i) { - auto start = GetTime(); usleep(1000 * param.interval); if (lastErr != SUCCESS) { cerr << Perror() << "\n"; @@ -212,17 +226,18 @@ int Collect(const Param ¶m) if (AllPidExit(param)) { break; } - auto end = GetTime(); - cout << " iteration time: " << end - start << "\n"; } + Ts("finish sampling"); PmuDisable(pd); while(toRead.load(memory_order_acquire)); + Ts("finish read samples"); PmuEndWrite(file); PmuClose(pd); running = false; pthread_join(t, NULL); FreeEvtList(evtlist, param.events.size()); + Ts("pmu close"); return 0; } @@ -258,7 +273,7 @@ bool ExecuteCommand(Param ¶m) int main(int argc, char** argv) { try { - auto start = GetTime(); + startTs = GetTime(); auto param = ParseArgs(argc, argv); if (!param.command.empty() && !ExecuteCommand(param)) { return 0; @@ -270,9 +285,7 @@ int main(int argc, char** argv) if (!param.command.empty() && !param.pidList.empty()) { kill(param.pidList[0], SIGTERM); } - auto end = GetTime(); - cout << " elapsed time: " << end - start << "\n"; - + Ts("end"); } catch (exception &ex) { cout << "Failed: " << ex.what() << "\n"; } diff --git a/pmu/dump_perf_data.cpp b/pmu/dump_perf_data.cpp index 21250ca92df5e625fc19a8c21bdb4ae0c1a7d100..4b48869e540f9e0fb93861415f5b75277db5f024 100644 --- a/pmu/dump_perf_data.cpp +++ b/pmu/dump_perf_data.cpp @@ -76,12 +76,10 @@ struct PerfBuildId { // Simplified perf sample struct, only includes essential fields. struct PerfSample { perf_event_header header; - __u64 sampleid; __u64 ip; __u32 pid, tid; __u64 time; __u64 id; - __u32 cpu; __u64 period; __u64 bnr; perf_branch_entry lbr[]; @@ -182,13 +180,25 @@ public: return err; } // Write PmuData list. + size_t bufferSize = GetPmuDataSize(data, len); + // Copy pmu data to buffer and write ONCE, that's much faster. + uint8_t *buffer = new uint8_t[bufferSize]; + size_t offset = 0; for (int i = 0; i < len; ++i) { auto &d = data[i]; - err = WritePmuData(d); + err = WritePmuData(d, offset, buffer); if (err != SUCCESS) { + delete[] buffer; return err; } } + err = write(fd, buffer, bufferSize); + if (err < 0) { + delete[] buffer; + return COMMON_ERR_WRITE; + } + ph.data.size += bufferSize; + delete[] buffer; return SUCCESS; } @@ -241,49 +251,49 @@ private: return SUCCESS; } - int WritePmuData(const PmuData &d) + size_t GetPmuDataSize(const PmuData *data, const int len) const + { + size_t size = sizeof(PerfSample) * len; + for (int i = 0;i < len;++i) { + if (data[i].ext) { + size += data[i].ext->nr * sizeof(perf_branch_entry); + } + } + return size; + } + + int WritePmuData(const PmuData &d, size_t &offset, uint8_t *buffer) { - int err = SUCCESS; size_t branchNr = 0; if (d.ext && d.ext->nr) { branchNr = d.ext->nr; } - PerfSample sample = {0}; - sample.header.type = PERF_RECORD_SAMPLE; - sample.header.misc = PERF_RECORD_MISC_USER; - sample.header.size = sizeof(sample) + branchNr * sizeof(perf_branch_entry); - sample.sampleid = evt2id[d.evt]; - sample.ip = d.stack->symbol->addr; - sample.tid = d.tid; - sample.pid = d.pid; - sample.time = d.ts; - sample.id = sample.sampleid; - sample.cpu = d.cpu; - sample.period = d.period; - sample.bnr = branchNr; + PerfSample *sample = (PerfSample*)(buffer + offset); + sample->header.type = PERF_RECORD_SAMPLE; + sample->header.misc = PERF_RECORD_MISC_USER; + sample->header.size = sizeof(PerfSample) + branchNr * sizeof(perf_branch_entry); + sample->ip = d.stack->symbol->addr; + sample->tid = d.tid; + sample->pid = d.pid; + sample->time = d.ts; + sample->id = evt2id[d.evt]; + sample->period = d.period; + sample->bnr = branchNr; modules.insert(d.stack->symbol->module); - // Write perf sample except brbe data. - err = write(fd, &sample, sizeof(sample)); - if (err < 0) { - return COMMON_ERR_WRITE; - } - // Write brbe data. + // To write branch entries after PerfSample. + perf_branch_entry *bentryList = (perf_branch_entry*)(buffer + offset + sizeof(PerfSample)); for (size_t i = 0;i < branchNr; ++i) { - perf_branch_entry bentry = {0}; - bentry.from = d.ext->branchRecords[i].fromAddr; - bentry.to = d.ext->branchRecords[i].toAddr; - bentry.cycles = d.ext->branchRecords[i].cycles; - bentry.mispred = d.ext->branchRecords[i].misPred; - bentry.predicted = d.ext->branchRecords[i].predicted; - err = write(fd, &bentry, sizeof(bentry)); - if (err < 0) { - return COMMON_ERR_WRITE; - } - } - ph.data.size += sample.header.size; + perf_branch_entry *bentry = &bentryList[i]; + bentry->from = d.ext->branchRecords[i].fromAddr; + bentry->to = d.ext->branchRecords[i].toAddr; + bentry->cycles = d.ext->branchRecords[i].cycles; + bentry->mispred = d.ext->branchRecords[i].misPred; + bentry->predicted = d.ext->branchRecords[i].predicted; + } + offset += sample->header.size; return SUCCESS; } @@ -464,7 +474,7 @@ private: __u64 GetSampleType() { return PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID | - PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_BRANCH_STACK; + PERF_SAMPLE_PERIOD | PERF_SAMPLE_BRANCH_STACK; } PerfFileAttr GetFileAttr(const char *evt, const map &evt2offset) @@ -665,4 +675,4 @@ void PmuEndWrite(PmuFile file) } catch (exception& ex) { New(UNKNOWN_ERROR, ex.what()); } -} \ No newline at end of file +} diff --git a/symbol/symbol_resolve.cpp b/symbol/symbol_resolve.cpp index bcbaa833e1983540f3c79916cdac25b59375ca8d..974fb6d4c7bda9f1235da6bfba511c6ae8ffb221 100644 --- a/symbol/symbol_resolve.cpp +++ b/symbol/symbol_resolve.cpp @@ -543,10 +543,8 @@ int SymbolResolve::RecordModule(int pid, RecordModuleType recordModuleType) return LIBSYM_ERR_PARAM_PID_INVALID; } SetFalse(this->isCleared); - moduleSafeHandler.tryLock(pid); if (this->moduleMap.find(pid) != this->moduleMap.end()) { pcerr::New(0, "success"); - moduleSafeHandler.releaseLock(pid); return 0; } std::string mapFile = "/proc/" + std::to_string(pid) + "/maps"; @@ -554,7 +552,6 @@ int SymbolResolve::RecordModule(int pid, RecordModuleType recordModuleType) if (!file.is_open()) { pcerr::New(LIBSYM_ERR_OPEN_FILE_FAILED, "libsym can't open file named " + mapFile + " because of " + std::string{strerror(errno)}); - moduleSafeHandler.releaseLock(pid); return LIBSYM_ERR_OPEN_FILE_FAILED; } std::vector> modVec; @@ -567,7 +564,6 @@ int SymbolResolve::RecordModule(int pid, RecordModuleType recordModuleType) } this->moduleMap.insert({pid, modVec}); pcerr::New(0, "success"); - moduleSafeHandler.releaseLock(pid); return 0; }