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