aboutsummaryrefslogtreecommitdiff
path: root/llvm/include/llvm/Telemetry/Telemetry.h
blob: 9b607f1a3a8fc9a9ebeaf84fbd96fc6c8f2b55bd (plain)
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file provides the basic framework for Telemetry.
/// Refer to its documentation at llvm/docs/Telemetry.rst for more details.
//===---------------------------------------------------------------------===//

#ifndef LLVM_TELEMETRY_TELEMETRY_H
#define LLVM_TELEMETRY_TELEMETRY_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
#include <memory>
#include <optional>
#include <string>
#include <vector>

namespace llvm {
namespace telemetry {

class Serializer {
public:
  virtual ~Serializer() = default;

  virtual Error init() = 0;
  virtual void write(StringRef KeyName, bool Value) = 0;
  virtual void write(StringRef KeyName, StringRef Value) = 0;
  virtual void write(StringRef KeyName, int Value) = 0;
  virtual void write(StringRef KeyName, long Value) = 0;
  virtual void write(StringRef KeyName, long long Value) = 0;
  virtual void write(StringRef KeyName, unsigned int Value) = 0;
  virtual void write(StringRef KeyName, unsigned long Value) = 0;
  virtual void write(StringRef KeyName, unsigned long long Value) = 0;
  virtual void beginObject(StringRef KeyName) = 0;
  virtual void endObject() = 0;
  virtual Error finalize() = 0;

  template <typename T, typename = typename T::mapped_type>
  void write(StringRef KeyName, const T &Map) {
    static_assert(std::is_convertible_v<typename T::key_type, StringRef>,
                  "KeyType must be convertible to string");
    beginObject(KeyName);
    for (const auto &KeyVal : Map)
      write(KeyVal.first, KeyVal.second);
    endObject();
  }
};

/// Configuration for the Manager class.
/// This stores configurations from both users and vendors and is passed
/// to the Manager upon construction. (Any changes to the config after
/// the Manager's construction will not have any effect on it).
///
/// This struct can be extended as needed to add additional configuration
/// points specific to a vendor's implementation.
struct Config {
  static constexpr bool BuildTimeEnableTelemetry = LLVM_ENABLE_TELEMETRY;

  // If true, telemetry will be enabled.
  const bool EnableTelemetry;

  explicit Config() : EnableTelemetry(BuildTimeEnableTelemetry) {}

  virtual ~Config() = default;

  // Telemetry can only be enabled if both the runtime and buildtime flag
  // are set.
  explicit Config(bool E) : EnableTelemetry(E && BuildTimeEnableTelemetry) {}

  virtual std::optional<std::string> makeSessionId() { return std::nullopt; }
};

/// For isa, dyn_cast, etc operations on TelemetryInfo.
typedef unsigned KindType;
/// This struct is used by TelemetryInfo to support isa<>, dyn_cast<>
/// operations.
/// It is defined as a struct (rather than an enum) because it is
/// expected to be extended by subclasses which may have
/// additional TelemetryInfo types defined to describe different events.
struct EntryKind {
  static const KindType Base = 0;
};

/// TelemetryInfo is the data courier, used to move instrumented data
/// from the tool being monitored to the Telemetry framework.
///
/// This base class contains only the basic set of telemetry data.
/// Downstream implementations can define more subclasses with
/// additional fields to describe different events and concepts.
///
/// For example, The LLDB debugger can define a DebugCommandInfo subclass
/// which has additional fields about the debug-command being instrumented,
/// such as `CommandArguments` or `CommandName`.
struct LLVM_ABI TelemetryInfo {
  // This represents a unique-id, conventionally corresponding to
  // a tool's session - i.e., every time the tool starts until it exits.
  //
  // Note: a tool could have multiple sessions running at once, in which
  // case, these shall be multiple sets of TelemetryInfo with multiple unique
  // IDs.
  //
  // Different usages can assign different types of IDs to this field.
  std::string SessionId;

  TelemetryInfo() = default;
  virtual ~TelemetryInfo() = default;

  virtual void serialize(Serializer &serializer) const;

  // For isa, dyn_cast, etc, operations.
  virtual KindType getKind() const { return EntryKind::Base; }
  static bool classof(const TelemetryInfo *T) {
    return T->getKind() == EntryKind::Base;
  }
};

/// This class presents a data sink to which the Telemetry framework
/// sends data.
///
/// Its implementation is transparent to the framework.
/// It is up to the vendor to decide which pieces of data to forward
/// and where to forward them.
class Destination {
public:
  virtual ~Destination() = default;
  virtual Error receiveEntry(const TelemetryInfo *Entry) = 0;
  virtual StringLiteral name() const = 0;
};

/// This class is the main interaction point between any LLVM tool
/// and this framework.
/// It is responsible for collecting telemetry data from the tool being
/// monitored and transmitting the data elsewhere.
class LLVM_ABI Manager {
public:
  Manager() = default;
  virtual ~Manager() = default;

  // Explicitly non-copyable.
  Manager(Manager const &) = delete;
  Manager &operator=(Manager const &) = delete;

  // Dispatch Telemetry data to the Destination(s).
  // The argument is non-const because the Manager may add or remove
  // data from the entry.
  virtual Error dispatch(TelemetryInfo *Entry);

  // Register a Destination.
  void addDestination(std::unique_ptr<Destination> Destination);

protected:
  // Optional callback for subclasses to perform additional tasks before
  // dispatching to Destinations.
  virtual Error preDispatch(TelemetryInfo *Entry);

private:
  std::vector<std::unique_ptr<Destination>> Destinations;
};

} // namespace telemetry
} // namespace llvm

#endif // LLVM_TELEMETRY_TELEMETRY_H