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