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

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: Move ticks-Time and ticks-TimeDelta conversions to shared_sampler_win.cc Created 4 years 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>
11 11
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/bit_cast.h"
13 #include "base/command_line.h" 14 #include "base/command_line.h"
14 #include "base/path_service.h" 15 #include "base/path_service.h"
15 #include "base/time/time.h" 16 #include "base/time/time.h"
16 #include "chrome/browser/task_manager/task_manager_observer.h" 17 #include "chrome/browser/task_manager/task_manager_observer.h"
17 #include "chrome/common/chrome_constants.h" 18 #include "chrome/common/chrome_constants.h"
18 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/browser_thread.h"
19 20
20 namespace task_manager { 21 namespace task_manager {
21 22
22 namespace { 23 namespace {
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 ULONG context_switches; 214 ULONG context_switches;
214 }; 215 };
215 216
216 // Per-process data extracted from SYSTEM_PROCESS_INFORMATION and stored in a 217 // Per-process data extracted from SYSTEM_PROCESS_INFORMATION and stored in a
217 // snapshot. This structure is accessed only on the worker thread. 218 // snapshot. This structure is accessed only on the worker thread.
218 struct ProcessData { 219 struct ProcessData {
219 ProcessData() = default; 220 ProcessData() = default;
220 ProcessData(ProcessData&&) = default; 221 ProcessData(ProcessData&&) = default;
221 222
222 int64_t physical_bytes; 223 int64_t physical_bytes;
224 base::Time start_time;
225 base::TimeDelta cpu_time;
223 std::vector<ThreadData> threads; 226 std::vector<ThreadData> threads;
224 227
225 private: 228 private:
226 DISALLOW_COPY_AND_ASSIGN(ProcessData); 229 DISALLOW_COPY_AND_ASSIGN(ProcessData);
227 }; 230 };
228 231
229 typedef std::map<base::ProcessId, ProcessData> ProcessDataMap; 232 typedef std::map<base::ProcessId, ProcessData> ProcessDataMap;
230 233
231 ULONG CountContextSwitchesDelta(const ProcessData& prev_process_data, 234 ULONG CountContextSwitchesDelta(const ProcessData& prev_process_data,
232 const ProcessData& new_process_data) { 235 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 309 // 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 310 // will be used to assert we're running the expensive operations on one of the
308 // blocking pool threads. 311 // blocking pool threads.
309 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 312 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
310 worker_pool_sequenced_checker_.DetachFromSequence(); 313 worker_pool_sequenced_checker_.DetachFromSequence();
311 } 314 }
312 315
313 SharedSampler::~SharedSampler() {} 316 SharedSampler::~SharedSampler() {}
314 317
315 int64_t SharedSampler::GetSupportedFlags() const { 318 int64_t SharedSampler::GetSupportedFlags() const {
316 return REFRESH_TYPE_IDLE_WAKEUPS | REFRESH_TYPE_PHYSICAL_MEMORY; 319 return REFRESH_TYPE_IDLE_WAKEUPS | REFRESH_TYPE_PHYSICAL_MEMORY |
320 REFRESH_TYPE_START_TIME | REFRESH_TYPE_CPU_TIME;
317 } 321 }
318 322
319 SharedSampler::Callbacks::Callbacks() {} 323 SharedSampler::Callbacks::Callbacks() {}
320 324
321 SharedSampler::Callbacks::~Callbacks() {} 325 SharedSampler::Callbacks::~Callbacks() {}
322 326
323 SharedSampler::Callbacks::Callbacks(Callbacks&& other) { 327 SharedSampler::Callbacks::Callbacks(Callbacks&& other) {
324 on_idle_wakeups = std::move(other.on_idle_wakeups); 328 on_idle_wakeups = std::move(other.on_idle_wakeups);
325 on_physical_memory = std::move(other.on_physical_memory); 329 on_physical_memory = std::move(other.on_physical_memory);
330 on_start_time = std::move(other.on_start_time);
331 on_cpu_time = std::move(other.on_cpu_time);
326 } 332 }
327 333
328 void SharedSampler::RegisterCallbacks( 334 void SharedSampler::RegisterCallbacks(
329 base::ProcessId process_id, 335 base::ProcessId process_id,
330 const OnIdleWakeupsCallback& on_idle_wakeups, 336 const OnIdleWakeupsCallback& on_idle_wakeups,
331 const OnPhysicalMemoryCallback& on_physical_memory) { 337 const OnPhysicalMemoryCallback& on_physical_memory,
338 const OnStartTimeCallback& on_start_time,
339 const OnCpuTimeCallback& on_cpu_time) {
332 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 340 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
333 341
334 if (process_id == 0) 342 if (process_id == 0)
335 return; 343 return;
336 344
337 Callbacks callbacks; 345 Callbacks callbacks;
338 callbacks.on_idle_wakeups = on_idle_wakeups; 346 callbacks.on_idle_wakeups = on_idle_wakeups;
339 callbacks.on_physical_memory = on_physical_memory; 347 callbacks.on_physical_memory = on_physical_memory;
348 callbacks.on_start_time = on_start_time;
349 callbacks.on_cpu_time = on_cpu_time;
340 bool result = callbacks_map_.insert( 350 bool result = callbacks_map_.insert(
341 std::make_pair(process_id, std::move(callbacks))).second; 351 std::make_pair(process_id, std::move(callbacks))).second;
342 DCHECK(result); 352 DCHECK(result);
343 } 353 }
344 354
345 void SharedSampler::UnregisterCallbacks(base::ProcessId process_id) { 355 void SharedSampler::UnregisterCallbacks(base::ProcessId process_id) {
346 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 356 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
347 357
348 if (process_id == 0) 358 if (process_id == 0)
349 return; 359 return;
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
426 base::FilePath::StringPieceType image_name) const { 436 base::FilePath::StringPieceType image_name) const {
427 for (const base::FilePath supported_name : supported_image_names_) { 437 for (const base::FilePath supported_name : supported_image_names_) {
428 if (base::FilePath::CompareEqualIgnoreCase(image_name, 438 if (base::FilePath::CompareEqualIgnoreCase(image_name,
429 supported_name.value())) 439 supported_name.value()))
430 return true; 440 return true;
431 } 441 }
432 442
433 return false; 443 return false;
434 } 444 }
435 445
446 namespace {
afakhry 2017/01/09 21:03:42 Nit: Usually we have a single anonymous namespace
chengx 2017/01/10 00:39:27 I have moved these two functions to the existing a
447 // A wrapper function converting ticks (in units of 100 ns) to Time.
448 base::Time ConvertTicksToTime(uint64_t ticks) {
449 FILETIME ft = bit_cast<FILETIME, uint64_t>(ticks);
450 return base::Time::FromFileTime(ft);
451 }
452
453 // A wrapper function converting ticks (in units of 100 ns) to TimeDelta.
454 base::TimeDelta ConvertTicksToTimeDelta(uint64_t ticks) {
455 return base::TimeDelta::FromMicroseconds(ticks / 10);
456 }
457 }
afakhry 2017/01/09 21:03:42 Nit: } // namespace
chengx 2017/01/10 00:39:27 Done.
458
436 std::unique_ptr<ProcessDataSnapshot> SharedSampler::CaptureSnapshot() { 459 std::unique_ptr<ProcessDataSnapshot> SharedSampler::CaptureSnapshot() {
437 DCHECK(worker_pool_sequenced_checker_.CalledOnValidSequence()); 460 DCHECK(worker_pool_sequenced_checker_.CalledOnValidSequence());
438 461
439 // Preallocate the buffer with the size determined on the previous call to 462 // Preallocate the buffer with the size determined on the previous call to
440 // QuerySystemProcessInformation. This should be sufficient most of the time. 463 // QuerySystemProcessInformation. This should be sufficient most of the time.
441 // QuerySystemProcessInformation will grow the buffer if necessary. 464 // QuerySystemProcessInformation will grow the buffer if necessary.
442 ByteBuffer data_buffer(previous_buffer_size_); 465 ByteBuffer data_buffer(previous_buffer_size_);
443 466
444 if (!QuerySystemProcessInformation(&data_buffer)) 467 if (!QuerySystemProcessInformation(&data_buffer))
445 return std::unique_ptr<ProcessDataSnapshot>(); 468 return std::unique_ptr<ProcessDataSnapshot>();
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
480 // terminated the total number of context switches for the process might 503 // terminated the total number of context switches for the process might
481 // go down and the delta would be negative. 504 // go down and the delta would be negative.
482 // To avoid that we need to compare thread IDs between two snapshots and 505 // 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 506 // not count context switches for threads that are missing in the most
484 // recent snapshot. 507 // recent snapshot.
485 ProcessData process_data; 508 ProcessData process_data;
486 509
487 process_data.physical_bytes = 510 process_data.physical_bytes =
488 static_cast<int64_t>(pi->WorkingSetPrivateSize); 511 static_cast<int64_t>(pi->WorkingSetPrivateSize);
489 512
513 process_data.start_time = ConvertTicksToTime(pi->CreateTime);
514
515 process_data.cpu_time =
516 ConvertTicksToTimeDelta(pi->KernelTime + pi->UserTime);
517
490 // Iterate over threads and store each thread's ID and number of context 518 // Iterate over threads and store each thread's ID and number of context
491 // switches. 519 // switches.
492 for (ULONG thread_index = 0; thread_index < pi->NumberOfThreads; 520 for (ULONG thread_index = 0; thread_index < pi->NumberOfThreads;
493 ++thread_index) { 521 ++thread_index) {
494 const SYSTEM_THREAD_INFORMATION* ti = &pi->Threads[thread_index]; 522 const SYSTEM_THREAD_INFORMATION* ti = &pi->Threads[thread_index];
495 if (ti->ClientId.UniqueProcess != pi->ProcessId) 523 if (ti->ClientId.UniqueProcess != pi->ProcessId)
496 continue; 524 continue;
497 525
498 ThreadData thread_data; 526 ThreadData thread_data;
499 thread_data.thread_id = static_cast<base::PlatformThreadId>( 527 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. 585 // Process is missing in the previous snapshot.
558 // Use entire number of context switches of the current process. 586 // Use entire number of context switches of the current process.
559 idle_wakeups_delta = CountContextSwitchesDelta(ProcessData(), process); 587 idle_wakeups_delta = CountContextSwitchesDelta(ProcessData(), process);
560 } 588 }
561 589
562 RefreshResult result; 590 RefreshResult result;
563 result.process_id = process_id; 591 result.process_id = process_id;
564 result.idle_wakeups_per_second = 592 result.idle_wakeups_per_second =
565 static_cast<int>(round(idle_wakeups_delta / time_delta)); 593 static_cast<int>(round(idle_wakeups_delta / time_delta));
566 result.physical_bytes = process.physical_bytes; 594 result.physical_bytes = process.physical_bytes;
595 result.start_time = process.start_time;
596 result.cpu_time = process.cpu_time;
567 results->push_back(result); 597 results->push_back(result);
568 } 598 }
569 } 599 }
570 600
571 void SharedSampler::MakeResultsFromSnapshot(const ProcessDataSnapshot& snapshot, 601 void SharedSampler::MakeResultsFromSnapshot(const ProcessDataSnapshot& snapshot,
572 RefreshResults* results) { 602 RefreshResults* results) {
573 for (const auto& pair : snapshot.processes) { 603 for (const auto& pair : snapshot.processes) {
574 RefreshResult result; 604 RefreshResult result;
575 result.process_id = pair.first; 605 result.process_id = pair.first;
576 // Use 0 for Idle Wakeups / sec in this case. This is consistent with 606 // Use 0 for Idle Wakeups / sec in this case. This is consistent with
577 // ProcessMetrics::CalculateIdleWakeupsPerSecond implementation. 607 // ProcessMetrics::CalculateIdleWakeupsPerSecond implementation.
578 result.idle_wakeups_per_second = 0; 608 result.idle_wakeups_per_second = 0;
579 result.physical_bytes = pair.second.physical_bytes; 609 result.physical_bytes = pair.second.physical_bytes;
610 result.start_time = pair.second.start_time;
611 result.cpu_time = pair.second.cpu_time;
580 results->push_back(result); 612 results->push_back(result);
581 } 613 }
582 } 614 }
583 615
584 void SharedSampler::OnRefreshDone( 616 void SharedSampler::OnRefreshDone(
585 std::unique_ptr<RefreshResults> refresh_results) { 617 std::unique_ptr<RefreshResults> refresh_results) {
586 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 618 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
587 DCHECK_NE(0, refresh_flags_); 619 DCHECK_NE(0, refresh_flags_);
588 620
589 size_t result_index = 0; 621 size_t result_index = 0;
590 622
591 for (const auto& callback_entry : callbacks_map_) { 623 for (const auto& callback_entry : callbacks_map_) {
592 base::ProcessId process_id = callback_entry.first; 624 base::ProcessId process_id = callback_entry.first;
593 // A sentinel value of -1 is used when the result isn't available. 625 // A sentinel value of -1 is used when the result isn't available.
594 // Task manager will use this to display 'N/A'. 626 // Task manager will use this to display '-'.
595 int idle_wakeups_per_second = -1; 627 int idle_wakeups_per_second = -1;
596 int64_t physical_bytes = -1; 628 int64_t physical_bytes = -1;
629 base::Time start_time;
630 base::TimeDelta cpu_time;
597 631
598 // Match refresh result by |process_id|. 632 // Match refresh result by |process_id|.
599 // This relies on refresh results being ordered by Process ID. 633 // This relies on refresh results being ordered by Process ID.
600 // Please note that |refresh_results| might contain some extra entries that 634 // 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 635 // 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 636 // 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 637 // between getting process information on the worker thread and adding a
604 // corresponding TaskGroup to the task manager. 638 // corresponding TaskGroup to the task manager.
605 for (; result_index < refresh_results->size(); ++result_index) { 639 for (; result_index < refresh_results->size(); ++result_index) {
606 const auto& result = (*refresh_results)[result_index]; 640 const auto& result = (*refresh_results)[result_index];
607 if (result.process_id == process_id) { 641 if (result.process_id == process_id) {
608 // Data matched in |refresh_results|. 642 // Data matched in |refresh_results|.
609 idle_wakeups_per_second = result.idle_wakeups_per_second; 643 idle_wakeups_per_second = result.idle_wakeups_per_second;
610 physical_bytes = result.physical_bytes; 644 physical_bytes = result.physical_bytes;
645 start_time = result.start_time;
646 cpu_time = result.cpu_time;
611 ++result_index; 647 ++result_index;
612 break; 648 break;
613 } 649 }
614 650
615 if (result.process_id > process_id) { 651 if (result.process_id > process_id) {
616 // An entry corresponding to |process_id| is missing. See above. 652 // An entry corresponding to |process_id| is missing. See above.
617 break; 653 break;
618 } 654 }
619 } 655 }
620 656
621 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_IDLE_WAKEUPS, 657 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_IDLE_WAKEUPS,
622 refresh_flags_)) { 658 refresh_flags_)) {
623 DCHECK(callback_entry.second.on_idle_wakeups); 659 DCHECK(callback_entry.second.on_idle_wakeups);
624 callback_entry.second.on_idle_wakeups.Run(idle_wakeups_per_second); 660 callback_entry.second.on_idle_wakeups.Run(idle_wakeups_per_second);
625 } 661 }
626 662
627 if (TaskManagerObserver::IsResourceRefreshEnabled( 663 if (TaskManagerObserver::IsResourceRefreshEnabled(
628 REFRESH_TYPE_PHYSICAL_MEMORY, refresh_flags_)) { 664 REFRESH_TYPE_PHYSICAL_MEMORY, refresh_flags_)) {
629 DCHECK(callback_entry.second.on_physical_memory); 665 DCHECK(callback_entry.second.on_physical_memory);
630 callback_entry.second.on_physical_memory.Run(physical_bytes); 666 callback_entry.second.on_physical_memory.Run(physical_bytes);
631 } 667 }
668
669 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_START_TIME,
670 refresh_flags_)) {
671 DCHECK(callback_entry.second.on_start_time);
672 callback_entry.second.on_start_time.Run(start_time);
673 }
674
675 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_CPU_TIME,
676 refresh_flags_)) {
677 DCHECK(callback_entry.second.on_cpu_time);
678 callback_entry.second.on_cpu_time.Run(cpu_time);
679 }
632 } 680 }
633 681
634 // Reset refresh_results_ to trigger RefreshOnWorkerThread next time Refresh 682 // Reset refresh_results_ to trigger RefreshOnWorkerThread next time Refresh
635 // is called. 683 // is called.
636 refresh_flags_ = 0; 684 refresh_flags_ = 0;
637 } 685 }
638 686
639 } // namespace task_manager 687 } // namespace task_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698