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

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

Issue 2035483003: Hibernate the thread if there are no events in the queue. Wake it up when an event is added to the … (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Rename SignalStopFile() -> WaitForFileFinished() Created 4 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
1 /* 1 /*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
(...skipping 17 matching lines...) Expand all
28 event_type == rtclog::Event::VIDEO_SENDER_CONFIG_EVENT || 28 event_type == rtclog::Event::VIDEO_SENDER_CONFIG_EVENT ||
29 event_type == rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT || 29 event_type == rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT ||
30 event_type == rtclog::Event::AUDIO_SENDER_CONFIG_EVENT; 30 event_type == rtclog::Event::AUDIO_SENDER_CONFIG_EVENT;
31 } 31 }
32 } // namespace 32 } // namespace
33 33
34 // RtcEventLogImpl member functions. 34 // RtcEventLogImpl member functions.
35 RtcEventLogHelperThread::RtcEventLogHelperThread( 35 RtcEventLogHelperThread::RtcEventLogHelperThread(
36 SwapQueue<ControlMessage>* message_queue, 36 SwapQueue<ControlMessage>* message_queue,
37 SwapQueue<std::unique_ptr<rtclog::Event>>* event_queue, 37 SwapQueue<std::unique_ptr<rtclog::Event>>* event_queue,
38 rtc::Event* wake_up,
39 rtc::Event* stopped,
40 const Clock* const clock) 38 const Clock* const clock)
41 : message_queue_(message_queue), 39 : message_queue_(message_queue),
42 event_queue_(event_queue), 40 event_queue_(event_queue),
43 history_(kEventsInHistory), 41 history_(kEventsInHistory),
44 config_history_(), 42 config_history_(),
45 file_(FileWrapper::Create()), 43 file_(FileWrapper::Create()),
46 thread_(&ThreadOutputFunction, this, "RtcEventLog thread"), 44 thread_(&ThreadOutputFunction, this, "RtcEventLog thread"),
47 max_size_bytes_(std::numeric_limits<int64_t>::max()), 45 max_size_bytes_(std::numeric_limits<int64_t>::max()),
48 written_bytes_(0), 46 written_bytes_(0),
49 start_time_(0), 47 start_time_(0),
50 stop_time_(std::numeric_limits<int64_t>::max()), 48 stop_time_(std::numeric_limits<int64_t>::max()),
51 has_recent_event_(false), 49 has_recent_event_(false),
52 most_recent_event_(), 50 most_recent_event_(),
53 output_string_(), 51 output_string_(),
54 wake_up_(wake_up), 52 wake_periodically_(false, false),
55 stopped_(stopped), 53 wake_from_hibernation_(false, false),
54 file_finished_(false, false),
56 clock_(clock) { 55 clock_(clock) {
57 RTC_DCHECK(message_queue_); 56 RTC_DCHECK(message_queue_);
58 RTC_DCHECK(event_queue_); 57 RTC_DCHECK(event_queue_);
59 RTC_DCHECK(wake_up_);
60 RTC_DCHECK(stopped_);
61 RTC_DCHECK(clock_); 58 RTC_DCHECK(clock_);
62 thread_.Start(); 59 thread_.Start();
63 } 60 }
64 61
65 RtcEventLogHelperThread::~RtcEventLogHelperThread() { 62 RtcEventLogHelperThread::~RtcEventLogHelperThread() {
66 ControlMessage message; 63 ControlMessage message;
67 message.message_type = ControlMessage::TERMINATE_THREAD; 64 message.message_type = ControlMessage::TERMINATE_THREAD;
68 message.stop_time = clock_->TimeInMicroseconds(); 65 message.stop_time = clock_->TimeInMicroseconds();
69 while (!message_queue_->Insert(&message)) { 66 while (!message_queue_->Insert(&message)) {
70 // We can't destroy the event log until we have stopped the thread, 67 // 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 68 // 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 69 // any STOP_FILE events, then the threads calling StopLogging would likely
73 // wait indefinitely. However, there should not be any such calls as we 70 // wait indefinitely. However, there should not be any such calls as we
74 // are executing the destructor. 71 // are executing the destructor.
75 LOG(LS_WARNING) << "Clearing message queue to terminate thread."; 72 LOG(LS_WARNING) << "Clearing message queue to terminate thread.";
76 message_queue_->Clear(); 73 message_queue_->Clear();
77 } 74 }
78 wake_up_->Set(); // Wake up the output thread. 75 wake_from_hibernation_.Set();
76 wake_periodically_.Set(); // Wake up the output thread.
79 thread_.Stop(); // Wait for the thread to terminate. 77 thread_.Stop(); // Wait for the thread to terminate.
80 } 78 }
81 79
80 void RtcEventLogHelperThread::WaitForFileFinished() {
81 wake_from_hibernation_.Set();
82 wake_periodically_.Set();
83 file_finished_.Wait(rtc::Event::kForever);
84 }
85
86 void RtcEventLogHelperThread::SignalNewEvent() {
87 wake_from_hibernation_.Set();
88 }
89
82 bool RtcEventLogHelperThread::AppendEventToString(rtclog::Event* event) { 90 bool RtcEventLogHelperThread::AppendEventToString(rtclog::Event* event) {
83 rtclog::EventStream event_stream; 91 rtclog::EventStream event_stream;
84 event_stream.add_stream(); 92 event_stream.add_stream();
85 event_stream.mutable_stream(0)->Swap(event); 93 event_stream.mutable_stream(0)->Swap(event);
86 // We create a new event stream per event but because of the way protobufs 94 // 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, 95 // 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. 96 // it will look like a single stream when we read it back from file.
89 bool stop = true; 97 bool stop = true;
90 if (written_bytes_ + static_cast<int64_t>(output_string_.size()) + 98 if (written_bytes_ + static_cast<int64_t>(output_string_.size()) +
91 event_stream.ByteSize() <= 99 event_stream.ByteSize() <=
92 max_size_bytes_) { 100 max_size_bytes_) {
93 event_stream.AppendToString(&output_string_); 101 event_stream.AppendToString(&output_string_);
94 stop = false; 102 stop = false;
95 } 103 }
96 // Swap the event back so that we don't mix event types in the queues. 104 // Swap the event back so that we don't mix event types in the queues.
97 event_stream.mutable_stream(0)->Swap(event); 105 event_stream.mutable_stream(0)->Swap(event);
98 return stop; 106 return stop;
99 } 107 }
100 108
101 void RtcEventLogHelperThread::LogToMemory() { 109 bool RtcEventLogHelperThread::LogToMemory() {
102 RTC_DCHECK(!file_->Open()); 110 RTC_DCHECK(!file_->Open());
111 bool message_received = false;
103 112
104 // Process each event earlier than the current time and append it to the 113 // Process each event earlier than the current time and append it to the
105 // appropriate history_. 114 // appropriate history_.
106 int64_t current_time = clock_->TimeInMicroseconds(); 115 int64_t current_time = clock_->TimeInMicroseconds();
107 if (!has_recent_event_) { 116 if (!has_recent_event_) {
108 has_recent_event_ = event_queue_->Remove(&most_recent_event_); 117 has_recent_event_ = event_queue_->Remove(&most_recent_event_);
109 } 118 }
110 while (has_recent_event_ && 119 while (has_recent_event_ &&
111 most_recent_event_->timestamp_us() <= current_time) { 120 most_recent_event_->timestamp_us() <= current_time) {
112 if (IsConfigEvent(*most_recent_event_)) { 121 if (IsConfigEvent(*most_recent_event_)) {
113 config_history_.push_back(std::move(most_recent_event_)); 122 config_history_.push_back(std::move(most_recent_event_));
114 } else { 123 } else {
115 history_.push_back(std::move(most_recent_event_)); 124 history_.push_back(std::move(most_recent_event_));
116 } 125 }
117 has_recent_event_ = event_queue_->Remove(&most_recent_event_); 126 has_recent_event_ = event_queue_->Remove(&most_recent_event_);
127 message_received = true;
118 } 128 }
129 return message_received;
119 } 130 }
120 131
121 void RtcEventLogHelperThread::StartLogFile() { 132 void RtcEventLogHelperThread::StartLogFile() {
122 RTC_DCHECK(file_->Open()); 133 RTC_DCHECK(file_->Open());
123 bool stop = false; 134 bool stop = false;
124 output_string_.clear(); 135 output_string_.clear();
125 136
126 // Create and serialize the LOG_START event. 137 // Create and serialize the LOG_START event.
127 rtclog::Event start_event; 138 rtclog::Event start_event;
128 start_event.set_timestamp_us(start_time_); 139 start_event.set_timestamp_us(start_time_);
(...skipping 26 matching lines...) Expand all
155 // space again. 166 // space again.
156 output_string_.clear(); 167 output_string_.clear();
157 output_string_.shrink_to_fit(); 168 output_string_.shrink_to_fit();
158 169
159 if (stop) { 170 if (stop) {
160 RTC_DCHECK(file_->Open()); 171 RTC_DCHECK(file_->Open());
161 StopLogFile(); 172 StopLogFile();
162 } 173 }
163 } 174 }
164 175
165 void RtcEventLogHelperThread::LogToFile() { 176 bool RtcEventLogHelperThread::LogToFile() {
166 RTC_DCHECK(file_->Open()); 177 RTC_DCHECK(file_->Open());
167 output_string_.clear(); 178 output_string_.clear();
179 bool message_received = false;
168 180
169 // Append each event older than both the current time and the stop time 181 // Append each event older than both the current time and the stop time
170 // to the output_string_. 182 // to the output_string_.
171 int64_t current_time = clock_->TimeInMicroseconds(); 183 int64_t current_time = clock_->TimeInMicroseconds();
172 int64_t time_limit = std::min(current_time, stop_time_); 184 int64_t time_limit = std::min(current_time, stop_time_);
173 if (!has_recent_event_) { 185 if (!has_recent_event_) {
174 has_recent_event_ = event_queue_->Remove(&most_recent_event_); 186 has_recent_event_ = event_queue_->Remove(&most_recent_event_);
175 } 187 }
176 bool stop = false; 188 bool stop = false;
177 while (!stop && has_recent_event_ && 189 while (!stop && has_recent_event_ &&
178 most_recent_event_->timestamp_us() <= time_limit) { 190 most_recent_event_->timestamp_us() <= time_limit) {
179 stop = AppendEventToString(most_recent_event_.get()); 191 stop = AppendEventToString(most_recent_event_.get());
180 if (!stop) { 192 if (!stop) {
181 if (IsConfigEvent(*most_recent_event_)) { 193 if (IsConfigEvent(*most_recent_event_)) {
182 config_history_.push_back(std::move(most_recent_event_)); 194 config_history_.push_back(std::move(most_recent_event_));
183 } 195 }
184 has_recent_event_ = event_queue_->Remove(&most_recent_event_); 196 has_recent_event_ = event_queue_->Remove(&most_recent_event_);
185 } 197 }
198 message_received = true;
186 } 199 }
187 200
188 // Write string to file. 201 // Write string to file.
189 if (!file_->Write(output_string_.data(), output_string_.size())) { 202 if (!file_->Write(output_string_.data(), output_string_.size())) {
190 LOG(LS_ERROR) << "FileWrapper failed to write WebRtcEventLog file."; 203 LOG(LS_ERROR) << "FileWrapper failed to write WebRtcEventLog file.";
191 // The current FileWrapper implementation closes the file on error. 204 // The current FileWrapper implementation closes the file on error.
192 RTC_DCHECK(!file_->Open()); 205 RTC_DCHECK(!file_->Open());
193 return; 206 return message_received;
194 } 207 }
195 written_bytes_ += output_string_.size(); 208 written_bytes_ += output_string_.size();
196 209
197 // We want to stop logging if we have reached the file size limit. We also 210 // We want to stop logging if we have reached the file size limit. We also
198 // want to stop logging if the remaining events are more recent than the 211 // want to stop logging if the remaining events are more recent than the
199 // time limit, or in other words if we have terminated the loop despite 212 // time limit, or in other words if we have terminated the loop despite
200 // having more events in the queue. 213 // having more events in the queue.
201 if ((has_recent_event_ && most_recent_event_->timestamp_us() > stop_time_) || 214 if ((has_recent_event_ && most_recent_event_->timestamp_us() > stop_time_) ||
202 stop) { 215 stop) {
203 RTC_DCHECK(file_->Open()); 216 RTC_DCHECK(file_->Open());
204 StopLogFile(); 217 StopLogFile();
205 } 218 }
219 return message_received;
206 } 220 }
207 221
208 void RtcEventLogHelperThread::StopLogFile() { 222 void RtcEventLogHelperThread::StopLogFile() {
209 RTC_DCHECK(file_->Open()); 223 RTC_DCHECK(file_->Open());
210 output_string_.clear(); 224 output_string_.clear();
211 225
212 rtclog::Event end_event; 226 rtclog::Event end_event;
213 end_event.set_timestamp_us(stop_time_); 227 end_event.set_timestamp_us(stop_time_);
214 end_event.set_type(rtclog::Event::LOG_END); 228 end_event.set_type(rtclog::Event::LOG_END);
215 AppendEventToString(&end_event); 229 AppendEventToString(&end_event);
(...skipping 10 matching lines...) Expand all
226 240
227 max_size_bytes_ = std::numeric_limits<int64_t>::max(); 241 max_size_bytes_ = std::numeric_limits<int64_t>::max();
228 written_bytes_ = 0; 242 written_bytes_ = 0;
229 start_time_ = 0; 243 start_time_ = 0;
230 stop_time_ = std::numeric_limits<int64_t>::max(); 244 stop_time_ = std::numeric_limits<int64_t>::max();
231 output_string_.clear(); 245 output_string_.clear();
232 file_->CloseFile(); 246 file_->CloseFile();
233 RTC_DCHECK(!file_->Open()); 247 RTC_DCHECK(!file_->Open());
234 } 248 }
235 249
236 void RtcEventLogHelperThread::WriteLog() { 250 void RtcEventLogHelperThread::ProcessEvents() {
237 ControlMessage message; 251 ControlMessage message;
238 252
239 while (true) { 253 while (true) {
254 bool message_received = false;
240 // Process control messages. 255 // Process control messages.
241 while (message_queue_->Remove(&message)) { 256 while (message_queue_->Remove(&message)) {
242 switch (message.message_type) { 257 switch (message.message_type) {
243 case ControlMessage::START_FILE: 258 case ControlMessage::START_FILE:
244 if (!file_->Open()) { 259 if (!file_->Open()) {
245 max_size_bytes_ = message.max_size_bytes; 260 max_size_bytes_ = message.max_size_bytes;
246 start_time_ = message.start_time; 261 start_time_ = message.start_time;
247 stop_time_ = message.stop_time; 262 stop_time_ = message.stop_time;
248 file_.swap(message.file); 263 file_.swap(message.file);
249 StartLogFile(); 264 StartLogFile();
250 } else { 265 } else {
251 // Already started. Ignore message and close file handle. 266 // Already started. Ignore message and close file handle.
252 message.file->CloseFile(); 267 message.file->CloseFile();
253 } 268 }
269 message_received = true;
254 break; 270 break;
255 case ControlMessage::STOP_FILE: 271 case ControlMessage::STOP_FILE:
256 if (file_->Open()) { 272 if (file_->Open()) {
257 stop_time_ = message.stop_time; 273 stop_time_ = message.stop_time;
258 LogToFile(); // Log remaining events from message queues. 274 LogToFile(); // Log remaining events from message queues.
259 } 275 }
260 // LogToFile might stop on it's own so we need to recheck the state. 276 // LogToFile might stop on it's own so we need to recheck the state.
261 if (file_->Open()) { 277 if (file_->Open()) {
262 StopLogFile(); 278 StopLogFile();
263 } 279 }
264 stopped_->Set(); 280 file_finished_.Set();
281 message_received = true;
265 break; 282 break;
266 case ControlMessage::TERMINATE_THREAD: 283 case ControlMessage::TERMINATE_THREAD:
267 if (file_->Open()) { 284 if (file_->Open()) {
268 StopLogFile(); 285 StopLogFile();
269 } 286 }
270 return; 287 return;
271 } 288 }
272 } 289 }
273 290
274 // Write events to file or memory 291 // Write events to file or memory.
275 if (file_->Open()) { 292 if (file_->Open()) {
276 LogToFile(); 293 message_received |= LogToFile();
277 } else { 294 } else {
278 LogToMemory(); 295 message_received |= LogToMemory();
279 } 296 }
280 297
281 // Accumulate a new batch of events instead of processing them one at a 298 // Accumulate a new batch of events instead of processing them one at a
282 // time. 299 // time.
283 wake_up_->Wait(50); 300 if (message_received) {
301 wake_periodically_.Wait(100);
302 } else {
303 wake_from_hibernation_.Wait(rtc::Event::kForever);
304 }
284 } 305 }
285 } 306 }
286 307
287 bool RtcEventLogHelperThread::ThreadOutputFunction(void* obj) { 308 bool RtcEventLogHelperThread::ThreadOutputFunction(void* obj) {
288 RtcEventLogHelperThread* helper = static_cast<RtcEventLogHelperThread*>(obj); 309 RtcEventLogHelperThread* helper = static_cast<RtcEventLogHelperThread*>(obj);
289 helper->WriteLog(); 310 helper->ProcessEvents();
290 return false; 311 return false;
291 } 312 }
292 313
293 } // namespace webrtc 314 } // namespace webrtc
294 315
295 #endif // ENABLE_RTC_EVENT_LOG 316 #endif // ENABLE_RTC_EVENT_LOG
OLDNEW
« webrtc/call/rtc_event_log.cc ('K') | « webrtc/call/rtc_event_log_helper_thread.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698