xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-xray/xray-account.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- xray-account.h - XRay Function Call Accounting ---------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines the interface for performing some basic function call
100b57cec5SDimitry Andric // accounting from an XRay trace.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric #ifndef LLVM_TOOLS_LLVM_XRAY_XRAY_ACCOUNT_H
140b57cec5SDimitry Andric #define LLVM_TOOLS_LLVM_XRAY_XRAY_ACCOUNT_H
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include <utility>
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include "func-id-helper.h"
19e8d8bef9SDimitry Andric #include "llvm/ADT/Bitfields.h"
200b57cec5SDimitry Andric #include "llvm/Support/Program.h"
210b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
220b57cec5SDimitry Andric #include "llvm/XRay/XRayRecord.h"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric namespace llvm {
250b57cec5SDimitry Andric namespace xray {
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric class LatencyAccountant {
280b57cec5SDimitry Andric public:
29e8d8bef9SDimitry Andric   typedef llvm::DenseMap<int32_t, llvm::SmallVector<uint64_t, 0>>
30e8d8bef9SDimitry Andric       FunctionLatencyMap;
31e8d8bef9SDimitry Andric   typedef llvm::DenseMap<uint32_t, std::pair<uint64_t, uint64_t>>
320b57cec5SDimitry Andric       PerThreadMinMaxTSCMap;
33e8d8bef9SDimitry Andric   typedef llvm::DenseMap<uint8_t, std::pair<uint64_t, uint64_t>>
34e8d8bef9SDimitry Andric       PerCPUMinMaxTSCMap;
35e8d8bef9SDimitry Andric   struct FunctionStack {
36e8d8bef9SDimitry Andric     llvm::SmallVector<std::pair<int32_t, uint64_t>, 32> Stack;
37e8d8bef9SDimitry Andric     class RecursionStatus {
38e8d8bef9SDimitry Andric       uint32_t Storage = 0;
39e8d8bef9SDimitry Andric       using Depth = Bitfield::Element<int32_t, 0, 31>;    // Low 31 bits.
40e8d8bef9SDimitry Andric       using IsRecursive = Bitfield::Element<bool, 31, 1>; // Sign bit.
41e8d8bef9SDimitry Andric     public:
42e8d8bef9SDimitry Andric       RecursionStatus &operator++();
43e8d8bef9SDimitry Andric       RecursionStatus &operator--();
44e8d8bef9SDimitry Andric       bool isRecursive() const;
45e8d8bef9SDimitry Andric     };
46*bdd1243dSDimitry Andric     std::optional<llvm::DenseMap<int32_t, RecursionStatus>> RecursionDepth;
47e8d8bef9SDimitry Andric   };
48e8d8bef9SDimitry Andric   typedef llvm::DenseMap<uint32_t, FunctionStack> PerThreadFunctionStackMap;
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric private:
510b57cec5SDimitry Andric   PerThreadFunctionStackMap PerThreadFunctionStack;
520b57cec5SDimitry Andric   FunctionLatencyMap FunctionLatencies;
530b57cec5SDimitry Andric   PerThreadMinMaxTSCMap PerThreadMinMaxTSC;
540b57cec5SDimitry Andric   PerCPUMinMaxTSCMap PerCPUMinMaxTSC;
550b57cec5SDimitry Andric   FuncIdConversionHelper &FuncIdHelper;
560b57cec5SDimitry Andric 
57e8d8bef9SDimitry Andric   bool RecursiveCallsOnly = false;
580b57cec5SDimitry Andric   bool DeduceSiblingCalls = false;
590b57cec5SDimitry Andric   uint64_t CurrentMaxTSC = 0;
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   void recordLatency(int32_t FuncId, uint64_t Latency) {
620b57cec5SDimitry Andric     FunctionLatencies[FuncId].push_back(Latency);
630b57cec5SDimitry Andric   }
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric public:
660b57cec5SDimitry Andric   explicit LatencyAccountant(FuncIdConversionHelper &FuncIdHelper,
67e8d8bef9SDimitry Andric                              bool RecursiveCallsOnly, bool DeduceSiblingCalls)
68e8d8bef9SDimitry Andric       : FuncIdHelper(FuncIdHelper), RecursiveCallsOnly(RecursiveCallsOnly),
69e8d8bef9SDimitry Andric         DeduceSiblingCalls(DeduceSiblingCalls) {}
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   const FunctionLatencyMap &getFunctionLatencies() const {
720b57cec5SDimitry Andric     return FunctionLatencies;
730b57cec5SDimitry Andric   }
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   const PerThreadMinMaxTSCMap &getPerThreadMinMaxTSC() const {
760b57cec5SDimitry Andric     return PerThreadMinMaxTSC;
770b57cec5SDimitry Andric   }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric   const PerCPUMinMaxTSCMap &getPerCPUMinMaxTSC() const {
800b57cec5SDimitry Andric     return PerCPUMinMaxTSC;
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric   /// Returns false in case we fail to account the provided record. This happens
840b57cec5SDimitry Andric   /// in the following cases:
850b57cec5SDimitry Andric   ///
860b57cec5SDimitry Andric   ///   - An exit record does not match any entry records for the same function.
870b57cec5SDimitry Andric   ///     If we've been set to deduce sibling calls, we try walking up the stack
880b57cec5SDimitry Andric   ///     and recording times for the higher level functions.
890b57cec5SDimitry Andric   ///   - A record has a TSC that's before the latest TSC that has been
900b57cec5SDimitry Andric   ///     recorded. We still record the TSC for the min-max.
910b57cec5SDimitry Andric   ///
920b57cec5SDimitry Andric   bool accountRecord(const XRayRecord &Record);
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric   const PerThreadFunctionStackMap &getPerThreadFunctionStack() const {
950b57cec5SDimitry Andric     return PerThreadFunctionStack;
960b57cec5SDimitry Andric   }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   // Output Functions
990b57cec5SDimitry Andric   // ================
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   void exportStatsAsText(raw_ostream &OS, const XRayFileHeader &Header) const;
1020b57cec5SDimitry Andric   void exportStatsAsCSV(raw_ostream &OS, const XRayFileHeader &Header) const;
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric private:
1050b57cec5SDimitry Andric   // Internal helper to implement common parts of the exportStatsAs...
1060b57cec5SDimitry Andric   // functions.
1070b57cec5SDimitry Andric   template <class F> void exportStats(const XRayFileHeader &Header, F fn) const;
1080b57cec5SDimitry Andric };
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric } // namespace xray
1110b57cec5SDimitry Andric } // namespace llvm
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric #endif // LLVM_TOOLS_LLVM_XRAY_XRAY_ACCOUNT_H
114