Commit 9dbab9bb authored by Sami Kyostila's avatar Sami Kyostila Committed by Commit Bot

[tracing] Migrate tracing to Perfetto track events

This patch replaces V8's tracing implementation (i.e., the TRACE_EVENT
macros) with the track event base implementation from Perfetto. The
advantages of doing this are:

1) This allows us to remove most tracing-related backend code from V8.

2) V8 can start writing strongly typed trace event arguments, which
   are more compact, easier to process and more extensible than legacy
   JSON-based trace arguments.

For the time being, we still support the old trace macros when V8 is
embedded into Chrome and other embedders.

Design doc: https://docs.google.com/document/d/1f7tt4cb-JcA5bQFR1oXk60ncJPpkL02_Hi_Bc6MfTQk/edit#heading=h.398p6b4eaen2

Bug: chromium:1006766
Change-Id: Ie71474fbe065821772b13d851487ebbca680c4ae
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1947688
Commit-Queue: Sami Kyöstilä <skyostil@chromium.org>
Auto-Submit: Sami Kyöstilä <skyostil@chromium.org>
Reviewed-by: 's avatarPeter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67217}
parent 8c8ff95a
......@@ -62,6 +62,7 @@
!/third_party/antlr4
!/third_party/binutils
!/third_party/inspector_protocol
!/third_party/jsoncpp
!/third_party/colorama
/third_party/colorama/src
!/third_party/googletest
......
......@@ -297,6 +297,8 @@ v8_toolset_for_shell = "host"
config("internal_config_base") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
configs = [ ":v8_tracing_config" ]
include_dirs = [
".",
"$target_gen_dir",
......@@ -311,7 +313,6 @@ config("internal_config") {
"//build/config/compiler:wexit_time_destructors",
":internal_config_base",
":v8_header_features",
":v8_tracing_config",
]
if (is_component_build) {
......@@ -1282,6 +1283,7 @@ v8_source_set("torque_generated_initializers") {
deps = [
":generate_bytecode_builtins_list",
":run_torque",
":v8_tracing",
]
public_deps = [ ":v8_maybe_icu" ]
......@@ -1310,6 +1312,7 @@ v8_source_set("torque_generated_definitions") {
deps = [
":generate_bytecode_builtins_list",
":run_torque",
":v8_tracing",
]
public_deps = [ ":v8_maybe_icu" ]
......@@ -2054,6 +2057,18 @@ group("v8_compiler_for_mksnapshot") {
}
}
# Any target using trace events must directly or indirectly depend on
# v8_tracing.
group("v8_tracing") {
if (v8_use_perfetto) {
if (build_with_chromium) {
public_deps = [ "//third_party/perfetto:libperfetto" ]
} else {
public_deps = [ ":v8_libperfetto" ]
}
}
}
v8_source_set("v8_base_without_compiler") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
......@@ -3439,6 +3454,7 @@ v8_source_set("v8_base_without_compiler") {
":v8_libbase",
":v8_libsampler",
":v8_shared_internal_headers",
":v8_tracing",
":v8_version",
"src/inspector:inspector",
]
......@@ -3530,6 +3546,14 @@ v8_source_set("v8_base_without_compiler") {
]
deps += [ "src/third_party/vtune:v8_vtune_trace_mark" ]
}
if (v8_use_perfetto) {
sources -= [ "//base/trace_event/common/trace_event_common.h" ]
sources += [
"src/tracing/trace-categories.cc",
"src/tracing/trace-categories.h",
]
}
}
group("v8_base") {
......@@ -3892,20 +3916,25 @@ v8_component("v8_libplatform") {
deps = [
":v8_headers",
":v8_libbase",
":v8_tracing",
]
if (v8_use_perfetto) {
sources -= [
"//base/trace_event/common/trace_event_common.h",
"src/libplatform/tracing/trace-buffer.cc",
"src/libplatform/tracing/trace-buffer.h",
"src/libplatform/tracing/trace-object.cc",
"src/libplatform/tracing/trace-writer.cc",
"src/libplatform/tracing/trace-writer.h",
]
sources += [
"src/libplatform/tracing/json-trace-event-listener.cc",
"src/libplatform/tracing/json-trace-event-listener.h",
"src/libplatform/tracing/trace-event-listener.cc",
"src/libplatform/tracing/trace-event-listener.h",
]
deps += [
# TODO(skyostil): Switch TraceEventListener to protozero.
"//third_party/perfetto/protos/perfetto/trace:lite",
"//third_party/perfetto/protos/perfetto/trace/chrome:minimal_complete_lite",
"//third_party/perfetto/protos/perfetto/trace/chrome:zero",
"//third_party/perfetto/src/tracing:client_api",
"//third_party/perfetto/src/tracing:platform_posix",
]
}
}
......@@ -3933,9 +3962,8 @@ v8_source_set("fuzzer_support") {
configs = [ ":internal_config_base" ]
deps = [ ":v8" ]
public_deps = [
":v8",
":v8_libbase",
":v8_libplatform",
":v8_maybe_icu",
......@@ -4443,6 +4471,7 @@ v8_executable("d8") {
":v8",
":v8_libbase",
":v8_libplatform",
":v8_tracing",
"//build/win:default_exe_manifest",
]
......@@ -4461,10 +4490,6 @@ v8_executable("d8") {
if (v8_enable_vtunejit) {
deps += [ "src/third_party/vtune:v8_vtune" ]
}
if (v8_use_perfetto) {
deps += [ "//third_party/perfetto/src/tracing:in_process_backend" ]
}
}
v8_executable("v8_hello_world") {
......@@ -4620,6 +4645,7 @@ v8_source_set("wasm_module_runner") {
deps = [
":generate_bytecode_builtins_list",
":run_torque",
":v8_tracing",
]
public_deps = [ ":v8_maybe_icu" ]
......@@ -4696,6 +4722,7 @@ v8_source_set("lib_wasm_fuzzer_common") {
deps = [
":generate_bytecode_builtins_list",
":run_torque",
":v8_tracing",
]
public_deps = [ ":v8_maybe_icu" ]
......@@ -4778,7 +4805,7 @@ if (!build_with_chromium && v8_use_perfetto) {
"-Wno-tautological-constant-compare",
]
}
if (is_win) {
if (is_win && is_clang) {
cflags += [ "-Wno-microsoft-unqualified-friend" ]
}
}
......@@ -4937,4 +4964,21 @@ if (!build_with_chromium && v8_use_perfetto) {
configs += [ "//build/config/compiler:no_chromium_code" ]
}
} # host_toolchain
v8_component("v8_libperfetto") {
configs = [ ":v8_tracing_config" ]
public_configs = [ "//third_party/perfetto/gn:public_config" ]
deps = [
"//third_party/perfetto/src/trace_processor:export_json",
"//third_party/perfetto/src/trace_processor:storage_minimal",
"//third_party/perfetto/src/tracing:client_api",
"//third_party/perfetto/src/tracing/core",
# TODO(skyostil): Support non-POSIX platforms.
"//third_party/perfetto/protos/perfetto/config:cpp",
"//third_party/perfetto/protos/perfetto/trace/track_event:zero",
"//third_party/perfetto/src/tracing:in_process_backend",
"//third_party/perfetto/src/tracing:platform_posix",
]
}
} # if (!build_with_chromium && v8_use_perfetto)
......@@ -266,11 +266,13 @@ deps = {
'dep_type': 'cipd',
},
'v8/third_party/perfetto':
Var('android_url') + '/platform/external/perfetto.git' + '@' + 'b9b24d1b0b80aafec393af085067e9eae829412f',
Var('android_url') + '/platform/external/perfetto.git' + '@' + '9bd480acdcad450c5ed5d2aa329eb603c53e5f40',
'v8/third_party/protobuf':
Var('chromium_url') + '/external/github.com/google/protobuf'+ '@' + 'b68a347f56137b4b1a746e8c7438495a6ac1bd91',
'v8/third_party/zlib':
Var('chromium_url') + '/chromium/src/third_party/zlib.git'+ '@' + '156be8c52f80cde343088b4a69a80579101b6e67',
'v8/third_party/jsoncpp/source':
Var('chromium_url') + '/external/github.com/open-source-parsers/jsoncpp.git'+ '@' + '645250b6690785be60ab6780ce4b58698d884d11',
'v8/third_party/ittapi': {
# Force checkout ittapi libraries to pass v8 header includes check on
# bots that has check_v8_header_includes enabled.
......
......@@ -16,6 +16,10 @@ perfetto_build_with_embedder = true
perfetto_protobuf_target_prefix = "//"
perfetto_protobuf_gni = "//gni/proto_library.gni"
# We use Perfetto's Trace Processor to convert traces to the legacy JSON
# format.
enable_perfetto_trace_processor = true
# Uncomment these to specify a different NDK location and version in
# non-Chromium builds.
# default_android_ndk_root = "//third_party/android_ndk"
......
......@@ -54,8 +54,7 @@ declare_args() {
# Expose symbols for dynamic linking.
v8_expose_symbols = false
# Use Perfetto (https://perfetto.dev) as the default TracingController. Not
# currently implemented.
# Implement tracing using Perfetto (https://perfetto.dev).
v8_use_perfetto = false
# Override global symbol level setting for v8
......
......@@ -15,6 +15,9 @@
#include "v8-platform.h" // NOLINT(build/include)
namespace perfetto {
namespace trace_processor {
class TraceProcessorStorage;
}
class TracingSession;
}
......@@ -28,7 +31,6 @@ namespace platform {
namespace tracing {
class TraceEventListener;
class JSONTraceEventListener;
const int kTraceMaxNumArgs = 2;
......@@ -197,6 +199,9 @@ class V8_PLATFORM_EXPORT TraceConfig {
TraceConfig() : enable_systrace_(false), enable_argument_filter_(false) {}
TraceRecordMode GetTraceRecordMode() const { return record_mode_; }
const StringList& GetEnabledCategories() const {
return included_categories_;
}
bool IsSystraceEnabled() const { return enable_systrace_; }
bool IsArgumentFilterEnabled() const { return enable_argument_filter_; }
......@@ -229,6 +234,17 @@ class V8_PLATFORM_EXPORT TraceConfig {
class V8_PLATFORM_EXPORT TracingController
: public V8_PLATFORM_NON_EXPORTED_BASE(v8::TracingController) {
public:
TracingController();
~TracingController() override;
#if defined(V8_USE_PERFETTO)
// Must be called before StartTracing() if V8_USE_PERFETTO is true. Provides
// the output stream for the JSON trace data.
void InitializeForPerfetto(std::ostream* output_stream);
// Provide an optional listener for testing that will receive trace events.
// Must be called before StartTracing().
void SetTraceEventListenerForTesting(TraceEventListener* listener);
#else // defined(V8_USE_PERFETTO)
// The pointer returned from GetCategoryGroupEnabled() points to a value with
// zero or more of the following bits. Used in this class only. The
// TRACE_EVENT macros should only use the value as a bool. These values must
......@@ -242,19 +258,8 @@ class V8_PLATFORM_EXPORT TracingController
ENABLED_FOR_ETW_EXPORT = 1 << 3
};
TracingController();
~TracingController() override;
// Takes ownership of |trace_buffer|.
void Initialize(TraceBuffer* trace_buffer);
#ifdef V8_USE_PERFETTO
// Must be called before StartTracing() if V8_USE_PERFETTO is true. Provides
// the output stream for the JSON trace data.
void InitializeForPerfetto(std::ostream* output_stream);
// Provide an optional listener for testing that will receive trace events.
// Must be called before StartTracing().
void SetTraceEventListenerForTesting(TraceEventListener* listener);
#endif
// v8::TracingController implementation.
const uint8_t* GetCategoryGroupEnabled(const char* category_group) override;
......@@ -274,6 +279,10 @@ class V8_PLATFORM_EXPORT TracingController
unsigned int flags, int64_t timestamp) override;
void UpdateTraceEventDuration(const uint8_t* category_enabled_flag,
const char* name, uint64_t handle) override;
static const char* GetCategoryGroupName(const uint8_t* category_enabled_flag);
#endif // !defined(V8_USE_PERFETTO)
void AddTraceStateObserver(
v8::TracingController::TraceStateObserver* observer) override;
void RemoveTraceStateObserver(
......@@ -282,27 +291,32 @@ class V8_PLATFORM_EXPORT TracingController
void StartTracing(TraceConfig* trace_config);
void StopTracing();
static const char* GetCategoryGroupName(const uint8_t* category_enabled_flag);
protected:
#if !defined(V8_USE_PERFETTO)
virtual int64_t CurrentTimestampMicroseconds();
virtual int64_t CurrentCpuTimestampMicroseconds();
#endif // !defined(V8_USE_PERFETTO)
private:
#if !defined(V8_USE_PERFETTO)
void UpdateCategoryGroupEnabledFlag(size_t category_index);
void UpdateCategoryGroupEnabledFlags();
#endif // !defined(V8_USE_PERFETTO)
std::unique_ptr<TraceBuffer> trace_buffer_;
std::unique_ptr<TraceConfig> trace_config_;
std::unique_ptr<base::Mutex> mutex_;
std::unordered_set<v8::TracingController::TraceStateObserver*> observers_;
std::unique_ptr<TraceConfig> trace_config_;
std::atomic_bool recording_{false};
#ifdef V8_USE_PERFETTO
std::unordered_set<v8::TracingController::TraceStateObserver*> observers_;
#if defined(V8_USE_PERFETTO)
std::ostream* output_stream_ = nullptr;
std::unique_ptr<JSONTraceEventListener> json_listener_;
std::unique_ptr<perfetto::trace_processor::TraceProcessorStorage>
trace_processor_;
TraceEventListener* listener_for_testing_ = nullptr;
std::unique_ptr<perfetto::TracingSession> tracing_session_;
#endif
#else // !defined(V8_USE_PERFETTO)
std::unique_ptr<TraceBuffer> trace_buffer_;
#endif // !defined(V8_USE_PERFETTO)
// Disallow copy and assign
TracingController(const TracingController&) = delete;
......
......@@ -138,6 +138,10 @@ class TracingController {
public:
virtual ~TracingController() = default;
// In Perfetto mode, trace events are written using Perfetto's Track Event
// API directly without going through the embedder. However, it is still
// possible to observe tracing being enabled and disabled.
#if !defined(V8_USE_PERFETTO)
/**
* Called by TRACE_EVENT* macros, don't call this directly.
* The name parameter is a category group for example:
......@@ -183,6 +187,7 @@ class TracingController {
**/
virtual void UpdateTraceEventDuration(const uint8_t* category_enabled_flag,
const char* name, uint64_t handle) {}
#endif // !defined(V8_USE_PERFETTO)
class TraceStateObserver {
public:
......
......@@ -55,4 +55,7 @@ specific_include_rules = {
"+include/libplatform/v8-tracing.h",
"+perfetto/tracing.h"
],
"builtins-trace\.cc": [
"+protos/perfetto",
],
}
......@@ -10,6 +10,10 @@
#include "src/logging/counters.h"
#include "src/objects/objects-inl.h"
#if defined(V8_USE_PERFETTO)
#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
#endif
namespace v8 {
namespace internal {
......@@ -69,6 +73,7 @@ class MaybeUtf8 {
std::unique_ptr<uint8_t> allocated_;
};
#if !defined(V8_USE_PERFETTO)
class JsonTraceValue : public ConvertableToTraceFormat {
public:
explicit JsonTraceValue(Isolate* isolate, Handle<String> object) {
......@@ -91,6 +96,7 @@ const uint8_t* GetCategoryGroupEnabled(Isolate* isolate,
MaybeUtf8 category(isolate, string);
return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(*category);
}
#endif // !defined(V8_USE_PERFETTO)
#undef MAX_STACK_LENGTH
......@@ -104,8 +110,15 @@ BUILTIN(IsTraceCategoryEnabled) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kTraceEventCategoryError));
}
return isolate->heap()->ToBoolean(
*GetCategoryGroupEnabled(isolate, Handle<String>::cast(category)));
bool enabled;
#if defined(V8_USE_PERFETTO)
MaybeUtf8 category_str(isolate, Handle<String>::cast(category));
perfetto::DynamicCategory dynamic_category{*category_str};
enabled = TRACE_EVENT_CATEGORY_ENABLED(dynamic_category);
#else
enabled = *GetCategoryGroupEnabled(isolate, Handle<String>::cast(category));
#endif
return isolate->heap()->ToBoolean(enabled);
}
// Builtins::kTrace(phase, category, name, id, data) : bool
......@@ -118,18 +131,23 @@ BUILTIN(Trace) {
Handle<Object> id_arg = args.atOrUndefined(isolate, 4);
Handle<Object> data_arg = args.atOrUndefined(isolate, 5);
const uint8_t* category_group_enabled =
GetCategoryGroupEnabled(isolate, Handle<String>::cast(category));
// Exit early if the category group is not enabled.
if (!*category_group_enabled) {
#if defined(V8_USE_PERFETTO)
MaybeUtf8 category_str(isolate, Handle<String>::cast(category));
perfetto::DynamicCategory dynamic_category{*category_str};
if (!TRACE_EVENT_CATEGORY_ENABLED(dynamic_category))
return ReadOnlyRoots(isolate).false_value();
}
#else
const uint8_t* category_group_enabled =
GetCategoryGroupEnabled(isolate, Handle<String>::cast(category));
if (!*category_group_enabled) return ReadOnlyRoots(isolate).false_value();
#endif
if (!phase_arg->IsNumber()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kTraceEventPhaseError));
}
char phase = static_cast<char>(DoubleToInt32(phase_arg->Number()));
if (!category->IsString()) {
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kTraceEventCategoryError));
......@@ -160,32 +178,67 @@ BUILTIN(Trace) {
// We support passing one additional trace event argument with the
// name "data". Any JSON serializable value may be passed.
static const char* arg_name = "data";
Handle<Object> arg_json;
int32_t num_args = 0;
uint8_t arg_type;
uint64_t arg_value;
if (!data_arg->IsUndefined(isolate)) {
// Serializes the data argument as a JSON string, which is then
// copied into an object. This eliminates duplicated code but
// could have perf costs. It is also subject to all the same
// limitations as JSON.stringify() as it relates to circular
// references and value limitations (e.g. BigInt is not supported).
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
isolate, arg_json,
JsonStringify(isolate, data_arg, isolate->factory()->undefined_value(),
isolate->factory()->undefined_value()));
std::unique_ptr<JsonTraceValue> traced_value;
traced_value.reset(
new JsonTraceValue(isolate, Handle<String>::cast(result)));
tracing::SetTraceValue(std::move(traced_value), &arg_type, &arg_value);
num_args++;
}
#if defined(V8_USE_PERFETTO)
auto trace_args = [&](perfetto::EventContext ctx) {
// TODO(skyostil): Use interned names to reduce trace size.
if (phase != TRACE_EVENT_PHASE_END) {
ctx.event()->set_name(*name);
}
if (num_args) {
MaybeUtf8 arg_contents(isolate, Handle<String>::cast(arg_json));
auto annotation = ctx.event()->add_debug_annotations();
annotation->set_name(arg_name);
annotation->set_legacy_json_value(*arg_contents);
}
if (flags & TRACE_EVENT_FLAG_HAS_ID) {
auto legacy_event = ctx.event()->set_legacy_event();
legacy_event->set_global_id(id);
}
};
switch (phase) {
case TRACE_EVENT_PHASE_BEGIN:
TRACE_EVENT_BEGIN(dynamic_category, nullptr, trace_args);
break;
case TRACE_EVENT_PHASE_END:
TRACE_EVENT_END(dynamic_category, trace_args);
break;
case TRACE_EVENT_PHASE_INSTANT:
TRACE_EVENT_INSTANT(dynamic_category, nullptr, trace_args);
break;
default:
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kTraceEventPhaseError));
}
#else // !defined(V8_USE_PERFETTO)
uint8_t arg_type;
uint64_t arg_value;
if (num_args) {
std::unique_ptr<JsonTraceValue> traced_value(
new JsonTraceValue(isolate, Handle<String>::cast(arg_json)));
tracing::SetTraceValue(std::move(traced_value), &arg_type, &arg_value);
}
TRACE_EVENT_API_ADD_TRACE_EVENT(
static_cast<char>(DoubleToInt32(phase_arg->Number())),
category_group_enabled, *name, tracing::kGlobalScope, id, tracing::kNoId,
num_args, &arg_name, &arg_type, &arg_value, flags);
phase, category_group_enabled, *name, tracing::kGlobalScope, id,
tracing::kNoId, num_args, &arg_name, &arg_type, &arg_value, flags);
#endif // !defined(V8_USE_PERFETTO)
return ReadOnlyRoots(isolate).true_value();
}
......
......@@ -19,7 +19,7 @@ namespace {
// We log detailed phase information about the pipeline
// in both the v8.turbofan and the v8.wasm categories.
const char kTraceCategory[] = // --
constexpr const char kTraceCategory[] = // --
TRACE_DISABLED_BY_DEFAULT("v8.turbofan") "," // --
TRACE_DISABLED_BY_DEFAULT("v8.wasm");
......
......@@ -106,6 +106,9 @@ void V8::InitializeOncePerProcessImpl() {
if (FLAG_random_seed) SetRandomMmapSeed(FLAG_random_seed);
#if defined(V8_USE_PERFETTO)
TrackEvent::Register();
#endif
Isolate::InitializeOncePerProcess();
#if defined(USE_SIMULATOR)
......
......@@ -31,13 +31,9 @@ _protocol_generated = [
action("protocol_compatibility") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
script = "$_inspector_protocol/check_protocol_compatibility.py"
inputs = [
v8_inspector_js_protocol,
]
inputs = [ v8_inspector_js_protocol ]
_stamp = "$target_gen_dir/js_protocol.stamp"
outputs = [
_stamp,
]
outputs = [ _stamp ]
args = [
"--stamp",
rebase_path(_stamp, root_build_dir),
......@@ -47,9 +43,7 @@ action("protocol_compatibility") {
inspector_protocol_generate("protocol_generated_sources") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
deps = [
":protocol_compatibility",
]
deps = [ ":protocol_compatibility" ]
inspector_protocol_dir = _inspector_protocol
out_dir = target_gen_dir
......@@ -71,13 +65,9 @@ config("inspector_config") {
v8_header_set("inspector_test_headers") {
configs = [ ":inspector_config" ]
public_deps = [
"../..:v8_headers",
]
public_deps = [ "../..:v8_headers" ]
sources = [
"test-interface.h",
]
sources = [ "test-interface.h" ]
}
v8_source_set("inspector_string_conversions") {
......@@ -86,14 +76,13 @@ v8_source_set("inspector_string_conversions") {
"v8-string-conversions.h",
]
configs = [ "../..:internal_config_base" ]
deps = [
"../..:v8_libbase",
]
deps = [ "../..:v8_libbase" ]
}
v8_source_set("inspector") {
deps = [
":inspector_string_conversions",
"../..:v8_tracing",
"../..:v8_version",
"../../third_party/inspector_protocol:crdtp",
]
......@@ -166,7 +155,5 @@ v8_source_set("inspector") {
group("v8_generated_cc_files") {
testonly = true
deps = [
":protocol_generated_sources",
]
deps = [ ":protocol_generated_sources" ]
}
......@@ -76,7 +76,9 @@ DefaultPlatform::DefaultPlatform(
time_function_for_testing_(nullptr) {
if (!tracing_controller_) {
tracing::TracingController* controller = new tracing::TracingController();
#if !defined(V8_USE_PERFETTO)
controller->Initialize(nullptr);
#endif
tracing_controller_.reset(controller);
}
}
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/libplatform/tracing/json-trace-event-listener.h"
#include <cmath>
#include "base/trace_event/common/trace_event_common.h"
#include "perfetto/tracing.h"
#include "protos/perfetto/trace/chrome/chrome_trace_packet.pb.h"
#include "protos/perfetto/trace/trace.pb.h"
#include "src/base/logging.h"
#include "src/base/macros.h"
namespace v8 {
namespace platform {
namespace tracing {
JSONTraceEventListener::JSONTraceEventListener(std::ostream* stream)
: stream_(stream) {
*stream_ << "{\"traceEvents\":[";
}
JSONTraceEventListener::~JSONTraceEventListener() { *stream_ << "]}"; }
// TODO(petermarshall): Clean up this code which was copied from trace-writer.cc
// once we've removed that file.
// Writes the given string, taking care to escape characters when necessary.
void JSONTraceEventListener::AppendJSONString(const char* str) {
size_t len = strlen(str);
*stream_ << "\"";
for (size_t i = 0; i < len; ++i) {
// All of the permitted escape sequences in JSON strings, as per
// https://mathiasbynens.be/notes/javascript-escapes
switch (str[i]) {
case '\b':
*stream_ << "\\b";
break;
case '\f':
*stream_ << "\\f";
break;
case '\n':
*stream_ << "\\n";
break;
case '\r':
*stream_ << "\\r";
break;
case '\t':
*stream_ << "\\t";
break;
case '\"':
*stream_ << "\\\"";
break;
case '\\':
*stream_ << "\\\\";
break;
// Note that because we use double quotes for JSON strings,
// we don't need to escape single quotes.
default:
*stream_ << str[i];
break;
}
}
*stream_ << "\"";
}
void JSONTraceEventListener::AppendArgValue(
const ::perfetto::protos::ChromeTraceEvent_Arg& arg) {
if (arg.has_bool_value()) {
*stream_ << (arg.bool_value() ? "true" : "false");
} else if (arg.has_uint_value()) {
*stream_ << arg.uint_value();
} else if (arg.has_int_value()) {
*stream_ << arg.int_value();
} else if (arg.has_double_value()) {
std::string real;
double val = arg.double_value();
if (std::isfinite(val)) {
std::ostringstream convert_stream;
convert_stream << val;
real = convert_stream.str();
// Ensure that the number has a .0 if there's no decimal or 'e'. This
// makes sure that when we read the JSON back, it's interpreted as a
// real rather than an int.
if (real.find('.') == std::string::npos &&
real.find('e') == std::string::npos &&
real.find('E') == std::string::npos) {
real += ".0";
}
} else if (std::isnan(val)) {
// The JSON spec doesn't allow NaN and Infinity (since these are
// objects in EcmaScript). Use strings instead.
real = "\"NaN\"";
} else if (val < 0) {
real = "\"-Infinity\"";
} else {
real = "\"Infinity\"";
}
*stream_ << real;
} else if (arg.has_string_value()) {
AppendJSONString(arg.string_value().c_str());
} else if (arg.has_pointer_value()) {
// JSON only supports double and int numbers.
// So as not to lose bits from a 64-bit pointer, output as a hex string.
*stream_ << "\"0x" << std::hex << arg.pointer_value() << std::dec << "\"";
} else if (arg.has_json_value()) {
*stream_ << arg.json_value();
}
// V8 does not emit proto arguments currently.
CHECK(!arg.has_traced_value());
}
void JSONTraceEventListener::ProcessPacket(
const ::perfetto::protos::TracePacket& packet) {
for (const ::perfetto::protos::ChromeTraceEvent& event :
packet.chrome_events().trace_events()) {
if (append_comma_) *stream_ << ",";
append_comma_ = true;
// TODO(petermarshall): Handle int64 fields differently?
// clang-format off
*stream_ << "{\"pid\":" << event.process_id()
<< ",\"tid\":" << event.thread_id()
<< ",\"ts\":" << event.timestamp()
<< ",\"tts\":" << event.thread_timestamp()
<< ",\"ph\":\"" << static_cast<char>(event.phase())
<< "\",\"cat\":\"" << event.category_group_name()
<< "\",\"name\":\"" << event.name()
<< "\",\"dur\":" << event.duration()
<< ",\"tdur\":" << event.thread_duration();
// clang-format on
if (event.flags() &
(TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT)) {
*stream_ << ",\"bind_id\":\"0x" << std::hex << event.bind_id() << "\""
<< std::dec;
if (event.flags() & TRACE_EVENT_FLAG_FLOW_IN) {
*stream_ << ",\"flow_in\":true";
}
if (event.flags() & TRACE_EVENT_FLAG_FLOW_OUT) {
*stream_ << ",\"flow_out\":true";
}
}
if (event.flags() & TRACE_EVENT_FLAG_HAS_ID) {
if (event.has_scope()) {
*stream_ << ",\"scope\":\"" << event.scope() << "\"";
}
// So as not to lose bits from a 64-bit integer, output as a hex string.
*stream_ << ",\"id\":\"0x" << std::hex << event.id() << "\"" << std::dec;
}
*stream_ << ",\"args\":{";
int i = 0;
for (const ::perfetto::protos::ChromeTraceEvent_Arg& arg : event.args()) {
if (i++ > 0) *stream_ << ",";
*stream_ << "\"" << arg.name() << "\":";
AppendArgValue(arg);
}
*stream_ << "}}";
}
}
} // namespace tracing
} // namespace platform
} // namespace v8
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_LIBPLATFORM_TRACING_JSON_TRACE_EVENT_LISTENER_H_
#define V8_LIBPLATFORM_TRACING_JSON_TRACE_EVENT_LISTENER_H_
#include <ostream>
#include "libplatform/libplatform-export.h"
#include "src/libplatform/tracing/trace-event-listener.h"
namespace perfetto {
namespace protos {
class ChromeTraceEvent_Arg;
} // namespace protos
} // namespace perfetto
namespace v8 {
namespace platform {
namespace tracing {
// A listener that converts the proto trace data to JSON and writes it to a
// file.
class V8_PLATFORM_EXPORT JSONTraceEventListener final
: public TraceEventListener {
public:
explicit JSONTraceEventListener(std::ostream* stream);
~JSONTraceEventListener() override;
void ProcessPacket(const ::perfetto::protos::TracePacket& packet) override;
private:
// Internal implementation
void AppendJSONString(const char* str);
void AppendArgValue(const ::perfetto::protos::ChromeTraceEvent_Arg& arg);
std::ostream* stream_;
bool append_comma_ = false;
};
} // namespace tracing
} // namespace platform
} // namespace v8
#endif // V8_LIBPLATFORM_TRACING_JSON_TRACE_EVENT_LISTENER_H_
include_rules = [
"+perfetto/tracing.h",
"+protos/perfetto"
]
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/tracing/trace-categories.h"
#if defined(V8_USE_PERFETTO)
PERFETTO_TRACK_EVENT_STATIC_STORAGE();
#endif
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_TRACING_TRACE_CATEGORIES_H_
#define V8_TRACING_TRACE_CATEGORIES_H_
#include "src/base/macros.h"
#if defined(V8_USE_PERFETTO)
// Exports tracks events into the v8 namespace to avoid conflicts with embedders
// like Chrome.
#define PERFETTO_TRACK_EVENT_NAMESPACE v8
// Export trace categories and the track event data source in components builds.
#define PERFETTO_COMPONENT_EXPORT V8_EXPORT_PRIVATE
// For now most of v8 uses legacy trace events.
#define PERFETTO_ENABLE_LEGACY_TRACE_EVENTS 1
#include "perfetto/tracing.h"
// Trace category prefixes used in tests.
PERFETTO_DEFINE_TEST_CATEGORY_PREFIXES("v8-cat", "cat", "v8.Test2");
// List of categories used by built-in V8 trace events.
// clang-format off
PERFETTO_DEFINE_CATEGORIES(
perfetto::Category("V8.HandleInterrupts"),
perfetto::Category("v8"),
perfetto::Category("v8.console"),
perfetto::Category("v8.execute"),
perfetto::Category("v8.runtime"),
perfetto::Category::Group("devtools.timeline,v8"),
perfetto::Category(TRACE_DISABLED_BY_DEFAULT("devtools.timeline")),
perfetto::Category(TRACE_DISABLED_BY_DEFAULT("v8")),
perfetto::Category(TRACE_DISABLED_BY_DEFAULT("v8.compile")),
perfetto::Category(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler")),
perfetto::Category(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler.hires")),
perfetto::Category(TRACE_DISABLED_BY_DEFAULT("v8.gc")),
perfetto::Category(TRACE_DISABLED_BY_DEFAULT("v8.gc_stats")),
perfetto::Category(TRACE_DISABLED_BY_DEFAULT("v8.ic_stats")),
perfetto::Category(TRACE_DISABLED_BY_DEFAULT("v8.runtime")),
perfetto::Category(TRACE_DISABLED_BY_DEFAULT("v8.runtime_stats")),
perfetto::Category(TRACE_DISABLED_BY_DEFAULT("v8.runtime_stats_sampling")),
perfetto::Category(TRACE_DISABLED_BY_DEFAULT("v8.turbofan")),
perfetto::Category(TRACE_DISABLED_BY_DEFAULT("v8.wasm")),
perfetto::Category::Group(TRACE_DISABLED_BY_DEFAULT("v8.turbofan") ","
TRACE_DISABLED_BY_DEFAULT("v8.wasm")));
// clang-format on
#endif // defined(V8_USE_PERFETTO)
#endif // V8_TRACING_TRACE_CATEGORIES_H_
......@@ -15,6 +15,7 @@ namespace v8 {
namespace internal {
namespace tracing {
#if !defined(V8_USE_PERFETTO)
v8::TracingController* TraceEventHelper::GetTracingController() {
return v8::internal::V8::GetCurrentPlatform()->GetTracingController();
}
......@@ -51,6 +52,7 @@ void CallStatsScopedTracer::Initialize(v8::internal::Isolate* isolate,
v8::internal::tracing::kGlobalScope, v8::internal::tracing::kNoId,
TRACE_EVENT_FLAG_NONE, v8::internal::tracing::kNoId);
}
#endif // !defined(V8_USE_PERFETTO)
} // namespace tracing
} // namespace internal
......
......@@ -8,7 +8,13 @@
#include <stddef.h>
#include <memory>
#if defined(V8_USE_PERFETTO)
#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
#include "src/tracing/trace-categories.h"
#else
#include "base/trace_event/common/trace_event_common.h"
#endif // !defined(V8_USE_PERFETTO)
#include "include/v8-platform.h"
#include "src/base/atomicops.h"
#include "src/base/macros.h"
......@@ -32,6 +38,8 @@ enum CategoryGroupEnabledFlags {
kEnabledForETWExport_CategoryGroupEnabledFlags = 1 << 3,
};
#if !defined(V8_USE_PERFETTO)
// TODO(petermarshall): Remove with the old tracing implementation - Perfetto
// copies const char* arguments by default.
// By default, const char* argument values are assumed to have long-lived scope
......@@ -284,8 +292,8 @@ class Isolate;
namespace tracing {
// Specify these values when the corresponding argument of AddTraceEvent is not
// used.
// Specify these values when the corresponding argument of AddTraceEvent
// is not used.
const int kZeroNumArgs = 0;
const decltype(nullptr) kGlobalScope = nullptr;
const uint64_t kNoId = 0;
......@@ -605,4 +613,39 @@ class CallStatsScopedTracer {
} // namespace internal
} // namespace v8
#else // defined(V8_USE_PERFETTO)
#define TRACE_EVENT_CALL_STATS_SCOPED(isolate, category, name) \
struct PERFETTO_UID(ScopedEvent) { \
struct ScopedStats { \
ScopedStats(v8::internal::Isolate* isolate_arg, int) { \
TRACE_EVENT_BEGIN(category, name, [&](perfetto::EventContext) { \
isolate_ = isolate_arg; \
internal::RuntimeCallStats* table = \
isolate_->counters()->runtime_call_stats(); \
has_parent_scope_ = table->InUse(); \
if (!has_parent_scope_) table->Reset(); \
}); \
} \
~ScopedStats() { \
TRACE_EVENT_END(category, [&](perfetto::EventContext ctx) { \
if (!has_parent_scope_ && isolate_) { \
/* TODO(skyostil): Write as typed event instead of JSON */ \
auto value = v8::tracing::TracedValue::Create(); \
isolate_->counters()->runtime_call_stats()->Dump(value.get()); \
auto annotation = ctx.event()->add_debug_annotations(); \
annotation->set_name("runtime-call-stats"); \
value->Add(annotation); \
} \
}); \
} \
v8::internal::Isolate* isolate_; \
bool has_parent_scope_; \
} stats; \
} PERFETTO_UID(scoped_event) { \
{ isolate, 0 } \
}
#endif // defined(V8_USE_PERFETTO)
#endif // V8_TRACING_TRACE_EVENT_H_
......@@ -8,6 +8,10 @@
#include "src/numbers/conversions.h"
#include "src/utils/vector.h"
#ifdef V8_USE_PERFETTO
#include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
#endif
namespace v8 {
namespace tracing {
......@@ -207,5 +211,16 @@ void TracedValue::AppendAsTraceFormat(std::string* out) const {
*out += '}';
}
#ifdef V8_USE_PERFETTO
void TracedValue::Add(
perfetto::protos::pbzero::DebugAnnotation* annotation) const {
std::string json;
json += "{";
json += data_;
json += "}";
annotation->set_legacy_json_value(json);
}
#endif // V8_USE_PERFETTO
} // namespace tracing
} // namespace v8
......@@ -12,11 +12,17 @@
#include "include/v8-platform.h"
#include "src/base/macros.h"
#include "src/tracing/trace-event.h"
namespace v8 {
namespace tracing {
class V8_EXPORT_PRIVATE TracedValue : public ConvertableToTraceFormat {
class V8_EXPORT_PRIVATE TracedValue : public ConvertableToTraceFormat
#ifdef V8_USE_PERFETTO
,
public perfetto::DebugAnnotation
#endif // V8_USE_PERFETTO
{
public:
~TracedValue() override;
......@@ -54,6 +60,11 @@ class V8_EXPORT_PRIVATE TracedValue : public ConvertableToTraceFormat {
// ConvertableToTraceFormat implementation.
void AppendAsTraceFormat(std::string* out) const override;
#ifdef V8_USE_PERFETTO
// DebugAnnotation implementation.
void Add(perfetto::protos::pbzero::DebugAnnotation*) const override;
#endif // V8_USE_PERFETTO
private:
TracedValue();
......
......@@ -35,6 +35,14 @@ v8_executable("cctest") {
ldflags = []
if (v8_use_perfetto) {
deps += [
# TODO(skyostil): Switch the test to use protozero.
"//third_party/perfetto/protos/perfetto/trace/interned_data:lite",
"//third_party/perfetto/protos/perfetto/trace/track_event:lite",
]
}
# TODO(machenbach): Translate from gyp.
#["OS=="aix"", {
# "ldflags": [ "-Wl,-bbigtoc" ],
......@@ -378,6 +386,11 @@ v8_source_set("cctest_sources") {
]
}
if (v8_use_perfetto) {
# Perfetto doesn't use TraceObject.
sources -= [ "test-trace-event.cc" ]
}
configs = [
"../..:external_config",
"../..:internal_config_base",
......@@ -435,10 +448,8 @@ v8_source_set("cctest_sources") {
if (v8_use_perfetto) {
deps += [
"//third_party/perfetto/include/perfetto/tracing",
"//third_party/perfetto/protos/perfetto/trace/chrome:lite",
"//third_party/perfetto/protos/perfetto/trace/chrome:zero",
"//third_party/perfetto/src/tracing:in_process_backend",
# TODO(skyostil): Migrate to protozero.
"//third_party/perfetto/protos/perfetto/trace:lite",
]
}
}
......
......@@ -40,7 +40,7 @@
#include "test/cctest/trace-extension.h"
#ifdef V8_USE_PERFETTO
#include "perfetto/tracing.h"
#include "src/tracing/trace-event.h"
#endif // V8_USE_PERFETTO
#if V8_OS_WIN
......
This diff is collapsed.
......@@ -54,7 +54,6 @@
#include "src/tracing/trace-event.h"
#ifdef V8_USE_PERFETTO
#include "protos/perfetto/trace/chrome/chrome_trace_event.pb.h"
#include "protos/perfetto/trace/trace.pb.h"
#endif
......@@ -2625,22 +2624,34 @@ using v8::platform::tracing::TraceObject;
namespace {
#ifdef V8_USE_PERFETTO
class CpuProfilerListener : public platform::tracing::TraceEventListener {
public:
void ProcessPacket(const ::perfetto::protos::TracePacket& packet) {
for (const ::perfetto::protos::ChromeTraceEvent& trace_event :
packet.chrome_events().trace_events()) {
if (trace_event.name() != std::string("Profile") &&
trace_event.name() != std::string("ProfileChunk"))
return;
CHECK(!profile_id_ || trace_event.id() == profile_id_);
CHECK_EQ(1, trace_event.args_size());
CHECK(trace_event.args()[0].has_json_value());
profile_id_ = trace_event.id();
result_json_ += result_json_.empty() ? "[" : ",\n";
result_json_ += trace_event.args()[0].json_value();
auto& seq_state = sequence_state_[packet.trusted_packet_sequence_id()];
if (packet.incremental_state_cleared()) seq_state = SequenceState{};
if (!packet.has_track_event()) return;
// Update incremental state.
if (packet.has_interned_data()) {
const auto& interned_data = packet.interned_data();
for (const auto& it : interned_data.event_names()) {
CHECK_EQ(seq_state.event_names_.find(it.iid()),
seq_state.event_names_.end());
seq_state.event_names_[it.iid()] = it.name();
}
}
const auto& track_event = packet.track_event();
auto name = seq_state.event_names_[track_event.name_iid()];
if (name != "Profile" && name != "ProfileChunk") return;
CHECK_EQ(1, track_event.debug_annotations_size());
CHECK(track_event.debug_annotations()[0].has_legacy_json_value());
CHECK(!profile_id_ ||
track_event.legacy_event().unscoped_id() == profile_id_);
profile_id_ = track_event.legacy_event().unscoped_id();
result_json_ += result_json_.empty() ? "[" : ",\n";
result_json_ += track_event.debug_annotations()[0].legacy_json_value();
}
const std::string& result_json() {
......@@ -2650,11 +2661,17 @@ class CpuProfilerListener : public platform::tracing::TraceEventListener {
void Reset() {
result_json_.clear();
profile_id_ = 0;
sequence_state_.clear();
}
private:
std::string result_json_;
uint64_t profile_id_ = 0;
struct SequenceState {
std::map<uint64_t, std::string> event_names_;
};
std::map<uint32_t, SequenceState> sequence_state_;
};
#else
......@@ -2732,6 +2749,9 @@ TEST(TracingCpuProfiler) {
tracing_controller->StartTracing(trace_config);
CompileRun(test_code.c_str());
#ifdef V8_USE_PERFETTO
TrackEvent::Flush();
#endif
tracing_controller->StopTracing();
#ifdef V8_USE_PERFETTO
......@@ -2757,9 +2777,11 @@ TEST(TracingCpuProfiler) {
->IsTrue();
}
#ifndef V8_USE_PERFETTO
static_cast<v8::platform::tracing::TracingController*>(
i::V8::GetCurrentPlatform()->GetTracingController())
->Initialize(nullptr);
#endif // !V8_USE_PERFETTO
}
TEST(Issue763073) {
......
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
config("jsoncpp_config") {
include_dirs = [
"source/include",
"generated",
]
# TODO(crbug.com/983223): Update JsonCpp BUILD.gn to remove deprecated
# declaration flag.
# This temporary flag allowing clients to update to the new version, and then
# update to the new StreamWriter and CharReader classes.
if (!is_win || is_clang) {
cflags_cc = [ "-Wno-deprecated-declarations" ]
}
}
source_set("jsoncpp") {
sources = [
"generated/version.h",
"source/include/json/assertions.h",
"source/include/json/autolink.h",
"source/include/json/config.h",
"source/include/json/features.h",
"source/include/json/forwards.h",
"source/include/json/json.h",
"source/include/json/reader.h",
"source/include/json/value.h",
"source/include/json/writer.h",
"source/src/lib_json/json_reader.cpp",
"source/src/lib_json/json_tool.h",
"source/src/lib_json/json_value.cpp",
"source/src/lib_json/json_writer.cpp",
]
public_configs = [ ":jsoncpp_config" ]
defines = [
"JSON_USE_EXCEPTION=0",
"JSON_USE_NULLREF=0",
]
include_dirs = [ "source/src/lib_json" ]
if (!is_win || is_clang) {
cflags_cc = [ "-Wno-implicit-fallthrough" ]
}
}
The JsonCpp library's source code, including accompanying documentation,
tests and demonstration applications, are licensed under the following
conditions...
The author (Baptiste Lepilleur) explicitly disclaims copyright in all
jurisdictions which recognize such a disclaimer. In such jurisdictions,
this software is released into the Public Domain.
In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
released under the terms of the MIT License (see below).
In jurisdictions which recognize Public Domain property, the user of this
software may choose to accept it either as 1) Public Domain, 2) under the
conditions of the MIT License (see below), or 3) under the terms of dual
Public Domain/MIT License conditions described here, as they choose.
The MIT License is about as close to Public Domain as a license can get, and is
described in clear, concise terms at:
http://en.wikipedia.org/wiki/MIT_License
The full text of the MIT License follows:
========================================================================
Copyright (c) 2007-2010 Baptiste Lepilleur
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
========================================================================
(END LICENSE TEXT)
The MIT license is compatible with both the GPL and commercial
software, affording one all of the rights of Public Domain with the
minor nuisance of being required to keep the above copyright notice
and license text in the source code. Note also that by accepting the
Public Domain "license" you can re-license your copy using whatever
license you like.
Name: jsoncpp
URL: https://github.com/open-source-parsers/jsoncpp
Version: f572e8e42e22cfcf5ab0aea26574f408943edfa4
License: MIT
License File: LICENSE
Security Critical: yes
Description:
JsonCpp is used by multiple projects for parsing and generating JSON data. This
project is mirrored here from the public GitHub project, with a custom BUILD.gn
to allow for building with our Ninja + GN configuration. The main project uses
Meson or CMake for building.
Note: to update this project to a new version, regenerating the version.h header
is required. This can be done by installing either CMake or Meson, building the
project, and copying the generated version.h to the generated/ subfolder.
// DO NOT EDIT. This file (and "version") is a template used by the build system
// (either CMake or Meson) to generate a "version.h" header file.
#ifndef JSON_VERSION_H_INCLUDED
#define JSON_VERSION_H_INCLUDED
#define JSONCPP_VERSION_STRING "1.9.0"
#define JSONCPP_VERSION_MAJOR 1
#define JSONCPP_VERSION_MINOR 9
#define JSONCPP_VERSION_PATCH 0
#define JSONCPP_VERSION_QUALIFIER
#define JSONCPP_VERSION_HEXA \
((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
(JSONCPP_VERSION_PATCH << 8))
#ifdef JSONCPP_USING_SECURE_MEMORY
#undef JSONCPP_USING_SECURE_MEMORY
#endif
#define JSONCPP_USING_SECURE_MEMORY 0
// If non-zero, the library zeroes any memory that it has allocated before
// it frees its memory.
#endif // JSON_VERSION_H_INCLUDED
......@@ -12,6 +12,8 @@ config("internal_config") {
defines = [ "BUILDING_V8_DEBUG_HELPER" ]
}
configs = [ "../..:v8_tracing_config" ]
include_dirs = [
".",
"../..",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment