diff --git a/docs/compare.html b/docs/compare.html new file mode 100644 index 000000000..ac5da9d6a --- /dev/null +++ b/docs/compare.html @@ -0,0 +1,371 @@ + + +
+ +Warning: although measurements known to have high variation are marked with + '?'/'??', this does not mean that unmarked measurements are guaranteed to have + low variation. Verify the measurement against the + + last "noise run" which shows the perf difference of a non-functional change. +
+See brief explanation at bottom of this page for details on what each run kind means.
+ +Most benchmarks have at least 4 "runs"
+
+
+
+
+
+
diff --git a/docs/favicon.ico b/docs/favicon.ico
new file mode 100644
index 000000000..b8ad23769
Binary files /dev/null and b/docs/favicon.ico differ
diff --git a/docs/info.json b/docs/info.json
new file mode 100644
index 000000000..fad8e788c
--- /dev/null
+++ b/docs/info.json
@@ -0,0 +1 @@
+{"stats":["cpu-clock","cycles:u","faults","instructions:u","max-rss","task-clock","wall-time"],"as_of":"2020-03-29T09:50:52+00:00"}
diff --git a/docs/perf.css b/docs/perf.css
new file mode 100644
index 000000000..873d77a41
--- /dev/null
+++ b/docs/perf.css
@@ -0,0 +1,125 @@
+body {
+ font-family: monospace;
+ margin: 3em auto;
+}
+p {
+ margin-top: 1.2em;
+ margin-bottom: 1.2em;
+}
+span.settings {
+ display: inline-block;
+ vertical-align: top;
+ padding: 10px;
+}
+
+#dates {
+ text-align: right;
+}
+
+#dates h3 {
+ text-align: left;
+}
+
+span.compare {
+ display: inline-block;
+ vertical-align: top;
+ padding: 10px;
+}
+div.submit {
+ padding: 20px;
+ padding-top: 10px;
+ padding-right: 0;
+ text-align: right;
+}
+table {
+ font-size: small;
+}
+li {
+ max-width: 580px;
+}
+a {
+ color: #428bca;
+ text-decoration: none;
+}
+a:hover,
+a:focus {
+ color: #2a6496;
+ text-decoration: underline;
+}
+a:focus {
+ outline: thin dotted;
+ outline-offset: -2px;
+}
+li {
+ margin-bottom: .5em;
+}
+
+ul {
+ padding-left: 30px;
+}
+
+h2 {
+ font-weight: 500;
+ font-size: 18.5px; /* gridfit */
+}
+h3 {
+ font-weight: 500;
+}
+
+img {
+ border: 0;
+}
+.container {
+ padding-right: 4em;
+ padding-left: 4em;
+ margin-right: auto;
+ margin-left: auto;
+}
+
+.big_summary {
+ display: block;
+ margin-top: -20px;
+ font-size: 15em;
+ font-weight: 500;
+ z-index: -1;
+}
+.positive {
+ color: red;
+}
+.negative {
+ color: green;
+}
+.neutral {
+ color: black;
+}
+.summary_table td {
+ padding: 4px;
+}
+.summary_table th {
+ padding: 4px;
+}
+
+#as-of {
+ text-align: center;
+}
+
+.compare, .stats {
+ table-layout: fixed;
+}
+
+.stats td, .compare td, .stats th, .compare th {
+ padding: 0.3em;
+}
+
+table td, table th {
+ text-align: right;
+}
+
+.space {
+ width: 1em;
+}
+
+.group-by {
+ padding-bottom: 1em;
+ display: block;
+}
diff --git a/docs/perfdata b/docs/perfdata
new file mode 100644
index 000000000..f36814a32
Binary files /dev/null and b/docs/perfdata differ
diff --git a/docs/shared.js b/docs/shared.js
new file mode 100644
index 000000000..7fa8a4bef
--- /dev/null
+++ b/docs/shared.js
@@ -0,0 +1,120 @@
+const BASE_URL = window.location.origin + "/perf";
+
+function getSelected(name) {
+ let e = document.getElementById(name);
+ return e.options[e.selectedIndex].value;
+}
+
+// Get lists of the available crates from the server and make
+// the lists of checkboxes and other settings.
+// Assumes the initial graph is total/total/by crate
+function make_settings(callback) {
+ let infoURL = 'info.json'; // FIXME use perf-rlo
+ return fetch(infoURL, {}).then(function(response) {
+ response.json().then(function(data) {
+ let phases_html = "";
+ for (let stat of data.stats) {
+ phases_html += ``;
+ }
+ let list = document.getElementById("stats");
+ if (list) {
+ list.innerHTML = phases_html;
+ list.value = 'instructions:u';
+ }
+ document.getElementById("as-of").innerHTML =
+ "Updated as of: " + (new Date(data.as_of)).toLocaleString();
+ callback();
+ });
+ }, function(err) {
+ document.getElementById("settings").innerHTML = "Error fetching info";
+ console.log("Error fetching info:");
+ console.log(err);
+ });
+}
+
+
+function query_string_for_state(state) {
+ let result = "?";
+ for (let k in state) {
+ if (result.length > 1) {
+ result += "&";
+ }
+ // Best known way to check if passed state is a date object.
+ if (state[k].toISOString) {
+ result += k + "=" + encodeURIComponent(state[k].toISOString());
+ } else if (typeof state[k] == "string") {
+ result += k + "=" + encodeURIComponent(state[k]);
+ } else {
+ result += k + "=" + encodeURIComponent(JSON.stringify(state[k]));
+ }
+ }
+ return result;
+}
+
+function load_state(callback, skip_settings) {
+ let params = new URLSearchParams(window.location.search.slice(1));
+ let state = {};
+ for (let param of params) {
+ let key = param[0];
+ let value = param[1];
+ if (key === "absolute") {
+ value = value === "true";
+ }
+ state[key] = value;
+ }
+ callback(state);
+ if (!skip_settings) {
+ make_settings(() => {
+ if (state.stat) {
+ let e = document.getElementById("stats");
+ for (let i = 0; i < e.options.length; i++) {
+ if (e.options[i].text === state.stat) {
+ e.options[i].selected = true;
+ break;
+ }
+ }
+ }
+ });
+ }
+ if (state.start) {
+ document.getElementById("start-bound").value = state.start;
+ }
+ if (state.end) {
+ document.getElementById("end-bound").value = state.end;
+ }
+ if (state.absolute === true || state.absolute === false) {
+ document.getElementById("absolute").checked = state.absolute;
+ } else {
+ // check absolute by default
+ let element = document.getElementById("absolute");
+ if (element) {
+ element.checked = true;
+ }
+ }
+}
+
+// This one is for making the request we send to the backend.
+function make_request(path, body) {
+ return fetch(BASE_URL + path, {
+ method: "POST",
+ body: JSON.stringify(body),
+ mode: "cors"
+ }).then(response => {
+ if (response.ok) {
+ if(MessagePack === undefined) {
+ alert("msgpack is not loaded");
+ return Promise.reject("msgpack is not loaded");
+ }
+ return MessagePack.decodeAsync(response.clone().body).catch(() => {
+ return response.text().then(data => alert(data));
+ });
+ } else {
+ return response.text().then(data => {
+ alert(data);
+ return Promise.reject(data);
+ });
+ }
+ }, err => {
+ console.log("error fetching ", path, ": ", err);
+ });
+}
diff --git a/site/static/compare.html b/site/static/compare.html
index 2db379a4e..ac5da9d6a 100644
--- a/site/static/compare.html
+++ b/site/static/compare.html
@@ -3,6 +3,56 @@
-
diff --git a/site/static/shared.js b/site/static/shared.js
index 18631947f..7fa8a4bef 100644
--- a/site/static/shared.js
+++ b/site/static/shared.js
@@ -1,89 +1,16 @@
-var BASE_URL = window.location.origin + "/perf";
-
-function getDate(id) {
- var result = document.getElementById(id).value;
- var as_date = new Date(result);
- if (isNaN(as_date.getTime())) {
- return "";
- } else {
- return as_date.toISOString();
- }
-}
-
-function getValue(id) {
- return document.getElementById(id).value;
-}
-
-function gatherChecks(name) {
- if (document.getElementById(name + "-total") &&
- document.getElementById(name + "-total").checked) {
- return { list: "All", content: null }; // Decoded as all variants
- }
- let result = [];
- let elements = document.getElementsByName(name);
- for (let element of elements) {
- if (element.checked && element.id && element.id != name + "-total") {
- result.push(element.id);
- }
- }
-
- return { list: "List", content: result };
-}
+const BASE_URL = window.location.origin + "/perf";
function getSelected(name) {
let e = document.getElementById(name);
return e.options[e.selectedIndex].value;
}
-function setSelected(id, text) {
- let e = document.getElementById(id);
- for (let i = 0; i < e.options.length; i++) {
- if (e.options[i].text === text) {
- e.options[i].selected = true;
- return;
- }
- }
-}
-
-function toList(list_object, type) {
- if (list_object.list == "All") {
- let result = [];
- let elements = document.getElementsByName(name);
- for (let element of elements) {
- if (element.checked && element.id && element.id != `check-${type}-total`) {
- result.push(element.id);
- }
- }
-
- return result;
- }
-
- return list_object.content;
-}
-
-function addTotalHandler(name) {
- var elements = document.getElementsByName(name);
- for (var i in elements) {
- if (elements[i].id != name + "-total") {
- elements[i].onclick = function() {
- document.getElementById(name + "-total").checked = false;
- };
- }
- }
- document.getElementById(name + "-total").onclick = function() {
- for (var i in elements) {
- if (elements[i].id != name + "-total") {
- elements[i].checked = false;
- }
- }
- };
-}
-
// Get lists of the available crates from the server and make
// the lists of checkboxes and other settings.
// Assumes the initial graph is total/total/by crate
function make_settings(callback) {
- return fetch(BASE_URL + "/info", {}).then(function(response) {
+ let infoURL = 'info.json'; // FIXME use perf-rlo
+ return fetch(infoURL, {}).then(function(response) {
response.json().then(function(data) {
let phases_html = "";
for (let stat of data.stats) {
@@ -105,72 +32,10 @@ function make_settings(callback) {
});
}
-function truncate_name(name) {
- if (name.length > 30) {
- return name.substring(0, 30) + "...";
- }
-
- return name;
-}
-
-function set_date(id, date) {
- let d = new Date(date);
- if (!Number.isNaN(d.getTime())) {
- document.getElementById(id).value = new Date(date).toISOString().split('T')[0];
- } else {
- console.warn("could not set", id, "to:", date, "; invalid date");
- }
- return document.getElementById(id).value;
-}
-
-function set_value(id, value) {
- document.getElementById(id).value = value;
-}
-
-// A bunch of helper functions for helping with keeping URLs up to date and
-// interacting with the browser history.
-
-// Dispatches on query string state. This examines the ?... part of the URL.
-//
-// The query string may not contain all of the parameters. If it doesn't, we simply pass what
-// exists.
-function dispatch_on_params(f) {
- if (!window.location.search) {
- f({}, false);
- return;
- }
-
- let params = new URLSearchParams(window.location.search.substring(1));
- let state = {};
- for (let param of params) {
- let key = param[0];
- let value = param[1];
-
- if (key == "phases" || key == "dates") {
- value = JSON.parse(value);
- }
-
- state[key] = value;
- }
- f(state, false);
-}
-
-// Add an entry into the browser's history to allow the back button to work correctly.
-//
-// This does not refresh the page in any way.
-//
-// For more information, see:
-// https://developer.mozilla.org/en-US/docs/Web/API/History_API#The_pushState()_method
-function push_state_to_history(state) {
- var query_string = query_string_for_state(state);
- if (query_string !== "") {
- history.pushState(state, "", query_string);
- }
-}
function query_string_for_state(state) {
- var result = "?";
- for (k in state) {
+ let result = "?";
+ for (let k in state) {
if (result.length > 1) {
result += "&";
}
@@ -192,11 +57,25 @@ function load_state(callback, skip_settings) {
for (let param of params) {
let key = param[0];
let value = param[1];
- if (key == "absolute") {
- value = value == "true" ? true : false;
+ if (key === "absolute") {
+ value = value === "true";
}
state[key] = value;
}
+ callback(state);
+ if (!skip_settings) {
+ make_settings(() => {
+ if (state.stat) {
+ let e = document.getElementById("stats");
+ for (let i = 0; i < e.options.length; i++) {
+ if (e.options[i].text === state.stat) {
+ e.options[i].selected = true;
+ break;
+ }
+ }
+ }
+ });
+ }
if (state.start) {
document.getElementById("start-bound").value = state.start;
}
@@ -212,34 +91,21 @@ function load_state(callback, skip_settings) {
element.checked = true;
}
}
- if (!skip_settings) {
- make_settings(() => {
- if (state.stat) {
- setSelected("stats", state.stat);
- }
- callback(state);
- });
- } else {
- callback(state);
- }
}
// This one is for making the request we send to the backend.
function make_request(path, body) {
- if(window.msgpack === undefined) {
- alert("msgpack is not loaded, maybe allow scripts from cdnjs.cloudflare.com?");
- return Promise.reject("msgpack is not loaded");
- }
-
return fetch(BASE_URL + path, {
method: "POST",
body: JSON.stringify(body),
mode: "cors"
}).then(response => {
if (response.ok) {
- return response.clone().arrayBuffer().then((arrayBuffer) => {
- return msgpack.decode(new Uint8Array(arrayBuffer))
- }).catch(() => {
+ if(MessagePack === undefined) {
+ alert("msgpack is not loaded");
+ return Promise.reject("msgpack is not loaded");
+ }
+ return MessagePack.decodeAsync(response.clone().body).catch(() => {
return response.text().then(data => alert(data));
});
} else {