Perf - Migrate cluster-page-sk away from Polymer.
Bug: skia:9219
Change-Id: I32ef32d644190fe5948cc8faadee1b3e133c625b
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/232538
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Commit-Queue: Joe Gregorio <jcgregorio@google.com>
diff --git a/go.sum b/go.sum
index 6559426..062dc72 100644
--- a/go.sum
+++ b/go.sum
@@ -1353,6 +1353,7 @@
k8s.io/utils v0.0.0-20190712204705-3dccf664f023/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1 h1:+ySTxfHnfzZb9ys375PXNlLhkJPLKgHajBU0N62BDvE=
k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
+rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
sigs.k8s.io/structured-merge-diff v0.0.0-20190426204423-ea680f03cc65/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/structured-merge-diff v0.0.0-20190521201008-1c46bef2e9c8/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
diff --git a/perf/modules/cluster-page-sk/cluster-page-sk-demo.html b/perf/modules/cluster-page-sk/cluster-page-sk-demo.html
new file mode 100644
index 0000000..a06ba9b
--- /dev/null
+++ b/perf/modules/cluster-page-sk/cluster-page-sk-demo.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>cluster-page-sk</title>
+ <meta charset="utf-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <script type="text/javascript" charset="utf-8">
+ var sk = {};
+ sk.perf = {};
+ sk.perf.commit_range_url = "";
+ sk.perf.key_order = ['config'];
+ </script>
+</head>
+<body>
+ <h1>cluster-page-sk</h1>
+ <!-- the element will appear here. -->
+
+ <error-toast-sk> </error-toast-sk>
+ <h2>Events</h2>
+ <pre id=events></pre>
+ <script type="text/javascript" charset="utf-8">
+ customElements.whenDefined('cluster-page-sk').then(() => {
+ // Insert the element later, which should given enough time for fetchMock to be in place.
+ document.querySelector('h1').insertAdjacentElement('afterend', document.createElement('cluster-page-sk'));
+
+ document.querySelector('cluster-page-sk').addEventListener('some-event-name', (e) => {
+ document.querySelector('#events').textContent = JSON.stringify(e.detail, null, ' ');
+ });
+
+ });
+ </script>
+</body>
+</html>
diff --git a/perf/modules/cluster-page-sk/cluster-page-sk-demo.js b/perf/modules/cluster-page-sk/cluster-page-sk-demo.js
new file mode 100644
index 0000000..4c0f6bc
--- /dev/null
+++ b/perf/modules/cluster-page-sk/cluster-page-sk-demo.js
@@ -0,0 +1,140 @@
+import './index.js'
+import 'elements-sk/error-toast-sk'
+import { fetchMock } from '@bundled-es-modules/fetch-mock';
+
+fetchMock.post('/_/count/', async function() {
+ // Wait 1s before returning the content so we can see the spinner in action.
+ return await new Promise(res => setTimeout(() => res({count: Math.floor(Math.random()*2000)}), 1000))
+});
+
+fetchMock.get('/_/initpage/?tz=America/New_York', () => {
+ return {
+ "dataframe": {
+ "traceset": null,
+ "header": null,
+ "paramset": {
+ "arch": [
+ "WASM",
+ "arm",
+ "arm64",
+ "asmjs",
+ "wasm",
+ "x86",
+ "x86_64"
+ ],
+ "bench_type": [
+ "BRD",
+ "deserial",
+ "micro",
+ "playback",
+ "recording",
+ "skandroidcodec",
+ "skcodec",
+ "tracing"
+ ],
+ "browser": [
+ "Chrome"
+ ],
+ "clip": [
+ "0_0_1000_1000"
+ ],
+ "compiled_language": [
+ "asmjs",
+ "wasm"
+ ],
+ "compiler": [
+ "Clang",
+ "EMCC",
+ "GCC",
+ "MSVC",
+ "emsdk",
+ "none"
+ ],
+ "config": [
+ "8888",
+ "angle_d3d11_es2",
+ "angle_d3d11_es2_msaa8",
+ "angle_gl_es2",
+ "angle_gl_es2_msaa8",
+ "commandbuffer",
+ "default",
+ "enarrow",
+ "esrgb",
+ "f16",
+ "gl",
+ "gles",
+ "glesmsaa4",
+ "glessrgb",
+ "glmsaa4",
+ "glmsaa8",
+ "glsrgb",
+ "meta",
+ "mtl",
+ ],
+ "configuration": [
+ "Debug",
+ "Presubmit",
+ "Release",
+ "devrel",
+ "eng",
+ "sdk"
+ ],
+ "cpu_or_gpu": [
+ "CPU",
+ "GPU"
+ ],
+ },
+ "skip": 0
+ },
+ "ticks": [],
+ "skps": [],
+ "msg": "",
+ };
+});
+
+fetchMock.post('/_/cidRange/', () => {
+ console.log('fetch /_/cidRange');
+ return [
+ {
+ "offset":43389,
+ "source":"master",
+ "author":"Avinash Parchuri (aparchur@google.com)",
+ "message":"3a543aa - 23h 34m - Reland \"[skottie] Add onTextProperty support into ",
+ "url":"https://skia.googlesource.com/skia/+/3a543aafd4e68af182ef88572086c094cd63f0b2",
+ "hash":"3a543aafd4e68af182ef88572086c094cd63f0b2",
+ "ts":1565099441
+ },
+ {
+ "offset":43390,
+ "source":"master",
+ "author":"Robert Phillips (robertphillips@google.com)",
+ "message":"bdb0919 - 21h 15m - Use GrComputeTightCombinedBufferSize in GrMtlGpu::",
+ "url":"https://skia.googlesource.com/skia/+/bdb0919dcc6a700b41492c53ecf06b40983d13d7",
+ "hash":"bdb0919dcc6a700b41492c53ecf06b40983d13d7",
+ "ts":1565107798
+ },
+ {
+ "offset":43391,
+ "source":"master",
+ "author":"Hal Canary (halcanary@google.com)",
+ "message":"e45bf6a - 20h 33m - experimental/editor: interface no longer uses stri",
+ "url":"https://skia.googlesource.com/skia/+/e45bf6a603b7990f418eaf19ef0e2a2e59a9f449",
+ "hash":"e45bf6a603b7990f418eaf19ef0e2a2e59a9f449",
+ "ts":1565110328
+ },
+ ];
+});
+
+
+fetchMock.get('https://skia.org/loginstatus/', () => {
+ return {
+ "Email":"jcgregorio@google.com",
+ "ID":"110642259984599645813",
+ "LoginURL":"https://accounts.google.com/...",
+ "IsAGoogler":true,
+ "IsAdmin":true,
+ "IsEditor":false,
+ "IsViewer":true,
+ }
+});
+
diff --git a/perf/modules/cluster-page-sk/cluster-page-sk.js b/perf/modules/cluster-page-sk/cluster-page-sk.js
new file mode 100644
index 0000000..23e4a6c
--- /dev/null
+++ b/perf/modules/cluster-page-sk/cluster-page-sk.js
@@ -0,0 +1,369 @@
+/**
+ * @module module/cluster-page-sk
+ * @description <h2><code>cluster-page-sk</code></h2>
+ *
+ * The top level element for clustering traces.
+ *
+ */
+import { ElementSk } from '../../../infra-sk/modules/ElementSk'
+import { errorMessage } from 'elements-sk/errorMessage'
+import { html, render } from 'lit-html'
+import { jsonOrThrow } from 'common-sk/modules/jsonOrThrow'
+import { stateReflector } from 'common-sk/modules/stateReflector'
+
+import 'elements-sk/spinner-sk'
+import 'elements-sk/checkbox-sk'
+import 'elements-sk/styles/buttons'
+
+import '../../../infra-sk/modules/sort-sk'
+
+import '../algo-select-sk'
+import '../cluster-summary2-sk'
+import '../commit-detail-picker-sk'
+import '../day-range-sk'
+import '../query-count-sk'
+import '../query-sk'
+import '../query-summary-sk'
+
+const _summaryRows = (ele) => {
+ const ret = ele._summaries.map((summary) => {
+ return html`<cluster-summary2-sk .full_summary=${summary} notriage></cluster-summary2-sk>`;
+ });
+ if (!ret.length) {
+ ret.push(html`
+ <p class=info>
+ No clusters found.
+ </p>
+ `);
+ }
+ return ret;
+}
+
+const template = (ele) => html`
+ <h2>Commit</h2>
+ <h3>Appears in Date Range</h3>
+ <div class=day-range-with-spinner>
+ <day-range-sk
+ id=range
+ @day-range-change=${ele._rangeChange}
+ begin=${ele._state.begin}
+ end=${ele._state.end}
+ ></day-range-sk>
+ <spinner-sk ?active=${ele._updating_commits}></spinner-sk>
+ </div>
+ <h3>Commit</h3>
+ <div>
+ <commit-detail-picker-sk
+ @commit-selected=${ele._commitSelected}
+ .selected=${ele._selected_commit_index}
+ .details=${ele._cids}
+ id=commit
+ ></commit-picker-sk>
+ </div>
+
+ <h2>Algorithm</h2>
+ <algo-select-sk
+ algo=${ele._state.algo}
+ @algo-change=${(e) => ele._state.algo = e.detail.algo}
+ ></algo-select-sk>
+
+ <h2>Query</h2>
+ <div class=query-action>
+ <query-sk
+ @query-change=${ele._queryChanged}
+ .key_order=${sk.perf.key_order}
+ .paramset=${ele._paramset}
+ current_query=${ele._state.query}
+ ></query-sk>
+ <div id=selections>
+ <h3>Selections</h3>
+ <query-summary-sk id=summary selection=${ele._state.query}></query-summary-sk>
+ <div>
+ Matches:
+ <query-count-sk
+ url='/_/count/'
+ current_query=${ele._state.query}
+ @paramset-changed=${ele._paramsetChanged}
+ ></query-count-sk>
+ </div>
+ <button @click=${ele._start} class=action id=start ?disabled=${!!ele._requestId} >
+ Run
+ </button>
+ <div>
+ <spinner-sk ?active=${!!ele._requestId}></spinner-sk>
+ <span>${ele._status}</span>
+ </div>
+ </div>
+ </div>
+
+ <details>
+ <summary id=advanced>
+ <h2>Advanced</h2>
+ </summary>
+ <div id=inputs>
+ <label>
+ K (A value of 0 means the server chooses).
+ <input
+ type=number
+ min=0
+ max=100
+ .value=${ele._state.k}
+ @input=${(e) => ele._state.k = e.target.value}>
+ </label>
+ <label>
+ Number of commits to include on either side.
+ <input
+ type=number
+ min=1
+ max=25
+ .value=${ele._state.radius}
+ @input=${(e) => ele._state.radius = e.target.value}>
+ </label>
+ <label>
+ Clusters are interesting if regression score >= this.
+ <input
+ type=number
+ min=0
+ max=500
+ .value=${ele._state.interesting}
+ @input=${(e) => ele._state.interesting = e.target.value}>
+ </label>
+ <checkbox-sk
+ ?checked=${ele._state.sparse}
+ @input=${(e) => ele._state.sparse = e.target.checked}
+ label='Data is sparse, so only include commits that have data.'
+ >
+ </checkbox-sk>
+ </div>
+ </details>
+
+ <h2>Results</h2>
+ <sort-sk target=clusters>
+ <button data-key=clustersize>Cluster Size </button>
+ <button data-key=stepregression data-default=up>Regression </button>
+ <button data-key=stepsize>Step Size </button>
+ <button data-key=steplse>Least Squares</button>
+ </sort-sk>
+ <div id=clusters @open-keys=${ele._openKeys}>
+ ${_summaryRows(ele)}
+ </div>
+ `;
+
+window.customElements.define('cluster-page-sk', class extends ElementSk {
+ constructor() {
+ super(template);
+
+ // The computed clusters.
+ this._summaries = [];
+
+ // The commits to choose from.
+ this._cids = [];
+
+ // Which commit is selected.
+ this._selected_commit_index = -1;
+
+ // The paramset to build queries from.
+ this._paramset = {};
+
+ // The id of the current cluster request. Will be the empty string if
+ // there is no pending request.
+ this._requestId = '';
+
+ // The status of a running request.
+ this._status = '';
+
+ // True if we are fetching a new list of _cids from the server.
+ this._updating_commits = false;
+
+ // The state that gets reflected to the URL.
+ this._state = {
+ begin: Math.floor(Date.now()/1000 - 24*60*60),
+ end: Math.floor(Date.now()/1000),
+ source: '',
+ offset: -1,
+ radius: '' + sk.perf.radius,
+ query: '',
+ k: '0',
+ algo: 'kmeans',
+ interesting: '' + sk.perf.interesting,
+ sparse: false,
+ };
+
+ // Only update _cids if the date range is different from the last fetch.
+ this._lastRange = {
+ begin: null,
+ end: null,
+ };
+ }
+
+ connectedCallback() {
+ super.connectedCallback();
+ this._render();
+ this._clusters = this.querySelector('#clusters');
+
+ const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
+ fetch(`/_/initpage/?tz=${tz}`).then(jsonOrThrow).then((json) => {
+ this._paramset = json.dataframe.paramset;
+ this._render();
+ }).catch(errorMessage);
+
+ this._stateHasChanged = stateReflector(() => this._state, (state) => {
+ this._state = state;
+ this._render();
+ this._updateCommitSelections();
+ });
+ // There are a lot of pieces of _state, so just keep the URL up to date by polling.
+ this._keepURLUpdated();
+ }
+
+ _keepURLUpdated() {
+ this._stateHasChanged();
+ window.setTimeout(() => this._keepURLUpdated(), 100);
+ }
+
+ _queryChanged(e) {
+ this._state.query = e.detail.q;
+ this._render();
+ }
+
+ _paramsetChanged(e) {
+ this._paramset = e.detail;
+ this._render();
+ }
+
+ _openKeys(e) {
+ const query = {
+ keys: e.detail.shortcut,
+ begin: e.detail.begin,
+ end: e.detail.end,
+ xbaroffset: e.detail.xbar.offset,
+ num_commits: 50,
+ request_type: 1,
+ };
+ window.open(`/e/?${sk.query.fromObject(query)}`, '_blank');
+ }
+
+ _rangeChange(e) {
+ this._state.begin = e.detail.begin;
+ this._state.end = e.detail.end;
+ this._updateCommitSelections();
+ }
+
+ _commitSelected(e) {
+ this._state.source = e.detail.commit.source;
+ this._state.offset = e.detail.commit.offset;
+ }
+
+ _updateCommitSelections() {
+ if (this._lastRange.begin === this._state.begin && this._lastRange.end === this._state.end) {
+ return;
+ }
+ this._lastRange = {
+ begin: this._state.begin,
+ end: this._state.end,
+ };
+ const body = {
+ begin: this._state.begin,
+ end: this._state.end,
+ source: this._state.source,
+ offset: this._state.offset,
+ };
+ this._updating_commits = true;
+ fetch('/_/cidRange/', {
+ method: 'POST',
+ body: JSON.stringify(body),
+ headers:{
+ 'Content-Type': 'application/json'
+ }
+ }).then(jsonOrThrow).then((cids) => {
+ this._updating_commits = false;
+ cids.reverse();
+ this._cids = cids;
+
+ this._selected_commit_index = -1;
+ // Look for commit id in this._cids.
+ for (let i = 0; i < cids.length; i++) {
+ if (cids[i].source == this._state.source && cids[i].offset == this._state.offset) {
+ this._selected_commit_index = i;
+ break
+ }
+ }
+
+ if (!this._state.begin) {
+ this._state.begin = cids[cids.length-1].ts;
+ this._state.end = cids[0].ts;
+ }
+ this._render();
+ }).catch((msg) => {
+ if (msg) {
+ errorMessage(msg, 10000);
+ }
+ this._updating_commits = false;
+ this._render();
+ });
+ }
+
+ _catch(msg) {
+ this._requestId = '';
+ this._status = '';
+ if (msg) {
+ sk.errorMessage(msg, 10000);
+ }
+ this._render();
+ }
+
+ _checkClusterRequestStatus(cb) {
+ fetch(`/_/cluster/status/${this._requestId}`).then(jsonOrThrow).then((json) => {
+ if (json.state === 'Running') {
+ this._status = json.message;
+ this._render();
+ window.setTimeout(() => this._checkClusterRequestStatus(cb), 300);
+ } else {
+ if (json.value) {
+ cb(json.value);
+ }
+ this._catch(json.message);
+ }
+ }).catch(msg => this._catch(msg));
+ }
+
+ _start() {
+ if (this._requestId) {
+ errorMessage('There is a pending query already running.');
+ return;
+ }
+ const body = {
+ source: this._state.source,
+ offset: this._state.offset,
+ radius: +this._state.radius,
+ query: this._state.query,
+ k: +this._state.k,
+ tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
+ algo: this._state.algo,
+ interesting: +this._state.interesting,
+ sparse: this._state.sparse,
+ };
+ this._summaries = [];
+ fetch('/_/cluster/start', {
+ method: 'POST',
+ body: JSON.stringify(body),
+ headers:{
+ 'Content-Type': 'application/json'
+ }
+ }).then(jsonOrThrow).then((json) => {
+ this._requestId = json.id;
+ this._checkClusterRequestStatus((summaries) => {
+ this._summaries = [];
+ summaries.summary.Clusters.forEach((cl) => {
+ cl.ID = -1;
+ this._summaries.push({
+ summary: cl,
+ frame: summaries.frame,
+ });
+ });
+ this._render();
+ });
+ }).catch(msg => this._catch(msg));
+ }
+
+});
diff --git a/perf/modules/cluster-page-sk/cluster-page-sk.scss b/perf/modules/cluster-page-sk/cluster-page-sk.scss
new file mode 100644
index 0000000..17c0ed4
--- /dev/null
+++ b/perf/modules/cluster-page-sk/cluster-page-sk.scss
@@ -0,0 +1,24 @@
+@import '~elements-sk/colors';
+
+cluster-page-sk {
+ algo-select-sk {
+ max-width: 10em;
+ display: block;
+ }
+
+ summary h2 {
+ display: inline-block;
+ }
+
+ div#inputs > * {
+ display: block;
+ margin: 1em;
+ }
+ div#inputs > label > input {
+ display: block;
+ }
+
+ .query-action {
+ display: flex;
+ }
+}
diff --git a/perf/modules/cluster-page-sk/index.js b/perf/modules/cluster-page-sk/index.js
new file mode 100644
index 0000000..d45c7a9
--- /dev/null
+++ b/perf/modules/cluster-page-sk/index.js
@@ -0,0 +1,2 @@
+import './cluster-page-sk.js'
+import './cluster-page-sk.scss'
diff --git a/perf/modules/commit-detail-panel-sk/commit-detail-panel-sk.js b/perf/modules/commit-detail-panel-sk/commit-detail-panel-sk.js
index 194a70e..bd94913 100644
--- a/perf/modules/commit-detail-panel-sk/commit-detail-panel-sk.js
+++ b/perf/modules/commit-detail-panel-sk/commit-detail-panel-sk.js
@@ -8,6 +8,7 @@
*
* <pre>
* {
+ * selected: 2,
* description: "foo (foo@example.org) 62W Commit from foo.",
* commit: {
* author: "foo (foo@example.org)",
@@ -87,6 +88,7 @@
}
this.selected = +ele.dataset['id']
let detail = {
+ selected: ele.dataset.id,
description: ele.textContent.trim(),
commit: this._details[this.selected],
}
diff --git a/perf/modules/commit-detail-picker-sk/commit-detail-picker-sk.js b/perf/modules/commit-detail-picker-sk/commit-detail-picker-sk.js
index d4de190..06c1063 100644
--- a/perf/modules/commit-detail-picker-sk/commit-detail-picker-sk.js
+++ b/perf/modules/commit-detail-picker-sk/commit-detail-picker-sk.js
@@ -23,8 +23,21 @@
import { html, render } from 'lit-html'
import { ElementSk } from '../../../infra-sk/modules/ElementSk'
+
+function _titleFrom(ele) {
+ const index = ele.selected;
+ if (index === -1) {
+ return 'Choose a commit.';
+ }
+ const d = ele._details[index];
+ if (!d) {
+ return 'Choose a commit.';
+ }
+ return `${d.author} - ${d.message}`;
+}
+
const template = (ele) => html`
- <button @click=${ele._open}>${ele._title}</button>
+ <button @click=${ele._open}>${_titleFrom(ele)}</button>
<dialog-sk>
<commit-detail-panel-sk @commit-selected='${ele._panelSelect}' .details='${ele._details}' selectable selected=${ele.selected}></commit-detail-panel-sk>
<button @click=${ele._close}>Close</button>
@@ -47,6 +60,7 @@
_panelSelect(e) {
this._title = e.detail.description;
+ this.selected = e.detail.selected;
this._render();
}
@@ -65,8 +79,10 @@
}
/** @prop selected {string} Mirrors the selected attribute. */
- get selected() { return this.getAttribute('selected'); }
- set selected(val) { this.setAttribute('selected', val); }
+ get selected() { return +this.getAttribute('selected'); }
+ set selected(val) {
+ this.setAttribute('selected', val);
+ }
attributeChangedCallback(name, oldValue, newValue) {
this._render();
diff --git a/perf/modules/explore-sk/explore-sk.js b/perf/modules/explore-sk/explore-sk.js
index 92474ca..2de9513 100644
--- a/perf/modules/explore-sk/explore-sk.js
+++ b/perf/modules/explore-sk/explore-sk.js
@@ -115,7 +115,8 @@
<h3>Selections</h3>
<query-summary-sk id=summary></query-summary-sk>
<div class=query-counts>
- Matches: <query-count-sk url='/_/count/'></query-count-sk>
+ Matches: <query-count-sk url='/_/count/' @paramset-changed=${ele._paramsetChanged}>
+ </query-count-sk>
</div>
<button @click=${ele._add} class=action>Plot</button>
</div>
@@ -234,6 +235,10 @@
}).catch(errorMessage);
}
+ _paramsetChanged(e) {
+ this._query.paramset = e.detail;
+ }
+
_queryChangeDelayedHandler(e) {
this._query_count.current_query = e.detail.q;
}
diff --git a/perf/modules/perf-scaffold-sk/perf-scaffold-sk.scss b/perf/modules/perf-scaffold-sk/perf-scaffold-sk.scss
index 02d0529..58abfed 100644
--- a/perf/modules/perf-scaffold-sk/perf-scaffold-sk.scss
+++ b/perf/modules/perf-scaffold-sk/perf-scaffold-sk.scss
@@ -8,6 +8,22 @@
font-size: 12px;
}
+ h1 {
+ font-size: 20px;
+ }
+
+ h2 {
+ font-size: 18px;
+ }
+
+ h3 {
+ font-size: 16px;
+ }
+
+ h4 {
+ font-size: 14px;
+ }
+
nav-button-sk button {
fill: var(--white);
color: var(--white);
diff --git a/perf/modules/query-count-sk/query-count-sk.js b/perf/modules/query-count-sk/query-count-sk.js
index 1c7fb47..a4a2e89 100644
--- a/perf/modules/query-count-sk/query-count-sk.js
+++ b/perf/modules/query-count-sk/query-count-sk.js
@@ -8,6 +8,9 @@
*
* @attr {string} url - The URL to POST the query to.
*
+ * @evt paramset-changed - An event with the updated paramset in e.detail
+ * from the fetch response.
+ *
*/
import { html, render } from 'lit-html'
import { ElementSk } from '../../../infra-sk/modules/ElementSk'
@@ -44,7 +47,7 @@
if (!this._connected) {
return;
}
- if (!this.url || !this.current_query) {
+ if (!this.url) {
return;
}
if (this._requestInProgress) {
@@ -72,6 +75,7 @@
if (this._last_query != this.current_query) {
this._fetch();
}
+ this.dispatchEvent(new CustomEvent('paramset-changed', {detail: json.paramset, bubbles: true }));
}).catch((msg) => {
this._requestInProgress = false;
this._render();
diff --git a/perf/pages/main.js b/perf/pages/main.js
index 440ca07..a91579e 100644
--- a/perf/pages/main.js
+++ b/perf/pages/main.js
@@ -7,6 +7,7 @@
import '../modules/algo-select-sk'
import '../modules/alert-config-sk'
import '../modules/alerts-page-sk'
+import '../modules/cluster-page-sk'
import '../modules/cluster-summary2-sk'
import '../modules/commit-detail-panel-sk'
import '../modules/commit-detail-picker-sk'
diff --git a/perf/res/imp/cluster-page.html b/perf/res/imp/cluster-page.html
deleted file mode 100644
index 515b131..0000000
--- a/perf/res/imp/cluster-page.html
+++ /dev/null
@@ -1,396 +0,0 @@
-<!-- The <cluster-page-sk> custom element declaration.
-
- The top level element for clustering traces.
-
- Attributes:
- None.
-
- Events:
- None.
-
- Methods:
- None.
-
--->
-<link rel="import" href="/res/imp/bower_components/iron-flex-layout/iron-flex-layout-classes.html">
-<link rel="import" href="/res/imp/bower_components/paper-checkbox/paper-checkbox.html">
-<link rel="import" href="/res/imp/bower_components/paper-spinner/paper-spinner.html">
-<link rel="import" href="/res/imp/bower_components/paper-input/paper-input.html">
-<link rel="import" href="/res/imp/bower_components/iron-selector/iron-selector.html">
-
-<link rel="import" href="/res/common/imp/details-summary.html">
-<link rel="import" href="/res/common/imp/sort.html" />
-<link rel="stylesheet" href="/res/common/css/md.css">
-
-<dom-module id="cluster-page-sk">
- <style include="iron-flex iron-flex-alignment iron-positioning">
- day-range-sk {
- display: block;
- }
-
- label {
- width: 4em;
- display: inline-block;
- text-align: right;
- }
-
- #status {
- display: inline-block;
- margin: 0.5em;
- }
-
- cluster-summary2-sk {
- box-shadow: 4px 4px 10px 1px rgba(0,0,0,0.75);
- display: block;
- padding: 1em;
- margin: 1em;
- width: 80em;
- }
-
- #advanced h2 {
- display: inline-block;
- margin: 0;
- }
-
- #advanced {
- height: 2em;
- display: inline-block;
- vertical-align: bottom;
- }
-
- #inputs {
- margin-left: 2em;
- }
-
- #inputs paper-input {
- width: 20em;
- }
-
- .iron-selected {
- background: #eee;
- }
-
- iron-selector div {
- width: 10em;
- margin: 0.3em 1em;
- padding: 0.2em;
- }
-
- .info {
- margin: 1em;
- font-size: 18px;
- color: #E7298A;
- }
-
- paper-checkbox {
- --paper-checkbox-checked-color: #1f78b4;
- --paper-checkbox-checked-ink-color: #1f78b4;
- }
-
- algo-select-sk {
- width: 20em;
- display: block;
- }
- </style>
- <template>
- <h2>Commit</h2>
- <h3>Appears in Date Range</h3>
- <div class="layout horizontal">
- <day-range-sk id=range on-day-range-change="_rangeChange"></day-range-sk>
- <paper-spinner id=spinner></paper-spinner>
- </div>
- <h3>Commit</h3>
- <div>
- <commit-detail-picker-sk on-commit-selected="_commitSelected" id=commit></commit-picker-sk>
- </div>
-
- <h2>Algorithm</h2>
- <algo-select-sk on-algo-change=_algoChange algo="[[state.algo]]"></algo-select-sk>
-
- <h2>Query</h2>
- <div class="layout horizontal">
- <query-sk id=query on-query-change="_queryChange" on-query-change-delayed="_queryChangeDelayed"></query-sk>
- <div class="layout vertical" id=selections>
- <h3>Selections</h3>
- <query-summary-sk id=summary></query-summary-sk>
- <div>
- Matches: <span id=matches></span>
- </div>
- <button on-tap="_start" class=action id=start>Run</button>
- <div class="layout horizontal center">
- <paper-spinner id=clusterSpinner></paper-spinner>
- <span id=status></span>
- </div>
- </div>
- </div>
-
- <details-sk>
- <summary-sk id=advanced>
- <h2>Advanced</h2>
- </summary-sk>
- <div id=inputs>
- <paper-input type=number min=0 max=100 value="{{state.k}}" label="K (A value of 0 means the server chooses)."></paper-input>
- <paper-input type=number min=1 max=25 value="{{state.radius}}" label="Number of commits to include on either side."></paper-input>
- <paper-input type=number min=0 max=500 value="{{state.interesting}}" label="Clusters are interesting if regression score >= this."></paper-input>
- <paper-checkbox checked="{{state.sparse}}">Data is sparse, so only include commits that have data.</paper-checkbox>
- </div>
- </details-sk>
-
- <h2>Results</h2>
- <sort-sk target=clusters node_name="CLUSTER-SUMMARY2-SK">
- <button data-key="clustersize">Cluster Size </button>
- <button data-key="stepregression" data-default=up>Regression </button>
- <button data-key="stepsize">Step Size </button>
- <button data-key="steplse">Least Squares</button>
- </sort-sk>
- <div id=clusters>
- <template id=results is="dom-repeat" items="{{_summaries}}">
- <cluster-summary2-sk full_summary="[[item]]" notriage></cluster-summary2-sk>
- </template>
- <template is="dom-if" if="{{_isZeroLength(_summaries,_requestId)}}">
- <p class=info>
- No clusters found.
- </p>
- </template>
- </div>
- </template>
-</dom-module>
-
-<script>
- Polymer({
- is: "cluster-page-sk",
-
- properties: {
- _dataframe: {
- type: Object,
- value: function() { return {
- traceset: {},
- }; },
- },
- // Keep track of whether a request is inflight to count the number of traces that match the current query.
- _countInProgress: {
- type: Boolean,
- value: false,
- },
- // The state that goes into the URL.
- //
- state: {
- type: Object,
- value: function() { return {
- begin: Math.floor(Date.now()/1000 - 24*60*60),
- end: Math.floor(Date.now()/1000),
- source: "",
- offset: -1,
- radius: "" + sk.perf.radius,
- query: "",
- k: "" + 0,
- algo: "kmeans",
- interesting: "" + sk.perf.interesting,
- sparse: false,
- }; },
- },
- // The id of the current cluster request. Will be the empty string
- // if there is no pending request.
- _requestId: {
- type: String,
- value: "",
- },
- _cids: {
- type: Array,
- value: function() { return [] },
- },
- // Keep track of whether a request is inflight to count the number of traces that match the current query.
- _countInProgress: {
- type: Boolean,
- value: false,
- },
- _requestId: {
- type: String,
- value: "",
- }
- },
-
- ready: function() {
- var tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
- sk.get("/_/initpage/?tz=" + tz).then(JSON.parse).then(function(json) {
- this.$.query.key_order = sk.perf.key_order;
- this.$.query.paramset = json.dataframe.paramset;
- }.bind(this)).catch(sk.errorMessage);
-
-
- // From this point on reflect the state to the URL.
- sk.stateReflector(this, this._updateCommitSelections.bind(this));
-
- this.$.clusters.addEventListener("open-keys", function(e) {
- var query = {
- keys: e.detail.shortcut,
- begin: e.detail.begin,
- end: e.detail.end,
- xbaroffset: e.detail.xbar.offset,
- num_commits: 50,
- request_type: 1,
- };
- window.open('/e/?' + sk.query.fromObject(query), '_blank');
- }.bind(this));
- },
-
- // _catch for sk.post and sk.get requests around clustering.
- _catch: function(msg) {
- this._requestId = "";
- this.$.clusterSpinner.active = false;
- this.$.start.disabled = false;
- if (msg) {
- sk.errorMessage(msg, 10000);
- }
- this.$.status.textContent = "";
- },
-
- _start: function() {
- if (this._requestId != "") {
- sk.errorMessage("There is a pending query already running.");
- return
- }
- var body = {
- source: this.state.source,
- offset: this.state.offset,
- radius: +this.state.radius,
- query: this.state.query,
- k: +this.state.k,
- tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
- algo: this.state.algo,
- interesting: +this.state.interesting,
- sparse: this.state.sparse,
- };
- this._summaries = [];
- this.$.results.render();
- this.$.clusterSpinner.active = true;
- this.$.start.disabled = true;
- sk.post("/_/cluster/start", JSON.stringify(body), "application/json").then(JSON.parse).then(function(json) {
- this._requestId = json.id;
- this._checkClusterRequestStatus(function(summaries) {
- var fullSummaries = [];
- summaries.summary.Clusters.forEach(function(cl) {
- cl.ID = -1;
- fullSummaries.push({
- summary: cl,
- frame: summaries.frame,
- });
- });
- this.set('_summaries', fullSummaries);
- }.bind(this));
- }.bind(this)).catch(this._catch.bind(this));
- },
-
- _algoChange: function(e) {
- this.state.algo = e.detail.algo;
- },
-
- _checkClusterRequestStatus: function(cb) {
- sk.get("/_/cluster/status/"+this._requestId).then(JSON.parse).then(function(json) {
- if (json.state == "Running") {
- this.$.status.textContent = json.message;
- window.setTimeout(this._checkClusterRequestStatus.bind(this, cb), 300);
- } else {
- if (json.value) {
- cb(json.value);
- }
- this._catch(json.message);
- }
- }.bind(this)).catch(this._catch.bind(this));
- },
-
- _updateCommitSelections: function() {
- this.$.range.begin = this.state.begin;
- this.$.range.end = this.state.end;
- this.$.query.current_query = this.state.query;
- var body = {
- begin: this.state.begin,
- end: this.state.end,
- source: this.state.source,
- offset: this.state.offset,
- };
- this.$.spinner.active = true;
- sk.post("/_/cidRange/", JSON.stringify(body), "application/json").then(JSON.parse).then(function(cids) {
- this.$.spinner.active = false;
- cids.reverse();
- this._cids = cids;
- this.$.commit.details = cids;
-
- var index = -1;
- // Look for commit id in this._cids.
- for (var i = 0; i < cids.length; i++) {
- if (cids[i].source == this.state.source && cids[i].offset == this.state.offset) {
- index = i;
- break
- }
- }
- // If there is then select via index.
- if (index != -1) {
- this.$.commit.selected = index;
- }
-
- if (this.state.begin == 0) {
- this.state.begin = cids[cids.length-1].ts;
- this.$.range.begin = cids[cids.length-1].ts;
- this.state.end = cids[0].ts;
- this.$.range.end = cids[0].ts;
- }
- }.bind(this)).catch(function(msg) {
- if (msg) {
- sk.errorMessage(msg, 10000);
- }
- this.$.spinner.active = false;
- }.bind(this));
- this._updateCount();
- },
-
- _commitSelected: function(e) {
- this.state.source = e.detail.commit.source;
- this.state.offset = e.detail.commit.offset;
- },
-
- _queryChange: function(e) {
- this.state.query = e.detail.q;
- this.$.summary.selection = e.detail.q;
- },
-
- _queryChangeDelayed: function(e) {
- this._updateCount();
- },
-
- _rangeChange: function(e) {
- if (!this.state) {
- return
- }
- this.state.begin = e.detail.begin;
- this.state.end = e.detail.end;
- this._updateCommitSelections();
- },
-
- _updateCount: function() {
- if (this._countInProgress === true) {
- return
- }
- this._countInProgress = true;
- let body = {
- q: this.$.query.current_query,
- begin: this.state.begin,
- end: this.state.end,
- };
- sk.post("/_/count/", JSON.stringify(body)).then(JSON.parse).then(function(json) {
- this._countInProgress = false;
- this.$.matches.textContent = json.count;
- if (json.paramset) {
- this.$.query.paramset = json.paramset;
- }
- }.bind(this)).catch(function() {
- this._countInProgress = false;
- });
- },
-
- _isZeroLength: function(ar, _requestId) {
- return ar.length == 0 && this._requestId == "";
- }
-
- });
-</script>
diff --git a/perf/templates/clusters2.html b/perf/templates/clusters2.html
index 57a80f9..4f60a70 100644
--- a/perf/templates/clusters2.html
+++ b/perf/templates/clusters2.html
@@ -6,7 +6,46 @@
this.sk = this.sk || {};
this.sk.perf = {{.context}};
</script>
- {{template "header.html" .}}
+ <!-- Can't use header.html here until everything is ported away from Polymer. -->
+ <meta charset="utf-8">
+ <meta name="theme-color" content="#1f78b4">
+ <link rel="shortcut icon" href="/res/img/favicon.ico" />
+ <link rel="manifest" href="/res/manifest.json">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <script src="/res/js/core.js" type="text/javascript" charset="utf-8"></script>
+ <style type="text/css" media="screen">
+ body {
+ margin: 0;
+ padding: 0;
+ }
+
+ .main * {
+ font-size: 12px;
+ }
+
+ .main h2 {
+ font-size: 16px !important;
+ }
+
+ .main h3 {
+ font-size: 14px !important;
+ }
+
+ .main button {
+ text-transform: none !important;
+ }
+ </style>
+ <script>
+ // Check that service workers are registered
+ if ('serviceWorker' in navigator) {
+ window.addEventListener('load', () => {
+ navigator.serviceWorker.register('/service-worker.js');
+ });
+ }
+ </script>
+ <link href="/dist/main-bundle.css" rel="stylesheet">
+ <script type="text/javascript" src="/dist/main-bundle.js"></script>
</head>
<body>
<perf-scaffold-sk>