From 6d1140f9b19e02437fc541d9eb48b601d17c5472 Mon Sep 17 00:00:00 2001 From: Vy Nguyen Date: Mon, 23 Dec 2024 15:57:54 -0500 Subject: [PATCH] Reapply "[llvm]Add a simple Telemetry framework" (#120769) This reverts commit 2ec6174bef4bc9ef3d5cedbffd7169017c9669c3. New changes: - Use explicit overloads of write() - Fix link error due to missing dependency (lib/Support) - Updated tests and docs --- llvm/docs/Telemetry.rst | 257 ++++++++++++++++++++ llvm/docs/UserGuides.rst | 4 + llvm/docs/llvm_telemetry_design.png | Bin 0 -> 94604 bytes llvm/include/llvm/Telemetry/Telemetry.h | 154 ++++++++++++ llvm/lib/CMakeLists.txt | 1 + llvm/lib/Telemetry/CMakeLists.txt | 9 + llvm/lib/Telemetry/Telemetry.cpp | 26 +++ llvm/unittests/CMakeLists.txt | 1 + llvm/unittests/Telemetry/CMakeLists.txt | 9 + llvm/unittests/Telemetry/TelemetryTest.cpp | 258 +++++++++++++++++++++ 10 files changed, 719 insertions(+) create mode 100644 llvm/docs/Telemetry.rst create mode 100644 llvm/docs/llvm_telemetry_design.png create mode 100644 llvm/include/llvm/Telemetry/Telemetry.h create mode 100644 llvm/lib/Telemetry/CMakeLists.txt create mode 100644 llvm/lib/Telemetry/Telemetry.cpp create mode 100644 llvm/unittests/Telemetry/CMakeLists.txt create mode 100644 llvm/unittests/Telemetry/TelemetryTest.cpp diff --git a/llvm/docs/Telemetry.rst b/llvm/docs/Telemetry.rst new file mode 100644 index 0000000000000..4f30ae82b5628 --- /dev/null +++ b/llvm/docs/Telemetry.rst @@ -0,0 +1,257 @@ +=========================== +Telemetry framework in LLVM +=========================== + +.. contents:: + :local: + +.. toctree:: + :hidden: + +Objective +========= + +Provides a common framework in LLVM for collecting various usage and performance +metrics. +It is located at ``llvm/Telemetry/Telemetry.h``. + +Characteristics +--------------- +* Configurable and extensible by: + + * Tools: any tool that wants to use Telemetry can extend and customize it. + * Vendors: Toolchain vendors can also provide custom implementation of the + library, which could either override or extend the given tool's upstream + implementation, to best fit their organization's usage and privacy models. + * End users of such tool can also configure Telemetry (as allowed by their + vendor). + +Important notes +--------------- + +* There is no concrete implementation of a Telemetry library in upstream LLVM. + We only provide the abstract API here. Any tool that wants telemetry will + implement one. + + The rationale for this is that all the tools in LLVM are very different in + what they care about (what/where/when to instrument data). Hence, it might not + be practical to have a single implementation. + However, in the future, if we see enough common pattern, we can extract them + into a shared place. This is TBD - contributions are welcome. + +* No implementation of Telemetry in upstream LLVM shall store any of the + collected data due to privacy and security reasons: + + * Different organizations have different privacy models: + + * Which data is sensitive, which is not? + * Whether it is acceptable for instrumented data to be stored anywhere? + (to a local file, what not?) + + * Data ownership and data collection consents are hard to accommodate from + LLVM developers' point of view: + + * E.g., data collected by Telemetry is not necessarily owned by the user + of an LLVM tool with Telemetry enabled, hence the user's consent to data + collection is not meaningful. On the other hand, LLVM developers have no + reasonable ways to request consent from the "real" owners. + + +High-level design +================= + +Key components +-------------- + +The framework consists of four important classes: + +* ``llvm::telemetry::Manager``: The class responsible for collecting and + transmitting telemetry data. This is the main point of interaction between the + framework and any tool that wants to enable telemetry. +* ``llvm::telemetry::TelemetryInfo``: Data courier +* ``llvm::telemetry::Destination``: 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 to for their final storage. +* ``llvm::telemetry::Config``: Configurations for the ``Manager``. + +.. image:: llvm_telemetry_design.png + +How to implement and interact with the API +------------------------------------------ + +To use Telemetry in your tool, you need to provide a concrete implementation of the ``Manager`` class and ``Destination``. + +1) Define a custom ``Serializer``, ``Manager``, ``Destination`` and optionally a subclass of ``TelemetryInfo`` + +.. code-block:: c++ + + class JsonSerializer : public Serializer { + public: + json::Object *getOutputObject() { return Out.get(); } + + Error init() override { + if (Started) + return createStringError("Serializer already in use"); + started = true; + Out = std::make_unique(); + return Error::success(); + } + + // Serialize the given value. + void write(StringRef KeyName, bool Value) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, int Value) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, long Value) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, long long Value ) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, unsigned int Value) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, unsigned long Value) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, unsigned long long Value) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, StringRef Value) override { + writeHelper(KeyName, Value); + } + + void beginObject(StringRef KeyName) override { + Children.push_back(json::Object()); + ChildrenNames.push_back(KeyName.str()); + } + + void endObject() override { + assert(!Children.empty() && !ChildrenNames.empty()); + json::Value Val = json::Value(std::move(Children.back())); + std::string Name = ChildrenNames.back(); + + Children.pop_back(); + ChildrenNames.pop_back(); + writeHelper(Name, std::move(Val)); + } + + Error finalize() override { + if (!Started) + return createStringError("Serializer not currently in use"); + Started = false; + return Error::success(); + } + + private: + template void writeHelper(StringRef Name, T Value) { + assert(Started && "serializer not started"); + if (Children.empty()) + Out->try_emplace(Name, Value); + else + Children.back().try_emplace(Name, Value); + } + bool Started = false; + std::unique_ptr Out; + std::vector Children; + std::vector ChildrenNames; + }; + + class MyManager : public telemery::Manager { + public: + static std::unique_ptr createInstatnce(telemetry::Config *Config) { + // If Telemetry is not enabled, then just return null; + if (!Config->EnableTelemetry) + return nullptr; + return std::make_unique(); + } + MyManager() = default; + + Error preDispatch(TelemetryInfo *Entry) override { + Entry->SessionId = SessionId; + return Error::success(); + } + + // You can also define additional instrumentation points. + void logStartup(TelemetryInfo *Entry) { + // Add some additional data to entry. + Entry->Msg = "Some message"; + dispatch(Entry); + } + + void logAdditionalPoint(TelemetryInfo *Entry) { + // .... code here + } + + private: + const std::string SessionId; + }; + + class MyDestination : public telemetry::Destination { + public: + Error receiveEntry(const TelemetryInfo *Entry) override { + if (Error Err = Serializer.init()) + return Err; + + Entry->serialize(Serializer); + if (Error Err = Serializer.finalize()) + return Err; + + json::Object Copied = *Serializer.getOutputObject(); + // Send the `Copied` object to wherever. + return Error::success(); + } + + private: + JsonSerializer Serializer; + }; + + // This defines a custom TelemetryInfo that has an additional Msg field. + struct MyTelemetryInfo : public telemetry::TelemetryInfo { + std::string Msg; + + Error serialize(Serializer &Serializer) const override { + TelemetryInfo::serialize(serializer); + Serializer.writeString("MyMsg", Msg); + } + + // Note: implement getKind() and classof() to support dyn_cast operations. + }; + + +2) Use the library in your tool. + +Logging the tool init-process: + +.. code-block:: c++ + + // In tool's initialization code. + auto StartTime = std::chrono::time_point::now(); + telemetry::Config MyConfig = makeConfig(); // Build up the appropriate Config struct here. + auto Manager = MyManager::createInstance(&MyConfig); + + + // Any other tool's init code can go here. + // ... + + // Finally, take a snapshot of the time now so we know how long it took the + // init process to finish. + auto EndTime = std::chrono::time_point::now(); + MyTelemetryInfo Entry; + + Entry.Start = StartTime; + Entry.End = EndTime; + Manager->logStartup(&Entry); + +Similar code can be used for logging the tool's exit. diff --git a/llvm/docs/UserGuides.rst b/llvm/docs/UserGuides.rst index 0b204d512876a..6eee564713d6d 100644 --- a/llvm/docs/UserGuides.rst +++ b/llvm/docs/UserGuides.rst @@ -72,6 +72,7 @@ intermediate LLVM representation. SupportLibrary TableGen/index TableGenFundamentals + Telemetry Vectorizers WritingAnLLVMPass WritingAnLLVMNewPMPass @@ -293,3 +294,6 @@ Additional Topics :doc:`Sandbox IR ` This document describes the design and usage of Sandbox IR, a transactional layer over LLVM IR. + +:doc:`Telemetry` + This document describes the Telemetry framework in LLVM. diff --git a/llvm/docs/llvm_telemetry_design.png b/llvm/docs/llvm_telemetry_design.png new file mode 100644 index 0000000000000000000000000000000000000000..48fbc003da18e668b0a4bd2478a26bd47242f243 GIT binary patch literal 94604 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ξ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
1F2WqA6lM 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 z +#include +#include +#include +#include +#include + +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; + 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 + void write(StringRef KeyName, const T &Map) { + static_assert(std::is_convertible_v, + "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 { + // If true, telemetry will be enabled. + const bool EnableTelemetry; + Config(bool E) : EnableTelemetry(E) {} + + virtual std::optional 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); + +private: + std::vector> Destinations; +}; + +} // namespace telemetry +} // namespace llvm + +#endif // LLVM_TELEMETRY_TELEMETRY_H diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt index 503c77cb13bd0..f6465612d30c0 100644 --- a/llvm/lib/CMakeLists.txt +++ b/llvm/lib/CMakeLists.txt @@ -41,6 +41,7 @@ add_subdirectory(ProfileData) add_subdirectory(Passes) add_subdirectory(TargetParser) add_subdirectory(TextAPI) +add_subdirectory(Telemetry) add_subdirectory(ToolDrivers) add_subdirectory(XRay) if (LLVM_INCLUDE_TESTS) diff --git a/llvm/lib/Telemetry/CMakeLists.txt b/llvm/lib/Telemetry/CMakeLists.txt new file mode 100644 index 0000000000000..a30875747f13d --- /dev/null +++ b/llvm/lib/Telemetry/CMakeLists.txt @@ -0,0 +1,9 @@ +add_llvm_component_library(LLVMTelemetry + Telemetry.cpp + + ADDITIONAL_HEADER_DIRS + "${LLVM_MAIN_INCLUDE_DIR}/llvm/Telemetry" + + LINK_COMPONENTS + Support +) diff --git a/llvm/lib/Telemetry/Telemetry.cpp b/llvm/lib/Telemetry/Telemetry.cpp new file mode 100644 index 0000000000000..9e13d08334e3b --- /dev/null +++ b/llvm/lib/Telemetry/Telemetry.cpp @@ -0,0 +1,26 @@ +#include "llvm/Telemetry/Telemetry.h" + +namespace llvm { +namespace telemetry { + +void TelemetryInfo::serialize(Serializer &serializer) const { + serializer.write("SessionId", SessionId); +} + +Error Manager::dispatch(TelemetryInfo *Entry) { + if (Error Err = preDispatch(Entry)) + return Err; + + Error AllErrs = Error::success(); + for (auto &Dest : Destinations) { + AllErrs = joinErrors(std::move(AllErrs), Dest->receiveEntry(Entry)); + } + return AllErrs; +} + +void Manager::addDestination(std::unique_ptr Dest) { + Destinations.push_back(std::move(Dest)); +} + +} // namespace telemetry +} // namespace llvm diff --git a/llvm/unittests/CMakeLists.txt b/llvm/unittests/CMakeLists.txt index 8892f3e75729a..81abce51b8939 100644 --- a/llvm/unittests/CMakeLists.txt +++ b/llvm/unittests/CMakeLists.txt @@ -63,6 +63,7 @@ add_subdirectory(Support) add_subdirectory(TableGen) add_subdirectory(Target) add_subdirectory(TargetParser) +add_subdirectory(Telemetry) add_subdirectory(Testing) add_subdirectory(TextAPI) add_subdirectory(Transforms) diff --git a/llvm/unittests/Telemetry/CMakeLists.txt b/llvm/unittests/Telemetry/CMakeLists.txt new file mode 100644 index 0000000000000..a40ae4b2f5560 --- /dev/null +++ b/llvm/unittests/Telemetry/CMakeLists.txt @@ -0,0 +1,9 @@ +set(LLVM_LINK_COMPONENTS + Telemetry + Core + Support + ) + +add_llvm_unittest(TelemetryTests + TelemetryTest.cpp + ) diff --git a/llvm/unittests/Telemetry/TelemetryTest.cpp b/llvm/unittests/Telemetry/TelemetryTest.cpp new file mode 100644 index 0000000000000..f06cee04277fd --- /dev/null +++ b/llvm/unittests/Telemetry/TelemetryTest.cpp @@ -0,0 +1,258 @@ +//===- llvm/unittest/Telemetry/TelemetryTest.cpp - Telemetry unittests ---===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/Telemetry/Telemetry.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" +#include "gtest/gtest.h" +#include +#include + +namespace llvm { +namespace telemetry { +// Testing parameters. +// +// These are set by each test to force certain outcomes. +struct TestContext { + // Controlling whether there is vendor plugin. In "real" implementation, the + // plugin-registration framework will handle the overrides but for tests, we + // just use a bool flag to decide which function to call. + bool HasVendorPlugin = false; + + // This field contains data emitted by the framework for later + // verification by the tests. + std::string Buffer = ""; + + // The expected Uuid generated by the fake tool. + std::string ExpectedUuid = ""; +}; + +class StringSerializer : public Serializer { +public: + const std::string &getString() { return Buffer; } + + Error init() override { + if (Started) + return createStringError("Serializer already in use"); + Started = true; + Buffer.clear(); + return Error::success(); + } + + void write(StringRef KeyName, bool Value) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, StringRef Value) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, int Value) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, long Value) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, long long Value) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, unsigned int Value) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, unsigned long Value) override { + writeHelper(KeyName, Value); + } + + void write(StringRef KeyName, unsigned long long Value) override { + writeHelper(KeyName, Value); + } + + void beginObject(StringRef KeyName) override { + Children.push_back(std::string("\n")); + ChildrenNames.push_back(KeyName.str()); + } + + void endObject() override { + assert(!Children.empty() && !ChildrenNames.empty()); + std::string ChildBuff = Children.back(); + std::string Name = ChildrenNames.back(); + Children.pop_back(); + ChildrenNames.pop_back(); + writeHelper(Name, ChildBuff); + } + + Error finalize() override { + assert(Children.empty() && ChildrenNames.empty()); + if (!Started) + return createStringError("Serializer not currently in use"); + Started = false; + return Error::success(); + } + +private: + template void writeHelper(StringRef Name, T Value) { + assert(Started && "serializer not started"); + if (Children.empty()) + Buffer.append((Name + ":" + Twine(Value) + "\n").str()); + else + Children.back().append((Name + ":" + Twine(Value) + "\n").str()); + } + + bool Started = false; + std::string Buffer; + std::vector Children; + std::vector ChildrenNames; +}; + +namespace vendor { +struct VendorConfig : public Config { + VendorConfig(bool Enable) : Config(Enable) {} + std::optional makeSessionId() override { + static int seed = 0; + return std::to_string(seed++); + } +}; + +std::shared_ptr getTelemetryConfig(const TestContext &Ctxt) { + return std::make_shared(/*EnableTelemetry=*/true); +} + +class TestStorageDestination : public Destination { +public: + TestStorageDestination(TestContext *Ctxt) : CurrentContext(Ctxt) {} + + Error receiveEntry(const TelemetryInfo *Entry) override { + if (Error Err = serializer.init()) + return Err; + + Entry->serialize(serializer); + if (Error Err = serializer.finalize()) + return Err; + + CurrentContext->Buffer.append(serializer.getString()); + return Error::success(); + } + + StringLiteral name() const override { return "TestDestination"; } + +private: + TestContext *CurrentContext; + StringSerializer serializer; +}; + +struct StartupInfo : public TelemetryInfo { + std::string ToolName; + std::map MetaData; + + void serialize(Serializer &serializer) const override { + TelemetryInfo::serialize(serializer); + serializer.write("ToolName", ToolName); + serializer.write("MetaData", MetaData); + } +}; + +struct ExitInfo : public TelemetryInfo { + int ExitCode; + std::string ExitDesc; + void serialize(Serializer &serializer) const override { + TelemetryInfo::serialize(serializer); + serializer.write("ExitCode", ExitCode); + serializer.write("ExitDesc", ExitDesc); + } +}; + +class TestManager : public Manager { +public: + static std::unique_ptr + createInstance(Config *Config, TestContext *CurrentContext) { + if (!Config->EnableTelemetry) + return nullptr; + CurrentContext->ExpectedUuid = *(Config->makeSessionId()); + std::unique_ptr Ret = std::make_unique( + CurrentContext, CurrentContext->ExpectedUuid); + + // Add a destination. + Ret->addDestination( + std::make_unique(CurrentContext)); + + return Ret; + } + + TestManager(TestContext *Ctxt, std::string Id) + : CurrentContext(Ctxt), SessionId(Id) {} + + Error preDispatch(TelemetryInfo *Entry) override { + Entry->SessionId = SessionId; + return Error::success(); + } + + std::string getSessionId() { return SessionId; } + +private: + TestContext *CurrentContext; + const std::string SessionId; +}; +} // namespace vendor + +std::shared_ptr getTelemetryConfig(const TestContext &Ctxt) { + if (Ctxt.HasVendorPlugin) + return vendor::getTelemetryConfig(Ctxt); + + return std::make_shared(false); +} + +TEST(TelemetryTest, TelemetryDisabled) { + TestContext Context; + Context.HasVendorPlugin = false; + + std::shared_ptr Config = getTelemetryConfig(Context); + auto Manager = vendor::TestManager::createInstance(Config.get(), &Context); + EXPECT_EQ(nullptr, Manager); +} + +TEST(TelemetryTest, TelemetryEnabled) { + const std::string ToolName = "TelemetryTestTool"; + + // Preset some params. + TestContext Context; + Context.HasVendorPlugin = true; + Context.Buffer.clear(); + + std::shared_ptr Config = getTelemetryConfig(Context); + auto Manager = vendor::TestManager::createInstance(Config.get(), &Context); + + EXPECT_STREQ(Manager->getSessionId().c_str(), Context.ExpectedUuid.c_str()); + + vendor::StartupInfo S; + S.ToolName = ToolName; + S.MetaData["a"] = "A"; + S.MetaData["b"] = "B"; + + Error startupEmitStatus = Manager->dispatch(&S); + EXPECT_FALSE(startupEmitStatus); + std::string ExpectedBuffer = + "SessionId:0\nToolName:TelemetryTestTool\nMetaData:\na:A\nb:B\n\n"; + EXPECT_EQ(ExpectedBuffer, Context.Buffer); + Context.Buffer.clear(); + + vendor::ExitInfo E; + E.ExitCode = 0; + E.ExitDesc = "success"; + Error exitEmitStatus = Manager->dispatch(&E); + EXPECT_FALSE(exitEmitStatus); + ExpectedBuffer = "SessionId:0\nExitCode:0\nExitDesc:success\n"; + EXPECT_EQ(ExpectedBuffer, Context.Buffer); +} + +} // namespace telemetry +} // namespace llvm