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

Side by Side Diff: webrtc/logging/rtc_event_log/rtc_event_log2stats.cc

Issue 2717553004: Create tool to print statistics about the file size usage of an RTC event log. (Closed)
Patch Set: Portable format specifier in printf. Created 3 years, 8 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
« no previous file with comments | « webrtc/logging/BUILD.gn ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <inttypes.h>
12 #include <stdio.h>
13
14 #include <fstream>
15 #include <iostream>
16 #include <map>
17 #include <string>
18 #include <tuple>
19 #include <utility>
20 #include <vector>
21
22 #include "gflags/gflags.h"
23 #include "webrtc/base/checks.h"
24 #include "webrtc/base/ignore_wundef.h"
25 #include "webrtc/base/logging.h"
26 #include "webrtc/logging/rtc_event_log/rtc_event_log.h"
27
28 // Files generated at build-time by the protobuf compiler.
29 RTC_PUSH_IGNORING_WUNDEF()
30 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD
31 #include "external/webrtc/webrtc/logging/rtc_event_log/rtc_event_log.pb.h"
32 #else
33 #include "webrtc/logging/rtc_event_log/rtc_event_log.pb.h"
34 #endif
35 RTC_POP_IGNORING_WUNDEF()
36
37 namespace {
38
39 struct Stats {
40 int count = 0;
41 size_t total_size = 0;
42 };
43
44 // We are duplicating some parts of the parser here because we want to get
45 // access to raw protobuf events.
46 std::pair<uint64_t, bool> ParseVarInt(std::istream& stream) {
47 uint64_t varint = 0;
48 for (size_t bytes_read = 0; bytes_read < 10; ++bytes_read) {
49 // The most significant bit of each byte is 0 if it is the last byte in
50 // the varint and 1 otherwise. Thus, we take the 7 least significant bits
51 // of each byte and shift them 7 bits for each byte read previously to get
52 // the (unsigned) integer.
53 int byte = stream.get();
54 if (stream.eof()) {
55 return std::make_pair(varint, false);
56 }
57 RTC_DCHECK(0 <= byte && byte <= 255);
58 varint |= static_cast<uint64_t>(byte & 0x7F) << (7 * bytes_read);
59 if ((byte & 0x80) == 0) {
60 return std::make_pair(varint, true);
61 }
62 }
63 return std::make_pair(varint, false);
64 }
65
66 bool ParseEvents(const std::string& filename,
67 std::vector<webrtc::rtclog::Event>* events) {
68 std::ifstream stream(filename, std::ios_base::in | std::ios_base::binary);
69 if (!stream.good() || !stream.is_open()) {
70 LOG(LS_WARNING) << "Could not open file for reading.";
71 return false;
72 }
73
74 const size_t kMaxEventSize = (1u << 16) - 1;
75 std::vector<char> tmp_buffer(kMaxEventSize);
76 uint64_t tag;
77 uint64_t message_length;
78 bool success;
79
80 RTC_DCHECK(stream.good());
81
82 while (1) {
83 // Check whether we have reached end of file.
84 stream.peek();
85 if (stream.eof()) {
86 return true;
87 }
88
89 // Read the next message tag. The tag number is defined as
90 // (fieldnumber << 3) | wire_type. In our case, the field number is
91 // supposed to be 1 and the wire type for an length-delimited field is 2.
92 const uint64_t kExpectedTag = (1 << 3) | 2;
93 std::tie(tag, success) = ParseVarInt(stream);
94 if (!success) {
95 LOG(LS_WARNING) << "Missing field tag from beginning of protobuf event.";
96 return false;
97 } else if (tag != kExpectedTag) {
98 LOG(LS_WARNING) << "Unexpected field tag at beginning of protobuf event.";
99 return false;
100 }
101
102 // Read the length field.
103 std::tie(message_length, success) = ParseVarInt(stream);
104 if (!success) {
105 LOG(LS_WARNING) << "Missing message length after protobuf field tag.";
106 return false;
107 } else if (message_length > kMaxEventSize) {
108 LOG(LS_WARNING) << "Protobuf message length is too large.";
109 return false;
110 }
111
112 // Read the next protobuf event to a temporary char buffer.
113 stream.read(tmp_buffer.data(), message_length);
114 if (stream.gcount() != static_cast<int>(message_length)) {
115 LOG(LS_WARNING) << "Failed to read protobuf message from file.";
116 return false;
117 }
118
119 // Parse the protobuf event from the buffer.
120 webrtc::rtclog::Event event;
121 if (!event.ParseFromArray(tmp_buffer.data(), message_length)) {
122 LOG(LS_WARNING) << "Failed to parse protobuf message.";
123 return false;
124 }
125 events->push_back(event);
126 }
127 }
128
129 // TODO(terelius): Should this be placed in some utility file instead?
130 std::string EventTypeToString(webrtc::rtclog::Event::EventType event_type) {
131 switch (event_type) {
132 case webrtc::rtclog::Event::UNKNOWN_EVENT:
133 return "UNKNOWN_EVENT";
134 case webrtc::rtclog::Event::LOG_START:
135 return "LOG_START";
136 case webrtc::rtclog::Event::LOG_END:
137 return "LOG_END";
138 case webrtc::rtclog::Event::RTP_EVENT:
139 return "RTP_EVENT";
140 case webrtc::rtclog::Event::RTCP_EVENT:
141 return "RTCP_EVENT";
142 case webrtc::rtclog::Event::AUDIO_PLAYOUT_EVENT:
143 return "AUDIO_PLAYOUT_EVENT";
144 case webrtc::rtclog::Event::LOSS_BASED_BWE_UPDATE:
145 return "LOSS_BASED_BWE_UPDATE";
146 case webrtc::rtclog::Event::DELAY_BASED_BWE_UPDATE:
147 return "DELAY_BASED_BWE_UPDATE";
148 case webrtc::rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT:
149 return "VIDEO_RECV_CONFIG";
150 case webrtc::rtclog::Event::VIDEO_SENDER_CONFIG_EVENT:
151 return "VIDEO_SEND_CONFIG";
152 case webrtc::rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT:
153 return "AUDIO_RECV_CONFIG";
154 case webrtc::rtclog::Event::AUDIO_SENDER_CONFIG_EVENT:
155 return "AUDIO_SEND_CONFIG";
156 case webrtc::rtclog::Event::AUDIO_NETWORK_ADAPTATION_EVENT:
157 return "AUDIO_NETWORK_ADAPTATION";
158 case webrtc::rtclog::Event::BWE_PROBE_CLUSTER_CREATED_EVENT:
159 return "BWE_PROBE_CREATED";
160 case webrtc::rtclog::Event::BWE_PROBE_RESULT_EVENT:
161 return "BWE_PROBE_RESULT";
162 }
163 RTC_NOTREACHED();
164 return "UNKNOWN_EVENT";
165 }
166
167 } // namespace
168
169 // This utility will print basic information about each packet to stdout.
170 // Note that parser will assert if the protobuf event is missing some required
171 // fields and we attempt to access them. We don't handle this at the moment.
172 int main(int argc, char* argv[]) {
173 std::string program_name = argv[0];
174 std::string usage =
175 "Tool for file usage statistics from an RtcEventLog.\n"
176 "Run " +
177 program_name +
178 " --helpshort for usage.\n"
179 "Example usage:\n" +
180 program_name + " input.rel\n";
181 google::SetUsageMessage(usage);
182 google::ParseCommandLineFlags(&argc, &argv, true);
183
184 if (argc != 2) {
185 std::cout << google::ProgramUsage();
186 return 0;
187 }
188 std::string file_name = argv[1];
189
190 std::vector<webrtc::rtclog::Event> events;
191 if (!ParseEvents(file_name, &events)) {
192 LOG(LS_ERROR) << "Failed to parse event log.";
193 return -1;
194 }
195
196 // Get file size
197 FILE* file = fopen(file_name.c_str(), "rb");
198 fseek(file, 0L, SEEK_END);
199 int64_t file_size = ftell(file);
200 fclose(file);
201
202 // We are deliberately using low level protobuf functions to get the stats
203 // since the convenience functions in the parser would CHECK that the events
204 // are well formed.
205 std::map<webrtc::rtclog::Event::EventType, Stats> stats;
206 int malformed_events = 0;
207 size_t malformed_event_size = 0;
208 size_t accumulated_event_size = 0;
209 for (const webrtc::rtclog::Event& event : events) {
210 size_t serialized_size = event.ByteSize();
211 // When the event is written on the disk, it is part of an EventStream
212 // object. The event stream will prepend a 1 byte field number/wire type,
213 // and a varint encoding (base 128) of the event length.
214 serialized_size =
215 1 + (1 + (serialized_size > 127) + (serialized_size > 16383)) +
216 serialized_size;
217
218 if (event.has_type() && event.has_timestamp_us()) {
219 stats[event.type()].count++;
220 stats[event.type()].total_size += serialized_size;
221 } else {
222 // The event is missing the type or the timestamp field.
223 malformed_events++;
224 malformed_event_size += serialized_size;
225 }
226 accumulated_event_size += serialized_size;
227 }
228
229 printf("Type \tCount\tTotal size\tAverage size\tPercent\n");
230 printf(
231 "-----------------------------------------------------------------------"
232 "\n");
233 for (const auto it : stats) {
234 printf("%-22s\t%5d\t%10zu\t%12.2lf\t%7.2lf\n",
235 EventTypeToString(it.first).c_str(), it.second.count,
236 it.second.total_size,
237 static_cast<double>(it.second.total_size) / it.second.count,
238 static_cast<double>(it.second.total_size) / file_size * 100);
239 }
240 if (malformed_events != 0) {
241 printf("%-22s\t%5d\t%10zu\t%12.2lf\t%7.2lf\n", "MALFORMED",
242 malformed_events, malformed_event_size,
243 static_cast<double>(malformed_event_size) / malformed_events,
244 static_cast<double>(malformed_event_size) / file_size * 100);
245 }
246 if (file_size - accumulated_event_size != 0) {
247 printf("WARNING: %" PRId64 " bytes not accounted for\n",
248 file_size - accumulated_event_size);
249 }
250
251 return 0;
252 }
OLDNEW
« no previous file with comments | « webrtc/logging/BUILD.gn ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698