Commit 131e21f4 authored by dskiba's avatar dskiba Committed by Commit Bot

[tracing] Optimize TracedValue::AppendAsTraceFormat().

This CL optimizes TracedValue::AppendAsTraceFormat() by removing
intermediate base::Value conversion.

HeapProfilerPerfTest.AppendStackFramesAsTraceFormat shows ~1.9x improvement
on macOS (1730ms -> 920ms).

TBR=jbauman@chromium.org

BUG=739378, 664350

Review-Url: https://codereview.chromium.org/2975033002
Cr-Commit-Position: refs/heads/master@{#487019}
parent 6da431cd
...@@ -6,11 +6,14 @@ ...@@ -6,11 +6,14 @@
#include <stdint.h> #include <stdint.h>
#include <stack>
#include <utility> #include <utility>
#include "base/bits.h" #include "base/bits.h"
#include "base/json/json_writer.h" #include "base/json/string_escape.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event_impl.h"
#include "base/trace_event/trace_event_memory_overhead.h" #include "base/trace_event/trace_event_memory_overhead.h"
#include "base/values.h" #include "base/values.h"
...@@ -26,7 +29,7 @@ const char kTypeBool = 'b'; ...@@ -26,7 +29,7 @@ const char kTypeBool = 'b';
const char kTypeInt = 'i'; const char kTypeInt = 'i';
const char kTypeDouble = 'd'; const char kTypeDouble = 'd';
const char kTypeString = 's'; const char kTypeString = 's';
const char kTypeCStr = '*'; const char kTypeCStr = '*'; // only used for key names
#ifndef NDEBUG #ifndef NDEBUG
const bool kStackTypeDict = false; const bool kStackTypeDict = false;
...@@ -454,12 +457,100 @@ void TracedValue::AppendAsTraceFormat(std::string* out) const { ...@@ -454,12 +457,100 @@ void TracedValue::AppendAsTraceFormat(std::string* out) const {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
DCHECK_CONTAINER_STACK_DEPTH_EQ(1u); DCHECK_CONTAINER_STACK_DEPTH_EQ(1u);
// TODO(primiano): this could be smarter, skip the ToBaseValue encoding and struct State {
// produce the JSON on its own. This will require refactoring JSONWriter enum Type { kTypeDict, kTypeArray };
// to decouple the base::Value traversal from the JSON writing bits Type type;
std::string tmp; bool needs_comma;
JSONWriter::Write(*ToBaseValue(), &tmp); };
*out += tmp;
auto maybe_append_key_name = [](State current_state, PickleIterator* it,
std::string* out) {
if (current_state.type == State::kTypeDict) {
EscapeJSONString(ReadKeyName(*it), true, out);
out->append(":");
}
};
std::stack<State> state_stack;
out->append("{");
state_stack.push({State::kTypeDict});
PickleIterator it(pickle_);
for (const char* type; it.ReadBytes(&type, 1);) {
switch (*type) {
case kTypeEndDict:
out->append("}");
state_stack.pop();
continue;
case kTypeEndArray:
out->append("]");
state_stack.pop();
continue;
}
State& current_state = state_stack.top();
if (current_state.needs_comma) {
out->append(",");
}
switch (*type) {
case kTypeStartDict:
maybe_append_key_name(current_state, &it, out);
out->append("{");
state_stack.push({State::kTypeDict});
break;
case kTypeStartArray:
maybe_append_key_name(current_state, &it, out);
out->append("[");
state_stack.push({State::kTypeArray});
break;
case kTypeBool: {
TraceEvent::TraceValue json_value;
CHECK(it.ReadBool(&json_value.as_bool));
maybe_append_key_name(current_state, &it, out);
TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_BOOL, json_value, out);
} break;
case kTypeInt: {
int value;
CHECK(it.ReadInt(&value));
maybe_append_key_name(current_state, &it, out);
TraceEvent::TraceValue json_value;
json_value.as_int = value;
TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_INT, json_value, out);
} break;
case kTypeDouble: {
TraceEvent::TraceValue json_value;
CHECK(it.ReadDouble(&json_value.as_double));
maybe_append_key_name(current_state, &it, out);
TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_DOUBLE, json_value, out);
} break;
case kTypeString: {
std::string value;
CHECK(it.ReadString(&value));
maybe_append_key_name(current_state, &it, out);
TraceEvent::TraceValue json_value;
json_value.as_string = value.c_str();
TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_STRING, json_value, out);
} break;
default:
NOTREACHED();
}
current_state.needs_comma = true;
}
out->append("}");
state_stack.pop();
DCHECK(state_stack.empty());
} }
void TracedValue::EstimateTraceMemoryOverhead( void TracedValue::EstimateTraceMemoryOverhead(
......
...@@ -17,9 +17,9 @@ namespace trace_event { ...@@ -17,9 +17,9 @@ namespace trace_event {
TEST(TraceEventArgumentTest, FlatDictionary) { TEST(TraceEventArgumentTest, FlatDictionary) {
std::unique_ptr<TracedValue> value(new TracedValue()); std::unique_ptr<TracedValue> value(new TracedValue());
value->SetInteger("int", 2014);
value->SetDouble("double", 0.0);
value->SetBoolean("bool", true); value->SetBoolean("bool", true);
value->SetDouble("double", 0.0);
value->SetInteger("int", 2014);
value->SetString("string", "string"); value->SetString("string", "string");
std::string json = "PREFIX"; std::string json = "PREFIX";
value->AppendAsTraceFormat(&json); value->AppendAsTraceFormat(&json);
...@@ -30,9 +30,9 @@ TEST(TraceEventArgumentTest, FlatDictionary) { ...@@ -30,9 +30,9 @@ TEST(TraceEventArgumentTest, FlatDictionary) {
TEST(TraceEventArgumentTest, NoDotPathExpansion) { TEST(TraceEventArgumentTest, NoDotPathExpansion) {
std::unique_ptr<TracedValue> value(new TracedValue()); std::unique_ptr<TracedValue> value(new TracedValue());
value->SetInteger("in.t", 2014);
value->SetDouble("doub.le", 0.0);
value->SetBoolean("bo.ol", true); value->SetBoolean("bo.ol", true);
value->SetDouble("doub.le", 0.0);
value->SetInteger("in.t", 2014);
value->SetString("str.ing", "str.ing"); value->SetString("str.ing", "str.ing");
std::string json; std::string json;
value->AppendAsTraceFormat(&json); value->AppendAsTraceFormat(&json);
...@@ -43,16 +43,6 @@ TEST(TraceEventArgumentTest, NoDotPathExpansion) { ...@@ -43,16 +43,6 @@ TEST(TraceEventArgumentTest, NoDotPathExpansion) {
TEST(TraceEventArgumentTest, Hierarchy) { TEST(TraceEventArgumentTest, Hierarchy) {
std::unique_ptr<TracedValue> value(new TracedValue()); std::unique_ptr<TracedValue> value(new TracedValue());
value->SetInteger("i0", 2014);
value->BeginDictionary("dict1");
value->SetInteger("i1", 2014);
value->BeginDictionary("dict2");
value->SetBoolean("b2", false);
value->EndDictionary();
value->SetString("s1", "foo");
value->EndDictionary();
value->SetDouble("d0", 0.0);
value->SetBoolean("b0", true);
value->BeginArray("a1"); value->BeginArray("a1");
value->AppendInteger(1); value->AppendInteger(1);
value->AppendBoolean(true); value->AppendBoolean(true);
...@@ -60,6 +50,16 @@ TEST(TraceEventArgumentTest, Hierarchy) { ...@@ -60,6 +50,16 @@ TEST(TraceEventArgumentTest, Hierarchy) {
value->SetInteger("i2", 3); value->SetInteger("i2", 3);
value->EndDictionary(); value->EndDictionary();
value->EndArray(); value->EndArray();
value->SetBoolean("b0", true);
value->SetDouble("d0", 0.0);
value->BeginDictionary("dict1");
value->BeginDictionary("dict2");
value->SetBoolean("b2", false);
value->EndDictionary();
value->SetInteger("i1", 2014);
value->SetString("s1", "foo");
value->EndDictionary();
value->SetInteger("i0", 2014);
value->SetString("s0", "foo"); value->SetString("s0", "foo");
std::string json; std::string json;
value->AppendAsTraceFormat(&json); value->AppendAsTraceFormat(&json);
......
...@@ -970,8 +970,8 @@ TEST(FilterOperationsTest, ToString) { ...@@ -970,8 +970,8 @@ TEST(FilterOperationsTest, ToString) {
filters.Append(FilterOperation::CreateSaturateFilter(3.f)); filters.Append(FilterOperation::CreateSaturateFilter(3.f));
filters.Append(FilterOperation::CreateBlurFilter(2.f)); filters.Append(FilterOperation::CreateBlurFilter(2.f));
EXPECT_EQ(std::string("{\"FilterOperations\":[{\"amount\":3.0,\"type\":2}," EXPECT_EQ(std::string("{\"FilterOperations\":[{\"type\":2,\"amount\":3.0},"
"{\"amount\":2.0,\"type\":8}]}"), "{\"type\":8,\"amount\":2.0}]}"),
filters.ToString()); filters.ToString());
} }
......
...@@ -25,10 +25,10 @@ TEST(GraphicsMemoryDumpProviderTest, ParseResponse) { ...@@ -25,10 +25,10 @@ TEST(GraphicsMemoryDumpProviderTest, ParseResponse) {
std::string json; std::string json;
mad->attributes_for_testing()->AppendAsTraceFormat(&json); mad->attributes_for_testing()->AppendAsTraceFormat(&json);
ASSERT_EQ( ASSERT_EQ(
"{\"memtrack_pss\":{\"type\":\"scalar\",\"units\":\"bytes\",\"value\":" "{\"memtrack_total\":{\"type\":\"scalar\",\"units\":\"bytes\",\"value\":"
"\"22\"}," "\"c\"},"
"\"memtrack_total\":{\"type\":\"scalar\",\"units\":\"bytes\",\"value\":" "\"memtrack_pss\":{\"type\":\"scalar\",\"units\":\"bytes\",\"value\":"
"\"c\"}}", "\"22\"}}",
json); json);
// Check the "gl" row. // Check the "gl" row.
...@@ -37,10 +37,10 @@ TEST(GraphicsMemoryDumpProviderTest, ParseResponse) { ...@@ -37,10 +37,10 @@ TEST(GraphicsMemoryDumpProviderTest, ParseResponse) {
json = ""; json = "";
mad->attributes_for_testing()->AppendAsTraceFormat(&json); mad->attributes_for_testing()->AppendAsTraceFormat(&json);
ASSERT_EQ( ASSERT_EQ(
"{\"memtrack_pss\":{\"type\":\"scalar\",\"units\":\"bytes\",\"value\":" "{\"memtrack_total\":{\"type\":\"scalar\",\"units\":\"bytes\",\"value\":"
"\"4e\"}," "\"38\"},"
"\"memtrack_total\":{\"type\":\"scalar\",\"units\":\"bytes\",\"value\":" "\"memtrack_pss\":{\"type\":\"scalar\",\"units\":\"bytes\",\"value\":"
"\"38\"}}", "\"4e\"}}",
json); json);
// Test for truncated input. // Test for truncated input.
......
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