1 //===- xray-account.h - XRay Function Call Accounting ---------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the interface for performing some basic function call 10 // accounting from an XRay trace. 11 // 12 //===----------------------------------------------------------------------===// 13 #ifndef LLVM_TOOLS_LLVM_XRAY_XRAY_ACCOUNT_H 14 #define LLVM_TOOLS_LLVM_XRAY_XRAY_ACCOUNT_H 15 16 #include <map> 17 #include <utility> 18 #include <vector> 19 20 #include "func-id-helper.h" 21 #include "llvm/ADT/Bitfields.h" 22 #include "llvm/Support/Program.h" 23 #include "llvm/Support/raw_ostream.h" 24 #include "llvm/XRay/XRayRecord.h" 25 26 namespace llvm { 27 namespace xray { 28 29 class LatencyAccountant { 30 public: 31 typedef llvm::DenseMap<int32_t, llvm::SmallVector<uint64_t, 0>> 32 FunctionLatencyMap; 33 typedef llvm::DenseMap<uint32_t, std::pair<uint64_t, uint64_t>> 34 PerThreadMinMaxTSCMap; 35 typedef llvm::DenseMap<uint8_t, std::pair<uint64_t, uint64_t>> 36 PerCPUMinMaxTSCMap; 37 struct FunctionStack { 38 llvm::SmallVector<std::pair<int32_t, uint64_t>, 32> Stack; 39 class RecursionStatus { 40 uint32_t Storage = 0; 41 using Depth = Bitfield::Element<int32_t, 0, 31>; // Low 31 bits. 42 using IsRecursive = Bitfield::Element<bool, 31, 1>; // Sign bit. 43 public: 44 RecursionStatus &operator++(); 45 RecursionStatus &operator--(); 46 bool isRecursive() const; 47 }; 48 std::optional<llvm::DenseMap<int32_t, RecursionStatus>> RecursionDepth; 49 }; 50 typedef llvm::DenseMap<uint32_t, FunctionStack> PerThreadFunctionStackMap; 51 52 private: 53 PerThreadFunctionStackMap PerThreadFunctionStack; 54 FunctionLatencyMap FunctionLatencies; 55 PerThreadMinMaxTSCMap PerThreadMinMaxTSC; 56 PerCPUMinMaxTSCMap PerCPUMinMaxTSC; 57 FuncIdConversionHelper &FuncIdHelper; 58 59 bool RecursiveCallsOnly = false; 60 bool DeduceSiblingCalls = false; 61 uint64_t CurrentMaxTSC = 0; 62 63 void recordLatency(int32_t FuncId, uint64_t Latency) { 64 FunctionLatencies[FuncId].push_back(Latency); 65 } 66 67 public: 68 explicit LatencyAccountant(FuncIdConversionHelper &FuncIdHelper, 69 bool RecursiveCallsOnly, bool DeduceSiblingCalls) 70 : FuncIdHelper(FuncIdHelper), RecursiveCallsOnly(RecursiveCallsOnly), 71 DeduceSiblingCalls(DeduceSiblingCalls) {} 72 73 const FunctionLatencyMap &getFunctionLatencies() const { 74 return FunctionLatencies; 75 } 76 77 const PerThreadMinMaxTSCMap &getPerThreadMinMaxTSC() const { 78 return PerThreadMinMaxTSC; 79 } 80 81 const PerCPUMinMaxTSCMap &getPerCPUMinMaxTSC() const { 82 return PerCPUMinMaxTSC; 83 } 84 85 /// Returns false in case we fail to account the provided record. This happens 86 /// in the following cases: 87 /// 88 /// - An exit record does not match any entry records for the same function. 89 /// If we've been set to deduce sibling calls, we try walking up the stack 90 /// and recording times for the higher level functions. 91 /// - A record has a TSC that's before the latest TSC that has been 92 /// recorded. We still record the TSC for the min-max. 93 /// 94 bool accountRecord(const XRayRecord &Record); 95 96 const PerThreadFunctionStackMap &getPerThreadFunctionStack() const { 97 return PerThreadFunctionStack; 98 } 99 100 // Output Functions 101 // ================ 102 103 void exportStatsAsText(raw_ostream &OS, const XRayFileHeader &Header) const; 104 void exportStatsAsCSV(raw_ostream &OS, const XRayFileHeader &Header) const; 105 106 private: 107 // Internal helper to implement common parts of the exportStatsAs... 108 // functions. 109 template <class F> void exportStats(const XRayFileHeader &Header, F fn) const; 110 }; 111 112 } // namespace xray 113 } // namespace llvm 114 115 #endif // LLVM_TOOLS_LLVM_XRAY_XRAY_ACCOUNT_H 116