| 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 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 212 base::PlatformThreadId thread_id; | 212 base::PlatformThreadId thread_id; |
| 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 std::vector<ThreadData> threads; | 223 std::vector<ThreadData> threads; |
| 223 | 224 |
| 224 private: | 225 private: |
| 225 DISALLOW_COPY_AND_ASSIGN(ProcessData); | 226 DISALLOW_COPY_AND_ASSIGN(ProcessData); |
| 226 }; | 227 }; |
| 227 | 228 |
| 228 typedef std::map<base::ProcessId, ProcessData> ProcessDataMap; | 229 typedef std::map<base::ProcessId, ProcessData> ProcessDataMap; |
| 229 | 230 |
| 230 ULONG CountContextSwitchesDelta(const ProcessData& prev_process_data, | 231 ULONG CountContextSwitchesDelta(const ProcessData& prev_process_data, |
| 231 const ProcessData& new_process_data) { | 232 const ProcessData& new_process_data) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 // This object will be created on the UI thread, however the sequenced checker | 306 // This object will be created on the UI thread, however the sequenced checker |
| 306 // will be used to assert we're running the expensive operations on one of the | 307 // will be used to assert we're running the expensive operations on one of the |
| 307 // blocking pool threads. | 308 // blocking pool threads. |
| 308 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 309 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 309 worker_pool_sequenced_checker_.DetachFromSequence(); | 310 worker_pool_sequenced_checker_.DetachFromSequence(); |
| 310 } | 311 } |
| 311 | 312 |
| 312 SharedSampler::~SharedSampler() {} | 313 SharedSampler::~SharedSampler() {} |
| 313 | 314 |
| 314 int64_t SharedSampler::GetSupportedFlags() const { | 315 int64_t SharedSampler::GetSupportedFlags() const { |
| 315 return REFRESH_TYPE_IDLE_WAKEUPS; | 316 return REFRESH_TYPE_IDLE_WAKEUPS | REFRESH_TYPE_PHYSICAL_MEMORY; |
| 316 } | 317 } |
| 317 | 318 |
| 318 SharedSampler::Callbacks::Callbacks() {} | 319 SharedSampler::Callbacks::Callbacks() {} |
| 319 | 320 |
| 320 SharedSampler::Callbacks::~Callbacks() {} | 321 SharedSampler::Callbacks::~Callbacks() {} |
| 321 | 322 |
| 322 SharedSampler::Callbacks::Callbacks(Callbacks&& other) { | 323 SharedSampler::Callbacks::Callbacks(Callbacks&& other) { |
| 323 on_idle_wakeups = std::move(other.on_idle_wakeups); | 324 on_idle_wakeups = std::move(other.on_idle_wakeups); |
| 325 on_physical_memory = std::move(other.on_physical_memory); |
| 324 } | 326 } |
| 325 | 327 |
| 326 void SharedSampler::RegisterCallbacks( | 328 void SharedSampler::RegisterCallbacks( |
| 327 base::ProcessId process_id, | 329 base::ProcessId process_id, |
| 328 const OnIdleWakeupsCallback& on_idle_wakeups) { | 330 const OnIdleWakeupsCallback& on_idle_wakeups, |
| 331 const OnPhysicalMemoryCallback& on_physical_memory) { |
| 329 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 332 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 330 | 333 |
| 331 if (process_id == 0) | 334 if (process_id == 0) |
| 332 return; | 335 return; |
| 333 | 336 |
| 334 Callbacks callbacks; | 337 Callbacks callbacks; |
| 335 callbacks.on_idle_wakeups = on_idle_wakeups; | 338 callbacks.on_idle_wakeups = on_idle_wakeups; |
| 339 callbacks.on_physical_memory = on_physical_memory; |
| 336 bool result = callbacks_map_.insert( | 340 bool result = callbacks_map_.insert( |
| 337 std::make_pair(process_id, std::move(callbacks))).second; | 341 std::make_pair(process_id, std::move(callbacks))).second; |
| 338 DCHECK(result); | 342 DCHECK(result); |
| 339 } | 343 } |
| 340 | 344 |
| 341 void SharedSampler::UnregisterCallbacks(base::ProcessId process_id) { | 345 void SharedSampler::UnregisterCallbacks(base::ProcessId process_id) { |
| 342 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 346 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 343 | 347 |
| 344 if (process_id == 0) | 348 if (process_id == 0) |
| 345 return; | 349 return; |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 470 // Collect enough data to be able to do a diff between two snapshots. | 474 // Collect enough data to be able to do a diff between two snapshots. |
| 471 // Some threads might stop or new threads might be created between two | 475 // Some threads might stop or new threads might be created between two |
| 472 // snapshots. If a thread with a large number of context switches gets | 476 // snapshots. If a thread with a large number of context switches gets |
| 473 // terminated the total number of context switches for the process might | 477 // terminated the total number of context switches for the process might |
| 474 // go down and the delta would be negative. | 478 // go down and the delta would be negative. |
| 475 // To avoid that we need to compare thread IDs between two snapshots and | 479 // To avoid that we need to compare thread IDs between two snapshots and |
| 476 // not count context switches for threads that are missing in the most | 480 // not count context switches for threads that are missing in the most |
| 477 // recent snapshot. | 481 // recent snapshot. |
| 478 ProcessData process_data; | 482 ProcessData process_data; |
| 479 | 483 |
| 484 process_data.physical_bytes = |
| 485 static_cast<int64_t>(pi->WorkingSetPrivateSize); |
| 486 |
| 480 // Iterate over threads and store each thread's ID and number of context | 487 // Iterate over threads and store each thread's ID and number of context |
| 481 // switches. | 488 // switches. |
| 482 for (ULONG thread_index = 0; thread_index < pi->NumberOfThreads; | 489 for (ULONG thread_index = 0; thread_index < pi->NumberOfThreads; |
| 483 ++thread_index) { | 490 ++thread_index) { |
| 484 const SYSTEM_THREAD_INFORMATION* ti = &pi->Threads[thread_index]; | 491 const SYSTEM_THREAD_INFORMATION* ti = &pi->Threads[thread_index]; |
| 485 if (ti->ClientId.UniqueProcess != pi->ProcessId) | 492 if (ti->ClientId.UniqueProcess != pi->ProcessId) |
| 486 continue; | 493 continue; |
| 487 | 494 |
| 488 ThreadData thread_data; | 495 ThreadData thread_data; |
| 489 thread_data.thread_id = static_cast<base::PlatformThreadId>( | 496 thread_data.thread_id = static_cast<base::PlatformThreadId>( |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 546 } else { | 553 } else { |
| 547 // Process is missing in the previous snapshot. | 554 // Process is missing in the previous snapshot. |
| 548 // Use entire number of context switches of the current process. | 555 // Use entire number of context switches of the current process. |
| 549 idle_wakeups_delta = CountContextSwitchesDelta(ProcessData(), process); | 556 idle_wakeups_delta = CountContextSwitchesDelta(ProcessData(), process); |
| 550 } | 557 } |
| 551 | 558 |
| 552 RefreshResult result; | 559 RefreshResult result; |
| 553 result.process_id = process_id; | 560 result.process_id = process_id; |
| 554 result.idle_wakeups_per_second = | 561 result.idle_wakeups_per_second = |
| 555 static_cast<int>(round(idle_wakeups_delta / time_delta)); | 562 static_cast<int>(round(idle_wakeups_delta / time_delta)); |
| 563 result.physical_bytes = process.physical_bytes; |
| 556 results->push_back(result); | 564 results->push_back(result); |
| 557 } | 565 } |
| 558 } | 566 } |
| 559 | 567 |
| 560 void SharedSampler::MakeResultsFromSnapshot(const ProcessDataSnapshot& snapshot, | 568 void SharedSampler::MakeResultsFromSnapshot(const ProcessDataSnapshot& snapshot, |
| 561 RefreshResults* results) { | 569 RefreshResults* results) { |
| 562 for (const auto& pair : snapshot.processes) { | 570 for (const auto& pair : snapshot.processes) { |
| 563 RefreshResult result; | 571 RefreshResult result; |
| 564 result.process_id = pair.first; | 572 result.process_id = pair.first; |
| 565 // Use 0 for Idle Wakeups / sec in this case. This is consistent with | 573 // Use 0 for Idle Wakeups / sec in this case. This is consistent with |
| 566 // ProcessMetrics::CalculateIdleWakeupsPerSecond implementation. | 574 // ProcessMetrics::CalculateIdleWakeupsPerSecond implementation. |
| 567 result.idle_wakeups_per_second = 0; | 575 result.idle_wakeups_per_second = 0; |
| 576 result.physical_bytes = pair.second.physical_bytes; |
| 568 results->push_back(result); | 577 results->push_back(result); |
| 569 } | 578 } |
| 570 } | 579 } |
| 571 | 580 |
| 572 void SharedSampler::OnRefreshDone( | 581 void SharedSampler::OnRefreshDone( |
| 573 std::unique_ptr<RefreshResults> refresh_results) { | 582 std::unique_ptr<RefreshResults> refresh_results) { |
| 574 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 583 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 575 DCHECK_NE(0, refresh_flags_); | 584 DCHECK_NE(0, refresh_flags_); |
| 576 | 585 |
| 577 size_t result_index = 0; | 586 size_t result_index = 0; |
| 578 | 587 |
| 579 for (const auto& callback_entry : callbacks_map_) { | 588 for (const auto& callback_entry : callbacks_map_) { |
| 580 base::ProcessId process_id = callback_entry.first; | 589 base::ProcessId process_id = callback_entry.first; |
| 581 // A sentinel value of -1 is used when the result isn't available. | 590 // A sentinel value of -1 is used when the result isn't available. |
| 582 // Task manager will use this to display 'N/A'. | 591 // Task manager will use this to display 'N/A'. |
| 583 int idle_wakeups_per_second = -1; | 592 int idle_wakeups_per_second = -1; |
| 593 int64_t physical_bytes = -1; |
| 584 | 594 |
| 585 // Match refresh result by |process_id|. | 595 // Match refresh result by |process_id|. |
| 586 // This relies on refresh results being ordered by Process ID. | 596 // This relies on refresh results being ordered by Process ID. |
| 587 // Please note that |refresh_results| might contain some extra entries that | 597 // Please note that |refresh_results| might contain some extra entries that |
| 588 // don't exist in |callbacks_map_| if there is more than one instance of | 598 // don't exist in |callbacks_map_| if there is more than one instance of |
| 589 // Chrome. It might be missing some entries too if there is a race condition | 599 // Chrome. It might be missing some entries too if there is a race condition |
| 590 // between getting process information on the worker thread and adding a | 600 // between getting process information on the worker thread and adding a |
| 591 // corresponding TaskGroup to the task manager. | 601 // corresponding TaskGroup to the task manager. |
| 592 for (; result_index < refresh_results->size(); ++result_index) { | 602 for (; result_index < refresh_results->size(); ++result_index) { |
| 593 const auto& result = (*refresh_results)[result_index]; | 603 const auto& result = (*refresh_results)[result_index]; |
| 594 if (result.process_id == process_id) { | 604 if (result.process_id == process_id) { |
| 595 // Data matched in |refresh_results|. | 605 // Data matched in |refresh_results|. |
| 596 idle_wakeups_per_second = result.idle_wakeups_per_second; | 606 idle_wakeups_per_second = result.idle_wakeups_per_second; |
| 607 physical_bytes = result.physical_bytes; |
| 597 ++result_index; | 608 ++result_index; |
| 598 break; | 609 break; |
| 599 } | 610 } |
| 600 | 611 |
| 601 if (result.process_id > process_id) { | 612 if (result.process_id > process_id) { |
| 602 // An entry corresponding to |process_id| is missing. See above. | 613 // An entry corresponding to |process_id| is missing. See above. |
| 603 break; | 614 break; |
| 604 } | 615 } |
| 605 } | 616 } |
| 606 | 617 |
| 607 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_IDLE_WAKEUPS, | 618 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_IDLE_WAKEUPS, |
| 608 refresh_flags_)) { | 619 refresh_flags_)) { |
| 620 DCHECK(callback_entry.second.on_idle_wakeups); |
| 609 callback_entry.second.on_idle_wakeups.Run(idle_wakeups_per_second); | 621 callback_entry.second.on_idle_wakeups.Run(idle_wakeups_per_second); |
| 610 } | 622 } |
| 623 |
| 624 if (TaskManagerObserver::IsResourceRefreshEnabled( |
| 625 REFRESH_TYPE_PHYSICAL_MEMORY, refresh_flags_)) { |
| 626 DCHECK(callback_entry.second.on_physical_memory); |
| 627 callback_entry.second.on_physical_memory.Run(physical_bytes); |
| 628 } |
| 611 } | 629 } |
| 612 | 630 |
| 613 // Reset refresh_results_ to trigger RefreshOnWorkerThread next time Refresh | 631 // Reset refresh_results_ to trigger RefreshOnWorkerThread next time Refresh |
| 614 // is called. | 632 // is called. |
| 615 refresh_flags_ = 0; | 633 refresh_flags_ = 0; |
| 616 } | 634 } |
| 617 | 635 |
| 618 } // namespace task_manager | 636 } // namespace task_manager |
| OLD | NEW |