Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3540)

Unified Diff: chrome/profiling/memlog_stream_parser.cc

Issue 2943733002: Add out-of-process memory logging stream parsing. (Closed)
Patch Set: Add TODO Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/profiling/memlog_stream_parser.h ('k') | chrome/profiling/profiling_globals.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/profiling/memlog_stream_parser.cc
diff --git a/chrome/profiling/memlog_stream_parser.cc b/chrome/profiling/memlog_stream_parser.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b67d0d7f151879f82042773793c07e19ce377bca
--- /dev/null
+++ b/chrome/profiling/memlog_stream_parser.cc
@@ -0,0 +1,163 @@
+// Copyright 2017 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.
+
+#include "chrome/profiling/memlog_stream_parser.h"
+
+#include <algorithm>
+
+#include "base/containers/stack_container.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/common/profiling/memlog_stream.h"
+#include "chrome/profiling/address.h"
+#include "chrome/profiling/backtrace.h"
+#include "chrome/profiling/profiling_globals.h"
+
+namespace profiling {
+
+namespace {
+
+using AddressVector = base::StackVector<Address, 128>;
+
+} // namespace
+
+MemlogStreamParser::Block::Block(std::unique_ptr<char[]> d, size_t s)
+ : data(std::move(d)), size(s) {}
+
+MemlogStreamParser::MemlogStreamParser(MemlogReceiver* receiver)
+ : receiver_(receiver) {}
+
+MemlogStreamParser::~MemlogStreamParser() {}
+
+void MemlogStreamParser::OnStreamData(std::unique_ptr<char[]> data, size_t sz) {
+ blocks_.emplace_back(std::move(data), sz);
+
+ if (!received_header_) {
+ received_header_ = true;
+ ReadStatus status = ParseHeader();
+ if (status != READ_OK)
+ return; // TODO(brettw) signal error.
+ }
+
+ while (true) {
+ uint32_t msg_type;
+ if (!PeekBytes(sizeof(msg_type), &msg_type))
+ return;
+
+ ReadStatus status;
+ switch (msg_type) {
+ case kAllocPacketType:
+ status = ParseAlloc();
+ break;
+ case kFreePacketType:
+ status = ParseFree();
+ break;
+ default:
+ return; // TODO(brettw) signal error.
+ }
+ if (status != READ_OK)
+ return; // TODO(brettw) signal error.
+ }
+}
+
+void MemlogStreamParser::OnStreamComplete() {
+ receiver_->OnComplete();
+}
+
+bool MemlogStreamParser::AreBytesAvailable(size_t count) const {
+ size_t used = 0;
+ size_t current_block_offset = block_zero_offset_;
+ for (auto it = blocks_.begin(); it != blocks_.end() && used < count; ++it) {
+ used += it->size - current_block_offset;
+ current_block_offset = 0;
+ }
+ return used >= count;
+}
+
+bool MemlogStreamParser::PeekBytes(size_t count, void* dest) const {
+ char* dest_char = static_cast<char*>(dest);
+ size_t used = 0;
+
+ size_t current_block_offset = block_zero_offset_;
+ for (const auto& block : blocks_) {
+ size_t in_current_block = block.size - current_block_offset;
+ size_t to_copy = std::min(count - used, in_current_block);
+
+ memcpy(&dest_char[used], &block.data[current_block_offset], to_copy);
+ used += to_copy;
+
+ // All subsequent blocks start reading at offset 0.
+ current_block_offset = 0;
+ }
+ return used == count;
+}
+
+bool MemlogStreamParser::ReadBytes(size_t count, void* dest) {
+ if (!PeekBytes(count, dest))
+ return false;
+ ConsumeBytes(count);
+ return true;
+}
+
+void MemlogStreamParser::ConsumeBytes(size_t count) {
+ DCHECK(AreBytesAvailable(count));
+ while (count > 0) {
+ size_t bytes_left_in_block = blocks_.front().size - block_zero_offset_;
+ if (bytes_left_in_block > count) {
+ // Still data left in this block;
+ block_zero_offset_ += count;
+ return;
+ }
+
+ // Current block is consumed.
+ blocks_.pop_front();
+ block_zero_offset_ = 0;
+ count -= bytes_left_in_block;
+ }
+}
+
+MemlogStreamParser::ReadStatus MemlogStreamParser::ParseHeader() {
+ StreamHeader header;
+ if (!ReadBytes(sizeof(StreamHeader), &header))
+ return READ_NO_DATA;
+
+ if (header.signature != kStreamSignature)
+ return READ_ERROR;
+
+ receiver_->OnHeader(header);
+ return READ_OK;
+}
+
+MemlogStreamParser::ReadStatus MemlogStreamParser::ParseAlloc() {
+ // Read the packet. Can't commit the read until the stack is read and
+ // that has to be done below.
+ AllocPacket alloc_packet;
+ if (!PeekBytes(sizeof(AllocPacket), &alloc_packet))
+ return READ_NO_DATA;
+
+ std::vector<Address> stack;
+ stack.resize(alloc_packet.stack_len);
+ size_t stack_byte_size = sizeof(Address) * alloc_packet.stack_len;
+
+ if (!AreBytesAvailable(sizeof(AllocPacket) + stack_byte_size))
+ return READ_NO_DATA;
+
+ // Everything will fit, mark packet consumed, read stack.
+ ConsumeBytes(sizeof(AllocPacket));
+ if (!stack.empty())
+ ReadBytes(stack_byte_size, stack.data());
+
+ receiver_->OnAlloc(alloc_packet, std::move(stack));
+ return READ_OK;
+}
+
+MemlogStreamParser::ReadStatus MemlogStreamParser::ParseFree() {
+ FreePacket free_packet;
+ if (!ReadBytes(sizeof(FreePacket), &free_packet))
+ return READ_NO_DATA;
+
+ receiver_->OnFree(free_packet);
+ return READ_OK;
+}
+
+} // namespace profiling
« no previous file with comments | « chrome/profiling/memlog_stream_parser.h ('k') | chrome/profiling/profiling_globals.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698