| <!DOCTYPE html> |
| <!-- |
| Copyright 2015 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="import" href="/perf_insights/mre/function_handle.html"> |
| <link rel="import" href="/tracing/base/math/range.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tr.exportTo('pie', function() { |
| // Conservative estimate: if we hadn't been doing anything for 1ms, we |
| // probably needed to wake up the CPU for this. |
| // TODO(skyostil): Augment this with CPU power management states. |
| var IDLE_THRESHOLD_MILLISECONDS = 1; |
| |
| function sanitizeReason(reason) { |
| // Remove any path name components (e.g., '/foo/bar/baz' or 'c:\foo\bar\baz' |
| // are both reduced to 'baz'). |
| return reason.replace(/^.*[\/\\]/, ''); |
| } |
| |
| function findWakeUpReason(event) { |
| var tqmRunTask = event.findDescendentSlice('TaskQueueManager::RunTask'); |
| if (tqmRunTask && tqmRunTask.subSlices.length > 0) |
| return tqmRunTask.subSlices[0].title; |
| var processTask = |
| event.findDescendentSlice('TaskQueueManager::ProcessTaskFromWorkQueue'); |
| if (processTask && |
| processTask.args.src_file && |
| processTask.args.src_func) { |
| return processTask.args.src_file + ':' + processTask.args.src_func; |
| } |
| if (event.title === 'MessageLoop::RunTask' && |
| event.args.src_file && |
| event.args.src_func) { |
| return event.args.src_file + ':' + event.args.src_func; |
| } |
| return event.title; |
| } |
| |
| // Estimate number of times the CPU was woken up from idle to execute |
| // different types of work (e.g., timer work) and the time the CPU had been |
| // idle before that. |
| // See https://goo.gl/l7V5xg. |
| function findWakeUpsOnThread(thread) { |
| var wakeUps = {}; |
| var foundWakeUps = false; |
| var lastTaskEnd = undefined; |
| for (var event of thread.getDescendantEvents()) { |
| if (!event.isTopLevel) |
| continue; |
| var taskEnd = event.start + event.duration; |
| if (lastTaskEnd === undefined) { |
| lastTaskEnd = taskEnd; |
| continue; |
| } |
| var sleepTime = event.start - lastTaskEnd; |
| var isWakeUp = sleepTime >= IDLE_THRESHOLD_MILLISECONDS; |
| lastTaskEnd = taskEnd; |
| if (!isWakeUp) |
| continue; |
| var reason = sanitizeReason(findWakeUpReason(event)); |
| if (wakeUps[reason] === undefined) |
| wakeUps[reason] = {frequency: 0, sleepTimes: []}; |
| wakeUps[reason].frequency++; |
| wakeUps[reason].sleepTimes.push(sleepTime); |
| foundWakeUps = true; |
| } |
| return foundWakeUps ? wakeUps : undefined; |
| } |
| |
| function updateThreadWakeUps(existingWakeUps, newWakeUps) { |
| for (var reason in newWakeUps) { |
| if (!(reason in existingWakeUps)) { |
| existingWakeUps[reason] = newWakeUps[reason]; |
| continue; |
| } |
| existingWakeUps[reason].frequency += newWakeUps[reason].frequency; |
| existingWakeUps[reason].sleepTimes = |
| existingWakeUps[reason].sleepTimes.concat( |
| newWakeUps[reason].sleepTimes); |
| } |
| } |
| |
| function mapWakeUps(result, model) { |
| var allWakeUps = {}; |
| for (var pid in model.processes) { |
| var process = model.processes[pid]; |
| for (var tid in process.threads) { |
| var thread = process.threads[tid]; |
| var wakeUps = findWakeUpsOnThread(thread); |
| if (!wakeUps === undefined) |
| continue; |
| if (!(thread.name in allWakeUps)) |
| allWakeUps[thread.name] = {}; |
| updateThreadWakeUps(allWakeUps[thread.name], wakeUps); |
| } |
| } |
| |
| // Normalize frequency to wake-ups/second. |
| // Note: if we found any wake-ups, the total duration of the trace is |
| // guaranteed to be positive. |
| var totalDurationSeconds = model.bounds.duration / 1000; |
| var foundAnyWakeUps = false; |
| for (var thread in allWakeUps) { |
| var threadWakeUps = allWakeUps[thread]; |
| for (var reason in threadWakeUps) { |
| threadWakeUps[reason].frequency /= totalDurationSeconds; |
| foundAnyWakeUps = true; |
| } |
| } |
| |
| if (!foundAnyWakeUps) { |
| result.addPair('wakeUps', null); |
| return; |
| } |
| |
| result.addPair('wakeUps', allWakeUps); |
| } |
| |
| pi.FunctionRegistry.register(mapWakeUps); |
| |
| return { |
| mapWakeUpsForTest: mapWakeUps |
| }; |
| }); |
| </script> |