blob: 03db04866d9dfaeea941ae5f78f768277629325d [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright (c) 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="/tracing/base/unit_scale.html">
<link rel="import" href="/tracing/importer/importer.html">
<link rel="import" href="/tracing/model/model.html">
<link rel="import" href="/tracing/model/power_series.html">
<script>
/**
* @fileoverview Imports text files in the BattOr format into the
* Model. This format is output by the battor_agent executable and library.
*
* This importer assumes the events arrive as a string. The unit tests provide
* examples of the trace format.
*/
'use strict';
tr.exportTo('tr.e.importer.battor', function() {
/**
* Imports a BattOr power trace into a specified model.
* @constructor
*/
function BattorImporter(model, events) {
this.importPriority = 3; // runs after the linux_perf importer
this.model_ = model;
// The list of power samples contained within the trace.
this.samples_ = [];
// The clock sync markers contained within the trace.
this.syncTimestampsById_ = new Map();
this.parseTrace_(events);
}
var battorDataLineRE = new RegExp(
'^(-?\\d+\\.\\d+)\\s+(-?\\d+\\.\\d+)\\s+(-?\\d+\\.\\d+)' +
'(?:\\s+<(\\S+)>)?$'
);
var battorHeaderLineRE = /^# BattOr/;
/**
* Guesses whether the provided events is a BattOr string.
* Looks for the magic string "# BattOr" at the start of the file,
*
* @return {boolean} True when events is a BattOr array.
*/
BattorImporter.canImport = function(events) {
if (!(typeof(events) === 'string' || events instanceof String))
return false;
return battorHeaderLineRE.test(events);
};
BattorImporter.prototype = {
__proto__: tr.importer.Importer.prototype,
get importerName() {
return 'BattorImporter';
},
get model() {
return this.model_;
},
/**
* Imports clock sync markers from the trace into into this.model_.
*/
importClockSyncMarkers: function() {
for (var [syncId, ts] of this.syncTimestampsById_) {
this.model_.clockSyncManager.addClockSyncMarker(
tr.model.ClockDomainId.BATTOR, syncId, ts);
}
},
/**
* Imports the events from the trace into this.model_.
*/
importEvents: function() {
if (this.model_.device.powerSeries) {
this.model_.importWarning({
type: 'import_error',
message: 'Power counter exists, can not import BattOr power trace.'
});
return;
}
var modelTimeTransformer =
this.model_.clockSyncManager.getModelTimeTransformer(
tr.model.ClockDomainId.BATTOR);
var powerSeries = this.model_.device.powerSeries =
new tr.model.PowerSeries(this.model_.device);
for (var i = 0; i < this.samples_.length; i++) {
var sample = this.samples_[i];
powerSeries.addPowerSample(
modelTimeTransformer(sample.ts), sample.powerInW);
}
},
/**
* Given the BattOr trace as a string, parse it and store the results in
* this.samples_ and this.syncTimestampsById_.
*/
parseTrace_: function(trace) {
var lines = trace.split('\n');
for (var line of lines) {
line = line.trim();
if (line.length === 0)
continue;
if (line.startsWith('#'))
continue;
// Parse power sample.
var groups = battorDataLineRE.exec(line);
if (!groups) {
this.model_.importWarning({
type: 'parse_error',
message: 'Unrecognized line in BattOr trace: ' + line
});
continue;
}
var ts = parseFloat(groups[1]);
var voltageInV = tr.b.convertUnit(parseFloat(groups[2]),
tr.b.UnitScale.Metric.MILLI, tr.b.UnitScale.Metric.NONE);
var currentInA = tr.b.convertUnit(parseFloat(groups[3]),
tr.b.UnitScale.Metric.MILLI, tr.b.UnitScale.Metric.NONE);
var syncId = groups[4];
if (syncId)
this.syncTimestampsById_.set(syncId, ts);
if (voltageInV < 0 || currentInA < 0) {
this.model_.importWarning({
type: 'parse_error',
message: 'The following line in the BattOr trace has a negative ' +
'voltage or current, neither of which are allowed: ' + line +
'. A common cause of this is that the device is charging ' +
'while the trace is being recorded.'
});
continue;
}
this.samples_.push(new Sample(ts, voltageInV, currentInA));
}
}
};
/**
* A sample recorded by a BattOr.
*
* @param {number} ts The timestamp (in milliseconds) of the sample.
* @param {number} voltage The voltage (in volts) at the specified time.
* @param {number} current The current (in amps) at the specified time.
*
* @constructor
*/
function Sample(ts, voltageInV, currentInA) {
this.ts = ts;
this.voltageInV = voltageInV;
this.currentInA = currentInA;
}
Sample.prototype = {
/** Returns the instantaneous power consumption (in Watts). */
get powerInW() { return this.voltageInV * this.currentInA; }
};
tr.importer.Importer.register(BattorImporter);
return {
BattorImporter: BattorImporter
};
});
</script>