Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/trace_event/trace_event_argument.h" | 5 #include "base/trace_event/trace_event_argument.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <stack> | |
| 9 #include <utility> | 10 #include <utility> |
| 10 | 11 |
| 11 #include "base/bits.h" | 12 #include "base/bits.h" |
| 12 #include "base/json/json_writer.h" | 13 #include "base/json/string_escape.h" |
| 13 #include "base/memory/ptr_util.h" | 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/trace_event/common/trace_event_common.h" | |
| 16 #include "base/trace_event/trace_event_impl.h" | |
| 14 #include "base/trace_event/trace_event_memory_overhead.h" | 17 #include "base/trace_event/trace_event_memory_overhead.h" |
| 15 #include "base/values.h" | 18 #include "base/values.h" |
| 16 | 19 |
| 17 namespace base { | 20 namespace base { |
| 18 namespace trace_event { | 21 namespace trace_event { |
| 19 | 22 |
| 20 namespace { | 23 namespace { |
| 21 const char kTypeStartDict = '{'; | 24 const char kTypeStartDict = '{'; |
| 22 const char kTypeEndDict = '}'; | 25 const char kTypeEndDict = '}'; |
| 23 const char kTypeStartArray = '['; | 26 const char kTypeStartArray = '['; |
| 24 const char kTypeEndArray = ']'; | 27 const char kTypeEndArray = ']'; |
| 25 const char kTypeBool = 'b'; | 28 const char kTypeBool = 'b'; |
| 26 const char kTypeInt = 'i'; | 29 const char kTypeInt = 'i'; |
| 27 const char kTypeDouble = 'd'; | 30 const char kTypeDouble = 'd'; |
| 28 const char kTypeString = 's'; | 31 const char kTypeString = 's'; |
| 29 const char kTypeCStr = '*'; | 32 const char kTypeCStr = '*'; // only used for key names |
| 30 | 33 |
| 31 #ifndef NDEBUG | 34 #ifndef NDEBUG |
| 32 const bool kStackTypeDict = false; | 35 const bool kStackTypeDict = false; |
| 33 const bool kStackTypeArray = true; | 36 const bool kStackTypeArray = true; |
| 34 #define DCHECK_CURRENT_CONTAINER_IS(x) DCHECK_EQ(x, nesting_stack_.back()) | 37 #define DCHECK_CURRENT_CONTAINER_IS(x) DCHECK_EQ(x, nesting_stack_.back()) |
| 35 #define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) DCHECK_EQ(x, nesting_stack_.size()) | 38 #define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) DCHECK_EQ(x, nesting_stack_.size()) |
| 36 #define DEBUG_PUSH_CONTAINER(x) nesting_stack_.push_back(x) | 39 #define DEBUG_PUSH_CONTAINER(x) nesting_stack_.push_back(x) |
| 37 #define DEBUG_POP_CONTAINER() nesting_stack_.pop_back() | 40 #define DEBUG_POP_CONTAINER() nesting_stack_.pop_back() |
| 38 #else | 41 #else |
| 39 #define DCHECK_CURRENT_CONTAINER_IS(x) do {} while (0) | 42 #define DCHECK_CURRENT_CONTAINER_IS(x) do {} while (0) |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 447 } | 450 } |
| 448 } | 451 } |
| 449 DCHECK(stack.empty()); | 452 DCHECK(stack.empty()); |
| 450 return std::move(root); | 453 return std::move(root); |
| 451 } | 454 } |
| 452 | 455 |
| 453 void TracedValue::AppendAsTraceFormat(std::string* out) const { | 456 void TracedValue::AppendAsTraceFormat(std::string* out) const { |
| 454 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); | 457 DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict); |
| 455 DCHECK_CONTAINER_STACK_DEPTH_EQ(1u); | 458 DCHECK_CONTAINER_STACK_DEPTH_EQ(1u); |
| 456 | 459 |
| 457 // TODO(primiano): this could be smarter, skip the ToBaseValue encoding and | 460 struct State { |
|
Primiano Tucci (use gerrit)
2017/07/12 15:26:23
isn't this a gcc extension?
DmitrySkiba
2017/07/12 23:48:04
Inner structs? I believe it's valid C++11.
| |
| 458 // produce the JSON on its own. This will require refactoring JSONWriter | 461 enum Type { kTypeDict, kTypeArray }; |
| 459 // to decouple the base::Value traversal from the JSON writing bits | 462 Type type; |
| 460 std::string tmp; | 463 bool needs_comma; |
| 461 JSONWriter::Write(*ToBaseValue(), &tmp); | 464 }; |
| 462 *out += tmp; | 465 |
| 466 auto maybe_append_key_name = [](State current_state, PickleIterator* it, | |
| 467 std::string* out) { | |
| 468 if (current_state.type == State::kTypeDict) { | |
| 469 EscapeJSONString(ReadKeyName(*it), true, out); | |
| 470 out->append(":"); | |
| 471 } | |
| 472 }; | |
| 473 | |
| 474 std::stack<State> state_stack; | |
| 475 | |
| 476 out->append("{"); | |
|
Primiano Tucci (use gerrit)
2017/07/12 15:26:23
I think all ths might be even faster if you build
DmitrySkiba
2017/07/12 23:48:04
I don't think there will be a difference - strings
| |
| 477 state_stack.push({State::kTypeDict}); | |
| 478 | |
| 479 PickleIterator it(pickle_); | |
| 480 for (const char* type; it.ReadBytes(&type, 1);) { | |
| 481 switch (*type) { | |
| 482 case kTypeEndDict: | |
| 483 out->append("}"); | |
| 484 state_stack.pop(); | |
| 485 continue; | |
| 486 | |
| 487 case kTypeEndArray: | |
| 488 out->append("]"); | |
| 489 state_stack.pop(); | |
| 490 continue; | |
| 491 } | |
| 492 | |
| 493 State& current_state = state_stack.top(); | |
| 494 if (current_state.needs_comma) { | |
| 495 out->append(","); | |
| 496 } | |
| 497 | |
| 498 switch (*type) { | |
| 499 case kTypeStartDict: | |
| 500 maybe_append_key_name(current_state, &it, out); | |
| 501 out->append("{"); | |
| 502 state_stack.push({State::kTypeDict}); | |
| 503 break; | |
| 504 | |
| 505 case kTypeStartArray: | |
| 506 maybe_append_key_name(current_state, &it, out); | |
| 507 out->append("["); | |
| 508 state_stack.push({State::kTypeArray}); | |
| 509 break; | |
| 510 | |
| 511 case kTypeBool: { | |
| 512 TraceEvent::TraceValue json_value; | |
| 513 CHECK(it.ReadBool(&json_value.as_bool)); | |
| 514 maybe_append_key_name(current_state, &it, out); | |
| 515 TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_BOOL, json_value, out); | |
| 516 } break; | |
| 517 | |
| 518 case kTypeInt: { | |
| 519 int value; | |
| 520 CHECK(it.ReadInt(&value)); | |
| 521 maybe_append_key_name(current_state, &it, out); | |
| 522 TraceEvent::TraceValue json_value; | |
| 523 json_value.as_int = value; | |
| 524 TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_INT, json_value, out); | |
| 525 } break; | |
| 526 | |
| 527 case kTypeDouble: { | |
| 528 TraceEvent::TraceValue json_value; | |
| 529 CHECK(it.ReadDouble(&json_value.as_double)); | |
| 530 maybe_append_key_name(current_state, &it, out); | |
| 531 TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_DOUBLE, json_value, out); | |
| 532 } break; | |
| 533 | |
| 534 case kTypeString: { | |
| 535 std::string value; | |
| 536 CHECK(it.ReadString(&value)); | |
| 537 maybe_append_key_name(current_state, &it, out); | |
| 538 TraceEvent::TraceValue json_value; | |
| 539 json_value.as_string = value.c_str(); | |
| 540 TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_STRING, json_value, out); | |
| 541 } break; | |
| 542 | |
| 543 default: | |
| 544 NOTREACHED(); | |
| 545 } | |
| 546 | |
| 547 current_state.needs_comma = true; | |
| 548 } | |
| 549 | |
| 550 out->append("}"); | |
| 551 state_stack.pop(); | |
| 552 | |
| 553 DCHECK(state_stack.empty()); | |
| 463 } | 554 } |
| 464 | 555 |
| 465 void TracedValue::EstimateTraceMemoryOverhead( | 556 void TracedValue::EstimateTraceMemoryOverhead( |
| 466 TraceEventMemoryOverhead* overhead) { | 557 TraceEventMemoryOverhead* overhead) { |
| 467 overhead->Add(TraceEventMemoryOverhead::kTracedValue, | 558 overhead->Add(TraceEventMemoryOverhead::kTracedValue, |
| 468 /* allocated size */ | 559 /* allocated size */ |
| 469 pickle_.GetTotalAllocatedSize(), | 560 pickle_.GetTotalAllocatedSize(), |
| 470 /* resident size */ | 561 /* resident size */ |
| 471 pickle_.size()); | 562 pickle_.size()); |
| 472 } | 563 } |
| 473 | 564 |
| 474 } // namespace trace_event | 565 } // namespace trace_event |
| 475 } // namespace base | 566 } // namespace base |
| OLD | NEW |