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

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: Fix nits and conflicts. Created 3 years, 11 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>
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 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 if ((*iter_to_advance)->first == process_id) { 280 if ((*iter_to_advance)->first == process_id) {
278 return &((*iter_to_advance)++)->second; 281 return &((*iter_to_advance)++)->second;
279 } 282 }
280 if ((*iter_to_advance)->first > process_id) 283 if ((*iter_to_advance)->first > process_id)
281 break; 284 break;
282 } 285 }
283 286
284 return nullptr; 287 return nullptr;
285 } 288 }
286 289
290 // A wrapper function converting ticks (in units of 100 ns) to Time.
291 base::Time ConvertTicksToTime(uint64_t ticks) {
292 FILETIME ft = bit_cast<FILETIME, uint64_t>(ticks);
293 return base::Time::FromFileTime(ft);
294 }
295
296 // A wrapper function converting ticks (in units of 100 ns) to TimeDelta.
297 base::TimeDelta ConvertTicksToTimeDelta(uint64_t ticks) {
298 return base::TimeDelta::FromMicroseconds(ticks / 10);
299 }
300
287 } // namespace 301 } // namespace
288 302
289 // ProcessDataSnapshot gets created and accessed only on the worker thread. 303 // ProcessDataSnapshot gets created and accessed only on the worker thread.
290 // This is used to calculate metrics like Idle Wakeups / sec that require 304 // This is used to calculate metrics like Idle Wakeups / sec that require
291 // a delta between two snapshots. 305 // a delta between two snapshots.
292 // Please note that ProcessDataSnapshot has to be outside of anonymous namespace 306 // Please note that ProcessDataSnapshot has to be outside of anonymous namespace
293 // in order to match the declaration in shared_sampler.h. 307 // in order to match the declaration in shared_sampler.h.
294 struct ProcessDataSnapshot { 308 struct ProcessDataSnapshot {
295 ProcessDataMap processes; 309 ProcessDataMap processes;
296 base::TimeTicks timestamp; 310 base::TimeTicks timestamp;
297 }; 311 };
298 312
299 SharedSampler::SharedSampler( 313 SharedSampler::SharedSampler(
300 const scoped_refptr<base::SequencedTaskRunner>& blocking_pool_runner) 314 const scoped_refptr<base::SequencedTaskRunner>& blocking_pool_runner)
301 : refresh_flags_(0), previous_buffer_size_(0), 315 : refresh_flags_(0), previous_buffer_size_(0),
302 supported_image_names_(GetSupportedImageNames()), 316 supported_image_names_(GetSupportedImageNames()),
303 blocking_pool_runner_(blocking_pool_runner) { 317 blocking_pool_runner_(blocking_pool_runner) {
304 DCHECK(blocking_pool_runner.get()); 318 DCHECK(blocking_pool_runner.get());
305 319
306 // This object will be created on the UI thread, however the sequenced checker 320 // 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 321 // will be used to assert we're running the expensive operations on one of the
308 // blocking pool threads. 322 // blocking pool threads.
309 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 323 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
310 worker_pool_sequenced_checker_.DetachFromSequence(); 324 worker_pool_sequenced_checker_.DetachFromSequence();
311 } 325 }
312 326
313 SharedSampler::~SharedSampler() {} 327 SharedSampler::~SharedSampler() {}
314 328
315 int64_t SharedSampler::GetSupportedFlags() const { 329 int64_t SharedSampler::GetSupportedFlags() const {
316 return REFRESH_TYPE_IDLE_WAKEUPS | REFRESH_TYPE_PHYSICAL_MEMORY; 330 return REFRESH_TYPE_IDLE_WAKEUPS | REFRESH_TYPE_PHYSICAL_MEMORY |
331 REFRESH_TYPE_START_TIME | REFRESH_TYPE_CPU_TIME;
317 } 332 }
318 333
319 SharedSampler::Callbacks::Callbacks() {} 334 SharedSampler::Callbacks::Callbacks() {}
320 335
321 SharedSampler::Callbacks::~Callbacks() {} 336 SharedSampler::Callbacks::~Callbacks() {}
322 337
323 SharedSampler::Callbacks::Callbacks(Callbacks&& other) { 338 SharedSampler::Callbacks::Callbacks(Callbacks&& other) {
324 on_idle_wakeups = std::move(other.on_idle_wakeups); 339 on_idle_wakeups = std::move(other.on_idle_wakeups);
325 on_physical_memory = std::move(other.on_physical_memory); 340 on_physical_memory = std::move(other.on_physical_memory);
341 on_start_time = std::move(other.on_start_time);
342 on_cpu_time = std::move(other.on_cpu_time);
326 } 343 }
327 344
328 void SharedSampler::RegisterCallbacks( 345 void SharedSampler::RegisterCallbacks(
329 base::ProcessId process_id, 346 base::ProcessId process_id,
330 const OnIdleWakeupsCallback& on_idle_wakeups, 347 const OnIdleWakeupsCallback& on_idle_wakeups,
331 const OnPhysicalMemoryCallback& on_physical_memory) { 348 const OnPhysicalMemoryCallback& on_physical_memory,
349 const OnStartTimeCallback& on_start_time,
350 const OnCpuTimeCallback& on_cpu_time) {
332 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 351 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
333 352
334 if (process_id == 0) 353 if (process_id == 0)
335 return; 354 return;
336 355
337 Callbacks callbacks; 356 Callbacks callbacks;
338 callbacks.on_idle_wakeups = on_idle_wakeups; 357 callbacks.on_idle_wakeups = on_idle_wakeups;
339 callbacks.on_physical_memory = on_physical_memory; 358 callbacks.on_physical_memory = on_physical_memory;
359 callbacks.on_start_time = on_start_time;
360 callbacks.on_cpu_time = on_cpu_time;
340 bool result = callbacks_map_.insert( 361 bool result = callbacks_map_.insert(
341 std::make_pair(process_id, std::move(callbacks))).second; 362 std::make_pair(process_id, std::move(callbacks))).second;
342 DCHECK(result); 363 DCHECK(result);
343 } 364 }
344 365
345 void SharedSampler::UnregisterCallbacks(base::ProcessId process_id) { 366 void SharedSampler::UnregisterCallbacks(base::ProcessId process_id) {
346 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 367 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
347 368
348 if (process_id == 0) 369 if (process_id == 0)
349 return; 370 return;
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
486 // terminated the total number of context switches for the process might 507 // terminated the total number of context switches for the process might
487 // go down and the delta would be negative. 508 // go down and the delta would be negative.
488 // To avoid that we need to compare thread IDs between two snapshots and 509 // To avoid that we need to compare thread IDs between two snapshots and
489 // not count context switches for threads that are missing in the most 510 // not count context switches for threads that are missing in the most
490 // recent snapshot. 511 // recent snapshot.
491 ProcessData process_data; 512 ProcessData process_data;
492 513
493 process_data.physical_bytes = 514 process_data.physical_bytes =
494 static_cast<int64_t>(pi->WorkingSetPrivateSize); 515 static_cast<int64_t>(pi->WorkingSetPrivateSize);
495 516
517 process_data.start_time = ConvertTicksToTime(pi->CreateTime);
518
519 process_data.cpu_time =
520 ConvertTicksToTimeDelta(pi->KernelTime + pi->UserTime);
521
496 // Iterate over threads and store each thread's ID and number of context 522 // Iterate over threads and store each thread's ID and number of context
497 // switches. 523 // switches.
498 for (ULONG thread_index = 0; thread_index < pi->NumberOfThreads; 524 for (ULONG thread_index = 0; thread_index < pi->NumberOfThreads;
499 ++thread_index) { 525 ++thread_index) {
500 const SYSTEM_THREAD_INFORMATION* ti = &pi->Threads[thread_index]; 526 const SYSTEM_THREAD_INFORMATION* ti = &pi->Threads[thread_index];
501 if (ti->ClientId.UniqueProcess != pi->ProcessId) 527 if (ti->ClientId.UniqueProcess != pi->ProcessId)
502 continue; 528 continue;
503 529
504 ThreadData thread_data; 530 ThreadData thread_data;
505 thread_data.thread_id = static_cast<base::PlatformThreadId>( 531 thread_data.thread_id = static_cast<base::PlatformThreadId>(
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
563 // Process is missing in the previous snapshot. 589 // Process is missing in the previous snapshot.
564 // Use entire number of context switches of the current process. 590 // Use entire number of context switches of the current process.
565 idle_wakeups_delta = CountContextSwitchesDelta(ProcessData(), process); 591 idle_wakeups_delta = CountContextSwitchesDelta(ProcessData(), process);
566 } 592 }
567 593
568 RefreshResult result; 594 RefreshResult result;
569 result.process_id = process_id; 595 result.process_id = process_id;
570 result.idle_wakeups_per_second = 596 result.idle_wakeups_per_second =
571 static_cast<int>(round(idle_wakeups_delta / time_delta)); 597 static_cast<int>(round(idle_wakeups_delta / time_delta));
572 result.physical_bytes = process.physical_bytes; 598 result.physical_bytes = process.physical_bytes;
599 result.start_time = process.start_time;
600 result.cpu_time = process.cpu_time;
573 results->push_back(result); 601 results->push_back(result);
574 } 602 }
575 } 603 }
576 604
577 void SharedSampler::MakeResultsFromSnapshot(const ProcessDataSnapshot& snapshot, 605 void SharedSampler::MakeResultsFromSnapshot(const ProcessDataSnapshot& snapshot,
578 RefreshResults* results) { 606 RefreshResults* results) {
579 for (const auto& pair : snapshot.processes) { 607 for (const auto& pair : snapshot.processes) {
580 RefreshResult result; 608 RefreshResult result;
581 result.process_id = pair.first; 609 result.process_id = pair.first;
582 // Use 0 for Idle Wakeups / sec in this case. This is consistent with 610 // Use 0 for Idle Wakeups / sec in this case. This is consistent with
583 // ProcessMetrics::CalculateIdleWakeupsPerSecond implementation. 611 // ProcessMetrics::CalculateIdleWakeupsPerSecond implementation.
584 result.idle_wakeups_per_second = 0; 612 result.idle_wakeups_per_second = 0;
585 result.physical_bytes = pair.second.physical_bytes; 613 result.physical_bytes = pair.second.physical_bytes;
614 result.start_time = pair.second.start_time;
615 result.cpu_time = pair.second.cpu_time;
586 results->push_back(result); 616 results->push_back(result);
587 } 617 }
588 } 618 }
589 619
590 void SharedSampler::OnRefreshDone( 620 void SharedSampler::OnRefreshDone(
591 std::unique_ptr<RefreshResults> refresh_results) { 621 std::unique_ptr<RefreshResults> refresh_results) {
592 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 622 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
593 DCHECK_NE(0, refresh_flags_); 623 DCHECK_NE(0, refresh_flags_);
594 624
595 size_t result_index = 0; 625 size_t result_index = 0;
596 626
597 for (const auto& callback_entry : callbacks_map_) { 627 for (const auto& callback_entry : callbacks_map_) {
598 base::ProcessId process_id = callback_entry.first; 628 base::ProcessId process_id = callback_entry.first;
599 // A sentinel value of -1 is used when the result isn't available. 629 // A sentinel value of -1 is used when the result isn't available.
600 // Task manager will use this to display 'N/A'. 630 // Task manager will use this to display '-'.
601 int idle_wakeups_per_second = -1; 631 int idle_wakeups_per_second = -1;
602 int64_t physical_bytes = -1; 632 int64_t physical_bytes = -1;
633 base::Time start_time;
634 base::TimeDelta cpu_time;
603 635
604 // Match refresh result by |process_id|. 636 // Match refresh result by |process_id|.
605 // This relies on refresh results being ordered by Process ID. 637 // This relies on refresh results being ordered by Process ID.
606 // Please note that |refresh_results| might contain some extra entries that 638 // Please note that |refresh_results| might contain some extra entries that
607 // don't exist in |callbacks_map_| if there is more than one instance of 639 // don't exist in |callbacks_map_| if there is more than one instance of
608 // Chrome. It might be missing some entries too if there is a race condition 640 // Chrome. It might be missing some entries too if there is a race condition
609 // between getting process information on the worker thread and adding a 641 // between getting process information on the worker thread and adding a
610 // corresponding TaskGroup to the task manager. 642 // corresponding TaskGroup to the task manager.
611 for (; result_index < refresh_results->size(); ++result_index) { 643 for (; result_index < refresh_results->size(); ++result_index) {
612 const auto& result = (*refresh_results)[result_index]; 644 const auto& result = (*refresh_results)[result_index];
613 if (result.process_id == process_id) { 645 if (result.process_id == process_id) {
614 // Data matched in |refresh_results|. 646 // Data matched in |refresh_results|.
615 idle_wakeups_per_second = result.idle_wakeups_per_second; 647 idle_wakeups_per_second = result.idle_wakeups_per_second;
616 physical_bytes = result.physical_bytes; 648 physical_bytes = result.physical_bytes;
649 start_time = result.start_time;
650 cpu_time = result.cpu_time;
617 ++result_index; 651 ++result_index;
618 break; 652 break;
619 } 653 }
620 654
621 if (result.process_id > process_id) { 655 if (result.process_id > process_id) {
622 // An entry corresponding to |process_id| is missing. See above. 656 // An entry corresponding to |process_id| is missing. See above.
623 break; 657 break;
624 } 658 }
625 } 659 }
626 660
627 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_IDLE_WAKEUPS, 661 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_IDLE_WAKEUPS,
628 refresh_flags_)) { 662 refresh_flags_)) {
629 DCHECK(callback_entry.second.on_idle_wakeups); 663 DCHECK(callback_entry.second.on_idle_wakeups);
630 callback_entry.second.on_idle_wakeups.Run(idle_wakeups_per_second); 664 callback_entry.second.on_idle_wakeups.Run(idle_wakeups_per_second);
631 } 665 }
632 666
633 if (TaskManagerObserver::IsResourceRefreshEnabled( 667 if (TaskManagerObserver::IsResourceRefreshEnabled(
634 REFRESH_TYPE_PHYSICAL_MEMORY, refresh_flags_)) { 668 REFRESH_TYPE_PHYSICAL_MEMORY, refresh_flags_)) {
635 DCHECK(callback_entry.second.on_physical_memory); 669 DCHECK(callback_entry.second.on_physical_memory);
636 callback_entry.second.on_physical_memory.Run(physical_bytes); 670 callback_entry.second.on_physical_memory.Run(physical_bytes);
637 } 671 }
672
673 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_START_TIME,
674 refresh_flags_)) {
675 DCHECK(callback_entry.second.on_start_time);
676 callback_entry.second.on_start_time.Run(start_time);
677 }
678
679 if (TaskManagerObserver::IsResourceRefreshEnabled(REFRESH_TYPE_CPU_TIME,
680 refresh_flags_)) {
681 DCHECK(callback_entry.second.on_cpu_time);
682 callback_entry.second.on_cpu_time.Run(cpu_time);
683 }
638 } 684 }
639 685
640 // Reset refresh_results_ to trigger RefreshOnWorkerThread next time Refresh 686 // Reset refresh_results_ to trigger RefreshOnWorkerThread next time Refresh
641 // is called. 687 // is called.
642 refresh_flags_ = 0; 688 refresh_flags_ = 0;
643 } 689 }
644 690
645 } // namespace task_manager 691 } // 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