1 //===-- PerfContextSwitchDecoder.h --======----------------------*- C++ -*-===//
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 #ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_PERFCONTEXTSWITCHDECODER_H
10 #define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_PERFCONTEXTSWITCHDECODER_H
11 
12 #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
13 #include "lldb/lldb-types.h"
14 
15 #include "llvm/Support/Error.h"
16 
17 #include <set>
18 #include <vector>
19 
20 namespace lldb_private {
21 namespace trace_intel_pt {
22 
23 /// This class indicates the time interval in which a thread was running
24 /// continuously on a cpu core.
25 struct ThreadContinuousExecution {
26 
27   /// In most cases both the start and end of a continuous execution can be
28   /// accurately recovered from the context switch trace, but in some cases one
29   /// of these endpoints might be guessed or not known at all, due to contention
30   /// problems in the trace or because tracing was interrupted, e.g. with ioctl
31   /// calls, which causes gaps in the trace. Because of that, we identify which
32   /// situation we fall into with the following variants.
33   enum class Variant {
34     /// Both endpoints are known.
35     Complete,
36     /// The end is known and we have a lower bound for the start, i.e. the
37     /// previous execution in the same cpu happens strictly before the hinted
38     /// start.
39     HintedStart,
40     /// The start is known and we have an upper bound for the end, i.e. the next
41     /// execution in the same cpu happens strictly after the hinted end.
42     HintedEnd,
43     /// We only know the start. This might be the last entry of a cpu trace.
44     OnlyStart,
45     /// We only know the end. This might be the first entry or a cpu trace.
46     OnlyEnd,
47   } variant;
48 
49   /// \return
50   ///   The lowest tsc that we are sure of, i.e. not hinted.
51   uint64_t GetLowestKnownTSC() const;
52 
53   /// \return
54   ///   The known or hinted start tsc, or 0 if the variant is \a OnlyEnd.
55   uint64_t GetStartTSC() const;
56 
57   /// \return
58   ///   The known or hinted end tsc, or max \a uint64_t if the variant is \a
59   ///   OnlyStart.
60   uint64_t GetEndTSC() const;
61 
62   /// Constructors for the different variants of this object
63   ///
64   /// \{
65   static ThreadContinuousExecution
66   CreateCompleteExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid,
67                           lldb::pid_t pid, uint64_t start, uint64_t end);
68 
69   static ThreadContinuousExecution
70   CreateHintedStartExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid,
71                              lldb::pid_t pid, uint64_t hinted_start,
72                              uint64_t end);
73 
74   static ThreadContinuousExecution
75   CreateHintedEndExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid,
76                            lldb::pid_t pid, uint64_t start,
77                            uint64_t hinted_end);
78 
79   static ThreadContinuousExecution CreateOnlyEndExecution(lldb::cpu_id_t cpu_id,
80                                                           lldb::tid_t tid,
81                                                           lldb::pid_t pid,
82                                                           uint64_t end);
83 
84   static ThreadContinuousExecution
85   CreateOnlyStartExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid,
86                            lldb::pid_t pid, uint64_t start);
87   /// \}
88 
89   union {
90     struct {
91       uint64_t start;
92       uint64_t end;
93     } complete;
94     struct {
95       uint64_t start;
96     } only_start;
97     struct {
98       uint64_t end;
99     } only_end;
100     /// The following 'hinted' structures are useful when there are contention
101     /// problems in the trace
102     struct {
103       uint64_t hinted_start;
104       uint64_t end;
105     } hinted_start;
106     struct {
107       uint64_t start;
108       uint64_t hinted_end;
109     } hinted_end;
110   } tscs;
111 
112   lldb::cpu_id_t cpu_id;
113   lldb::tid_t tid;
114   lldb::pid_t pid;
115 
116 private:
117   /// We keep this constructor private to force the usage of the static named
118   /// constructors.
119   ThreadContinuousExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid,
120                             lldb::pid_t pid)
121       : cpu_id(cpu_id), tid(tid), pid(pid) {}
122 };
123 
124 /// Decodes a context switch trace collected with perf_event_open.
125 ///
126 /// \param[in] data
127 ///   The context switch trace in binary format.
128 ///
129 /// \param[i] cpu_id
130 ///   The cpu_id where the trace were gotten from.
131 ///
132 /// \param[in] tsc_conversion
133 ///   The conversion values used to confert nanoseconds to TSC.
134 ///
135 /// \return
136 ///   A list of continuous executions recovered from the raw trace sorted by
137 ///   time, or an \a llvm::Error if the data is malformed.
138 llvm::Expected<std::vector<ThreadContinuousExecution>>
139 DecodePerfContextSwitchTrace(llvm::ArrayRef<uint8_t> data,
140                              lldb::cpu_id_t cpu_id,
141                              const LinuxPerfZeroTscConversion &tsc_conversion);
142 
143 llvm::Expected<std::vector<uint8_t>>
144 FilterProcessesFromContextSwitchTrace(llvm::ArrayRef<uint8_t> data,
145                                       const std::set<lldb::pid_t> &pids);
146 
147 } // namespace trace_intel_pt
148 } // namespace lldb_private
149 
150 #endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_PERFCONTEXTSWITCHDECODER_H
151