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