OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |