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

Side by Side Diff: chrome/profiling/memlog_stream_parser.cc

Issue 2943733002: Add out-of-process memory logging stream parsing. (Closed)
Patch Set: Remove version 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/profiling/memlog_stream_parser.h"
6
7 #include <algorithm>
8
9 #include "base/containers/stack_container.h"
10 #include "base/strings/stringprintf.h"
11 #include "chrome/common/profiling/memlog_stream.h"
12 #include "chrome/profiling/address.h"
13 #include "chrome/profiling/profiling_globals.h"
14 #include "chrome/profiling/stack.h"
15
16 namespace profiling {
17
18 using AddressVector = base::StackVector<Address, 128>;
awong 2017/06/19 21:51:27 Random C++11 question... does this need to be in a
brettw 2017/06/19 23:29:45 I think it will be OK, but the anon namespace seem
19
20 struct MemlogStreamParser::Block {
21 Block(std::unique_ptr<char[]> d, size_t s) : data(std::move(d)), size(s) {}
22
23 std::unique_ptr<char[]> data;
24 size_t size;
25 };
26
27 MemlogStreamParser::MemlogStreamParser(MemlogReceiver* receiver)
28 : receiver_(receiver) {}
29
30 MemlogStreamParser::~MemlogStreamParser() {}
31
32 void MemlogStreamParser::OnStreamData(std::unique_ptr<char[]> data, size_t sz) {
Boris Vidolov 2017/06/17 00:53:07 Should this be std::unique_ptr<char[]>&& data ?
brettw 2017/06/17 02:41:51 I think these are usually passed by value also (gi
awong 2017/06/19 21:51:27 Definitely should not be &&. If the API is denoti
33 blocks_.emplace_back(std::move(data), sz);
34
35 if (!received_header_) {
36 received_header_ = true;
37 ReadStatus status = ParseHeader();
38 if (status != READ_OK)
39 return; // TODO(brettw) signal error.
40 }
41
42 while (true) {
43 uint32_t msg_type;
44 if (!PeekBytes(sizeof(msg_type), &msg_type))
45 return;
46
47 ReadStatus status;
48 switch (msg_type) {
49 case kAllocPacketType:
50 status = ParseAlloc();
51 break;
52 case kFreePacketType:
53 status = ParseFree();
54 break;
55 default:
56 return; // TODO(brettw) signal error.
57 }
58 if (status != READ_OK)
59 return; // TODO(brettw) signal error.
60 }
61 }
62
63 void MemlogStreamParser::OnStreamComplete() {
64 receiver_->OnComplete();
65 }
66
67 bool MemlogStreamParser::AreBytesAvailable(size_t count) const {
68 size_t used = 0;
69
70 size_t current_block = 0;
71 size_t current_block_offset = block_zero_offset_;
72 while (current_block < blocks_.size() && used < count) {
73 used += blocks_[current_block].size - current_block_offset;
74 current_block++;
75 current_block_offset = 0;
76 }
77 return used >= count;
78 }
79
80 bool MemlogStreamParser::PeekBytes(size_t count, void* dest) const {
81 if (!AreBytesAvailable(count))
82 return false;
83
84 char* dest_char = static_cast<char*>(dest);
85 size_t used = 0;
86
87 size_t current_block = 0;
88 size_t current_block_offset = block_zero_offset_;
89 while (current_block < blocks_.size()) {
90 size_t in_current_block =
91 blocks_[current_block].size - current_block_offset;
92
93 size_t to_copy = std::min(count - used, in_current_block);
94 memcpy(&dest_char[used], &blocks_[current_block].data[current_block_offset],
awong 2017/06/19 21:51:27 std::copy? https://stackoverflow.com/questions/47
brettw 2017/06/19 23:29:46 I didn't want to do an element-by-element copy her
95 to_copy);
96
97 used += to_copy;
98
99 current_block++;
100 current_block_offset = 0;
101 }
102 return used == count;
awong 2017/06/19 21:51:27 Can this ever be false if we didn't return in line
brettw 2017/06/19 23:29:45 It can be now since I removed the AreBytesAvailabl
103 }
104
105 bool MemlogStreamParser::ReadBytes(size_t count, void* dest) {
106 if (!PeekBytes(count, dest))
Boris Vidolov 2017/06/17 03:13:14 This doesn't sound to be very efficient: ReadBytes
brettw 2017/06/19 23:29:45 I don't think returning an iterator would be very
107 return false;
108 ConsumeBytes(count);
109 return true;
110 }
111
112 void MemlogStreamParser::ConsumeBytes(size_t count) {
113 DCHECK(AreBytesAvailable(count));
114 while (count > 0) {
115 size_t bytes_left_in_block = blocks_[0].size - block_zero_offset_;
116 if (bytes_left_in_block > count) {
117 // Still data left in this block;
118 block_zero_offset_ += count;
119 return;
120 }
121
122 // Current block is consumed.
123 blocks_.erase(blocks_.begin());
Boris Vidolov 2017/06/17 03:13:15 Can we erase a range instead of single block? Eras
brettw 2017/06/19 23:29:46 I would hope the common case is 0-2 blocks (they'r
124 block_zero_offset_ = 0;
125 count -= bytes_left_in_block;
126 }
127 }
128
129 MemlogStreamParser::ReadStatus MemlogStreamParser::ParseHeader() {
130 StreamHeader header;
131 if (!ReadBytes(sizeof(StreamHeader), &header))
132 return READ_NO_DATA;
133
134 if (header.signature != kStreamSignature)
135 return READ_ERROR;
136
137 receiver_->OnHeader(header);
138 return READ_OK;
139 }
140
141 MemlogStreamParser::ReadStatus MemlogStreamParser::ParseAlloc() {
142 // Read the packet. Can't commit the read until the stack is read and
143 // that has to be done below.
144 AllocPacket alloc_packet;
145 if (!PeekBytes(sizeof(AllocPacket), &alloc_packet))
146 return READ_NO_DATA;
147
148 std::vector<Address> stack_addrs;
149 stack_addrs.resize(alloc_packet.stack_len);
150 size_t stack_byte_size = sizeof(Address) * alloc_packet.stack_len;
151
152 if (!AreBytesAvailable(sizeof(AllocPacket) + stack_byte_size))
153 return READ_NO_DATA;
154
155 // Everything will fit, mark packet consumed, read stack.
156 ConsumeBytes(sizeof(AllocPacket));
157 if (!stack_addrs.empty())
158 ReadBytes(stack_byte_size, stack_addrs.data());
159
160 Stack stack(std::move(stack_addrs));
Boris Vidolov 2017/06/17 03:13:14 Do we need to go through an intermediary 'Stack' v
brettw 2017/06/19 23:29:46 The stack object exists to store the hash so we do
161 receiver_->OnAlloc(alloc_packet, std::move(stack));
162 return READ_OK;
163 }
164
165 MemlogStreamParser::ReadStatus MemlogStreamParser::ParseFree() {
166 FreePacket free_packet;
167 if (!ReadBytes(sizeof(FreePacket), &free_packet))
168 return READ_NO_DATA;
169
170 receiver_->OnFree(free_packet);
171 return READ_OK;
172 }
173
174 } // namespace profiling
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698