aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h
blob: a16a437e1888ef3e1a680d0557b80e46ce9c80ed (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//===-- PerfContextSwitchDecoder.h --======----------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_PERFCONTEXTSWITCHDECODER_H
#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_PERFCONTEXTSWITCHDECODER_H

#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
#include "lldb/lldb-types.h"

#include "llvm/Support/Error.h"

#include <set>
#include <vector>

namespace lldb_private {
namespace trace_intel_pt {

/// This class indicates the time interval in which a thread was running
/// continuously on a cpu core.
struct ThreadContinuousExecution {

  /// In most cases both the start and end of a continuous execution can be
  /// accurately recovered from the context switch trace, but in some cases one
  /// of these endpoints might be guessed or not known at all, due to contention
  /// problems in the trace or because tracing was interrupted, e.g. with ioctl
  /// calls, which causes gaps in the trace. Because of that, we identify which
  /// situation we fall into with the following variants.
  enum class Variant {
    /// Both endpoints are known.
    Complete,
    /// The end is known and we have a lower bound for the start, i.e. the
    /// previous execution in the same cpu happens strictly before the hinted
    /// start.
    HintedStart,
    /// The start is known and we have an upper bound for the end, i.e. the next
    /// execution in the same cpu happens strictly after the hinted end.
    HintedEnd,
    /// We only know the start. This might be the last entry of a cpu trace.
    OnlyStart,
    /// We only know the end. This might be the first entry or a cpu trace.
    OnlyEnd,
  } variant;

  /// \return
  ///   The lowest tsc that we are sure of, i.e. not hinted.
  uint64_t GetLowestKnownTSC() const;

  /// \return
  ///   The known or hinted start tsc, or 0 if the variant is \a OnlyEnd.
  uint64_t GetStartTSC() const;

  /// \return
  ///   The known or hinted end tsc, or max \a uint64_t if the variant is \a
  ///   OnlyStart.
  uint64_t GetEndTSC() const;

  /// Constructors for the different variants of this object
  ///
  /// \{
  static ThreadContinuousExecution
  CreateCompleteExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid,
                          lldb::pid_t pid, uint64_t start, uint64_t end);

  static ThreadContinuousExecution
  CreateHintedStartExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid,
                             lldb::pid_t pid, uint64_t hinted_start,
                             uint64_t end);

  static ThreadContinuousExecution
  CreateHintedEndExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid,
                           lldb::pid_t pid, uint64_t start,
                           uint64_t hinted_end);

  static ThreadContinuousExecution CreateOnlyEndExecution(lldb::cpu_id_t cpu_id,
                                                          lldb::tid_t tid,
                                                          lldb::pid_t pid,
                                                          uint64_t end);

  static ThreadContinuousExecution
  CreateOnlyStartExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid,
                           lldb::pid_t pid, uint64_t start);
  /// \}

  union {
    struct {
      uint64_t start;
      uint64_t end;
    } complete;
    struct {
      uint64_t start;
    } only_start;
    struct {
      uint64_t end;
    } only_end;
    /// The following 'hinted' structures are useful when there are contention
    /// problems in the trace
    struct {
      uint64_t hinted_start;
      uint64_t end;
    } hinted_start;
    struct {
      uint64_t start;
      uint64_t hinted_end;
    } hinted_end;
  } tscs;

  lldb::cpu_id_t cpu_id;
  lldb::tid_t tid;
  lldb::pid_t pid;

private:
  /// We keep this constructor private to force the usage of the static named
  /// constructors.
  ThreadContinuousExecution(lldb::cpu_id_t cpu_id, lldb::tid_t tid,
                            lldb::pid_t pid)
      : cpu_id(cpu_id), tid(tid), pid(pid) {}
};

/// Decodes a context switch trace collected with perf_event_open.
///
/// \param[in] data
///   The context switch trace in binary format.
///
/// \param[i] cpu_id
///   The cpu_id where the trace were gotten from.
///
/// \param[in] tsc_conversion
///   The conversion values used to confert nanoseconds to TSC.
///
/// \return
///   A list of continuous executions recovered from the raw trace sorted by
///   time, or an \a llvm::Error if the data is malformed.
llvm::Expected<std::vector<ThreadContinuousExecution>>
DecodePerfContextSwitchTrace(llvm::ArrayRef<uint8_t> data,
                             lldb::cpu_id_t cpu_id,
                             const LinuxPerfZeroTscConversion &tsc_conversion);

llvm::Expected<std::vector<uint8_t>>
FilterProcessesFromContextSwitchTrace(llvm::ArrayRef<uint8_t> data,
                                      const std::set<lldb::pid_t> &pids);

} // namespace trace_intel_pt
} // namespace lldb_private

#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_PERFCONTEXTSWITCHDECODER_H