OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 #include "content/browser/tracing/tracing_controller_impl.h" | 4 #include "content/browser/tracing/tracing_controller_impl.h" |
5 | 5 |
6 #include "base/bind.h" | 6 #include "base/bind.h" |
7 #include "base/cpu.h" | 7 #include "base/cpu.h" |
8 #include "base/files/file_util.h" | 8 #include "base/files/file_util.h" |
9 #include "base/guid.h" | 9 #include "base/guid.h" |
10 #include "base/json/string_escape.h" | 10 #include "base/json/string_escape.h" |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 TracingController* TracingController::GetInstance() { | 186 TracingController* TracingController::GetInstance() { |
187 return TracingControllerImpl::GetInstance(); | 187 return TracingControllerImpl::GetInstance(); |
188 } | 188 } |
189 | 189 |
190 TracingControllerImpl::TracingControllerImpl() | 190 TracingControllerImpl::TracingControllerImpl() |
191 : pending_start_tracing_ack_count_(0), | 191 : pending_start_tracing_ack_count_(0), |
192 pending_stop_tracing_ack_count_(0), | 192 pending_stop_tracing_ack_count_(0), |
193 pending_trace_log_status_ack_count_(0), | 193 pending_trace_log_status_ack_count_(0), |
194 maximum_trace_buffer_usage_(0), | 194 maximum_trace_buffer_usage_(0), |
195 approximate_event_count_(0), | 195 approximate_event_count_(0), |
196 pending_memory_dump_ack_count_(0), | |
197 failed_memory_dump_count_(0), | |
198 pending_clock_sync_ack_count_(0), | 196 pending_clock_sync_ack_count_(0), |
199 is_tracing_(false) { | 197 is_tracing_(false) { |
200 base::trace_event::MemoryDumpManager::GetInstance()->Initialize( | |
201 this /* delegate */, true /* is_coordinator */); | |
202 | |
203 // Deliberately leaked, like this class. | 198 // Deliberately leaked, like this class. |
204 base::FileTracing::SetProvider(new FileTracingProviderImpl); | 199 base::FileTracing::SetProvider(new FileTracingProviderImpl); |
205 } | 200 } |
206 | 201 |
207 TracingControllerImpl::~TracingControllerImpl() { | 202 TracingControllerImpl::~TracingControllerImpl() { |
208 // This is a Leaky instance. | 203 // This is a Leaky instance. |
209 NOTREACHED(); | 204 NOTREACHED(); |
210 } | 205 } |
211 | 206 |
212 TracingControllerImpl* TracingControllerImpl::GetInstance() { | 207 TracingControllerImpl* TracingControllerImpl::GetInstance() { |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
529 pending_trace_log_status_filters_.find(trace_message_filter); | 524 pending_trace_log_status_filters_.find(trace_message_filter); |
530 if (it != pending_trace_log_status_filters_.end()) { | 525 if (it != pending_trace_log_status_filters_.end()) { |
531 BrowserThread::PostTask( | 526 BrowserThread::PostTask( |
532 BrowserThread::UI, FROM_HERE, | 527 BrowserThread::UI, FROM_HERE, |
533 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply, | 528 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply, |
534 base::Unretained(this), | 529 base::Unretained(this), |
535 base::RetainedRef(trace_message_filter), | 530 base::RetainedRef(trace_message_filter), |
536 base::trace_event::TraceLogStatus())); | 531 base::trace_event::TraceLogStatus())); |
537 } | 532 } |
538 } | 533 } |
539 if (pending_memory_dump_ack_count_ > 0) { | |
540 DCHECK(!queued_memory_dump_requests_.empty()); | |
541 TraceMessageFilterSet::const_iterator it = | |
542 pending_memory_dump_filters_.find(trace_message_filter); | |
543 if (it != pending_memory_dump_filters_.end()) { | |
544 BrowserThread::PostTask( | |
545 BrowserThread::UI, FROM_HERE, | |
546 base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse, | |
547 base::Unretained(this), | |
548 base::RetainedRef(trace_message_filter), | |
549 queued_memory_dump_requests_.front().args.dump_guid, | |
550 false /* success */)); | |
551 } | |
552 } | |
553 trace_message_filters_.erase(trace_message_filter); | 534 trace_message_filters_.erase(trace_message_filter); |
554 } | 535 } |
555 | 536 |
556 void TracingControllerImpl::AddTracingAgent(const std::string& agent_name) { | 537 void TracingControllerImpl::AddTracingAgent(const std::string& agent_name) { |
557 #if defined(OS_CHROMEOS) | 538 #if defined(OS_CHROMEOS) |
558 auto* debug_daemon = | 539 auto* debug_daemon = |
559 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); | 540 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); |
560 if (agent_name == debug_daemon->GetTracingAgentName()) { | 541 if (agent_name == debug_daemon->GetTracingAgentName()) { |
561 additional_tracing_agents_.push_back(debug_daemon); | 542 additional_tracing_agents_.push_back(debug_daemon); |
562 debug_daemon->SetStopAgentTracingTaskRunner( | 543 debug_daemon->SetStopAgentTracingTaskRunner( |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
889 for (base::DictionaryValue::Iterator it(*metadata); !it.IsAtEnd(); | 870 for (base::DictionaryValue::Iterator it(*metadata); !it.IsAtEnd(); |
890 it.Advance()) { | 871 it.Advance()) { |
891 if (filter.Run(it.key())) | 872 if (filter.Run(it.key())) |
892 filtered_metadata->Set(it.key(), it.value().DeepCopy()); | 873 filtered_metadata->Set(it.key(), it.value().DeepCopy()); |
893 else | 874 else |
894 filtered_metadata->SetString(it.key(), "__stripped__"); | 875 filtered_metadata->SetString(it.key(), "__stripped__"); |
895 } | 876 } |
896 sink->AddMetadata(std::move(filtered_metadata)); | 877 sink->AddMetadata(std::move(filtered_metadata)); |
897 } | 878 } |
898 | 879 |
899 void TracingControllerImpl::RequestGlobalMemoryDump( | |
900 const base::trace_event::MemoryDumpRequestArgs& args, | |
901 const base::trace_event::MemoryDumpCallback& callback) { | |
902 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
903 BrowserThread::PostTask( | |
904 BrowserThread::UI, FROM_HERE, | |
905 base::Bind(&TracingControllerImpl::RequestGlobalMemoryDump, | |
906 base::Unretained(this), args, callback)); | |
907 return; | |
908 } | |
909 | |
910 bool another_dump_already_in_progress = !queued_memory_dump_requests_.empty(); | |
911 | |
912 // If this is a periodic memory dump request and there already is another | |
913 // request in the queue with the same level of detail, there's no point in | |
914 // enqueuing this request. | |
915 if (another_dump_already_in_progress && | |
916 args.dump_type == base::trace_event::MemoryDumpType::PERIODIC_INTERVAL) { | |
917 for (const auto& request : queued_memory_dump_requests_) { | |
918 if (request.args.level_of_detail == args.level_of_detail) { | |
919 VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix << " (" | |
920 << base::trace_event::MemoryDumpTypeToString(args.dump_type) | |
921 << ") skipped because another dump request with the same " | |
922 "level of detail (" | |
923 << base::trace_event::MemoryDumpLevelOfDetailToString( | |
924 args.level_of_detail) | |
925 << ") is already in the queue"; | |
926 if (!callback.is_null()) | |
927 callback.Run(args.dump_guid, false /* success */); | |
928 return; | |
929 } | |
930 } | |
931 } | |
932 | |
933 queued_memory_dump_requests_.emplace_back(args, callback); | |
934 | |
935 // If another dump is already in progress, this dump will automatically be | |
936 // scheduled when the other dump finishes. | |
937 if (another_dump_already_in_progress) | |
938 return; | |
939 | |
940 PerformNextQueuedGlobalMemoryDump(); | |
941 } | |
942 | |
943 void TracingControllerImpl::PerformNextQueuedGlobalMemoryDump() { | |
944 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
945 DCHECK(!queued_memory_dump_requests_.empty()); | |
946 const base::trace_event::MemoryDumpRequestArgs& args = | |
947 queued_memory_dump_requests_.front().args; | |
948 | |
949 // Count myself (local trace) in pending_memory_dump_ack_count_, acked by | |
950 // OnBrowserProcessMemoryDumpDone(). | |
951 pending_memory_dump_ack_count_ = trace_message_filters_.size() + 1; | |
952 pending_memory_dump_filters_.clear(); | |
953 failed_memory_dump_count_ = 0; | |
954 | |
955 MemoryDumpManagerDelegate::CreateProcessDump( | |
956 args, base::Bind(&TracingControllerImpl::OnBrowserProcessMemoryDumpDone, | |
957 base::Unretained(this))); | |
958 | |
959 // If there are no child processes we are just done. | |
960 if (pending_memory_dump_ack_count_ == 1) | |
961 return; | |
962 | |
963 pending_memory_dump_filters_ = trace_message_filters_; | |
964 | |
965 for (const scoped_refptr<TraceMessageFilter>& tmf : trace_message_filters_) | |
966 tmf->SendProcessMemoryDumpRequest(args); | |
967 } | |
968 | |
969 TracingControllerImpl::QueuedMemoryDumpRequest::QueuedMemoryDumpRequest( | |
970 const base::trace_event::MemoryDumpRequestArgs& args, | |
971 const base::trace_event::MemoryDumpCallback& callback) | |
972 : args(args), callback(callback) {} | |
973 | |
974 TracingControllerImpl::QueuedMemoryDumpRequest::~QueuedMemoryDumpRequest() {} | |
975 | |
976 uint64_t TracingControllerImpl::GetTracingProcessId() const { | |
977 return ChildProcessHost::kBrowserTracingProcessId; | |
978 } | |
979 | |
980 void TracingControllerImpl::AddTraceMessageFilterObserver( | 880 void TracingControllerImpl::AddTraceMessageFilterObserver( |
981 TraceMessageFilterObserver* observer) { | 881 TraceMessageFilterObserver* observer) { |
982 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 882 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
983 trace_message_filter_observers_.AddObserver(observer); | 883 trace_message_filter_observers_.AddObserver(observer); |
984 | 884 |
985 for (auto& filter : trace_message_filters_) | 885 for (auto& filter : trace_message_filters_) |
986 observer->OnTraceMessageFilterAdded(filter.get()); | 886 observer->OnTraceMessageFilterAdded(filter.get()); |
987 } | 887 } |
988 | 888 |
989 void TracingControllerImpl::RemoveTraceMessageFilterObserver( | 889 void TracingControllerImpl::RemoveTraceMessageFilterObserver( |
990 TraceMessageFilterObserver* observer) { | 890 TraceMessageFilterObserver* observer) { |
991 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 891 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
992 trace_message_filter_observers_.RemoveObserver(observer); | 892 trace_message_filter_observers_.RemoveObserver(observer); |
993 | 893 |
994 for (auto& filter : trace_message_filters_) | 894 for (auto& filter : trace_message_filters_) |
995 observer->OnTraceMessageFilterRemoved(filter.get()); | 895 observer->OnTraceMessageFilterRemoved(filter.get()); |
996 } | 896 } |
997 | 897 |
998 void TracingControllerImpl::OnProcessMemoryDumpResponse( | |
999 TraceMessageFilter* trace_message_filter, | |
1000 uint64_t dump_guid, | |
1001 bool success) { | |
1002 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | |
1003 BrowserThread::PostTask( | |
1004 BrowserThread::UI, FROM_HERE, | |
1005 base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse, | |
1006 base::Unretained(this), | |
1007 base::RetainedRef(trace_message_filter), dump_guid, | |
1008 success)); | |
1009 return; | |
1010 } | |
1011 | |
1012 TraceMessageFilterSet::iterator it = | |
1013 pending_memory_dump_filters_.find(trace_message_filter); | |
1014 | |
1015 DCHECK(!queued_memory_dump_requests_.empty()); | |
1016 if (queued_memory_dump_requests_.front().args.dump_guid != dump_guid || | |
1017 it == pending_memory_dump_filters_.end()) { | |
1018 DLOG(WARNING) << "Received unexpected memory dump response: " << dump_guid; | |
1019 return; | |
1020 } | |
1021 | |
1022 DCHECK_GT(pending_memory_dump_ack_count_, 0); | |
1023 --pending_memory_dump_ack_count_; | |
1024 pending_memory_dump_filters_.erase(it); | |
1025 if (!success) { | |
1026 ++failed_memory_dump_count_; | |
1027 VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix | |
1028 << " failed because of NACK from child " | |
1029 << trace_message_filter->peer_pid(); | |
1030 } | |
1031 FinalizeGlobalMemoryDumpIfAllProcessesReplied(); | |
1032 } | |
1033 | |
1034 void TracingControllerImpl::OnBrowserProcessMemoryDumpDone(uint64_t dump_guid, | |
1035 bool success) { | |
1036 DCHECK_GT(pending_memory_dump_ack_count_, 0); | |
1037 --pending_memory_dump_ack_count_; | |
1038 if (!success) { | |
1039 ++failed_memory_dump_count_; | |
1040 VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix | |
1041 << " aborted on the current process"; | |
1042 } | |
1043 FinalizeGlobalMemoryDumpIfAllProcessesReplied(); | |
1044 } | |
1045 | |
1046 void TracingControllerImpl::FinalizeGlobalMemoryDumpIfAllProcessesReplied() { | |
1047 if (pending_memory_dump_ack_count_ > 0) | |
1048 return; | |
1049 | |
1050 DCHECK(!queued_memory_dump_requests_.empty()); | |
1051 { | |
1052 const auto& callback = queued_memory_dump_requests_.front().callback; | |
1053 if (!callback.is_null()) { | |
1054 const bool global_success = failed_memory_dump_count_ == 0; | |
1055 callback.Run(queued_memory_dump_requests_.front().args.dump_guid, | |
1056 global_success); | |
1057 } | |
1058 } | |
1059 queued_memory_dump_requests_.pop_front(); | |
1060 | |
1061 // Schedule the next queued dump (if applicable). | |
1062 if (!queued_memory_dump_requests_.empty()) { | |
1063 BrowserThread::PostTask( | |
1064 BrowserThread::UI, FROM_HERE, | |
1065 base::Bind(&TracingControllerImpl::PerformNextQueuedGlobalMemoryDump, | |
1066 base::Unretained(this))); | |
1067 } | |
1068 } | |
1069 | |
1070 } // namespace content | 898 } // namespace content |
OLD | NEW |