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), |
196 pending_clock_sync_ack_count_(0), | 198 pending_clock_sync_ack_count_(0), |
197 is_tracing_(false) { | 199 is_tracing_(false) { |
| 200 base::trace_event::MemoryDumpManager::GetInstance()->Initialize( |
| 201 this /* delegate */, true /* is_coordinator */); |
| 202 |
198 // Deliberately leaked, like this class. | 203 // Deliberately leaked, like this class. |
199 base::FileTracing::SetProvider(new FileTracingProviderImpl); | 204 base::FileTracing::SetProvider(new FileTracingProviderImpl); |
200 } | 205 } |
201 | 206 |
202 TracingControllerImpl::~TracingControllerImpl() { | 207 TracingControllerImpl::~TracingControllerImpl() { |
203 // This is a Leaky instance. | 208 // This is a Leaky instance. |
204 NOTREACHED(); | 209 NOTREACHED(); |
205 } | 210 } |
206 | 211 |
207 TracingControllerImpl* TracingControllerImpl::GetInstance() { | 212 TracingControllerImpl* TracingControllerImpl::GetInstance() { |
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
524 pending_trace_log_status_filters_.find(trace_message_filter); | 529 pending_trace_log_status_filters_.find(trace_message_filter); |
525 if (it != pending_trace_log_status_filters_.end()) { | 530 if (it != pending_trace_log_status_filters_.end()) { |
526 BrowserThread::PostTask( | 531 BrowserThread::PostTask( |
527 BrowserThread::UI, FROM_HERE, | 532 BrowserThread::UI, FROM_HERE, |
528 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply, | 533 base::Bind(&TracingControllerImpl::OnTraceLogStatusReply, |
529 base::Unretained(this), | 534 base::Unretained(this), |
530 base::RetainedRef(trace_message_filter), | 535 base::RetainedRef(trace_message_filter), |
531 base::trace_event::TraceLogStatus())); | 536 base::trace_event::TraceLogStatus())); |
532 } | 537 } |
533 } | 538 } |
| 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 } |
534 trace_message_filters_.erase(trace_message_filter); | 553 trace_message_filters_.erase(trace_message_filter); |
535 } | 554 } |
536 | 555 |
537 void TracingControllerImpl::AddTracingAgent(const std::string& agent_name) { | 556 void TracingControllerImpl::AddTracingAgent(const std::string& agent_name) { |
538 #if defined(OS_CHROMEOS) | 557 #if defined(OS_CHROMEOS) |
539 auto* debug_daemon = | 558 auto* debug_daemon = |
540 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); | 559 chromeos::DBusThreadManager::Get()->GetDebugDaemonClient(); |
541 if (agent_name == debug_daemon->GetTracingAgentName()) { | 560 if (agent_name == debug_daemon->GetTracingAgentName()) { |
542 additional_tracing_agents_.push_back(debug_daemon); | 561 additional_tracing_agents_.push_back(debug_daemon); |
543 debug_daemon->SetStopAgentTracingTaskRunner( | 562 debug_daemon->SetStopAgentTracingTaskRunner( |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
870 for (base::DictionaryValue::Iterator it(*metadata); !it.IsAtEnd(); | 889 for (base::DictionaryValue::Iterator it(*metadata); !it.IsAtEnd(); |
871 it.Advance()) { | 890 it.Advance()) { |
872 if (filter.Run(it.key())) | 891 if (filter.Run(it.key())) |
873 filtered_metadata->Set(it.key(), it.value().DeepCopy()); | 892 filtered_metadata->Set(it.key(), it.value().DeepCopy()); |
874 else | 893 else |
875 filtered_metadata->SetString(it.key(), "__stripped__"); | 894 filtered_metadata->SetString(it.key(), "__stripped__"); |
876 } | 895 } |
877 sink->AddMetadata(std::move(filtered_metadata)); | 896 sink->AddMetadata(std::move(filtered_metadata)); |
878 } | 897 } |
879 | 898 |
| 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 |
880 void TracingControllerImpl::AddTraceMessageFilterObserver( | 980 void TracingControllerImpl::AddTraceMessageFilterObserver( |
881 TraceMessageFilterObserver* observer) { | 981 TraceMessageFilterObserver* observer) { |
882 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 982 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
883 trace_message_filter_observers_.AddObserver(observer); | 983 trace_message_filter_observers_.AddObserver(observer); |
884 | 984 |
885 for (auto& filter : trace_message_filters_) | 985 for (auto& filter : trace_message_filters_) |
886 observer->OnTraceMessageFilterAdded(filter.get()); | 986 observer->OnTraceMessageFilterAdded(filter.get()); |
887 } | 987 } |
888 | 988 |
889 void TracingControllerImpl::RemoveTraceMessageFilterObserver( | 989 void TracingControllerImpl::RemoveTraceMessageFilterObserver( |
890 TraceMessageFilterObserver* observer) { | 990 TraceMessageFilterObserver* observer) { |
891 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 991 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
892 trace_message_filter_observers_.RemoveObserver(observer); | 992 trace_message_filter_observers_.RemoveObserver(observer); |
893 | 993 |
894 for (auto& filter : trace_message_filters_) | 994 for (auto& filter : trace_message_filters_) |
895 observer->OnTraceMessageFilterRemoved(filter.get()); | 995 observer->OnTraceMessageFilterRemoved(filter.get()); |
896 } | 996 } |
897 | 997 |
| 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 |
898 } // namespace content | 1070 } // namespace content |
OLD | NEW |