Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(66)

Side by Side Diff: chrome/browser/task_manager/sampling/shared_sampler_win.cc

Issue 2238403003: Task manager: Get physical memory efficiently for all processes from SharedSampler (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed CR feedback Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/task_manager/sampling/shared_sampler_unittest_win.cc ('k') | chrome/browser/task_manager/sampling/task_group.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698