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 { |
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("{"); |
| 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 |