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

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

Issue 2573183002: Add process start time and CPU time columns to task manager (Closed)
Patch Set: Add TODO comment for a bug, which will be addressed in another CL. Created 3 years, 12 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 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 uint64_t start_time;
224 uint64_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
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);
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
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 = (uint64_t)pi->CreateTime;
brucedawson 2016/12/21 02:13:40 Should remove those casts - ULONGLONG and uint64_t
chengx 2016/12/21 22:05:54 Done.
500
501 process_data.cpu_time = (uint64_t)(pi->KernelTime + pi->UserTime);
brucedawson 2016/12/21 02:13:40 Ditto.
chengx 2016/12/21 22:05:54 Done.
502
490 // Iterate over threads and store each thread's ID and number of context 503 // Iterate over threads and store each thread's ID and number of context
491 // switches. 504 // switches.
492 for (ULONG thread_index = 0; thread_index < pi->NumberOfThreads; 505 for (ULONG thread_index = 0; thread_index < pi->NumberOfThreads;
493 ++thread_index) { 506 ++thread_index) {
494 const SYSTEM_THREAD_INFORMATION* ti = &pi->Threads[thread_index]; 507 const SYSTEM_THREAD_INFORMATION* ti = &pi->Threads[thread_index];
495 if (ti->ClientId.UniqueProcess != pi->ProcessId) 508 if (ti->ClientId.UniqueProcess != pi->ProcessId)
496 continue; 509 continue;
497 510
498 ThreadData thread_data; 511 ThreadData thread_data;
499 thread_data.thread_id = static_cast<base::PlatformThreadId>( 512 thread_data.thread_id = static_cast<base::PlatformThreadId>(
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
557 // Process is missing in the previous snapshot. 570 // Process is missing in the previous snapshot.
558 // Use entire number of context switches of the current process. 571 // Use entire number of context switches of the current process.
559 idle_wakeups_delta = CountContextSwitchesDelta(ProcessData(), process); 572 idle_wakeups_delta = CountContextSwitchesDelta(ProcessData(), process);
560 } 573 }
561 574
562 RefreshResult result; 575 RefreshResult result;
563 result.process_id = process_id; 576 result.process_id = process_id;
564 result.idle_wakeups_per_second = 577 result.idle_wakeups_per_second =
565 static_cast<int>(round(idle_wakeups_delta / time_delta)); 578 static_cast<int>(round(idle_wakeups_delta / time_delta));
566 result.physical_bytes = process.physical_bytes; 579 result.physical_bytes = process.physical_bytes;
580 result.start_time = process.start_time;
581 result.cpu_time = process.cpu_time;
567 results->push_back(result); 582 results->push_back(result);
568 } 583 }
569 } 584 }
570 585
571 void SharedSampler::MakeResultsFromSnapshot(const ProcessDataSnapshot& snapshot, 586 void SharedSampler::MakeResultsFromSnapshot(const ProcessDataSnapshot& snapshot,
572 RefreshResults* results) { 587 RefreshResults* results) {
573 for (const auto& pair : snapshot.processes) { 588 for (const auto& pair : snapshot.processes) {
574 RefreshResult result; 589 RefreshResult result;
575 result.process_id = pair.first; 590 result.process_id = pair.first;
576 // Use 0 for Idle Wakeups / sec in this case. This is consistent with 591 // Use 0 for Idle Wakeups / sec in this case. This is consistent with
577 // ProcessMetrics::CalculateIdleWakeupsPerSecond implementation. 592 // ProcessMetrics::CalculateIdleWakeupsPerSecond implementation.
578 result.idle_wakeups_per_second = 0; 593 result.idle_wakeups_per_second = 0;
579 result.physical_bytes = pair.second.physical_bytes; 594 result.physical_bytes = pair.second.physical_bytes;
595 result.start_time = pair.second.start_time;
596 result.cpu_time = pair.second.cpu_time;
580 results->push_back(result); 597 results->push_back(result);
581 } 598 }
582 } 599 }
583 600
584 void SharedSampler::OnRefreshDone( 601 void SharedSampler::OnRefreshDone(
585 std::unique_ptr<RefreshResults> refresh_results) { 602 std::unique_ptr<RefreshResults> refresh_results) {
586 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 603 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
587 DCHECK_NE(0, refresh_flags_); 604 DCHECK_NE(0, refresh_flags_);
588 605
589 size_t result_index = 0; 606 size_t result_index = 0;
590 607
591 for (const auto& callback_entry : callbacks_map_) { 608 for (const auto& callback_entry : callbacks_map_) {
592 base::ProcessId process_id = callback_entry.first; 609 base::ProcessId process_id = callback_entry.first;
593 // A sentinel value of -1 is used when the result isn't available. 610 // A sentinel value of -1 is used when the result isn't available.
594 // Task manager will use this to display 'N/A'. 611 // Task manager will use this to display 'N/A'.
stanisc 2016/12/21 19:17:52 Could you replace 'N/A' with '-'?
chengx 2016/12/21 22:05:54 Done.
595 int idle_wakeups_per_second = -1; 612 int idle_wakeups_per_second = -1;
596 int64_t physical_bytes = -1; 613 int64_t physical_bytes = -1;
614 uint64_t start_time = 0;
615 uint64_t cpu_time = 0;
597 616
598 // Match refresh result by |process_id|. 617 // Match refresh result by |process_id|.
599 // This relies on refresh results being ordered by Process ID. 618 // This relies on refresh results being ordered by Process ID.
600 // Please note that |refresh_results| might contain some extra entries that 619 // 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 620 // 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 621 // 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 622 // between getting process information on the worker thread and adding a
604 // corresponding TaskGroup to the task manager. 623 // corresponding TaskGroup to the task manager.
605 for (; result_index < refresh_results->size(); ++result_index) { 624 for (; result_index < refresh_results->size(); ++result_index) {
606 const auto& result = (*refresh_results)[result_index]; 625 const auto& result = (*refresh_results)[result_index];
607 if (result.process_id == process_id) { 626 if (result.process_id == process_id) {
608 // Data matched in |refresh_results|. 627 // Data matched in |refresh_results|.
609 idle_wakeups_per_second = result.idle_wakeups_per_second; 628 idle_wakeups_per_second = result.idle_wakeups_per_second;
610 physical_bytes = result.physical_bytes; 629 physical_bytes = result.physical_bytes;
630 start_time = result.start_time;
631 cpu_time = result.cpu_time;
611 ++result_index; 632 ++result_index;
612 break; 633 break;
613 } 634 }
614 635
615 if (result.process_id > process_id) { 636 if (result.process_id > process_id) {
616 // An entry corresponding to |process_id| is missing. See above. 637 // An entry corresponding to |process_id| is missing. See above.
617 break; 638 break;
618 } 639 }
619 } 640 }
620 641
621 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_IDLE_WAKEUPS, 642 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_IDLE_WAKEUPS,
622 refresh_flags_)) { 643 refresh_flags_)) {
623 DCHECK(callback_entry.second.on_idle_wakeups); 644 DCHECK(callback_entry.second.on_idle_wakeups);
624 callback_entry.second.on_idle_wakeups.Run(idle_wakeups_per_second); 645 callback_entry.second.on_idle_wakeups.Run(idle_wakeups_per_second);
625 } 646 }
626 647
627 if (TaskManagerObserver::IsResourceRefreshEnabled( 648 if (TaskManagerObserver::IsResourceRefreshEnabled(
628 REFRESH_TYPE_PHYSICAL_MEMORY, refresh_flags_)) { 649 REFRESH_TYPE_PHYSICAL_MEMORY, refresh_flags_)) {
629 DCHECK(callback_entry.second.on_physical_memory); 650 DCHECK(callback_entry.second.on_physical_memory);
630 callback_entry.second.on_physical_memory.Run(physical_bytes); 651 callback_entry.second.on_physical_memory.Run(physical_bytes);
631 } 652 }
653
654 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_START_TIME,
655 refresh_flags_)) {
656 DCHECK(callback_entry.second.on_start_time);
657 callback_entry.second.on_start_time.Run(start_time);
658 }
659
660 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_CPU_TIME,
661 refresh_flags_)) {
662 DCHECK(callback_entry.second.on_cpu_time);
663 callback_entry.second.on_cpu_time.Run(cpu_time);
664 }
632 } 665 }
633 666
634 // Reset refresh_results_ to trigger RefreshOnWorkerThread next time Refresh 667 // Reset refresh_results_ to trigger RefreshOnWorkerThread next time Refresh
635 // is called. 668 // is called.
636 refresh_flags_ = 0; 669 refresh_flags_ = 0;
637 } 670 }
638 671
639 } // namespace task_manager 672 } // namespace task_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698