-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[llvm]Add a simple Telemetry framework #102323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 25 commits
dbb8b15
6e43f67
e25f5fc
ad3906c
24d07d6
0057bcf
750e4ac
1378ed4
02e750e
63e99fc
fa88512
0866f64
a8523f7
47e8b06
690c6ab
db668f4
0290a14
14b5234
6ca87e5
4155add
11ead4a
48228ee
ed8a3f1
990e1ca
479cd13
6d8aee2
3a17dbb
a6a6c7b
f30dec6
fd3da20
60616ef
8c0ac5a
c8be829
1393c1f
eb07577
0376abc
e2f7c23
17dfac7
1ea0906
39fd0e7
67b7688
efd25d8
4a8276f
a16344b
26ee5eb
b766e3c
c8cddab
5f8d65f
dffeacd
398ed3e
e462908
df8a9af
70f4742
8eab77a
f9e1a65
2a1fbe5
6e3a85d
f9b1cce
0f38a74
ad57099
a2fcd4d
628e7e9
6ea4e92
08cf32f
3c52401
07f06c0
06e746e
2476294
5ce406c
fd57d06
a8a878b
54eeaba
32dfc6a
0893c5b
155f243
b255e3a
14d1c92
bf2172d
c2dcb7d
bbe9009
e2036c6
05947d5
f1100bb
2f64b29
a5df7a0
585fee8
3812cda
0cdc240
da8056f
c116074
a4e2799
2763d46
75c1b4b
9780ec7
4715743
d231bf2
1941b1f
bd3df5e
4351b94
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,214 @@ | ||
| =========================== | ||
| Telemetry framework in LLVM | ||
| =========================== | ||
|
|
||
| .. contents:: | ||
| :local: | ||
|
|
||
| .. toctree:: | ||
| :hidden: | ||
|
|
||
| =========================== | ||
| Telemetry framework in LLVM | ||
| =========================== | ||
|
|
||
| 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 | ||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| vendor). | ||
|
|
||
jh7370 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Important notes | ||
| ---------------- | ||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| * 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 | ||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| what they care about(what/where/when to instrument data). Hence, it might not | ||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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 welcomed. | ||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| * 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: | ||
|
|
||
| * Eg., data collected by Telemetry is not neccessarily owned by the user | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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 is consisted of four important classes: | ||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| * `llvm::telemetry::Telemeter`: 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 telemery. | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * `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 their final storage. | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * `llvm::telemetry::Config`: Configurations on the `Telemeter`. | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| .. 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 `Telemeter` class and `Destination`. | ||
|
|
||
| 1) Define a custom `Telemeter` and `Destination` | ||
|
|
||
| .. code-block:: c++ | ||
|
|
||
| // This destiantion just prints the given entry to a stdout. | ||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // In "real life", this would be where you forward the data to your | ||
| // custom data storage. | ||
| class MyStdoutDestination : public llvm::telemetry::Destiantion { | ||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| public: | ||
| Error emitEntry(const TelemetryInfo* Entry) override { | ||
| return sendToBlackBox(Entry); | ||
|
|
||
| } | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| private: | ||
| Error sendToBlackBox(const TelemetryInfo* Entry) { | ||
|
||
| // This could send the data anywhere. | ||
| // But we're simply sending it to stdout for the example. | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| llvm::outs() << entryToString(Entry) << "\n"; | ||
| return llvm::success(); | ||
| } | ||
|
|
||
| std::string entryToString(const TelemetryInfo* Entry) { | ||
| // make a string-representation of the given entry. | ||
| } | ||
| }; | ||
|
|
||
| // This defines a custom TelemetryInfo that has an addition Msg field. | ||
| struct MyTelemetryInfo : public llvm::telemetry::TelemetryInfo { | ||
| std::string Msg; | ||
|
|
||
| json::Object serializeToJson() const { | ||
|
||
| json::Object Ret = TelemeteryInfo::serializeToJson(); | ||
| Ret.emplace_back("MyMsg", Msg); | ||
| return std::move(Ret); | ||
| } | ||
|
|
||
| // TODO: implement getKind() and classof() to support dyn_cast operations. | ||
|
||
| }; | ||
|
|
||
| class MyTelemeter : public llvm::telemery::Telemeter { | ||
| public: | ||
| static std::unique_ptr<MyTelemeter> createInstatnce(llvm::telemetry::Config* config) { | ||
| // If Telemetry is not enabled, then just return null; | ||
| if (!config->EnableTelemetry) return nullptr; | ||
|
|
||
| std::make_unique<MyTelemeter>(); | ||
| } | ||
| MyTelemeter() = default; | ||
|
||
|
|
||
| void logStartup(llvm::StringRef ToolName, TelemetryInfo* Entry) override { | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (MyTelemetryInfo* M = dyn_cast<MyTelemetryInfo>(Entry)) { | ||
| M->Msg = "Starting up tool with name: " + ToolName; | ||
| emitToAllDestinations(M); | ||
| } else { | ||
| emitToAllDestinations(Entry); | ||
| } | ||
| } | ||
|
|
||
| void logExit(llvm::StringRef ToolName, TelemetryInfo* Entry) override { | ||
| if (MyTelemetryInfo* M = dyn_cast<MyTelemetryInfo>(Entry)) { | ||
| M->Msg = "Exitting tool with name: " + ToolName; | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| emitToAllDestinations(M); | ||
| } else { | ||
| emitToAllDestinations(Entry); | ||
| } | ||
| } | ||
|
|
||
| void addDestination(Destination* dest) override { | ||
| destinations.push_back(dest); | ||
| } | ||
|
|
||
| // You can also define additional instrumentation points.) | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| void logAdditionalPoint(TelemetryInfo* Entry) { | ||
| // .... code here | ||
| } | ||
| private: | ||
| void emitToAllDestinations(const TelemetryInfo* Entry) { | ||
| // Note: could do this in paralle, if needed. | ||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| for (Destination* Dest : Destinations) | ||
| Dest->emitEntry(Entry); | ||
| } | ||
| std::vector<Destination> Destinations; | ||
| }; | ||
|
|
||
| 2) Use the library in your tool. | ||
|
|
||
| Logging the tool init-process: | ||
|
|
||
| .. code-block:: c++ | ||
|
|
||
| // At tool's init code | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| auto StartTime = std::chrono::time_point<std::chrono::steady_clock>::now(); | ||
| llvm::telemetry::Config MyConfig = makeConfig(); // build up the appropriate Config struct here. | ||
jh7370 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| auto Telemeter = MyTelemeter::createInstance(&MyConfig); | ||
| std::string CurrentSessionId = ...; // Make some unique ID corresponding to the current session here. | ||
|
||
|
|
||
| // Any other tool's init code can go here | ||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // ... | ||
|
|
||
| // Finally, take a snapshot of the time now so we know how long it took the | ||
| // init process to finish | ||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| auto EndTime = std::chrono::time_point<std::chrono::steady_clock>::now(); | ||
| MyTelemetryInfo Entry; | ||
| Entry.SessionId = CurrentSessionId ; // Assign some unique ID here. | ||
|
||
| Entry.Stats = {StartTime, EndTime}; | ||
|
||
| Telemeter->logStartup("MyTool", &Entry); | ||
|
|
||
| Similar code can be used for logging the tool's exit. | ||
|
|
||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Additionall, at any other point in the tool's lifetime, it can also log telemetry: | ||
labath marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| .. code-block:: c++ | ||
|
|
||
| // At some execution point: | ||
| auto StartTime = std::chrono::time_point<std::chrono::steady_clock>::now(); | ||
|
|
||
| // ... other events happening here | ||
|
|
||
| auto EndTime = std::chrono::time_point<std::chrono::steady_clock>::now(); | ||
|
||
| MyTelemetryInfo Entry; | ||
| Entry.SessionId = CurrentSessionId ; // Assign some unique ID here. | ||
| Entry.Stats = {StartTime, EndTime}; | ||
| Telemeter->logAdditionalPoint(&Entry); | ||
Uh oh!
There was an error while loading. Please reload this page.