[vm] On Fuchsia, enable timeline streams based on the state of system trace categories.

Allows categories to be selected through arguments to `trace` instead of changing VM flags and rebuilding.

Change-Id: Ia1ec6b58ca0b765c3d675b7d4938acc5f624b768
Reviewed-on: https://dart-review.googlesource.com/c/91860
Reviewed-by: Zach Anderson <zra@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak 2019-03-01 18:05:40 +00:00 committed by commit-bot@chromium.org
parent 644026da51
commit dc555eb9a7
6 changed files with 87 additions and 65 deletions

View file

@ -221,6 +221,12 @@ library_for_all_configs("libdart") {
"third_party/double-conversion/src:libdouble_conversion",
":generate_version_cc_file",
]
if (is_fuchsia) {
extra_deps += [
"//zircon/public/lib/fbl",
"//zircon/public/lib/trace-engine",
]
}
configurable_deps = [
"platform:libdart_platform",
"vm:libdart_lib",

View file

@ -67,8 +67,6 @@ library_for_all_configs("libdart_vm") {
"//garnet/public/lib/component/cpp",
"//sdk/fidl/fuchsia.timezone",
# TODO(zra): When the platform-specific timeline code is moved out to
# the embedder, this can go away.
"//zircon/public/lib/fbl",
"//zircon/public/lib/trace-engine",
]
@ -85,6 +83,12 @@ library_for_all_configs("libdart_vm") {
library_for_all_configs("libdart_lib") {
target_type = "source_set"
if (is_fuchsia) {
extra_deps = [
"//zircon/public/lib/fbl",
"//zircon/public/lib/trace-engine",
]
}
include_dirs = [ ".." ]
allsources =
async_runtime_sources + collection_runtime_sources +

View file

@ -205,8 +205,8 @@ void Timeline::Init() {
ASSERT(recorder_ != NULL);
enabled_streams_ = GetEnabledByDefaultTimelineStreams();
// Global overrides.
#define TIMELINE_STREAM_FLAG_DEFAULT(name, not_used) \
stream_##name##_.Init(#name, HasStream(enabled_streams_, #name));
#define TIMELINE_STREAM_FLAG_DEFAULT(name, fuchsia_name) \
stream_##name##_.set_enabled(HasStream(enabled_streams_, #name));
TIMELINE_STREAM_LIST(TIMELINE_STREAM_FLAG_DEFAULT)
#undef TIMELINE_STREAM_FLAG_DEFAULT
}
@ -221,7 +221,7 @@ void Timeline::Cleanup() {
#endif
// Disable global streams.
#define TIMELINE_STREAM_DISABLE(name, not_used) \
#define TIMELINE_STREAM_DISABLE(name, fuchsia_name) \
Timeline::stream_##name##_.set_enabled(false);
TIMELINE_STREAM_LIST(TIMELINE_STREAM_DISABLE)
#undef TIMELINE_STREAM_DISABLE
@ -270,13 +270,13 @@ void Timeline::PrintFlagsToJSON(JSONStream* js) {
}
{
JSONArray availableStreams(&obj, "availableStreams");
#define ADD_STREAM_NAME(name, not_used) availableStreams.AddValue(#name);
#define ADD_STREAM_NAME(name, fuchsia_name) availableStreams.AddValue(#name);
TIMELINE_STREAM_LIST(ADD_STREAM_NAME);
#undef ADD_STREAM_NAME
}
{
JSONArray recordedStreams(&obj, "recordedStreams");
#define ADD_RECORDED_STREAM_NAME(name, not_used) \
#define ADD_RECORDED_STREAM_NAME(name, fuchsia_name) \
if (stream_##name##_.enabled()) { \
recordedStreams.AddValue(#name); \
}
@ -377,8 +377,8 @@ void TimelineEventArguments::Free() {
TimelineEventRecorder* Timeline::recorder_ = NULL;
MallocGrowableArray<char*>* Timeline::enabled_streams_ = NULL;
#define TIMELINE_STREAM_DEFINE(name, enabled_by_default) \
TimelineStream Timeline::stream_##name##_;
#define TIMELINE_STREAM_DEFINE(name, fuchsia_name) \
TimelineStream Timeline::stream_##name##_(#name, fuchsia_name, false);
TIMELINE_STREAM_LIST(TIMELINE_STREAM_DEFINE)
#undef TIMELINE_STREAM_DEFINE
@ -389,7 +389,7 @@ TimelineEvent::TimelineEvent()
thread_timestamp1_(-1),
state_(0),
label_(NULL),
category_(""),
stream_(NULL),
thread_(OSThread::kInvalidThreadId),
isolate_id_(ILLEGAL_PORT) {}
@ -404,7 +404,7 @@ void TimelineEvent::Reset() {
state_ = 0;
thread_ = OSThread::kInvalidThreadId;
isolate_id_ = ILLEGAL_PORT;
category_ = "";
stream_ = NULL;
label_ = NULL;
arguments_.Free();
set_event_type(kNone);
@ -546,14 +546,6 @@ void TimelineEvent::Complete() {
}
}
void TimelineEvent::StreamInit(TimelineStream* stream) {
if (stream != NULL) {
category_ = stream->name();
} else {
category_ = "";
}
}
void TimelineEvent::Init(EventType event_type, const char* label) {
ASSERT(label != NULL);
state_ = 0;
@ -607,7 +599,7 @@ void TimelineEvent::PrintJSON(JSONStream* stream) const {
int64_t pid = OS::ProcessId();
int64_t tid = OSThread::ThreadIdToIntPtr(thread_);
obj.AddProperty("name", label_);
obj.AddProperty("cat", category_);
obj.AddProperty("cat", stream_ != NULL ? stream_->name() : NULL);
obj.AddProperty64("tid", tid);
obj.AddProperty64("pid", pid);
obj.AddPropertyTimeMicros("ts", TimeOrigin());
@ -738,11 +730,16 @@ int64_t TimelineEvent::ThreadCPUTimeDuration() const {
return thread_timestamp1_ - thread_timestamp0_;
}
TimelineStream::TimelineStream() : name_(NULL), enabled_(false) {}
void TimelineStream::Init(const char* name, bool enabled) {
name_ = name;
enabled_ = enabled;
TimelineStream::TimelineStream(const char* name,
const char* fuchsia_name,
bool enabled)
: name_(name),
fuchsia_name_(fuchsia_name),
#if defined(HOST_OS_FUCHSIA)
enabled_(true) { // For generated code.
#else
enabled_(enabled) {
#endif
}
TimelineEvent* TimelineStream::StartEvent() {
@ -1111,10 +1108,13 @@ void TimelineEventRecorder::WriteTo(const char* directory) {
int64_t TimelineEventRecorder::GetNextAsyncId() {
// TODO(johnmccutchan): Gracefully handle wrap around.
// TODO(rmacnak): Use TRACE_NONCE() on Fuchsia?
#if defined(HOST_OS_FUCHSIA)
return trace_generate_nonce();
#else
uint32_t next =
static_cast<uint32_t>(AtomicOperations::FetchAndIncrement(&async_id_));
return static_cast<int64_t>(next);
#endif
}
void TimelineEventRecorder::FinishBlock(TimelineEventBlock* block) {

View file

@ -9,10 +9,16 @@
#include "vm/allocation.h"
#include "vm/bitfield.h"
#include "vm/globals.h"
#include "vm/growable_array.h"
#include "vm/os.h"
#include "vm/os_thread.h"
#if defined(HOST_OS_FUCHSIA)
#include <trace-engine/context.h>
#include <trace-engine/instrumentation.h>
#endif
namespace dart {
class JSONArray;
@ -30,29 +36,34 @@ class TimelineStream;
class VirtualMemory;
class Zone;
// (name, enabled by default for isolate).
// (name, fuchsia_name).
#define TIMELINE_STREAM_LIST(V) \
V(API, false) \
V(Compiler, false) \
V(CompilerVerbose, false) \
V(Dart, false) \
V(Debugger, false) \
V(Embedder, false) \
V(GC, false) \
V(Isolate, false) \
V(VM, false)
V(API, "dart:api") \
V(Compiler, "dart:compiler") \
V(CompilerVerbose, "dart:compiler.verbose") \
V(Dart, "dart:dart") \
V(Debugger, "dart:debugger") \
V(Embedder, "dart:embedder") \
V(GC, "dart:gc") \
V(Isolate, "dart:isolate") \
V(VM, "dart:vm")
// A stream of timeline events. A stream has a name and can be enabled or
// disabled (globally and per isolate).
class TimelineStream {
public:
TimelineStream();
void Init(const char* name, bool enabled);
TimelineStream(const char* name, const char* fuchsia_name, bool enabled);
const char* name() const { return name_; }
const char* fuchsia_name() const { return fuchsia_name_; }
bool enabled() const { return enabled_ != 0; }
bool enabled() {
#if defined(HOST_OS_FUCHSIA)
return trace_is_category_enabled(fuchsia_name_);
#else
return enabled_ != 0;
#endif
}
void set_enabled(bool enabled) { enabled_ = enabled ? 1 : 0; }
@ -66,12 +77,21 @@ class TimelineStream {
return OFFSET_OF(TimelineStream, enabled_);
}
#if defined(HOST_OS_FUCHSIA)
trace_site_t* trace_site() { return &trace_site_; }
#endif
private:
const char* name_;
const char* const name_;
const char* const fuchsia_name_;
// This field is accessed by generated code (intrinsic) and expects to see
// 0 or 1. If this becomes a BitField, the generated code must be updated.
uintptr_t enabled_;
#if defined(HOST_OS_FUCHSIA)
trace_site_t trace_site_ = {};
#endif
};
class Timeline : public AllStatic {
@ -95,12 +115,12 @@ class Timeline : public AllStatic {
static void PrintFlagsToJSON(JSONStream* json);
#endif
#define TIMELINE_STREAM_ACCESSOR(name, not_used) \
#define TIMELINE_STREAM_ACCESSOR(name, fuchsia_name) \
static TimelineStream* Get##name##Stream() { return &stream_##name##_; }
TIMELINE_STREAM_LIST(TIMELINE_STREAM_ACCESSOR)
#undef TIMELINE_STREAM_ACCESSOR
#define TIMELINE_STREAM_FLAGS(name, not_used) \
#define TIMELINE_STREAM_FLAGS(name, fuchsia_name) \
static void SetStream##name##Enabled(bool enabled) { \
stream_##name##_.set_enabled(enabled); \
}
@ -111,8 +131,7 @@ class Timeline : public AllStatic {
static TimelineEventRecorder* recorder_;
static MallocGrowableArray<char*>* enabled_streams_;
#define TIMELINE_STREAM_DECLARE(name, not_used) \
static bool stream_##name##_enabled_; \
#define TIMELINE_STREAM_DECLARE(name, fuchsia_name) \
static TimelineStream stream_##name##_;
TIMELINE_STREAM_LIST(TIMELINE_STREAM_DECLARE)
#undef TIMELINE_STREAM_DECLARE
@ -358,7 +377,7 @@ class TimelineEvent {
intptr_t arguments_length() const { return arguments_.length(); }
private:
void StreamInit(TimelineStream* stream);
void StreamInit(TimelineStream* stream) { stream_ = stream; }
void Init(EventType event_type, const char* label);
void set_event_type(EventType event_type) {
@ -415,7 +434,7 @@ class TimelineEvent {
TimelineEventArguments arguments_;
uword state_;
const char* label_;
const char* category_;
TimelineStream* stream_;
ThreadId thread_;
Dart_Port isolate_id_;

View file

@ -19,9 +19,10 @@ void TimelineEventFuchsiaRecorder::OnEvent(TimelineEvent* event) {
if (event == NULL) {
return;
}
TimelineStream* stream = event->stream_;
trace_string_ref_t category;
trace_context_t* context =
trace_acquire_context_for_category("dart", &category);
trace_context_t* context = trace_acquire_context_for_category_cached(
stream->fuchsia_name(), stream->trace_site(), &category);
if (context == NULL) {
return;
}

View file

@ -100,8 +100,7 @@ class TimelineTestHelper : public AllStatic {
TEST_CASE(TimelineEventIsValid) {
// Create a test stream.
TimelineStream stream;
stream.Init("testStream", true);
TimelineStream stream("testStream", "testStream", true);
TimelineEvent event;
TimelineTestHelper::SetStream(&event, &stream);
@ -120,8 +119,7 @@ TEST_CASE(TimelineEventIsValid) {
TEST_CASE(TimelineEventDuration) {
// Create a test stream.
TimelineStream stream;
stream.Init("testStream", true);
TimelineStream stream("testStream", "testStream", true);
// Create a test event.
TimelineEvent event;
@ -136,8 +134,7 @@ TEST_CASE(TimelineEventDuration) {
TEST_CASE(TimelineEventDurationPrintJSON) {
// Create a test stream.
TimelineStream stream;
stream.Init("testStream", true);
TimelineStream stream("testStream", "testStream", true);
// Create a test event.
TimelineEvent event;
@ -167,8 +164,7 @@ TEST_CASE(TimelineEventPrintSystrace) {
char buffer[kBufferLength];
// Create a test stream.
TimelineStream stream;
stream.Init("testStream", true);
TimelineStream stream("testStream", "testStream", true);
// Create a test event.
TimelineEvent event;
@ -212,8 +208,7 @@ TEST_CASE(TimelineEventPrintSystrace) {
TEST_CASE(TimelineEventArguments) {
// Create a test stream.
TimelineStream stream;
stream.Init("testStream", true);
TimelineStream stream("testStream", "testStream", true);
// Create a test event.
TimelineEvent event;
@ -233,8 +228,7 @@ TEST_CASE(TimelineEventArguments) {
TEST_CASE(TimelineEventArgumentsPrintJSON) {
// Create a test stream.
TimelineStream stream;
stream.Init("testStream", true);
TimelineStream stream("testStream", "testStream", true);
// Create a test event.
TimelineEvent event;
@ -296,8 +290,7 @@ TEST_CASE(TimelineEventCallbackRecorderBasic) {
}
// Create a test stream.
TimelineStream stream;
stream.Init("testStream", true);
TimelineStream stream("testStream", "testStream", true);
TimelineEvent* event = NULL;
@ -468,8 +461,7 @@ TEST_CASE(TimelineAnalysis_ThreadBlockCount) {
}
TEST_CASE(TimelineRingRecorderJSONOrder) {
TimelineStream stream;
stream.Init("testStream", true);
TimelineStream stream("testStream", "testStream", true);
TimelineEventRingRecorder* recorder =
new TimelineEventRingRecorder(TimelineEventBlock::kBlockSize * 2);