| <!-- |
| This in an HTML Import-able file that contains the definition |
| of the following elements: |
| |
| <job-timeline-sk> |
| |
| Status information about the task scheduler. |
| |
| To use this file import it: |
| |
| <link href="/res/imp/job-timeline-sk.html" rel="import" /> |
| |
| Usage: |
| |
| <job-timeline-sk job="[[job]]" tasks="[[tasks]]" epochs="[[epochs]]"></job-timeline-sk> |
| |
| Properties: |
| job: Job instance, as provided by the Task Scheduler server. |
| tasks: Array of Task instances, as provided by the Task Scheduler server. |
| epochs: Array of Strings; timestamps indicating events, eg. scheduler tick times. |
| |
| Methods: |
| None. |
| |
| Events: |
| None. |
| --> |
| <link rel="import" href="/res/imp/bower_components/polymer/polymer.html"> |
| <dom-module id="job-timeline-sk"> |
| <template> |
| <style> |
| :host{ |
| flex-grow: 1; |
| display: flex; |
| flex-direction: column; |
| } |
| #svg { |
| flex-grow: 1; |
| min-width: 600px; |
| min-height: 300px; |
| max-width: 1800px; |
| max-height: 800px; |
| } |
| </style> |
| <h2>Job <span>[[job.id]]</span></h2> |
| <div class="layout horizontal"><a href$="/job/[[job.id]]">[back to job page]</a></div> |
| <svg id="svg"></svg> |
| </template> |
| <script src="/res/imp/bower_components/d3/d3.min.js"></script> |
| <script src="/res/js/gantt.js"></script> |
| <script> |
| (function() { |
| function ts(tsStr) { |
| // If the timestamp is zero-ish, return the current datetime. |
| if (Date.parse(tsStr) <= 0) { |
| return new Date(); |
| } |
| return new Date(tsStr); |
| } |
| |
| Polymer({ |
| is: "job-timeline-sk", |
| |
| properties: { |
| job: { |
| type: Object, |
| }, |
| tasks: { |
| type: Array, |
| }, |
| epochs: { |
| type: Array, |
| }, |
| _chart: { |
| type: Object, |
| }, |
| }, |
| |
| observers: [ |
| "_draw(job.*, tasks.*, epochs.*)", |
| ], |
| |
| attached: function() { |
| this._chart = gantt(this.$.svg); |
| window.addEventListener("resize", this.draw.bind(this)); |
| this.draw(); |
| }, |
| |
| draw: function() { |
| this.debounce("draw", function() { |
| this._draw(); |
| }.bind(this)); |
| }, |
| |
| _draw: function() { |
| if (!this.job || !this.tasks || this.epochs === undefined || !this._chart) { |
| return; |
| } |
| const tasks = [{ |
| category: this.job.name + " (job)", |
| start: ts(this.job.created), |
| end: ts(this.job.finished), |
| color: "#0072b2", |
| }]; |
| for (const t of this.tasks) { |
| // Creation timestamp may be after start and finish timestamps in the |
| // case of deduplicated tasks. Since we care more about the |
| // contribution to the job than the task itself, set the start and |
| // finish timestamps equal to the creation timestamp in this case. |
| const createTs = ts(t.created); |
| if (t.started && ts(t.started).getTime() < createTs.getTime()) { |
| t.started = t.created; |
| } |
| if (t.finished && ts(t.finished).getTime() < createTs.getTime()) { |
| t.finished = t.created; |
| } |
| |
| const segments = []; |
| let lastSegmentEnd = createTs; |
| const seg = function(label, end, color) { |
| const s = { |
| label: label, |
| start: lastSegmentEnd, |
| end: ts(end), |
| color: color, |
| }; |
| lastSegmentEnd = s.end; |
| segments.push(s); |
| }; |
| if (t.started) { |
| seg("pending", t.started, "#e69f00"); |
| } |
| if (t.swarming && t.swarming.performance_stats && t.swarming.performance_stats.isolated_upload) { |
| const overheadTotal = t.swarming.performance_stats.bot_overhead * 1000; |
| const overheadUpload = t.swarming.performance_stats.isolated_upload.duration * 1000; |
| const overheadDownload = overheadTotal - overheadUpload; |
| const startTs = ts(t.started).getTime(); |
| const finishTs = ts(t.finished).getTime(); |
| seg("overhead", startTs + overheadDownload, "#d55e00"); |
| seg("running", finishTs - overheadUpload, "#0072b2"); |
| seg("overhead", t.finished, "#d55e00"); |
| } else { |
| seg("running", t.finished, "#0072b2"); |
| } |
| tasks.push({ |
| category: t.name, |
| start: ts(t.created), |
| end: ts(t.finished), |
| segments: segments, |
| }); |
| } |
| const epochs = []; |
| for (const epoch of this.epochs) { |
| epochs.push(ts(epoch)); |
| } |
| let g = this._chart.tasks(tasks).epochs(epochs); |
| if (this.job.requested) { |
| g.start(ts(this.job.requested)); |
| } |
| g.draw(); |
| } |
| }); |
| })(); |
| </script> |
| </dom-module> |