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