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

Side by Side Diff: webrtc/call/rtc_event_log_helper_thread.cc

Issue 1687703002: Refactored CL for moving the output to a separate thread. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Remove printf's that cause problems on Android Created 4 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
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2016 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 "webrtc/call/rtc_event_log_helper_thread.h"
12
13 #include <algorithm>
14
15 #include "webrtc/base/checks.h"
16 #include "webrtc/system_wrappers/include/logging.h"
17
18 #ifdef ENABLE_RTC_EVENT_LOG
19
20 namespace webrtc {
21
22 namespace {
23 const int kEventsInHistory = 10000;
24
25 bool IsConfigEvent(const rtclog::Event& event) {
26 rtclog::Event_EventType event_type = event.type();
27 return event_type == rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT ||
28 event_type == rtclog::Event::VIDEO_SENDER_CONFIG_EVENT ||
29 event_type == rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT ||
30 event_type == rtclog::Event::AUDIO_SENDER_CONFIG_EVENT;
31 }
32 } // namespace
33
34 // RtcEventLogImpl member functions.
35 RtcEventLogHelperThread::RtcEventLogHelperThread(
36 SwapQueue<ControlMessage>* message_queue,
37 SwapQueue<std::unique_ptr<rtclog::Event>>* event_queue,
38 rtc::Event* wake_up,
39 rtc::Event* stopped,
40 const Clock* const clock)
41 : message_queue_(message_queue),
42 event_queue_(event_queue),
43 history_(kEventsInHistory),
44 config_history_(),
45 file_(FileWrapper::Create()),
46 thread_(&ThreadOutputFunction, this, "RtcEventLog thread"),
47 max_size_bytes_(std::numeric_limits<int64_t>::max()),
48 written_bytes_(0),
49 start_time_(0),
50 stop_time_(std::numeric_limits<int64_t>::max()),
51 has_recent_event_(false),
52 most_recent_event_(),
53 output_string_(),
54 wake_up_(wake_up),
55 stopped_(stopped),
56 clock_(clock) {
57 RTC_DCHECK(message_queue_);
58 RTC_DCHECK(event_queue_);
59 RTC_DCHECK(wake_up_);
60 RTC_DCHECK(stopped_);
61 RTC_DCHECK(clock_);
62 thread_.Start();
63 }
64
65 RtcEventLogHelperThread::~RtcEventLogHelperThread() {
66 ControlMessage message;
67 message.message_type = ControlMessage::TERMINATE_THREAD;
68 message.stop_time = clock_->TimeInMicroseconds();
69 while (!message_queue_->Insert(&message)) {
70 // We can't destroy the event log until we have stopped the thread,
71 // so clear the message queue and try again. Note that if we clear
72 // any STOP_FILE events, then the threads calling StopLogging would likely
73 // wait indefinitely. However, there should not be any such calls as we
74 // are executing the destructor.
75 LOG(LS_WARNING) << "Clearing message queue to terminate thread.";
76 message_queue_->Clear();
77 }
78 wake_up_->Set(); // Wake up the output thread.
79 thread_.Stop(); // Wait for the thread to terminate.
80 }
81
82 bool RtcEventLogHelperThread::AppendEventToString(rtclog::Event* event) {
83 rtclog::EventStream event_stream;
84 event_stream.add_stream();
85 event_stream.mutable_stream(0)->Swap(event);
86 // We create a new event stream per event but because of the way protobufs
87 // are encoded, events can be merged by concatenating them. Therefore,
88 // it will look like a single stream when we read it back from file.
89 bool stop = true;
90 if (written_bytes_ + static_cast<int64_t>(output_string_.size()) +
91 event_stream.ByteSize() <=
92 max_size_bytes_) {
93 event_stream.AppendToString(&output_string_);
94 stop = false;
95 }
96 // Swap the event back so that we don't mix event types in the queues.
97 event_stream.mutable_stream(0)->Swap(event);
98 return stop;
99 }
100
101 // Traverses the SwapQueues in timestamp order and copies all events earlier
102 // than |time_limit| either to the history or to a string that will be
103 // written to disc.
104 bool RtcEventLogHelperThread::ProcessInOrder(bool memory, int64_t time_limit) {
105 if (!has_recent_event_) {
106 has_recent_event_ = event_queue_->Remove(&most_recent_event_);
107 }
108
109 while (has_recent_event_ &&
110 most_recent_event_->timestamp_us() <= time_limit) {
111 if (memory) {
112 if (IsConfigEvent(*most_recent_event_)) {
113 config_history_.push_back(std::move(most_recent_event_));
114 } else {
115 history_.push_back(std::move(most_recent_event_));
116 }
117 } else {
118 bool stop = AppendEventToString(most_recent_event_.get());
119 if (stop) {
120 return stop;
121 }
122 if (IsConfigEvent(*most_recent_event_)) {
123 config_history_.push_back(std::move(most_recent_event_));
124 }
125 }
126 has_recent_event_ = event_queue_->Remove(&most_recent_event_);
127 }
128 // We want to stop logging if the remaining events are more recent than the
129 // time limit, or in other words if we have terminated the loop despite
130 // having more event in the queue.
stefan-webrtc 2016/04/19 08:23:04 more events
terelius 2016/04/19 09:21:56 Done.
131 return has_recent_event_ && most_recent_event_->timestamp_us() > stop_time_;
132 }
133
134 void RtcEventLogHelperThread::LogToMemory() {
135 RTC_DCHECK(!file_->Open());
136
137 // Process each event in order and append it to the appropriate history_.
138 int64_t current_time = clock_->TimeInMicroseconds();
139 ProcessInOrder(true, current_time);
140 }
141
142 void RtcEventLogHelperThread::StartLogFile() {
143 RTC_DCHECK(file_->Open());
144 bool stop = false;
145 output_string_.clear();
146
147 // Create and serialize the LOG_START event.
148 rtclog::Event start_event;
149 start_event.set_timestamp_us(start_time_);
150 start_event.set_type(rtclog::Event::LOG_START);
151 AppendEventToString(&start_event);
152
153 // Serialize the config information for all old streams.
154 for (auto& event : config_history_) {
155 AppendEventToString(event.get());
156 }
157
158 // Serialize the events in the event queue.
159 while (!history_.empty() && !stop) {
160 stop = AppendEventToString(history_.front().get());
161 if (!stop) {
162 history_.pop_front();
163 }
164 }
165
166 // Write to file.
167 file_->Write(output_string_.data(), output_string_.size());
168 written_bytes_ += output_string_.size();
169
170 // Free the allocated memory since we probably won't need this amount of
171 // space again.
172 output_string_.clear();
173 output_string_.shrink_to_fit();
174
175 if (stop) {
176 RTC_DCHECK(file_->Open());
177 StopLogFile();
178 }
179 }
180
181 void RtcEventLogHelperThread::LogToFile() {
182 RTC_DCHECK(file_->Open());
183 output_string_.clear();
184
185 // Process each event in order and append it to the output_string_.
186 int64_t current_time = clock_->TimeInMicroseconds();
187 bool stop = ProcessInOrder(false, std::min(current_time, stop_time_));
188
189 // Write string to file.
190 file_->Write(output_string_.data(), output_string_.size());
191 written_bytes_ += output_string_.size();
192
193 if (!file_->Open()) {
194 LOG(LS_WARNING) << "WebRTC event log file closed by FileWrapper.";
195 }
196
197 if (stop) {
198 RTC_DCHECK(file_->Open());
199 StopLogFile();
200 }
201 }
202
203 void RtcEventLogHelperThread::StopLogFile() {
204 RTC_DCHECK(file_->Open());
205 output_string_.clear();
206
207 rtclog::Event end_event;
208 end_event.set_timestamp_us(stop_time_);
209 end_event.set_type(rtclog::Event::LOG_END);
210 AppendEventToString(&end_event);
211
212 if (written_bytes_ + static_cast<int64_t>(output_string_.size()) <=
213 max_size_bytes_) {
214 file_->Write(output_string_.data(), output_string_.size());
215 written_bytes_ += output_string_.size();
216 }
217
218 max_size_bytes_ = std::numeric_limits<int64_t>::max();
219 written_bytes_ = 0;
220 start_time_ = 0;
221 stop_time_ = std::numeric_limits<int64_t>::max();
222 output_string_.clear();
223 file_->CloseFile();
224 RTC_DCHECK(!file_->Open());
225 }
226
227 void RtcEventLogHelperThread::WriteLog() {
228 ControlMessage message;
229
230 while (true) {
231 // Process control messages.
232 while (message_queue_->Remove(&message)) {
233 switch (message.message_type) {
234 case ControlMessage::START_FILE:
235 if (!file_->Open()) {
236 max_size_bytes_ = message.max_size_bytes;
237 start_time_ = message.start_time;
238 stop_time_ = message.stop_time;
239 file_.swap(message.file);
240 StartLogFile();
241 } else {
242 // Already started. Ignore message and close file handle.
243 message.file->CloseFile();
244 }
245 break;
246 case ControlMessage::STOP_FILE:
247 if (file_->Open()) {
248 stop_time_ = message.stop_time;
249 LogToFile(); // Log remaining events from message queues.
250 }
251 // LogToFile might stop on it's own so we need to recheck the state.
252 if (file_->Open()) {
253 StopLogFile();
254 }
255 stopped_->Set();
256 break;
257 case ControlMessage::TERMINATE_THREAD:
258 if (file_->Open()) {
259 StopLogFile();
260 }
261 return;
262 }
263 }
264
265 // Write events to file or memory
266 if (file_->Open()) {
267 LogToFile();
268 } else {
269 LogToMemory();
270 }
271
272 // Accumulate a new batch of events instead of processing them one at a
273 // time.
274 wake_up_->Wait(50);
275 }
276 }
277
278 bool RtcEventLogHelperThread::ThreadOutputFunction(void* obj) {
279 RtcEventLogHelperThread* helper = static_cast<RtcEventLogHelperThread*>(obj);
280 helper->WriteLog();
281 return false;
282 }
283
284 } // namespace webrtc
285
286 #endif // ENABLE_RTC_EVENT_LOG
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698