Fix latency progress points.

This commit is contained in:
John Vilk 2016-10-21 13:13:07 -04:00
parent 35f3302b69
commit a4b4a07237
5 changed files with 169 additions and 54 deletions

View File

@ -1,3 +1,40 @@
/**
* Returns if this data point is valid.
* Infinity / -Infinity occurs when dividing by 0.
* NaN happens when the data is messed up and we get a NaN into a computation somewhere.
*/
function isValidDataPoint(data) {
return !isNaN(data) && data !== Infinity && data !== -Infinity;
}
/**
* Get the applicable data point from this particular experiment.
* Returns -Infinity or Infinity in undefined cases.
*/
function getDataPoint(data) {
// Discard obviously incorrect data points.
if (data.duration < 0) {
return NaN;
}
switch (data.type) {
case 'throughput':
return data.duration / data.delta;
case 'latency':
var arrivalRate = data.arrivals / data.duration;
// Average latency, according to Little's Law.
return data.difference / arrivalRate;
}
}
/**
* Are we trying to maximize or minimize this progress point?
*/
function shouldMaximize(data) {
switch (data.type) {
case 'latency':
return false;
case 'throughput':
return true;
}
}
function parseLine(s) {
if (s[0] == '{') {
return JSON.parse(s);
@ -11,14 +48,23 @@ function parseLine(s) {
continue;
var key = parts[i].substring(0, equals_index);
var value = parts[i].substring(equals_index + 1);
if (key === 'type' && obj.type === 'progress-point') {
key = 'point-type';
}
else if (key === 'delta' || key === 'time' || key === 'duration') {
value = parseInt(value);
}
else if (key === 'speedup') {
value = parseFloat(value);
switch (key) {
case 'type':
if (obj.type === 'progress-point') {
key = 'point-type';
}
break;
case 'delta':
case 'time':
case 'duration':
case 'arrivals':
case 'departures':
case 'difference':
value = parseInt(value, 10);
break;
case 'speedup':
value = parseFloat(value);
break;
}
obj[key] = value;
}
@ -138,7 +184,7 @@ var Profile = (function () {
var entry = this.ensureDataEntry(experiment.selected, point.name, experiment.speedup, {
arrivals: 0,
departures: 0,
delta: 0,
difference: 0,
duration: 0,
type: 'latency'
});
@ -146,15 +192,15 @@ var Profile = (function () {
entry.departures += point.departures;
// Compute a running weighted average of the difference between arrivals and departures
if (entry.duration === 0) {
entry.delta = point.difference;
entry.difference = point.difference;
}
else {
// Compute the new total duration of all experiments combined (including the new one)
var total_duration = entry.duration + experiment.duration;
// Scale the difference down by the ratio of the prior and total durations. This scale factor will be closer to 1 than 0, so divide first for better numerical stability
entry.delta *= entry.duration / total_duration;
entry.difference *= entry.duration / total_duration;
// Add the contribution to average difference from the current experiment. The scale factor will be close to zero, so multiply first for better numerical stability.
entry.delta += (point.difference * experiment.duration) / total_duration;
entry.difference += (point.difference * experiment.duration) / total_duration;
}
// Update the total duration
entry.duration += experiment.duration;
@ -180,29 +226,39 @@ var Profile = (function () {
for (var selected in this._data) {
var points = [];
var points_with_enough = 0;
for (var i = 0; i < progress_points.length; i++) {
progress_point_loop: for (var i = 0; i < progress_points.length; i++) {
// Set up an empty record for this progress point
var point = {
name: progress_points[i],
measurements: new Array()
};
points.push(point);
// Get the data for this progress point, if any
var point_data = this._data[selected][progress_points[i]];
// Check to be sure the point was observed and we have baseline (zero speedup) data
if (point_data !== undefined && point_data[0] !== undefined && point_data[0].delta > 0) {
// Compute the baseline progress period
var baseline_period = point_data[0].duration / point_data[0].delta;
if (point_data !== undefined && point_data[0] !== undefined) {
// Compute the baseline data point
var baseline_data_point = getDataPoint(point_data[0]);
var maximize = shouldMaximize(point_data[0]);
if (!isValidDataPoint(baseline_data_point)) {
// Baseline data point is invalid (divide by zero, or a NaN)
continue progress_point_loop;
}
// Loop over measurements and compute progress speedups in D3-friendly format
var measurements = [];
for (var speedup in point_data) {
// Skip this speedup measurement if period is undefined
if (point_data[speedup].delta == 0)
var data_point = getDataPoint(point_data[speedup]);
// Skip invalid data.
if (!isValidDataPoint(data_point)) {
continue;
// Compute progress period for this speedup size
var period = point_data[speedup].duration / point_data[speedup].delta;
var progress_speedup = (baseline_period - period) / baseline_period;
// Skip really large negative values
if (progress_speedup >= -1) {
}
var progress_speedup = (baseline_data_point - data_point) / baseline_data_point;
if (!maximize) {
// We are trying to *minimize* this progress point, so negate the speedup.
progress_speedup = -progress_speedup;
}
// Skip really large negative and positive values
if (progress_speedup >= -1 && progress_speedup <= 2) {
// Add entry to measurements
measurements.push({
speedup: +speedup,
@ -218,7 +274,6 @@ var Profile = (function () {
point.measurements = measurements;
}
}
points.push(point);
}
if (points_with_enough > 0) {
result.push({

File diff suppressed because one or more lines are too long

View File

@ -26,7 +26,7 @@ interface LatencyData {
type: 'latency';
arrivals: number;
departures: number;
delta: number;
difference: number;
duration: number;
}
@ -53,6 +53,46 @@ interface LatencyPoint {
difference: number;
}
/**
* Returns if this data point is valid.
* Infinity / -Infinity occurs when dividing by 0.
* NaN happens when the data is messed up and we get a NaN into a computation somewhere.
*/
function isValidDataPoint(data: number): boolean {
return !isNaN(data) && data !== Infinity && data !== -Infinity;
}
/**
* Get the applicable data point from this particular experiment.
* Returns -Infinity or Infinity in undefined cases.
*/
function getDataPoint(data: ExperimentData): number {
// Discard obviously incorrect data points.
if (data.duration < 0) {
return NaN;
}
switch (data.type) {
case 'throughput':
return data.duration / data.delta;
case 'latency':
const arrivalRate = data.arrivals / data.duration;
// Average latency, according to Little's Law.
return data.difference / arrivalRate;
}
}
/**
* Are we trying to maximize or minimize this progress point?
*/
function shouldMaximize(data: ExperimentData) {
switch (data.type) {
case 'latency':
return false;
case 'throughput':
return true;
}
}
function parseLine(s: string): Line {
if(s[0] == '{') {
return JSON.parse(s);
@ -68,12 +108,23 @@ function parseLine(s: string): Line {
let key = parts[i].substring(0, equals_index);
let value: string | number = parts[i].substring(equals_index + 1);
if (key === 'type' && obj.type === 'progress-point') {
key = 'point-type';
} else if (key === 'delta' || key === 'time' || key === 'duration') {
value = parseInt(value);
} else if (key === 'speedup') {
value = parseFloat(value);
switch (key) {
case 'type':
if (obj.type === 'progress-point') {
key = 'point-type';
}
break;
case 'delta':
case 'time':
case 'duration':
case 'arrivals':
case 'departures':
case 'difference':
value = parseInt(value, 10);
break;
case 'speedup':
value = parseFloat(value);
break;
}
obj[key] = value;
@ -170,7 +221,7 @@ class Profile {
experiment = entry;
} else if (entry.type === 'throughput-point' || entry.type === 'progress-point') {
this.addThroughputMeasurement(experiment, entry);
} else if(entry.type === 'latency-point') {
} else if (entry.type === 'latency-point') {
this.addLatencyMeasurement(experiment, entry);
}
}
@ -199,7 +250,7 @@ class Profile {
let entry = this.ensureDataEntry(experiment.selected, point.name, experiment.speedup, {
arrivals: 0,
departures: 0,
delta: 0,
difference: 0,
duration: 0,
type: 'latency'
});
@ -209,14 +260,14 @@ class Profile {
// Compute a running weighted average of the difference between arrivals and departures
if (entry.duration === 0) {
entry.delta = point.difference;
entry.difference = point.difference;
} else {
// Compute the new total duration of all experiments combined (including the new one)
let total_duration = entry.duration + experiment.duration;
// Scale the difference down by the ratio of the prior and total durations. This scale factor will be closer to 1 than 0, so divide first for better numerical stability
entry.delta *= entry.duration / total_duration;
entry.difference *= entry.duration / total_duration;
// Add the contribution to average difference from the current experiment. The scale factor will be close to zero, so multiply first for better numerical stability.
entry.delta += (point.difference * experiment.duration) / total_duration;
entry.difference += (point.difference * experiment.duration) / total_duration;
}
// Update the total duration
@ -243,34 +294,45 @@ class Profile {
for (let selected in this._data) {
let points: Point[] = [];
let points_with_enough = 0;
for(let i = 0; i < progress_points.length; i++) {
progress_point_loop:
for (let i = 0; i < progress_points.length; i++) {
// Set up an empty record for this progress point
let point = {
const point = {
name: progress_points[i],
measurements: new Array<Measurement>()
};
points.push(point);
// Get the data for this progress point, if any
let point_data = this._data[selected][progress_points[i]];
// Check to be sure the point was observed and we have baseline (zero speedup) data
if (point_data !== undefined && point_data[0] !== undefined && point_data[0].delta > 0) {
// Compute the baseline progress period
let baseline_period = point_data[0].duration / point_data[0].delta;
if (point_data !== undefined && point_data[0] !== undefined) {
// Compute the baseline data point
let baseline_data_point = getDataPoint(point_data[0]);
let maximize = shouldMaximize(point_data[0]);
if (!isValidDataPoint(baseline_data_point)) {
// Baseline data point is invalid (divide by zero, or a NaN)
continue progress_point_loop;
}
// Loop over measurements and compute progress speedups in D3-friendly format
let measurements: Measurement[] = [];
for (let speedup in point_data) {
// Skip this speedup measurement if period is undefined
if (point_data[speedup].delta == 0) continue;
let data_point = getDataPoint(point_data[speedup]);
// Skip invalid data.
if (!isValidDataPoint(data_point)) {
continue;
}
// Compute progress period for this speedup size
let period = point_data[speedup].duration / point_data[speedup].delta;
let progress_speedup = (baseline_data_point - data_point) / baseline_data_point;
if (!maximize) {
// We are trying to *minimize* this progress point, so negate the speedup.
progress_speedup = -progress_speedup;
}
let progress_speedup = (baseline_period - period) / baseline_period;
// Skip really large negative values
if (progress_speedup >= -1) {
// Skip really large negative and positive values
if (progress_speedup >= -1 && progress_speedup <= 2) {
// Add entry to measurements
measurements.push({
speedup: +speedup,
@ -288,8 +350,6 @@ class Profile {
point.measurements = measurements;
}
}
points.push(point);
}
if (points_with_enough > 0) {

2
ui.js
View File

@ -89,7 +89,7 @@ var samples_sel = d3.select('#samples').selectAll('.sample-profile').data(sample
.text(function (d) { return d; })
.on('click', function (d) {
var sel = d3.select(this);
if (sel.attr('loaded') != 'yes') {
if (sel.attr('loaded') !== 'yes') {
// Avoid race condition: Set first.
sel.attr('loaded', 'yes');
var xhr_1 = new XMLHttpRequest();

View File

@ -1 +1 @@
{"version":3,"file":"ui.js","sourceRoot":"","sources":["ui.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"ui.js","sourceRoot":"","sources":["ui.ts"],"names":[],"mappings":"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"}