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 
recordLatency(int32_t FuncId,uint64_t Latency)61   void recordLatency(int32_t FuncId, uint64_t Latency) {
62     FunctionLatencies[FuncId].push_back(Latency);
63   }
64 
65 public:
LatencyAccountant(FuncIdConversionHelper & FuncIdHelper,bool RecursiveCallsOnly,bool DeduceSiblingCalls)66   explicit LatencyAccountant(FuncIdConversionHelper &FuncIdHelper,
67                              bool RecursiveCallsOnly, bool DeduceSiblingCalls)
68       : FuncIdHelper(FuncIdHelper), RecursiveCallsOnly(RecursiveCallsOnly),
69         DeduceSiblingCalls(DeduceSiblingCalls) {}
70 
getFunctionLatencies()71   const FunctionLatencyMap &getFunctionLatencies() const {
72     return FunctionLatencies;
73   }
74 
getPerThreadMinMaxTSC()75   const PerThreadMinMaxTSCMap &getPerThreadMinMaxTSC() const {
76     return PerThreadMinMaxTSC;
77   }
78 
getPerCPUMinMaxTSC()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 
getPerThreadFunctionStack()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