-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[lldb][telemetry] Implement LLDB Telemetry (part 1) #119716
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 7 commits
b7216d7
fca4674
549e44f
157b5e4
ec5a661
5e19b7e
75dbb9e
c534405
e76c216
5bc42c0
4275ec5
507e562
aa9c9c7
9e584b5
8675094
8c7c82c
38d0cec
387a38c
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,93 @@ | ||||||||||
| //===-- Telemetry.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_CORE_TELEMETRY_H | ||||||||||
| #define LLDB_CORE_TELEMETRY_H | ||||||||||
|
|
||||||||||
| #include "lldb/Core/StructuredDataImpl.h" | ||||||||||
| #include "lldb/Interpreter/CommandReturnObject.h" | ||||||||||
| #include "lldb/Utility/StructuredData.h" | ||||||||||
| #include "lldb/lldb-forward.h" | ||||||||||
| #include "llvm/ADT/StringExtras.h" | ||||||||||
| #include "llvm/ADT/StringRef.h" | ||||||||||
| #include "llvm/Support/JSON.h" | ||||||||||
| #include "llvm/Telemetry/Telemetry.h" | ||||||||||
| #include <chrono> | ||||||||||
| #include <ctime> | ||||||||||
| #include <memory> | ||||||||||
| #include <optional> | ||||||||||
| #include <string> | ||||||||||
| #include <unordered_map> | ||||||||||
|
|
||||||||||
| namespace lldb_private { | ||||||||||
|
|
||||||||||
| struct LldbEntryKind : public ::llvm::telemetry::EntryKind { | ||||||||||
| static const llvm::telemetry::KindType BaseInfo = 0b11000; | ||||||||||
| }; | ||||||||||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||
|
|
||||||||||
| /// Defines a convenient type for timestamp of various events. | ||||||||||
| /// This is used by the EventStats below. | ||||||||||
| using SteadyTimePoint = std::chrono::time_point<std::chrono::steady_clock, | ||||||||||
| std::chrono::nanoseconds>; | ||||||||||
|
|
||||||||||
| /// Various time (and possibly memory) statistics of an event. | ||||||||||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||
| struct EventStats { | ||||||||||
|
||||||||||
| // REQUIRED: Start time of an event | ||||||||||
| SteadyTimePoint start; | ||||||||||
|
||||||||||
| // REQUIRED: Start time of an event | |
| SteadyTimePoint start; | |
| /// Start time of an event | |
| SteadyTimePoint start; |
This says REQUIRED but there's a default constructor that doesn't initialize it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what caught Jonas's eye (though he probably doesn't know it) is that this class was very protobuf-y. Let me try to unpack that. We don't have the (understandable if you know the background, but strange if you don't) situation of fields that are optional at the transport layer but required at the application layer elsewhere. And I don't think we need that here either because the transport layer is part of the downstream/vendor implementation, so we can just use regular c++ conventions for the application layer (if a type is std::optional, it's optional; if it's not, it's not).
That's one part of the issue. The second part is question whether the "required-ness" of a field can be enforced syntactically (through a constructor which intializes it). That's usually a nice property though it doesn't work in all situations, and I don't think it's that useful for objects which are plain data carriers (no internal logic). It also only works if every constructor initializes it, so the fact that you've added a constructor which does that, but then also kept the default one which does not (well, it initializes it, but to zero), doesn't really help there.
I'm saying this because this overload set is basically the same as what you'd get if you specified no explicit constructors -- you could still do the same thing, just with curly braces (EventStats{} default initializes everything, EventStats{start} initializes the first member, EventStats{start, end} initializes both). So, if this is the behavior you want, you can just delete all of them. If you want to enforce the requiredness (which might be nice, but I don't think it's necessary -- Jonas may disagree), then you should delete the default constructor -- but then you also need to use these classes differently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the confusion. Should ahve added more comment on this.
The "REQUIRED" here doesn't mean it has to be set at construction time .It just means it should be set at some point before the TelemetryInfo struct is sent off.
In any case, I've removed the EventStats and moved the start/end time fields directly into the TelemetryInfo struct.
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know what the exit signal of an event means. Do you mean the exit signal of a process? Of LLDB itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's used by a few subclasses of the TelemetryInfo. (Comment below)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to go with Jonas here. "Signal" is a very confusing word here, because a process can die from a (unix) signal (but lldb doesn't do a very good job of differentiating the "death by signal N" and "exit with status N"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To answer the orignal question, this is used to describe both the exit of LLDB and a process (or main executable).
I've removed the "signal" from the comment.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm kinda surprised to see this here. I wouldn't expect this to make sense on every (or even most) of the telemetry entries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're going to have 5 types of entries.I think the exit status (or more accurately "return status" for the command-info case) is applicable to the first 4 entries:
- debugger-info (whether LLDB terminates successfully)
- target-info (whether the main executable exits successfully)
- command-info (whether the command executed successfully)
- client-request-info (whether the request completed successfully)
- misc-info (optionall)
So that's 4 out of 5, which is why I thought it made sense to hoist it into the common class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, this answers my previous question. It seems like the meaning of the exit code is sufficiently different (debugger and target have a process exit code, which is meaningful based on the OS) but commands and client request infos share nothing with that. It seems like separate enums would be appropriate for the latter. In other words, I think debugger-info and target-info each can have an exit code field (or an ExitDescription) member. The other 3 should have their own dedicated enum.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok -ll remove the field from LLDBBaseTelemetry. (But will leave the ExitDescription struct decl since the two of following PRs will use it)
SG?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd be better to remove the struct completely for now. It'll be easier to figure out the exact meaning/description for it in the context of the PR which uses it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done - removed the ExistDescription
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everywhere else we use /// LLVM RTTI support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: missing period.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -257,8 +257,8 @@ enum StopReason { | |
| }; | ||
|
|
||
| /// Command Return Status Types. | ||
| enum ReturnStatus { | ||
| eReturnStatusInvalid, | ||
| enum ReturnStatus : int { | ||
| eReturnStatusInvalid = 0, | ||
|
||
| eReturnStatusSuccessFinishNoResult, | ||
| eReturnStatusSuccessFinishResult, | ||
| eReturnStatusSuccessContinuingNoResult, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| //===-- Telemetry.cpp -----------------------------------------------------===// | ||
| // | ||
| // 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 "lldb/Core/Telemetry.h" | ||
labath marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| #include "lldb/Core/Debugger.h" | ||
| #include "lldb/Target/Statistics.h" | ||
| #include "lldb/Utility/ConstString.h" | ||
| #include "lldb/Utility/LLDBLog.h" | ||
| #include "lldb/Utility/UUID.h" | ||
| #include "lldb/Version/Version.h" | ||
| #include "lldb/lldb-enumerations.h" | ||
| #include "lldb/lldb-forward.h" | ||
| #include "llvm/ADT/SmallString.h" | ||
| #include "llvm/ADT/StringRef.h" | ||
| #include "llvm/ADT/Twine.h" | ||
| #include "llvm/Support/Error.h" | ||
| #include "llvm/Support/RandomNumberGenerator.h" | ||
| #include "llvm/Telemetry/Telemetry.h" | ||
| #include <chrono> | ||
| #include <cstdlib> | ||
| #include <ctime> | ||
| #include <memory> | ||
| #include <string> | ||
| #include <utility> | ||
| #include <vector> | ||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
|
||
| namespace lldb_private { | ||
|
|
||
| using ::llvm::Error; | ||
| using ::llvm::telemetry::Destination; | ||
| using ::llvm::telemetry::Serializer; | ||
| using ::llvm::telemetry::TelemetryInfo; | ||
|
|
||
| static uint64_t ToNanosec(const SteadyTimePoint Point) { | ||
| return std::chrono::nanoseconds(Point.time_since_epoch()).count(); | ||
| } | ||
|
|
||
| void LldbBaseTelemetryInfo::serialize(Serializer &serializer) const { | ||
| serializer.write("entry_kind", getKind()); | ||
| serializer.write("session_id", SessionId); | ||
| serializer.write("start_time", ToNanosec(stats.start)); | ||
| if (stats.end.has_value()) | ||
| serializer.write("end_time", ToNanosec(stats.end.value())); | ||
| if (exit_desc.has_value()) { | ||
| serializer.write("exit_code", exit_desc->exit_code); | ||
| serializer.write("exit_msg", exit_desc->description); | ||
| } | ||
| } | ||
|
|
||
| static std::string MakeUUID(lldb_private::Debugger *debugger) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (all addressed in #126757) |
||
| std::string ret; | ||
| uint8_t random_bytes[16]; | ||
| if (auto ec = llvm::getRandomBytes(random_bytes, 16)) { | ||
| LLDB_LOG(GetLog(LLDBLog::Object), | ||
| "Failed to generate random bytes for UUID: {0}", ec.message()); | ||
| // fallback to using timestamp + debugger ID. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| ret = llvm::formatv( | ||
| "{0}_{1}", std::chrono::steady_clock::now().time_since_epoch().count(), | ||
| debugger->GetID()); | ||
| } else { | ||
| ret = lldb_private::UUID(random_bytes).GetAsString(); | ||
| } | ||
|
|
||
| return ret; | ||
oontvoo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| TelemetryManager::TelemetryManager( | ||
| std::unique_ptr<llvm::telemetry::Config> config) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're using
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| : m_config(std::move(config)) {} | ||
|
|
||
| llvm::Error TelemetryManager::preDispatch(TelemetryInfo *entry) { | ||
| // Do nothing for now. | ||
| // In up-coming patch, this would be where the manager | ||
| // attach the session_uuid to the entry. | ||
| } | ||
|
|
||
| } // namespace lldb_private | ||
Uh oh!
There was an error while loading. Please reload this page.