Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 | 4 |
| 5 #include "chrome/browser/task_manager/sampling/shared_sampler.h" | 5 #include "chrome/browser/task_manager/sampling/shared_sampler.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <winternl.h> | 8 #include <winternl.h> |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 213 ULONG context_switches; | 213 ULONG context_switches; |
| 214 }; | 214 }; |
| 215 | 215 |
| 216 // Per-process data extracted from SYSTEM_PROCESS_INFORMATION and stored in a | 216 // Per-process data extracted from SYSTEM_PROCESS_INFORMATION and stored in a |
| 217 // snapshot. This structure is accessed only on the worker thread. | 217 // snapshot. This structure is accessed only on the worker thread. |
| 218 struct ProcessData { | 218 struct ProcessData { |
| 219 ProcessData() = default; | 219 ProcessData() = default; |
| 220 ProcessData(ProcessData&&) = default; | 220 ProcessData(ProcessData&&) = default; |
| 221 | 221 |
| 222 int64_t physical_bytes; | 222 int64_t physical_bytes; |
| 223 int64_t start_time; | |
| 224 int64_t cpu_time; | |
| 223 std::vector<ThreadData> threads; | 225 std::vector<ThreadData> threads; |
| 224 | 226 |
| 225 private: | 227 private: |
| 226 DISALLOW_COPY_AND_ASSIGN(ProcessData); | 228 DISALLOW_COPY_AND_ASSIGN(ProcessData); |
| 227 }; | 229 }; |
| 228 | 230 |
| 229 typedef std::map<base::ProcessId, ProcessData> ProcessDataMap; | 231 typedef std::map<base::ProcessId, ProcessData> ProcessDataMap; |
| 230 | 232 |
| 231 ULONG CountContextSwitchesDelta(const ProcessData& prev_process_data, | 233 ULONG CountContextSwitchesDelta(const ProcessData& prev_process_data, |
| 232 const ProcessData& new_process_data) { | 234 const ProcessData& new_process_data) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 306 // This object will be created on the UI thread, however the sequenced checker | 308 // This object will be created on the UI thread, however the sequenced checker |
| 307 // will be used to assert we're running the expensive operations on one of the | 309 // will be used to assert we're running the expensive operations on one of the |
| 308 // blocking pool threads. | 310 // blocking pool threads. |
| 309 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 311 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 310 worker_pool_sequenced_checker_.DetachFromSequence(); | 312 worker_pool_sequenced_checker_.DetachFromSequence(); |
| 311 } | 313 } |
| 312 | 314 |
| 313 SharedSampler::~SharedSampler() {} | 315 SharedSampler::~SharedSampler() {} |
| 314 | 316 |
| 315 int64_t SharedSampler::GetSupportedFlags() const { | 317 int64_t SharedSampler::GetSupportedFlags() const { |
| 316 return REFRESH_TYPE_IDLE_WAKEUPS | REFRESH_TYPE_PHYSICAL_MEMORY; | 318 return REFRESH_TYPE_IDLE_WAKEUPS | REFRESH_TYPE_PHYSICAL_MEMORY | |
| 319 REFRESH_TYPE_START_TIME | REFRESH_TYPE_CPU_TIME; | |
| 317 } | 320 } |
| 318 | 321 |
| 319 SharedSampler::Callbacks::Callbacks() {} | 322 SharedSampler::Callbacks::Callbacks() {} |
| 320 | 323 |
| 321 SharedSampler::Callbacks::~Callbacks() {} | 324 SharedSampler::Callbacks::~Callbacks() {} |
| 322 | 325 |
| 323 SharedSampler::Callbacks::Callbacks(Callbacks&& other) { | 326 SharedSampler::Callbacks::Callbacks(Callbacks&& other) { |
| 324 on_idle_wakeups = std::move(other.on_idle_wakeups); | 327 on_idle_wakeups = std::move(other.on_idle_wakeups); |
| 325 on_physical_memory = std::move(other.on_physical_memory); | 328 on_physical_memory = std::move(other.on_physical_memory); |
| 329 on_start_time = std::move(other.on_start_time); | |
| 330 on_cpu_time = std::move(other.on_cpu_time); | |
|
brucedawson
2016/12/19 21:51:05
Why is std::move being used here? It offers no val
| |
| 326 } | 331 } |
| 327 | 332 |
| 328 void SharedSampler::RegisterCallbacks( | 333 void SharedSampler::RegisterCallbacks( |
| 329 base::ProcessId process_id, | 334 base::ProcessId process_id, |
| 330 const OnIdleWakeupsCallback& on_idle_wakeups, | 335 const OnIdleWakeupsCallback& on_idle_wakeups, |
| 331 const OnPhysicalMemoryCallback& on_physical_memory) { | 336 const OnPhysicalMemoryCallback& on_physical_memory, |
| 337 const OnStartTimeCallback& on_start_time, | |
| 338 const OnCpuTimeCallback& on_cpu_time) { | |
| 332 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 339 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 333 | 340 |
| 334 if (process_id == 0) | 341 if (process_id == 0) |
| 335 return; | 342 return; |
| 336 | 343 |
| 337 Callbacks callbacks; | 344 Callbacks callbacks; |
| 338 callbacks.on_idle_wakeups = on_idle_wakeups; | 345 callbacks.on_idle_wakeups = on_idle_wakeups; |
| 339 callbacks.on_physical_memory = on_physical_memory; | 346 callbacks.on_physical_memory = on_physical_memory; |
| 347 callbacks.on_start_time = on_start_time; | |
| 348 callbacks.on_cpu_time = on_cpu_time; | |
| 340 bool result = callbacks_map_.insert( | 349 bool result = callbacks_map_.insert( |
| 341 std::make_pair(process_id, std::move(callbacks))).second; | 350 std::make_pair(process_id, std::move(callbacks))).second; |
| 342 DCHECK(result); | 351 DCHECK(result); |
| 343 } | 352 } |
| 344 | 353 |
| 345 void SharedSampler::UnregisterCallbacks(base::ProcessId process_id) { | 354 void SharedSampler::UnregisterCallbacks(base::ProcessId process_id) { |
| 346 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 355 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 347 | 356 |
| 348 if (process_id == 0) | 357 if (process_id == 0) |
| 349 return; | 358 return; |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 480 // terminated the total number of context switches for the process might | 489 // terminated the total number of context switches for the process might |
| 481 // go down and the delta would be negative. | 490 // go down and the delta would be negative. |
| 482 // To avoid that we need to compare thread IDs between two snapshots and | 491 // To avoid that we need to compare thread IDs between two snapshots and |
| 483 // not count context switches for threads that are missing in the most | 492 // not count context switches for threads that are missing in the most |
| 484 // recent snapshot. | 493 // recent snapshot. |
| 485 ProcessData process_data; | 494 ProcessData process_data; |
| 486 | 495 |
| 487 process_data.physical_bytes = | 496 process_data.physical_bytes = |
| 488 static_cast<int64_t>(pi->WorkingSetPrivateSize); | 497 static_cast<int64_t>(pi->WorkingSetPrivateSize); |
| 489 | 498 |
| 499 process_data.start_time = static_cast<int64_t>(pi->CreateTime); | |
|
brucedawson
2016/12/19 21:51:05
What happens if you use uint64_t for start_time an
chengx
2016/12/20 00:51:12
Done.
| |
| 500 | |
| 501 process_data.cpu_time = | |
| 502 static_cast<int64_t>(pi->KernelTime + pi->UserTime); | |
| 503 | |
| 490 // Iterate over threads and store each thread's ID and number of context | 504 // Iterate over threads and store each thread's ID and number of context |
| 491 // switches. | 505 // switches. |
| 492 for (ULONG thread_index = 0; thread_index < pi->NumberOfThreads; | 506 for (ULONG thread_index = 0; thread_index < pi->NumberOfThreads; |
| 493 ++thread_index) { | 507 ++thread_index) { |
| 494 const SYSTEM_THREAD_INFORMATION* ti = &pi->Threads[thread_index]; | 508 const SYSTEM_THREAD_INFORMATION* ti = &pi->Threads[thread_index]; |
| 495 if (ti->ClientId.UniqueProcess != pi->ProcessId) | 509 if (ti->ClientId.UniqueProcess != pi->ProcessId) |
| 496 continue; | 510 continue; |
| 497 | 511 |
| 498 ThreadData thread_data; | 512 ThreadData thread_data; |
| 499 thread_data.thread_id = static_cast<base::PlatformThreadId>( | 513 thread_data.thread_id = static_cast<base::PlatformThreadId>( |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 557 // Process is missing in the previous snapshot. | 571 // Process is missing in the previous snapshot. |
| 558 // Use entire number of context switches of the current process. | 572 // Use entire number of context switches of the current process. |
| 559 idle_wakeups_delta = CountContextSwitchesDelta(ProcessData(), process); | 573 idle_wakeups_delta = CountContextSwitchesDelta(ProcessData(), process); |
| 560 } | 574 } |
| 561 | 575 |
| 562 RefreshResult result; | 576 RefreshResult result; |
| 563 result.process_id = process_id; | 577 result.process_id = process_id; |
| 564 result.idle_wakeups_per_second = | 578 result.idle_wakeups_per_second = |
| 565 static_cast<int>(round(idle_wakeups_delta / time_delta)); | 579 static_cast<int>(round(idle_wakeups_delta / time_delta)); |
| 566 result.physical_bytes = process.physical_bytes; | 580 result.physical_bytes = process.physical_bytes; |
| 581 result.start_time = process.start_time; | |
| 582 result.cpu_time = process.cpu_time; | |
| 567 results->push_back(result); | 583 results->push_back(result); |
| 568 } | 584 } |
| 569 } | 585 } |
| 570 | 586 |
| 571 void SharedSampler::MakeResultsFromSnapshot(const ProcessDataSnapshot& snapshot, | 587 void SharedSampler::MakeResultsFromSnapshot(const ProcessDataSnapshot& snapshot, |
| 572 RefreshResults* results) { | 588 RefreshResults* results) { |
| 573 for (const auto& pair : snapshot.processes) { | 589 for (const auto& pair : snapshot.processes) { |
| 574 RefreshResult result; | 590 RefreshResult result; |
| 575 result.process_id = pair.first; | 591 result.process_id = pair.first; |
| 576 // Use 0 for Idle Wakeups / sec in this case. This is consistent with | 592 // Use 0 for Idle Wakeups / sec in this case. This is consistent with |
| 577 // ProcessMetrics::CalculateIdleWakeupsPerSecond implementation. | 593 // ProcessMetrics::CalculateIdleWakeupsPerSecond implementation. |
| 578 result.idle_wakeups_per_second = 0; | 594 result.idle_wakeups_per_second = 0; |
| 579 result.physical_bytes = pair.second.physical_bytes; | 595 result.physical_bytes = pair.second.physical_bytes; |
| 596 result.start_time = pair.second.start_time; | |
| 597 result.cpu_time = pair.second.cpu_time; | |
| 580 results->push_back(result); | 598 results->push_back(result); |
| 581 } | 599 } |
| 582 } | 600 } |
| 583 | 601 |
| 584 void SharedSampler::OnRefreshDone( | 602 void SharedSampler::OnRefreshDone( |
| 585 std::unique_ptr<RefreshResults> refresh_results) { | 603 std::unique_ptr<RefreshResults> refresh_results) { |
| 586 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 604 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 587 DCHECK_NE(0, refresh_flags_); | 605 DCHECK_NE(0, refresh_flags_); |
| 588 | 606 |
| 589 size_t result_index = 0; | 607 size_t result_index = 0; |
| 590 | 608 |
| 591 for (const auto& callback_entry : callbacks_map_) { | 609 for (const auto& callback_entry : callbacks_map_) { |
| 592 base::ProcessId process_id = callback_entry.first; | 610 base::ProcessId process_id = callback_entry.first; |
| 593 // A sentinel value of -1 is used when the result isn't available. | 611 // A sentinel value of -1 is used when the result isn't available. |
| 594 // Task manager will use this to display 'N/A'. | 612 // Task manager will use this to display 'N/A'. |
| 595 int idle_wakeups_per_second = -1; | 613 int idle_wakeups_per_second = -1; |
| 596 int64_t physical_bytes = -1; | 614 int64_t physical_bytes = -1; |
| 615 int64_t start_time = -1; | |
| 616 int64_t cpu_time = -1; | |
| 597 | 617 |
| 598 // Match refresh result by |process_id|. | 618 // Match refresh result by |process_id|. |
| 599 // This relies on refresh results being ordered by Process ID. | 619 // This relies on refresh results being ordered by Process ID. |
| 600 // Please note that |refresh_results| might contain some extra entries that | 620 // Please note that |refresh_results| might contain some extra entries that |
| 601 // don't exist in |callbacks_map_| if there is more than one instance of | 621 // don't exist in |callbacks_map_| if there is more than one instance of |
| 602 // Chrome. It might be missing some entries too if there is a race condition | 622 // Chrome. It might be missing some entries too if there is a race condition |
| 603 // between getting process information on the worker thread and adding a | 623 // between getting process information on the worker thread and adding a |
| 604 // corresponding TaskGroup to the task manager. | 624 // corresponding TaskGroup to the task manager. |
| 605 for (; result_index < refresh_results->size(); ++result_index) { | 625 for (; result_index < refresh_results->size(); ++result_index) { |
| 606 const auto& result = (*refresh_results)[result_index]; | 626 const auto& result = (*refresh_results)[result_index]; |
| 607 if (result.process_id == process_id) { | 627 if (result.process_id == process_id) { |
| 608 // Data matched in |refresh_results|. | 628 // Data matched in |refresh_results|. |
| 609 idle_wakeups_per_second = result.idle_wakeups_per_second; | 629 idle_wakeups_per_second = result.idle_wakeups_per_second; |
| 610 physical_bytes = result.physical_bytes; | 630 physical_bytes = result.physical_bytes; |
| 631 start_time = result.start_time; | |
| 632 cpu_time = result.cpu_time; | |
| 611 ++result_index; | 633 ++result_index; |
| 612 break; | 634 break; |
| 613 } | 635 } |
| 614 | 636 |
| 615 if (result.process_id > process_id) { | 637 if (result.process_id > process_id) { |
| 616 // An entry corresponding to |process_id| is missing. See above. | 638 // An entry corresponding to |process_id| is missing. See above. |
| 617 break; | 639 break; |
| 618 } | 640 } |
| 619 } | 641 } |
| 620 | 642 |
| 621 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_IDLE_WAKEUPS, | 643 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_IDLE_WAKEUPS, |
| 622 refresh_flags_)) { | 644 refresh_flags_)) { |
| 623 DCHECK(callback_entry.second.on_idle_wakeups); | 645 DCHECK(callback_entry.second.on_idle_wakeups); |
| 624 callback_entry.second.on_idle_wakeups.Run(idle_wakeups_per_second); | 646 callback_entry.second.on_idle_wakeups.Run(idle_wakeups_per_second); |
| 625 } | 647 } |
| 626 | 648 |
| 627 if (TaskManagerObserver::IsResourceRefreshEnabled( | 649 if (TaskManagerObserver::IsResourceRefreshEnabled( |
| 628 REFRESH_TYPE_PHYSICAL_MEMORY, refresh_flags_)) { | 650 REFRESH_TYPE_PHYSICAL_MEMORY, refresh_flags_)) { |
| 629 DCHECK(callback_entry.second.on_physical_memory); | 651 DCHECK(callback_entry.second.on_physical_memory); |
| 630 callback_entry.second.on_physical_memory.Run(physical_bytes); | 652 callback_entry.second.on_physical_memory.Run(physical_bytes); |
| 631 } | 653 } |
| 654 | |
| 655 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_START_TIME, | |
| 656 refresh_flags_)) { | |
| 657 DCHECK(callback_entry.second.on_start_time); | |
| 658 callback_entry.second.on_start_time.Run(start_time); | |
| 659 } | |
| 660 | |
| 661 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_CPU_TIME, | |
| 662 refresh_flags_)) { | |
| 663 DCHECK(callback_entry.second.on_cpu_time); | |
| 664 callback_entry.second.on_cpu_time.Run(cpu_time); | |
| 665 } | |
| 632 } | 666 } |
| 633 | 667 |
| 634 // Reset refresh_results_ to trigger RefreshOnWorkerThread next time Refresh | 668 // Reset refresh_results_ to trigger RefreshOnWorkerThread next time Refresh |
| 635 // is called. | 669 // is called. |
| 636 refresh_flags_ = 0; | 670 refresh_flags_ = 0; |
| 637 } | 671 } |
| 638 | 672 |
| 639 } // namespace task_manager | 673 } // namespace task_manager |
| OLD | NEW |