Objective:
- Provide a common framework in LLVM for collecting various usage
metrics
- Characteristics:
- Extensible and configurable by:
- tools in LLVM that want to use it
- vendors in their downstream codebase
- tools users (as allowed by vendor)
Background:
The framework was originally proposed only for LLDB, but there were
quite a few requests to move it to llvm/lib given telemetry
is a common use case in a lot of tools, not just LLDB.
See more details on the design and discussions here on the RFC:
https://discourse.llvm.org/t/rfc-lldb-telemetry-metrics/64588/20?u=oontvoo
---------
Co-authored-by: Alina Sbirlea <alina.g.simion@gmail.com>
Co-authored-by: James Henderson <James.Henderson@sony.com>
Co-authored-by: Pavel Labath <pavel@labath.sk>
163 lines
5.4 KiB
C++
163 lines
5.4 KiB
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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \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/Error.h"
|
|
#include <map>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
namespace llvm {
|
|
namespace telemetry {
|
|
|
|
class Serializer {
|
|
public:
|
|
virtual Error init() = 0;
|
|
virtual void write(StringRef KeyName, bool Value) = 0;
|
|
virtual void write(StringRef KeyName, StringRef Value) = 0;
|
|
|
|
template <typename T>
|
|
std::enable_if_t<std::is_integral_v<T>> write(StringRef KeyName, T Value) {
|
|
if constexpr (std::is_signed_v<T>)
|
|
writeSigned(KeyName, Value);
|
|
else
|
|
writeUnsigned(KeyName, Value);
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
virtual void beginObject(StringRef KeyName) = 0;
|
|
virtual void endObject() = 0;
|
|
|
|
virtual Error finalize() = 0;
|
|
|
|
private:
|
|
virtual void writeUnsigned(StringRef KeyName, unsigned long long) = 0;
|
|
virtual void writeSigned(StringRef KeyName, long long) = 0;
|
|
};
|
|
|
|
/// 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 {
|
|
// If true, telemetry will be enabled.
|
|
const bool EnableTelemetry;
|
|
Config(bool E) : EnableTelemetry(E) {}
|
|
|
|
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 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 Manager {
|
|
public:
|
|
// Optional callback for subclasses to perform additional tasks before
|
|
// dispatching to Destinations.
|
|
virtual Error preDispatch(TelemetryInfo *Entry) = 0;
|
|
|
|
// 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);
|
|
|
|
private:
|
|
std::vector<std::unique_ptr<Destination>> Destinations;
|
|
};
|
|
|
|
} // namespace telemetry
|
|
} // namespace llvm
|
|
|
|
#endif // LLVM_TELEMETRY_TELEMETRY_H
|