已合并
fix: kernel trace at low version kernel #478
wuying39创建于 12 天前
fix: kernel trace at low version kernel #478
已合并
共 2 个文件变更+70-10
| @@ -275,6 +275,7 @@ struct RawTraceStream { | |||
| 275 | EventFormat entryFormat; | 275 | EventFormat entryFormat; |
| 276 | EventFormat returnFormat; | 276 | EventFormat returnFormat; |
| 277 | std::unordered_map<uint64_t, uint64_t> canonicalAddressByTraceAddress; | 277 | std::unordered_map<uint64_t, uint64_t> canonicalAddressByTraceAddress; |
| 278 | + std::vector<std::pair<uint64_t, uint64_t>> canonicalAddressRanges; | ||
| 278 | std::unordered_map<int, std::string> commByTid; | 279 | std::unordered_map<int, std::string> commByTid; |
| 279 | std::vector<CpuPipe> pipes; | 280 | std::vector<CpuPipe> pipes; |
| 280 | std::vector<RawFunctionGraphEvent> events; | 281 | std::vector<RawFunctionGraphEvent> events; |
| @@ -294,6 +295,7 @@ struct RawTraceStream { | |||
| 294 | uint64_t otherEventRecords = 0; | 295 | uint64_t otherEventRecords = 0; |
| 295 | uint64_t invalidPayloadRecords = 0; | 296 | uint64_t invalidPayloadRecords = 0; |
| 296 | uint64_t adjustedAddressRecords = 0; | 297 | uint64_t adjustedAddressRecords = 0; |
| 298 | + uint64_t rangeResolvedAddressRecords = 0; | ||
| 297 | uint64_t addressMissRecords = 0; | 299 | uint64_t addressMissRecords = 0; |
| 298 | uint64_t truncatedRecords = 0; | 300 | uint64_t truncatedRecords = 0; |
| 299 | uint64_t missedPages = 0; | 301 | uint64_t missedPages = 0; |
| @@ -377,9 +379,11 @@ struct RawTraceStream { | |||
| 377 | ++invalidPayloadRecords; | 379 | ++invalidPayloadRecords; |
| 378 | return; | 380 | return; |
| 379 | } | 381 | } |
| 380 | - uint64_t canonicalAddress = functionAddress; | 382 | + uint64_t canonicalAddress = 0; |
| 381 | - auto functionIt = canonicalAddressByTraceAddress.find(canonicalAddress); | 383 | + auto functionIt = canonicalAddressByTraceAddress.find(functionAddress); |
| 382 | - if (functionIt == canonicalAddressByTraceAddress.end()) { | 384 | + if (functionIt != canonicalAddressByTraceAddress.end()) { |
| 385 | + canonicalAddress = functionIt->second; | ||
| 386 | + } else { | ||
| 383 | // Convert the architecture-specific fentry call-site IP to the | 387 | // Convert the architecture-specific fentry call-site IP to the |
| 384 | // symbol start. Exact matching remains the primary path. | 388 | // symbol start. Exact matching remains the primary path. |
| 385 | 389 | ||
| @@ -404,11 +408,30 @@ struct RawTraceStream { | |||
| 404 | } | 408 | } |
| 405 | 409 | ||
| 406 | } | 410 | } |
| 407 | - if (functionIt == canonicalAddressByTraceAddress.end()) { | 411 | + |
| 412 | + if (canonicalAddress == 0 && !canonicalAddressRanges.empty()) { | ||
| 413 | + // Function-graph records the architecture's ftrace IP. The | ||
| 414 | + // kernel documentation explicitly permits this patch site to | ||
| 415 | + // differ from the /proc/kallsyms symbol address. If tracefs does | ||
| 416 | + // not provide available_filter_functions_addrs, symbolize the IP | ||
| 417 | + // in the same way as kallsyms: use the nearest preceding text | ||
| 418 | + // symbol. All records reaching this path have already been | ||
| 419 | + // identified as funcgraph entry/exit events. | ||
| 420 | + auto next = std::upper_bound(canonicalAddressRanges.begin(), canonicalAddressRanges.end(), | ||
| 421 | + functionAddress, | ||
| 422 | + [](uint64_t address, const std::pair<uint64_t, uint64_t> &symbol) { | ||
| 423 | + return address < symbol.first; | ||
| 424 | + }); | ||
| 425 | + if (next != canonicalAddressRanges.begin()) { | ||
| 426 | + --next; | ||
| 427 | + canonicalAddress = next->second; | ||
| 428 | + ++rangeResolvedAddressRecords; | ||
| 429 | + } | ||
| 430 | + } | ||
| 431 | + if (canonicalAddress == 0) { | ||
| 408 | ++addressMissRecords; | 432 | ++addressMissRecords; |
| 409 | return; | 433 | return; |
| 410 | } | 434 | } |
| 411 | - canonicalAddress = functionIt->second; | ||
| 412 | 435 | ||
| 413 | int tid = static_cast<int>(pidValue); | 436 | int tid = static_cast<int>(pidValue); |
| 414 | if (commByTid.find(tid) == commByTid.end()) { | 437 | if (commByTid.find(tid) == commByTid.end()) { |
| @@ -613,8 +636,21 @@ bool StartRawTraceStream(KernelTraceManager::Session &session, std::string *erro | |||
| 613 | for (const auto &symbol : session.addresses) { | 636 | for (const auto &symbol : session.addresses) { |
| 614 | if (symbol.second != 0) { | 637 | if (symbol.second != 0) { |
| 615 | stream->canonicalAddressByTraceAddress.emplace(symbol.second, symbol.second); | 638 | stream->canonicalAddressByTraceAddress.emplace(symbol.second, symbol.second); |
| 639 | + stream->canonicalAddressRanges.emplace_back(symbol.second, symbol.second); | ||
| 616 | } | 640 | } |
| 617 | } | 641 | } |
| 642 | + std::sort(stream->canonicalAddressRanges.begin(), stream->canonicalAddressRanges.end(), | ||
| 643 | + [](const std::pair<uint64_t, uint64_t> &left, | ||
| 644 | + const std::pair<uint64_t, uint64_t> &right) { | ||
| 645 | + return left.first < right.first; | ||
| 646 | + }); | ||
| 647 | + stream->canonicalAddressRanges.erase( | ||
| 648 | + std::unique(stream->canonicalAddressRanges.begin(), stream->canonicalAddressRanges.end(), | ||
| 649 | + [](const std::pair<uint64_t, uint64_t> &left, | ||
| 650 | + const std::pair<uint64_t, uint64_t> &right) { | ||
| 651 | + return left.first == right.first; | ||
| 652 | + }), | ||
| 653 | + stream->canonicalAddressRanges.end()); | ||
| 618 | for (const auto &patchSite : session.patchAddresses) { | 654 | for (const auto &patchSite : session.patchAddresses) { |
| 619 | auto canonical = session.addresses.find(patchSite.first); | 655 | auto canonical = session.addresses.find(patchSite.first); |
| 620 | if (canonical != session.addresses.end() && canonical->second != 0 && patchSite.second != 0) { | 656 | if (canonical != session.addresses.end() && canonical->second != 0 && patchSite.second != 0) { |
| @@ -806,6 +842,10 @@ bool TakeRawTraceEvents(KernelTraceManager::Session &session, std::vector<RawFun | |||
| 806 | TraceLog("[trace-kernel] warning: " + message + "\n"); | 842 | TraceLog("[trace-kernel] warning: " + message + "\n"); |
| 807 | pcerr::SetWarn(LIBPERF_WARN_UTRACE_KERNEL_FAILED, message); | 843 | pcerr::SetWarn(LIBPERF_WARN_UTRACE_KERNEL_FAILED, message); |
| 808 | } | 844 | } |
| 845 | + if (session.rawStream->rangeResolvedAddressRecords != 0) { | ||
| 846 | + TraceLog("[trace-kernel] symbolized ftrace IPs by kernel symbol range: count=" + | ||
| 847 | + std::to_string(session.rawStream->rangeResolvedAddressRecords) + "\n"); | ||
| 848 | + } | ||
| 809 | if (session.rawStream->events.empty() && !session.rawStream->firstPagePrefix.empty()) { | 849 | if (session.rawStream->events.empty() && !session.rawStream->firstPagePrefix.empty()) { |
| 810 | static constexpr char K_HEX[] = "0123456789abcdef"; | 850 | static constexpr char K_HEX[] = "0123456789abcdef"; |
| 811 | std::string prefixHex; | 851 | std::string prefixHex; |
| @@ -771,16 +771,17 @@ bool SelectTraceableFunctions(const std::vector<std::string> &requested, const s | |||
| 771 | 771 | ||
| 772 | std::unordered_map<std::string, uint64_t> ResolveKernelSymbols(const std::vector<std::string> &functions) | 772 | std::unordered_map<std::string, uint64_t> ResolveKernelSymbols(const std::vector<std::string> &functions) |
| 773 | { | 773 | { |
| 774 | - std::unordered_set<std::string> unresolved(functions.begin(), functions.end()); | 774 | + (void)functions; |
| 775 | std::unordered_map<std::string, uint64_t> addresses; | 775 | std::unordered_map<std::string, uint64_t> addresses; |
| 776 | std::ifstream kallsyms("/proc/kallsyms"); | 776 | std::ifstream kallsyms("/proc/kallsyms"); |
| 777 | std::string line; | 777 | std::string line; |
| 778 | - while (!unresolved.empty() && std::getline(kallsyms, line)) { | 778 | + while (std::getline(kallsyms, line)) { |
| 779 | std::istringstream fields(line); | 779 | std::istringstream fields(line); |
| 780 | std::string addressText; | 780 | std::string addressText; |
| 781 | std::string type; | 781 | std::string type; |
| 782 | std::string name; | 782 | std::string name; |
| 783 | - if (!(fields >> addressText >> type >> name) || unresolved.find(name) == unresolved.end()) { | 783 | + if (!(fields >> addressText >> type >> name) || |
| 784 | + (type != "t" && type != "T" && type != "w" && type != "W")) { | ||
| 784 | continue; | 785 | continue; |
| 785 | } | 786 | } |
| 786 | char *end = nullptr; | 787 | char *end = nullptr; |
| @@ -788,7 +789,6 @@ std::unordered_map<std::string, uint64_t> ResolveKernelSymbols(const std::vector | |||
| 788 | if (end != addressText.c_str() && *end == '\0' && address != 0) { | 789 | if (end != addressText.c_str() && *end == '\0' && address != 0) { |
| 789 | addresses.emplace(name, address); | 790 | addresses.emplace(name, address); |
| 790 | } | 791 | } |
| 791 | - unresolved.erase(name); | ||
| 792 | } | 792 | } |
| 793 | return addresses; | 793 | return addresses; |
| 794 | } | 794 | } |
| @@ -912,6 +912,25 @@ static bool WriteFunctionFilter(const KernelTraceManager::Session &session, | |||
| 912 | return true; | 912 | return true; |
| 913 | } | 913 | } |
| 914 | 914 | ||
| 915 | +static bool WriteGraphFunctionFilter(const KernelTraceManager::Session &session, | ||
| 916 | + const std::vector<std::string> &functions, std::string *error) | ||
| 917 | +{ | ||
| 918 | + std::string path = session.traceFsPath + "/set_graph_function"; | ||
| 919 | + // set_graph_function is not available on every supported tracefs version | ||
| 920 | + if (!IsRegularOrVirtualFile(path)) { | ||
| 921 | + return true; | ||
| 922 | + } | ||
| 923 | + if (!ClearTraceFile(path, error)) { | ||
| 924 | + return false; | ||
| 925 | + } | ||
| 926 | + for (const std::string &function : functions) { | ||
| 927 | + if (!AppendTraceFile(path, function + "\n", error)) { | ||
| 928 | + return false; | ||
| 929 | + } | ||
| 930 | + } | ||
| 931 | + return true; | ||
| 932 | +} | ||
| 933 | + | ||
| 915 | static bool SetTraceOption(const KernelTraceManager::Session &session, const std::string &name, | 934 | static bool SetTraceOption(const KernelTraceManager::Session &session, const std::string &name, |
| 916 | bool enabled, bool required, std::string *error) | 935 | bool enabled, bool required, std::string *error) |
| 917 | { | 936 | { |
| @@ -955,7 +974,8 @@ bool ConfigureGlobalTraceFs(KernelTraceManager::Session &session, | |||
| 955 | !WriteOptionalTraceFile(session.traceFsPath + "/max_graph_depth", "0\n", error) || | 974 | !WriteOptionalTraceFile(session.traceFsPath + "/max_graph_depth", "0\n", error) || |
| 956 | !WriteOptionalTraceFile(session.traceFsPath + "/tracing_thresh", "0\n", error) || | 975 | !WriteOptionalTraceFile(session.traceFsPath + "/tracing_thresh", "0\n", error) || |
| 957 | !WriteOptionalTraceFile(session.traceFsPath + "/tracing_cpumask", onlineCpuMask + "\n", error) || | 976 | !WriteOptionalTraceFile(session.traceFsPath + "/tracing_cpumask", onlineCpuMask + "\n", error) || |
| 958 | - !WriteFunctionFilter(session, functions, error)) { | 977 | + !WriteFunctionFilter(session, functions, error) || |
| 978 | + !WriteGraphFunctionFilter(session, functions, error)) { | ||
| 959 | return false; | 979 | return false; |
| 960 | } | 980 | } |
| 961 | 981 | ||