improved frontend for benchmarking
This commit is contained in:
parent
e7764eae7a
commit
b262cf9fe6
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,119 @@
|
||||||
|
|
||||||
|
|
||||||
|
var HyriseConnector = function(endpointUrl) {
|
||||||
|
this._endpointUrl = endpointUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
HyriseConnector.prototype.executeSQL = function(query, callback, errorCallback) {
|
||||||
|
var url = encodeURI(this._endpointUrl);
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
jQuery.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: url,
|
||||||
|
dataType: 'json',
|
||||||
|
data: {
|
||||||
|
performance: true,
|
||||||
|
sql: query
|
||||||
|
},
|
||||||
|
success: function(result) {
|
||||||
|
if (typeof result.real_size === "undefined") {
|
||||||
|
result.real_size = 0;
|
||||||
|
result.rows = [];
|
||||||
|
result.header = [];
|
||||||
|
if (!result.performanceData) result.performanceData = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
self._formatPerformanceData(result);
|
||||||
|
callback(result);
|
||||||
|
},
|
||||||
|
error: errorCallback
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
HyriseConnector.prototype._formatPerformanceData = function(object) {
|
||||||
|
var performanceData = object.performanceData;
|
||||||
|
|
||||||
|
var totalTime = 0;
|
||||||
|
var queryTaskTime = 0;
|
||||||
|
|
||||||
|
$.each(performanceData, function(i, data) {
|
||||||
|
data.time_ms = data.endTime - data.startTime;
|
||||||
|
|
||||||
|
totalTime += data.time_ms;
|
||||||
|
if (data.name === 'SQLQueryTask') queryTaskTime += data.time_ms;
|
||||||
|
});
|
||||||
|
|
||||||
|
object.performanceData = {
|
||||||
|
totalTime: totalTime,
|
||||||
|
queryTaskTime: queryTaskTime,
|
||||||
|
operators: performanceData
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
HyriseConnector.prototype.benchmarkSQL = function(query, numRuns, callback) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
function __aggregateData(allData) {
|
||||||
|
var result = {
|
||||||
|
totalTime: 0,
|
||||||
|
queryTaskTime: 0,
|
||||||
|
numRuns: allData.length,
|
||||||
|
operators: []
|
||||||
|
};
|
||||||
|
|
||||||
|
var operatorMap = {};
|
||||||
|
|
||||||
|
$.each(allData, function(i, run) {
|
||||||
|
var perfData = run.performanceData;
|
||||||
|
result.totalTime += perfData.totalTime;
|
||||||
|
result.queryTaskTime += perfData.queryTaskTime;
|
||||||
|
|
||||||
|
$.each(perfData.operators, function(i, data) {
|
||||||
|
if (!(data.id in operatorMap)) {
|
||||||
|
operatorMap[data.id] = data;
|
||||||
|
} else {
|
||||||
|
operatorMap[data.id].duration += data.duration;
|
||||||
|
operatorMap[data.id].startTime += data.startTime;
|
||||||
|
operatorMap[data.id].endTime += data.endTime;
|
||||||
|
operatorMap[data.id].time_ms += data.time_ms;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Calc average and Transform into array
|
||||||
|
result.totalTime /= result.numRuns;
|
||||||
|
result.queryTaskTime /= result.numRuns;
|
||||||
|
|
||||||
|
$.each(operatorMap, function(id, data) {
|
||||||
|
data.duration /= result.numRuns;
|
||||||
|
data.startTime /= result.numRuns;
|
||||||
|
data.time_ms /= result.numRuns;
|
||||||
|
result.operators.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
callback({
|
||||||
|
performanceData: result
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var allData = [];
|
||||||
|
var n = 0;
|
||||||
|
function __run() {
|
||||||
|
++n;
|
||||||
|
self.executeSQL(query, function(result) {
|
||||||
|
allData.push(result);
|
||||||
|
|
||||||
|
// Run again or return aggregated Data
|
||||||
|
if (n < numRuns) __run();
|
||||||
|
else __aggregateData(allData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
__run();
|
||||||
|
};
|
|
@ -1,30 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
var HyriseSQLConnector = function(endpointUrl) {
|
|
||||||
this._endpointUrl = endpointUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
HyriseSQLConnector.prototype.executeSQLQuery = function(query, callback, error_callback) {
|
|
||||||
var url = encodeURI(this._endpointUrl);
|
|
||||||
|
|
||||||
jQuery.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: url,
|
|
||||||
dataType: 'json',
|
|
||||||
data: {
|
|
||||||
performance: true,
|
|
||||||
sql: query
|
|
||||||
},
|
|
||||||
success: function(result) {
|
|
||||||
if (typeof result.real_size === "undefined") {
|
|
||||||
result.real_size = 0;
|
|
||||||
result.rows = [];
|
|
||||||
result.header = [];
|
|
||||||
}
|
|
||||||
callback(result);
|
|
||||||
},
|
|
||||||
error: error_callback
|
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
|
@ -1,9 +1,9 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.1.min.js"></script>
|
<script type="text/javascript" src="jquery-1.11.1.min.js"></script>
|
||||||
<link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet">
|
<link href="bootstrap.min.css" rel="stylesheet">
|
||||||
|
|
||||||
<script type="text/javascript" src="hyrise-sql-connector.js"></script>
|
<script type="text/javascript" src="hyrise-connector.js"></script>
|
||||||
<script type="text/javascript" src="ui.js"></script>
|
<script type="text/javascript" src="ui.js"></script>
|
||||||
<link href="style.css" rel="stylesheet" />
|
<link href="style.css" rel="stylesheet" />
|
||||||
<title>Hyrise SQL Frontend</title>
|
<title>Hyrise SQL Frontend</title>
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
<body>
|
<body>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-5">
|
||||||
<!-- Config -->
|
<!-- Config -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="form-group col-sm-12">
|
<div class="form-group col-sm-12">
|
||||||
|
@ -21,36 +21,54 @@
|
||||||
|
|
||||||
<!-- Sample Queries -->
|
<!-- Sample Queries -->
|
||||||
<div class="row" style="margin-bottom: 10px;">
|
<div class="row" style="margin-bottom: 10px;">
|
||||||
<div class="col-sm-8" id="sampleQueries"></div>
|
<div class="col-sm-12" id="sampleQueries"></div>
|
||||||
<div class="col-sm-4" id="buggyQueries"></div>
|
<!-- <div class="col-sm-4" id="buggyQueries"></div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Input -->
|
<!-- Input -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<textarea id="queryInput" class="form-control" style="height: 300px; resize: none;" placeholder="Enter your SQL query here..."></textarea>
|
<textarea id="queryInput" class="form-control" placeholder="Enter your SQL query here..."></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Submit -->
|
<!-- Submit -->
|
||||||
<div class="row" style="margin: 10px 0px;">
|
<div class="row" style="margin: 10px 0px;">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-6">
|
||||||
<button type="button" class="btn btn-primary" id="submitBtn">Submit Query (Shift + Enter)</button>
|
<button type="button" class="btn btn-primary" id="submitBtn">Submit Query (Shift + Enter)</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon" id="basic-addon1"># times</span>
|
||||||
|
<input type="text" class="form-control" id="benchmarkInput" placeholder="Number of times to run" value="10" />
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button class="btn btn-primary" type="button" id="benchmarkBtn">Benchmark</button>
|
||||||
|
</span>
|
||||||
|
</div><!-- /input-group -->
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class="col-lg-7">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<!-- View: Performance Data -->
|
<!-- View: Performance Data -->
|
||||||
<h3>Performance Data</h3>
|
<h3>Performance Data (<span id="timeTotal">?</span>ms)</h3>
|
||||||
|
|
||||||
<table id="performanceDataTable" class="table table-bordered table-striped table-hover">
|
<table id="performanceDataTable" class="table table-bordered table-striped table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>ID</th>
|
<th data-key="id">ID</th>
|
||||||
<th>Name</th>
|
<th data-key="name">Name</th>
|
||||||
<th>Duration</th>
|
<th data-key="duration">Duration</th>
|
||||||
<th>Start Time</th>
|
<!-- <th>Start Time</th> -->
|
||||||
<th>End Time</th>
|
<!-- <th>End Time</th> -->
|
||||||
|
<th data-key="time_ms">Time (ms)</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody></tbody>
|
<tbody></tbody>
|
||||||
|
@ -58,8 +76,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
<div class="row">
|
||||||
<div class="col-lg-6">
|
<div class="col-sm-12">
|
||||||
<!-- View: Result Table -->
|
<!-- View: Result Table -->
|
||||||
<h3>Results (first 100 rows)</h3>
|
<h3>Results (first 100 rows)</h3>
|
||||||
<div id="msgContainer" class="alert alert-success" role="alert">
|
<div id="msgContainer" class="alert alert-success" role="alert">
|
||||||
|
@ -68,6 +86,9 @@
|
||||||
<table id="resultTable" class="table table-bordered table-striped table-hover"></table>
|
<table id="resultTable" class="table table-bordered table-striped table-hover"></table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
File diff suppressed because one or more lines are too long
|
@ -21,3 +21,9 @@ table {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textarea#queryInput {
|
||||||
|
font-family: 'Monospace';
|
||||||
|
height: 500px;
|
||||||
|
resize: none;
|
||||||
|
}
|
|
@ -1,42 +1,63 @@
|
||||||
|
|
||||||
|
function SetUiStateRunning() {
|
||||||
|
$('#resultTable').html('');
|
||||||
|
$('#resultInfo').html('waiting for result...');
|
||||||
|
$('#msgContainer').attr('class', 'alert alert-warning');
|
||||||
|
$('#performanceDataTable tbody').html('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function SetUiStateError(msg) {
|
||||||
|
$('#resultInfo').html(msg);
|
||||||
|
$('#msgContainer').attr('class', 'alert alert-danger');
|
||||||
|
$('#performanceDataTable tbody').html('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function SetUiStateSuccess(msg) {
|
||||||
|
$('#msgContainer').attr('class', 'alert alert-success');
|
||||||
|
$('#resultInfo').html(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function GetHyriseUrl() {
|
||||||
|
var endpointUrl = $('#endpointInput').val();
|
||||||
|
return endpointUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
function GetQuery() {
|
||||||
|
var query = $('#queryInput').val();
|
||||||
|
// Check whether a part of the query has been selected
|
||||||
|
var selectedText = GetSelectedText();
|
||||||
|
if (query.indexOf(selectedText) >= 0) {
|
||||||
|
query = selectedText;
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrap
|
* Bootstrap
|
||||||
*/
|
*/
|
||||||
$(function() {
|
$(function() {
|
||||||
loadSampleQueries('sample-queries.sql');
|
LoadSampleQueries('sample-queries.sql');
|
||||||
|
|
||||||
|
// Simple query submit
|
||||||
$('#submitBtn').click(function() {
|
$('#submitBtn').click(function() {
|
||||||
$('#resultTable').html('');
|
SetUiStateRunning();
|
||||||
$('#resultInfo').html('waiting for result...');
|
var query = GetQuery();
|
||||||
$('#msgContainer').attr('class', 'alert alert-warning');
|
var hyrise = new HyriseConnector(GetHyriseUrl());
|
||||||
|
|
||||||
var endpointUrl = $('#endpointInput').val();
|
hyrise.executeSQL(query, function(result) {
|
||||||
var query = $('#queryInput').val();
|
|
||||||
|
|
||||||
// Check whether a part of the query has been selected
|
|
||||||
var selectedText = getSelectedText();
|
|
||||||
if (query.indexOf(selectedText) >= 0) {
|
|
||||||
query = selectedText;
|
|
||||||
}
|
|
||||||
|
|
||||||
var hyrise = new HyriseSQLConnector(endpointUrl);
|
|
||||||
|
|
||||||
hyrise.executeSQLQuery(query, function(result) {
|
|
||||||
// On Success
|
|
||||||
$('#msgContainer').attr('class', 'alert alert-success');
|
|
||||||
$('#resultInfo').html('Result contains ' + result.real_size + ' rows');
|
|
||||||
console.log("Query result: ", result);
|
console.log("Query result: ", result);
|
||||||
updateResultTable(result);
|
// On Success
|
||||||
updatePerformanceData(result);
|
SetUiStateSuccess('Result contains ' + result.real_size + ' rows');
|
||||||
|
UpdateResultTable(result);
|
||||||
|
UpdatePerformanceData(result.performanceData);
|
||||||
|
|
||||||
}, function(xhr, status, error) {
|
}, function(xhr, status, error) {
|
||||||
|
// console.log(arguments);
|
||||||
// On Error
|
// On Error
|
||||||
console.log(arguments);
|
|
||||||
var msg = 'Error when fetching result. Possibly no connection to Hyrise.';
|
var msg = 'Error when fetching result. Possibly no connection to Hyrise.';
|
||||||
if (xhr.responseJSON) msg = xhr.responseJSON.error[0];
|
if (xhr.responseJSON) msg = xhr.responseJSON.error[0];
|
||||||
$('#resultInfo').html(msg);
|
SetUiStateError(msg);
|
||||||
$('#msgContainer').attr('class', 'alert alert-danger');
|
|
||||||
$('#performanceDataTable tbody').html('');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -47,10 +68,42 @@ $(function() {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Benchmark submit
|
||||||
|
$('#benchmarkBtn').click(function() {
|
||||||
|
SetUiStateRunning();
|
||||||
|
var query = GetQuery();
|
||||||
|
var hyrise = new HyriseConnector(GetHyriseUrl());
|
||||||
|
|
||||||
|
// TODO: hardcoded 5
|
||||||
|
var numRuns = parseInt($('#benchmarkInput').val());
|
||||||
|
hyrise.benchmarkSQL(query, numRuns, function(result) {
|
||||||
|
console.log("Benchmark result: ", result);
|
||||||
|
UpdatePerformanceData(result.performanceData);
|
||||||
|
SetUiStateSuccess('Success! See PerformanceData for results.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Setup Table triggers
|
||||||
|
var table = document.querySelector('#performanceDataTable');
|
||||||
|
$('#performanceDataTable thead th').click(function() {
|
||||||
|
var key = $(this).attr('data-key');
|
||||||
|
|
||||||
|
if (table._sortKey && table._sortKey == key) table._asc = !table._asc;
|
||||||
|
else table._asc = true;
|
||||||
|
var sign = (table._asc) ? 1 : -1;
|
||||||
|
|
||||||
|
if (table._data) {
|
||||||
|
table._sortKey = key;
|
||||||
|
SortTableData(table);
|
||||||
|
InsertPerformanceData(table._data);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function getSelectedText() {
|
function GetSelectedText() {
|
||||||
var text = "";
|
var text = "";
|
||||||
if (window.getSelection) {
|
if (window.getSelection) {
|
||||||
text = window.getSelection().toString();
|
text = window.getSelection().toString();
|
||||||
|
@ -61,15 +114,15 @@ function getSelectedText() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function loadSampleQueries(url) {
|
function LoadSampleQueries(url) {
|
||||||
$.get(url, function(data) {
|
$.get(url, function(data) {
|
||||||
var lines = data.split('\n');
|
var lines = data.split('\n');
|
||||||
var name, query = "", isBuggy = false;
|
var name, query = "", isBuggy = false;
|
||||||
$.each(lines, function(i, line) {
|
$.each(lines, function(i, line) {
|
||||||
if (line[0] == '#') {
|
if (line[0] == '#') {
|
||||||
// Append last query
|
// Append last query
|
||||||
if (name && !isBuggy) addSampleQuery(name, query);
|
if (name && !isBuggy) AddSampleQuery(name, query);
|
||||||
if (name && isBuggy) addBuggyQuery(name, query);
|
if (name && isBuggy) AddBuggyQuery(name, query);
|
||||||
|
|
||||||
// New query
|
// New query
|
||||||
isBuggy = (line[1] == '!');
|
isBuggy = (line[1] == '!');
|
||||||
|
@ -80,13 +133,13 @@ function loadSampleQueries(url) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (name && !isBuggy) addSampleQuery(name, query);
|
if (name && !isBuggy) AddSampleQuery(name, query);
|
||||||
if (name && isBuggy) addBuggyQuery(name, query);
|
if (name && isBuggy) AddBuggyQuery(name, query);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function addSampleQuery(name, query) {
|
function AddSampleQuery(name, query) {
|
||||||
var btn = $('<button type="button" class="btn btn-sm btn-success">' + name + '</button>');
|
var btn = $('<button type="button" class="btn btn-sm btn-success">' + name + '</button>');
|
||||||
btn.click(function(evt) {
|
btn.click(function(evt) {
|
||||||
$('#queryInput').val(query);
|
$('#queryInput').val(query);
|
||||||
|
@ -97,7 +150,7 @@ function addSampleQuery(name, query) {
|
||||||
$('#sampleQueries').append(btn);
|
$('#sampleQueries').append(btn);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addBuggyQuery(name, query) {
|
function AddBuggyQuery(name, query) {
|
||||||
var btn = $('<button type="button" class="btn btn-sm btn-danger">' + name + '</button>');
|
var btn = $('<button type="button" class="btn btn-sm btn-danger">' + name + '</button>');
|
||||||
btn.click(function(evt) {
|
btn.click(function(evt) {
|
||||||
$('#queryInput').val(query);
|
$('#queryInput').val(query);
|
||||||
|
@ -108,11 +161,11 @@ function addBuggyQuery(name, query) {
|
||||||
$('#buggyQueries').append(btn);
|
$('#buggyQueries').append(btn);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createElement(tag, value) {
|
function CreateElement(tag, value) {
|
||||||
return $('<' + tag + '>' + value + '</' + tag + '>');
|
return $('<' + tag + '>' + value + '</' + tag + '>');
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateResultTable(result) {
|
function UpdateResultTable(result) {
|
||||||
// Present result json in result-view
|
// Present result json in result-view
|
||||||
var table = $('#resultTable');
|
var table = $('#resultTable');
|
||||||
table.html('');
|
table.html('');
|
||||||
|
@ -134,20 +187,42 @@ function updateResultTable(result) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function updatePerformanceData(result) {
|
function UpdatePerformanceData(performanceData) {
|
||||||
|
var table = document.querySelector('#performanceDataTable');
|
||||||
|
|
||||||
|
$('#timeTotal').html(performanceData.totalTime.toFixed(2));
|
||||||
|
|
||||||
|
// Sort and insert into table
|
||||||
|
if (!table._sortKey) table._sortKey = 'startTime';
|
||||||
|
if (!('_asc') in table) table._asc = true;
|
||||||
|
|
||||||
|
var tableData = performanceData.operators;
|
||||||
|
table._data = tableData;
|
||||||
|
SortTableData(table);
|
||||||
|
InsertPerformanceData(tableData);
|
||||||
|
};
|
||||||
|
|
||||||
|
function InsertPerformanceData(performanceData) {
|
||||||
var tbody = $('#performanceDataTable tbody');
|
var tbody = $('#performanceDataTable tbody');
|
||||||
tbody.html('');
|
tbody.html('');
|
||||||
|
|
||||||
result.performanceData.sort(function(a, b) {
|
$.each(performanceData, function(i, data) {
|
||||||
return a.startTime - b.startTime;
|
if (!data.time_ms) data.time_ms = data.endTime - data.startTime;
|
||||||
});
|
|
||||||
$.each(result.performanceData, function(i, data) {
|
|
||||||
var tr = $('<tr>');
|
var tr = $('<tr>');
|
||||||
tr.append(createElement('td', data.id))
|
tr.append(CreateElement('td', data.id));
|
||||||
tr.append(createElement('td', data.name))
|
tr.append(CreateElement('td', data.name));
|
||||||
tr.append(createElement('td', data.duration))
|
tr.append(CreateElement('td', data.duration));
|
||||||
tr.append(createElement('td', data.startTime))
|
tr.append(CreateElement('td', data.time_ms.toFixed(6)));
|
||||||
tr.append(createElement('td', data.endTime))
|
|
||||||
tbody.append(tr);
|
tbody.append(tr);
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
|
function SortTableData(table) {
|
||||||
|
var key = table._sortKey;
|
||||||
|
var sign = (table._asc) ? 1 : -1;
|
||||||
|
table._data.sort(function(a, b) {
|
||||||
|
if (a[key].localeCompare) return sign * a[key].localeCompare(b[key]);
|
||||||
|
return sign * (a[key] - b[key]);
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue