diff options
author | sleffler@chromium.org <sleffler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-07 04:19:09 +0000 |
---|---|---|
committer | sleffler@chromium.org <sleffler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-07 04:19:09 +0000 |
commit | 51bf2e11cf97a7d894eddd00622519fa373f2846 (patch) | |
tree | 0812a740722fa7e84a78c747665e9315e1577d70 | |
parent | 34d66d740438922899aab2fba51fcc59a23b8c37 (diff) | |
download | chromium_src-51bf2e11cf97a7d894eddd00622519fa373f2846.zip chromium_src-51bf2e11cf97a7d894eddd00622519fa373f2846.tar.gz chromium_src-51bf2e11cf97a7d894eddd00622519fa373f2846.tar.bz2 |
Add system event tracing to about:tracing
Add support for system events to about:tracing. System events are
collected outside of chrome and integrated into the event stream.
System events are saved+loaded together with the chrome events collected
at the same time.
System event collection is done for Chrome OS via the debugd service.
BUG=chromium-os:27809
TEST=exercise about:tracing on chrome os and linux (for chrome os build on !chrome os)
Change-Id: Ifb6c9a575d10653c4848000db33afe34635dfb61
Review URL: http://codereview.chromium.org/9702090
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@131247 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/resources/tracing/linux_perf_importer.js | 306 | ||||
-rw-r--r-- | chrome/browser/resources/tracing/linux_perf_importer_test.html | 98 | ||||
-rw-r--r-- | chrome/browser/resources/tracing/profiling_view.js | 29 | ||||
-rw-r--r-- | chrome/browser/resources/tracing/timeline_model.js | 14 | ||||
-rw-r--r-- | chrome/browser/resources/tracing/tracing_controller.js | 42 | ||||
-rw-r--r-- | chrome/browser/ui/webui/tracing_ui.cc | 67 |
6 files changed, 415 insertions, 141 deletions
diff --git a/chrome/browser/resources/tracing/linux_perf_importer.js b/chrome/browser/resources/tracing/linux_perf_importer.js index dff1bf84..c7bbb15 100644 --- a/chrome/browser/resources/tracing/linux_perf_importer.js +++ b/chrome/browser/resources/tracing/linux_perf_importer.js @@ -163,12 +163,18 @@ cr.define('tracing', function() { /** * @return {TimelinThread} A thread corresponding to the kernelThreadName. */ - getOrCreateKernelThread: function(kernelThreadName) { + getOrCreateKernelThread: function(kernelThreadName, opt_pid, opt_tid) { if (!this.kernelThreadStates_[kernelThreadName]) { - var pid = /.+-(\d+)/.exec(kernelThreadName)[1]; - pid = parseInt(pid); + var pid = opt_pid; + if (pid == undefined) { + pid = /.+-(\d+)/.exec(kernelThreadName)[1]; + pid = parseInt(pid, 10); + } + var tid = opt_tid; + if (tid == undefined) + tid = pid; - var thread = this.model_.getOrCreateProcess(pid).getOrCreateThread(pid); + var thread = this.model_.getOrCreateProcess(pid).getOrCreateThread(tid); thread.name = kernelThreadName; this.kernelThreadStates_[kernelThreadName] = { pid: pid, @@ -383,118 +389,194 @@ cr.define('tracing', function() { var eventName = eventBase[4]; - if (eventName == 'sched_switch') { - var event = schedSwitchRE.exec(eventBase[5]); - if (!event) { - this.model_.importErrors.push('Line ' + (lineNumber + 1) + - ': Malformed sched_switch event'); - continue; - } - - var prevState = event[4]; - var nextComm = event[5]; - var nextPid = parseInt(event[6]); - var nextPrio = parseInt(event[7]); - cpuState.switchRunningLinuxPid( - this, prevState, ts, nextPid, nextComm, nextPrio); - - } else if (eventName == 'sched_wakeup') { - var event = schedWakeupRE.exec(eventBase[5]); - if (!event) { - this.model_.importErrors.push('Line ' + (lineNumber + 1) + - ': Malformed sched_wakeup event'); - continue; - } - - var comm = event[1]; - var pid = parseInt(event[2]); - var prio = parseInt(event[3]); - this.markPidRunnable(ts, pid, comm, prio); - - } else if (eventName == 'power_start') { - var event = /type=(\d+) state=(\d) cpu_id=(\d)+/.exec(eventBase[5]); - if (!event) { - this.model_.importErrors.push('Line ' + (lineNumber + 1) + - ': Malformed power_start event'); - continue; - } - var targetCpuNumber = parseInt(event[3]); - var targetCpu = this.getOrCreateCpuState(targetCpuNumber); - var powerCounter; - if (event[1] == '1') { - powerCounter = targetCpu.cpu.getOrCreateCounter('', 'C-State'); - } else { - this.model_.importErrors.push('Line ' + (lineNumber + 1) + - ': Don\'t understand power_start events of type ' + event[1]); - continue; - } - if (powerCounter.numSeries == 0) { - powerCounter.seriesNames.push('state'); - powerCounter.seriesColors.push( - tracing.getStringColorId(powerCounter.name + '.' + 'state')); - } - var powerState = parseInt(event[2]); - powerCounter.timestamps.push(ts); - powerCounter.samples.push(powerState); - } else if (eventName == 'power_frequency') { - var event = /type=(\d+) state=(\d+) cpu_id=(\d)+/.exec(eventBase[5]); - if (!event) { - this.model_.importErrors.push('Line ' + (lineNumber + 1) + - ': Malformed power_start event'); - continue; - } - var targetCpuNumber = parseInt(event[3]); - var targetCpu = this.getOrCreateCpuState(targetCpuNumber); - var powerCounter = - targetCpu.cpu.getOrCreateCounter('', 'Power Frequency'); - if (powerCounter.numSeries == 0) { - powerCounter.seriesNames.push('state'); - powerCounter.seriesColors.push( - tracing.getStringColorId(powerCounter.name + '.' + 'state')); - } - var powerState = parseInt(event[2]); - powerCounter.timestamps.push(ts); - powerCounter.samples.push(powerState); - } else if (eventName == 'workqueue_execute_start') { - var event = workqueueExecuteStartRE.exec(eventBase[5]); - if (!event) { - this.model_.importErrors.push('Line ' + (lineNumber + 1) + - ': Malformed workqueue_execute_start event'); - continue; - } - var kthread = this.getOrCreateKernelThread(eventBase[1]); - kthread.openSliceTS = ts; - kthread.openSlice = event[2]; - - } else if (eventName == 'workqueue_execute_end') { - var event = workqueueExecuteEndRE.exec(eventBase[5]); - if (!event) { - this.model_.importErrors.push('Line ' + (lineNumber + 1) + - ': Malformed workqueue_execute_start event'); - continue; - } - var kthread = this.getOrCreateKernelThread(eventBase[1]); - if (kthread.openSlice) { + switch (eventName) { + case 'sched_switch': + var event = schedSwitchRE.exec(eventBase[5]); + if (!event) { + this.model_.importErrors.push('Line ' + (lineNumber + 1) + + ': Malformed sched_switch event'); + continue; + } + + var prevState = event[4]; + var nextComm = event[5]; + var nextPid = parseInt(event[6]); + var nextPrio = parseInt(event[7]); + cpuState.switchRunningLinuxPid( + this, prevState, ts, nextPid, nextComm, nextPrio); + break; + case 'sched_wakeup': + var event = schedWakeupRE.exec(eventBase[5]); + if (!event) { + this.model_.importErrors.push('Line ' + (lineNumber + 1) + + ': Malformed sched_wakeup event'); + continue; + } + + var comm = event[1]; + var pid = parseInt(event[2]); + var prio = parseInt(event[3]); + this.markPidRunnable(ts, pid, comm, prio); + break; + case 'power_start': + var event = /type=(\d+) state=(\d) cpu_id=(\d)+/.exec(eventBase[5]); + if (!event) { + this.model_.importErrors.push('Line ' + (lineNumber + 1) + + ': Malformed power_start event'); + continue; + } + var targetCpuNumber = parseInt(event[3]); + var targetCpu = this.getOrCreateCpuState(targetCpuNumber); + var powerCounter; + if (event[1] == '1') { + powerCounter = targetCpu.cpu.getOrCreateCounter('', 'C-State'); + } else { + this.model_.importErrors.push('Line ' + (lineNumber + 1) + + ': Don\'t understand power_start events of type ' + event[1]); + continue; + } + if (powerCounter.numSeries == 0) { + powerCounter.seriesNames.push('state'); + powerCounter.seriesColors.push( + tracing.getStringColorId(powerCounter.name + '.' + 'state')); + } + var powerState = parseInt(event[2]); + powerCounter.timestamps.push(ts); + powerCounter.samples.push(powerState); + break; + case 'power_frequency': + var event = /type=(\d+) state=(\d+) cpu_id=(\d)+/. + exec(eventBase[5]); + if (!event) { + this.model_.importErrors.push('Line ' + (lineNumber + 1) + + ': Malformed power_start event'); + continue; + } + var targetCpuNumber = parseInt(event[3]); + var targetCpu = this.getOrCreateCpuState(targetCpuNumber); + var powerCounter = + targetCpu.cpu.getOrCreateCounter('', 'Power Frequency'); + if (powerCounter.numSeries == 0) { + powerCounter.seriesNames.push('state'); + powerCounter.seriesColors.push( + tracing.getStringColorId(powerCounter.name + '.' + 'state')); + } + var powerState = parseInt(event[2]); + powerCounter.timestamps.push(ts); + powerCounter.samples.push(powerState); + break; + case 'workqueue_execute_start': + var event = workqueueExecuteStartRE.exec(eventBase[5]); + if (!event) { + this.model_.importErrors.push('Line ' + (lineNumber + 1) + + ': Malformed workqueue_execute_start event'); + continue; + } + var kthread = this.getOrCreateKernelThread(eventBase[1]); + kthread.openSliceTS = ts; + kthread.openSlice = event[2]; + break; + case 'workqueue_execute_end': + var event = workqueueExecuteEndRE.exec(eventBase[5]); + if (!event) { + this.model_.importErrors.push('Line ' + (lineNumber + 1) + + ': Malformed workqueue_execute_start event'); + continue; + } + var kthread = this.getOrCreateKernelThread(eventBase[1]); + if (kthread.openSlice) { + var slice = new tracing.TimelineSlice(kthread.openSlice, + tracing.getStringColorId(kthread.openSlice), + kthread.openSliceTS, + {}, + ts - kthread.openSliceTS); + + kthread.thread.subRows[0].push(slice); + } + kthread.openSlice = undefined; + break; + case 'i915_gem_object_pwrite': + var event = /obj=(.+), offset=(\d+), len=(\d+)/.exec(eventBase[5]); + if (!event) { + this.model_.importErrors.push('Line ' + (lineNumber + 1) + + ': Malformed ' + eventName + ' event'); + continue; + } + + var obj = event[1]; + var offset = parseInt(event[2]); + var len = parseInt(event[3]); + var kthread = this.getOrCreateKernelThread('i915_gem', 0, 1); + kthread.openSlice = 'pwrite:' + obj; var slice = new tracing.TimelineSlice(kthread.openSlice, tracing.getStringColorId(kthread.openSlice), - kthread.openSliceTS, - {}, - ts - kthread.openSliceTS); + ts, + { + obj: obj, + offset: offset, + len: len + }, 0); kthread.thread.subRows[0].push(slice); - } - kthread.openSlice = undefined; - - } else if (eventName == '0') { // trace_mark's show up with 0 prefixes. - var event = traceEventClockSyncRE.exec(eventBase[5]); - if (event) - this.clockSyncRecords_.push({ - perfTS: ts, - parentTS: event[1] * 1000 - }); - else - this.model_.importErrors.push('Line ' + (lineNumber + 1) + - ': Unrecognized event: ' + eventBase[5]); + break; + case 'i915_flip_request': + var event = /plane=(\d+), obj=(.+)/.exec(eventBase[5]); + if (!event) { + this.model_.importErrors.push('Line ' + (lineNumber + 1) + + ': Malformed ' + eventName + ' event'); + continue; + } + + var plane = parseInt(event[1]); + var obj = event[2]; + // use i915_obj_plane? + var kthread = this.getOrCreateKernelThread('i915_flip', 0, 2); + kthread.openSliceTS = ts; + kthread.openSlice = 'flip:' + obj + '/' + plane; + break; + case 'i915_flip_complete': + var event = /plane=(\d+), obj=(.+)/.exec(eventBase[5]); + if (!event) { + this.model_.importErrors.push('Line ' + (lineNumber + 1) + + ': Malformed ' + eventName + ' event'); + continue; + } + + var plane = parseInt(event[1]); + var obj = event[2]; + // use i915_obj_plane? + var kthread = this.getOrCreateKernelThread('i915_flip', 0, 2); + if (kthread.openSlice) { + var slice = new tracing.TimelineSlice(kthread.openSlice, + tracing.getStringColorId(kthread.openSlice), + kthread.openSliceTS, + { + obj: obj, + plane: plane, + }, + ts - kthread.openSliceTS); + + kthread.thread.subRows[0].push(slice); + } + kthread.openSlice = undefined; + break; + case '0': + case 'tracing_mark_write': + // trace_mark's show up with 0 prefixes in older kernels; in + // newer linux kernels they are demarcated by tracing_mark_write. + var event = traceEventClockSyncRE.exec(eventBase[5]); + if (event) + this.clockSyncRecords_.push({ + perfTS: ts, + parentTS: event[1] * 1000 + }); + else + this.model_.importErrors.push('Line ' + (lineNumber + 1) + + ': Unrecognized event: ' + eventBase[5]); + break; + default: + console.log('unknown event ' + eventName); + break; } } } diff --git a/chrome/browser/resources/tracing/linux_perf_importer_test.html b/chrome/browser/resources/tracing/linux_perf_importer_test.html index ccdac64..b9b5b8b 100644 --- a/chrome/browser/resources/tracing/linux_perf_importer_test.html +++ b/chrome/browser/resources/tracing/linux_perf_importer_test.html @@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <!-- -Copyright (c) 2011 The Chromium Authors. All rights reserved. +Copyright (c) 2012 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. --> @@ -91,7 +91,7 @@ function testTraceEventClockSyncRE() { } function testCanImport() { - lines = [ + var lines = [ '# tracer: nop', '#', '# TASK-PID CPU# TIMESTAMP FUNCTION', @@ -114,14 +114,14 @@ function testCanImport() { ]; assertTrue(tracing.LinuxPerfImporter.canImport(lines.join('\n'))); - lines = [ + var lines = [ ' <idle>-0 [001] 4467.843475: sched_switch: ' + 'prev_comm=swapper prev_pid=0 prev_prio=120 prev_state=R ==> ' + 'next_comm=SurfaceFlinger next_pid=178 next_prio=112' ]; assertTrue(tracing.LinuxPerfImporter.canImport(lines.join('\n'))); - lines = [ + var lines = [ ' <idle>-0 [001] 4467.843475: sched_switch: ' + 'prev_comm=swapper prev_pid=0 prev_prio=120 prev_state=R ==> ' + 'next_comm=SurfaceFlinger next_pid=178 next_prio=112', @@ -133,7 +133,7 @@ function testCanImport() { ]; assertTrue(tracing.LinuxPerfImporter.canImport(lines.join('\n'))); - lines = [ + var lines = [ 'SomeRandomText', 'More random text' ]; @@ -141,7 +141,7 @@ function testCanImport() { } function testImportOneSequence() { - lines = [ + var lines = [ ' <idle>-0 [001] 4467.843475: sched_switch: ' + 'prev_comm=swapper prev_pid=0 prev_prio=120 prev_state=R ==> ' + 'next_comm=SurfaceFlinger next_pid=178 next_prio=112', @@ -171,7 +171,7 @@ function testImportOneSequenceWithSchedWakeUp() { } function testImportWithNewline() { - lines = [ + var lines = [ '' ]; var m = new tracing.TimelineModel(lines.join('\n')); @@ -179,7 +179,7 @@ function testImportWithNewline() { } function testClockSync() { - lines = [ + var lines = [ ' <idle>-0 [001] 4467.843475: sched_switch: ' + 'prev_comm=swapper prev_pid=0 prev_prio=120 prev_state=R ' + '==> next_comm=SurfaceFlinger next_pid=178 next_prio=112', @@ -203,16 +203,98 @@ function testClockSync() { assertAlmostEquals((467.843475 - 467.843) * 1000, c.slices[0].start); } +function testClockSyncMarkWrite() { + var lines = [ + 'systrace.sh-8170 [001] 15180.978813: sched_switch: ' + + 'prev_comm=systrace.sh prev_pid=8170 prev_prio=120 ' + + 'prev_state=x ==> next_comm=kworker/1:0 next_pid=7873 ' + + 'next_prio=120', + ' kworker/1:0-7873 [001] 15180.978836: sched_switch: ' + + 'prev_comm=kworker/1:0 prev_pid=7873 prev_prio=120 ' + + 'prev_state=S ==> next_comm=debugd next_pid=4404 next_prio=120', + ' debugd-4404 [001] 15180.979010: sched_switch: prev_comm=debugd ' + + 'prev_pid=4404 prev_prio=120 prev_state=S ==> ' + + 'next_comm=dbus-daemon next_pid=510 next_prio=120', + 'systrace.sh-8182 [000] 15186.203900: tracing_mark_write: ' + + 'trace_event_clock_sync: parent_ts=0.0' + ]; + var m = new tracing.TimelineModel(lines.join('\n'), false); + assertEquals(0, m.importErrors.length); + + var c = m.cpus[1]; + assertEquals(2, c.slices.length); + + assertAlmostEquals((5180.978813 - 5186.2039) * 1000, c.slices[0].start); +} + + function testImportWithoutClockSyncDeletesEverything() { } function testWorkQueueImport() { + var lines = [ + 'kworker/0:3-6880 [000] 2784.771958: workqueue_execute_start: ' + + 'work struct ffff8800a5083a20: function intel_unpin_work_fn', + 'kworker/0:3-6880 [000] 2784.771966: workqueue_execute_end: ' + + 'work struct ffff8800a5083a20', + 'kworker/1:2-7269 [001] 2784.805966: workqueue_execute_start: ' + + 'work struct ffff88014fb0f158: function do_dbs_timer', + 'kworker/1:2-7269 [001] 2784.805975: workqueue_execute_end: ' + + 'work struct ffff88014fb0f158' + ]; + var m = new tracing.TimelineModel(lines.join('\n'), false); + assertEquals(0, m.importErrors.length); + + assertEquals(1, m.processes['6880'].threads['6880'].subRows.length); + assertEquals(1, m.processes['7269'].threads['7269'].subRows.length); } function testPowerStartImport() { } function testCpuFrequencyImport() { + var lines = [ + 'kworker/0:3-6880 [000] 2784.783015: power_frequency: ' + + 'type=2 state=1000000 cpu_id=0', + 'kworker/1:2-7269 [001] 2784.788993: power_frequency: ' + + 'type=2 state=800000 cpu_id=1', + 'kworker/1:2-7269 [001] 2784.993120: power_frequency: ' + + 'type=2 state=1300000 cpu_id=1' + ]; + var m = new tracing.TimelineModel(lines.join('\n'), false); + assertEquals(0, m.importErrors.length); + + var c0 = m.cpus[0]; + assertEquals(0, c0.slices.length); + assertEquals(1, c0.counters['Power Frequency'].samples.length); + + var c1 = m.cpus[1]; + assertEquals(0, c1.slices.length); + assertEquals(2, c1.counters['Power Frequency'].samples.length); +} + +function testi915Import() { + var lines = [ + ' chrome-1223 [000] 2784.773556: i915_gem_object_pwrite: ' + + 'obj=ffff88013f13fc00, offset=0, len=2984', + ' X-964 [000] 2784.774864: i915_flip_request: ' + + 'plane=0, obj=ffff88013f0b9a00', + ' <idle>-0 [000] 2784.788644: i915_flip_complete: ' + + 'plane=0, obj=ffff88013f0b9a00' + ]; + var m = new tracing.TimelineModel(lines.join('\n'), false); + assertEquals(0, m.importErrors.length); + + assertEquals('i915_gem', m.processes['0'].threads['1'].name); + assertEquals(1, m.processes['0'].threads['1'].subRows.length); + + assertEquals('i915_flip', m.processes['0'].threads['2'].name); + assertEquals(1, m.processes['0'].threads['1'].subRows.length); + + assertAlmostEquals(2784.774864 * 1000.0, + m.processes['0'].threads['2'].subRows[0][0].start); + assertAlmostEquals((2784.788644 - 2784.774864) * 1000.0, + m.processes['0'].threads['2'].subRows[0][0].duration); } </script> diff --git a/chrome/browser/resources/tracing/profiling_view.js b/chrome/browser/resources/tracing/profiling_view.js index 154f894..0e33878 100644 --- a/chrome/browser/resources/tracing/profiling_view.js +++ b/chrome/browser/resources/tracing/profiling_view.js @@ -19,6 +19,7 @@ cr.define('tracing', function() { __proto__: cr.ui.TabPanel.prototype, traceEvents_: [], + systemTraceEvents_: [], decorate: function() { cr.ui.TabPanel.prototype.decorate.apply(this); @@ -53,6 +54,19 @@ cr.define('tracing', function() { this.controlDiv_.appendChild(this.loadBn_); this.controlDiv_.appendChild(this.saveBn_); + if (cr.isChromeOS) { + this.systemTracingBn_ = document.createElement('input'); + this.systemTracingBn_.type = 'checkbox'; + this.systemTracingBn_.checked = true; + + var systemTracingLabelEl = document.createElement('div'); + systemTracingLabelEl.className = 'label'; + systemTracingLabelEl.textContent = 'System events'; + systemTracingLabelEl.appendChild(this.systemTracingBn_); + + this.controlDiv_.appendChild(systemTracingLabelEl); + } + this.container_.appendChild(this.timelineView_); this.appendChild(this.container_); @@ -72,11 +86,16 @@ cr.define('tracing', function() { }, refresh_: function() { - var hasEvents = this.traceEvents_ && this.traceEvents_.length; + var traceEvents = tracingController.traceEvents; + var hasEvents = traceEvents && traceEvents.length; this.saveBn_.disabled = !hasEvents; - this.timelineView_.traceData = this.traceEvents_; + if (!hasEvents) return; + + var m = new tracing.TimelineModel(); + m.importEvents(traceEvents, true, [tracingController.systemTraceEvents]); + this.timelineView_.model = m; }, onKeypress_: function(event) { @@ -88,11 +107,10 @@ cr.define('tracing', function() { /////////////////////////////////////////////////////////////////////////// onRecord_: function() { - tracingController.beginTracing(); + tracingController.beginTracing(this.systemTracingBn_.checked); }, onRecordDone_: function() { - this.traceEvents_ = tracingController.traceEvents; this.refresh_(); }, @@ -108,7 +126,7 @@ cr.define('tracing', function() { this.overlayEl_.appendChild(labelEl); this.overlayEl_.visible = true; - tracingController.beginSaveTraceFile(this.traceEvents_); + tracingController.beginSaveTraceFile(); }, onSaveTraceFileComplete_: function(e) { @@ -140,7 +158,6 @@ cr.define('tracing', function() { this.overlayEl_.visible = false; this.overlayEl_ = undefined; - this.traceEvents_ = e.events; this.refresh_(); }, diff --git a/chrome/browser/resources/tracing/timeline_model.js b/chrome/browser/resources/tracing/timeline_model.js index 4eb3741..e8a7486 100644 --- a/chrome/browser/resources/tracing/timeline_model.js +++ b/chrome/browser/resources/tracing/timeline_model.js @@ -605,7 +605,7 @@ cr.define('tracing', function() { // which can be used for random color selection, and // reserved colors, which are used when specific colors // need to be used, e.g. where red is desired. - const palletteBase = [ + var palletteBase = [ {r: 138, g: 113, b: 152}, {r: 175, g: 112, b: 133}, {r: 127, g: 135, b: 225}, @@ -644,7 +644,7 @@ cr.define('tracing', function() { // Make sure this number tracks the number of reserved entries in the // pallette. - const numReservedColorIds = 4; + var numReservedColorIds = 4; function brighten(c) { var k; @@ -664,10 +664,10 @@ cr.define('tracing', function() { /** * The number of color IDs that getStringColorId can choose from. */ - const numRegularColorIds = palletteBase.length - numReservedColorIds; - const highlightIdBoost = palletteBase.length; + var numRegularColorIds = palletteBase.length - numReservedColorIds; + var highlightIdBoost = palletteBase.length; - const pallette = palletteBase.concat(palletteBase.map(brighten)). + var pallette = palletteBase.concat(palletteBase.map(brighten)). map(colorToString); /** * Computes a simplistic hashcode of the provide name. Used to chose colors @@ -961,8 +961,8 @@ cr.define('tracing', function() { * for canImport(events) will be used to import the events. * * @param {Object} events Events to import. - * @param {boolean} isChildImport True the eventData being imported is an - * additional trace after the primary eventData. + * @param {boolean} isAdditionalImport True the eventData being imported is + * an additional trace after the primary eventData. * @return {TimelineModelImporter} The importer used for the eventData. */ importOneTrace_: function(eventData, isAdditionalImport) { diff --git a/chrome/browser/resources/tracing/tracing_controller.js b/chrome/browser/resources/tracing/tracing_controller.js index 6a99dc0..3bb7de8 100644 --- a/chrome/browser/resources/tracing/tracing_controller.js +++ b/chrome/browser/resources/tracing/tracing_controller.js @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -26,6 +26,7 @@ cr.define('tracing', function() { this.overlay_.appendChild(this.stopButton_); this.traceEvents_ = []; + this.systemTraceEvents_ = []; this.onKeydownBoundToThis_ = this.onKeydown_.bind(this); this.onKeypressBoundToThis_ = this.onKeypress_.bind(this); @@ -40,6 +41,7 @@ cr.define('tracing', function() { clientInfo_: undefined, tracingEnabled_: false, tracingEnding_: false, + systemTraceDataFilename_: undefined, onRequestBufferPercentFullComplete: function(percent_full) { if (!this.overlay_.visible) @@ -61,7 +63,7 @@ cr.define('tracing', function() { /** * Called by info_view to empty the trace buffer */ - beginTracing: function() { + beginTracing: function(opt_systemTracingEnabled) { if (this.tracingEnabled_) throw Error('Tracing already begun.'); @@ -70,15 +72,15 @@ cr.define('tracing', function() { this.overlay_.visible = true; this.tracingEnabled_ = true; + console.log('Beginning to trace...'); this.statusDiv_.textContent = 'Tracing active.'; this.traceEvents_ = []; - chrome.send('beginTracing'); + this.systemTraceEvents_ = []; + chrome.send('beginTracing', [opt_systemTracingEnabled || false]); this.beginRequestBufferPercentFull_(); - this.tracingEnabled_ = true; - var e = new cr.Event('traceBegun'); e.events = this.traceEvents_; this.dispatchEvent(e); @@ -176,6 +178,23 @@ cr.define('tracing', function() { }, /** + * Called by tracing c++ code when new system trace data arrives. + */ + onSystemTraceDataCollected: function(events) { + console.log('onSystemTraceDataCollected with ' + + events.length + ' chars of data.'); + this.systemTraceEvents_ = events; + }, + + /** + * Gets the currentl system trace events. If tracing is active, then + * this can change on the fly. + */ + get systemTraceEvents() { + return this.systemTraceEvents_; + }, + + /** * Tells browser to put up a load dialog and load the trace file */ beginLoadTraceFile: function() { @@ -194,6 +213,14 @@ cr.define('tracing', function() { else this.traceEvents_ = data; } + if (data.systemTraceEvents) { + this.systemTraceEvents_ = data.systemTraceEvents; + } else { // path for loading traces saved without metadata + if (!data.length) + console.log('Expected an array when loading the trace file'); + else + this.systemTraceEvents_ = data; + } var e = new cr.Event('loadTraceFileComplete'); e.events = this.traceEvents_; this.dispatchEvent(e); @@ -209,9 +236,10 @@ cr.define('tracing', function() { /** * Tells browser to put up a save dialog and save the trace file */ - beginSaveTraceFile: function(traceEvents) { + beginSaveTraceFile: function(traceEvents, systemTraceEvents) { var data = { - traceEvents: traceEvents, + traceEvents: this.traceEvents_, + systemTraceEvents: this.systemTraceEvents_, clientInfo: this.clientInfo_, gpuInfo: this.gpuInfo_ }; diff --git a/chrome/browser/ui/webui/tracing_ui.cc b/chrome/browser/ui/webui/tracing_ui.cc index 4b2cf03..dce1f4a 100644 --- a/chrome/browser/ui/webui/tracing_ui.cc +++ b/chrome/browser/ui/webui/tracing_ui.cc @@ -35,6 +35,11 @@ #include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" +#if defined(OS_CHROMEOS) +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/debug_daemon_client.h" +#endif + using content::BrowserThread; using content::GpuDataManager; using content::TraceController; @@ -109,6 +114,12 @@ class TracingMessageHandler // True while tracing is active. bool trace_enabled_; + // True while system tracing is active. + bool system_trace_in_progress_; + + void OnEndSystemTracingAck( + const scoped_refptr<base::RefCountedString>& events_str_ptr); + DISALLOW_COPY_AND_ASSIGN(TracingMessageHandler); }; @@ -146,7 +157,8 @@ class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> { TracingMessageHandler::TracingMessageHandler() : select_trace_file_dialog_type_(SelectFileDialog::SELECT_NONE), - trace_enabled_(false) { + trace_enabled_(false), + system_trace_in_progress_(false) { } TracingMessageHandler::~TracingMessageHandler() { @@ -157,6 +169,15 @@ TracingMessageHandler::~TracingMessageHandler() { // If we are the current subscriber, this will result in ending tracing. TraceController::GetInstance()->CancelSubscriber(this); + + // Shutdown any system tracing too. + if (system_trace_in_progress_) { +#if defined(OS_CHROMEOS) + chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> + RequestStopSystemTracing( + chromeos::DebugDaemonClient::EmptyStopSystemTracingCallback()); +#endif + } } void TracingMessageHandler::RegisterMessages() { @@ -354,12 +375,28 @@ void TracingMessageHandler::SaveTraceFileComplete() { void TracingMessageHandler::OnBeginTracing(const ListValue* args) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(args->GetSize() == 1); + + bool system_tracing_requested = false; + bool ok = args->GetBoolean(0, &system_tracing_requested); + DCHECK(ok); + trace_enabled_ = true; // TODO(jbates) This may fail, but that's OK for current use cases. // Ex: Multiple about:gpu traces can not trace simultaneously. // TODO(nduca) send feedback to javascript about whether or not BeginTracing // was successful. TraceController::GetInstance()->BeginTracing(this); + + if (system_tracing_requested) { +#if defined(OS_CHROMEOS) + DCHECK(!system_trace_in_progress_); + chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> + StartSystemTracing(); + // TODO(sleffler) async, could wait for completion + system_trace_in_progress_ = true; +#endif + } } void TracingMessageHandler::OnEndTracingAsync(const ListValue* list) { @@ -379,9 +416,37 @@ void TracingMessageHandler::OnEndTracingAsync(const ListValue* list) { void TracingMessageHandler::OnEndTracingComplete() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); trace_enabled_ = false; + if (system_trace_in_progress_) { + // Disable system tracing now that the local trace has shutdown. + // This must be done last because we potentially need to push event + // records into the system event log for synchronizing system event + // timestamps with chrome event timestamps--and since the system event + // log is a ring-buffer (on linux) adding them at the end is the only + // way we're confident we'll have them in the final result. + system_trace_in_progress_ = false; +#if defined(OS_CHROMEOS) + chromeos::DBusThreadManager::Get()->GetDebugDaemonClient()-> + RequestStopSystemTracing( + base::Bind(&TracingMessageHandler::OnEndSystemTracingAck, + base::Unretained(this))); + return; +#endif + } web_ui()->CallJavascriptFunction("tracingController.onEndTracingComplete"); } +void TracingMessageHandler::OnEndSystemTracingAck( + const scoped_refptr<base::RefCountedString>& events_str_ptr) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + web_ui()->CallJavascriptFunction( + "tracingController.onSystemTraceDataCollected", + *scoped_ptr<Value>(Value::CreateStringValue(events_str_ptr->data()))); + DCHECK(!system_trace_in_progress_); + + OnEndTracingComplete(); +} + void TracingMessageHandler::OnTraceDataCollected( const scoped_refptr<base::RefCountedString>& trace_fragment) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |