Commit 790f78a4 authored by venkatasai patnana's avatar venkatasai patnana Committed by Martin Peres

Add testing-latency metrics

v2 (Martin Peres):
 - move the html file to site/latency.md
 - use the existing template for the page
 - change the style
 - move the javascript part to latency.js
 - allow selecting multiple projects
 - add a loading indicator
 - clean up the js
 - more little things

v3 (Suggested by Arkadiusz Hiler):
 - stop using jquery, use ES6 instead
 - rename project 'latency' to 'latency_target_hours'
 - make the default latency_target_hours null, not 0
 - use addEventListener to detect the click on the test

v4 (Suggested by Arkadiusz Hiler):
 - Allow users to specify the project and test to be shown by default

Closes: #52
parent d6a5fa22
......@@ -164,3 +164,7 @@ body {
margin-left: 2px;
margin-right: 2px;
}
.inline-form {
display: block
}
var pw_latencies={};
var pw_project_cur = null;
var pw_plot_target = null;
function get_url_parameter(param, default_value) {
const urlParams = new URLSearchParams(window.location.search);
var value = urlParams.get(param);
if (value === null)
value = default_value
return value
}
function set_url_parameter(param, value) {
// Get the current list of parameters
const urlParams = new URLSearchParams(window.location.search);
var params = [];
var found = false;
urlParams.forEach(function(v, p) {
if (p === param) {
found = true;
if (value === undefined)
return;
v = value;
}
params.push(`${p}=${v}`);
});
// Add the new one, if missing
if (!found)
params.push(`${param}=${value}`);
// Reconstruct the URL
l = window.location;
url = `${window.location.href.split('?')[0]}?${params.join('&')}`;
// Set the URL
history.replaceState({}, "", url);
}
function pw_test_latency_fetch(project, tests_target, plot_target, weeks, default_test) {
Date.prototype.getWeek = function() {
let date = new Date(this.getTime());
date.setHours(0, 0, 0, 0);
date.setDate(date.getDate() + 3 - (date.getDay() + 6) % 7);
var week1 = new Date(date.getFullYear(), 0, 4);
return 1 + Math.round(((date.getTime() - week1.getTime()) / 86400000
- 3 + (week1.getDay() + 6) % 7) / 7);
}
function setProgress(data, cur_page) {
let text = "LOADING";
if (data !== null) {
let page_size = data.results.length;
let page_count = Math.ceil(data.count / page_size);
text = `LOADING ${cur_page} / ${page_count}`;
}
var loading_option = document.getElementById('test_loading_option');
if (loading_option === null) {
var loading_option = document.createElement("option");
loading_option.selected = true;
var select_tests = document.getElementById(tests_target);
select_tests.appendChild(loading_option);
}
loading_option.text = text;
}
function getLatencyTrendData(cur_page, url = apiUrl, json_data = []) {
if (cur_page === 0)
setProgress(null, cur_page);
return new Promise((resolve, reject) => fetch(url)
.then(response => {
if (response.status !== 200) {
throw `${response.status}: ${response.statusText}`;
}
response.json().then(data => {
json_data = json_data.concat(data.results);
cur_page += 1;
setProgress(data, cur_page);
if(data.next) {
getLatencyTrendData(cur_page, data.next, json_data).then(resolve).catch(reject)
} else {
resolve(json_data);
}
}).catch(reject);
}).catch(reject));
}
function FormatData(json_data){
json_data.forEach(item =>{
var sdate = new Date(item.event_time);
var elapsedTime = (sdate - new Date(item.parameters.revision_completed)) / (1000*60*60);
var label = `WW${sdate.getUTCFullYear()}'${sdate.getWeek()}.${sdate.getDay()}`
if (!pw_latencies[item.parameters.test]) pw_latencies[item.parameters.test] = {};
if (!pw_latencies[item.parameters.test][label]) pw_latencies[item.parameters.test][label] = [];
pw_latencies[item.parameters.test][label].push(elapsedTime)
});
var select_tests = document.getElementById(tests_target);
// Remove all the current options
var child = select_tests.lastElementChild;
while (child) {
select_tests.removeChild(child);
child = select_tests.lastElementChild;
}
// Add all the new options
Object.keys(pw_latencies).forEach(test_name=>{
var option = document.createElement("option");
option.text = test_name;
option.value = test_name.trim();
option.addEventListener('click', function(e) {pw_latency_plot(e.target.value);});
select_tests.appendChild(option);
});
select_tests.disabled = false;
}
// Reset everything
pw_latencies = {};
pw_project_cur = project;
pw_plot_target = plot_target;
set_url_parameter('project', pw_project_cur);
let date = new Date();
date.setHours(0, 0, 0, 0)
let since = new Date(date.getTime() - (7 * 24 * 60 * 60 * 1000));
const apiUrl=`https://patchwork.freedesktop.org/api/1.0/projects/${project}/events/?format=json&name=new-test-result&since=${since.toISOString()}`;
getLatencyTrendData(0)
.then(json_data => {
FormatData(json_data);
test = default_test !== undefined ? default_test : Object.keys(pw_latencies)[0];
pw_latency_plot(test);
document.getElementById(tests_target).value=test;
})
.catch(console.error);
}
function pw_latency_plot(test_name){
let project = projects[pw_project_cur];
let test = project.tests[test_name] || {"latency_target_hours": null};
let perWeekData = pw_latencies[test_name];
set_url_parameter('test', test_name);
let x_labels = [];
let y_latencies = [];
for (var j = 0; j < Object.keys(perWeekData).length; j++) {
let label = Object.keys(perWeekData)[j];
let samples = Object.values(perWeekData)[j];
let x_label = `${label} (${samples.length})`
samples.forEach(item => {
y_latencies.push(item);
x_labels.push(x_label);
});
}
let graphs = [];
if (test.latency_target_hours !== null) {
let object_line_data = {
x: [""].concat(x_labels.concat([" "])),
y: Array(x_labels.length + 2).fill(test.latency_target_hours),
mode: 'lines',
name: 'Median target',
line: {color: 'red'},
type: 'scatter'
};
graphs.push(object_line_data);
}
var violin_data = {
type: 'violin',
hoveron: "violins+points",
x: x_labels,
y: y_latencies,
name: 'Distribution',
line: {
color: 'skyblue',
width: 2
},
box: {
visible: true
},
boxpoints: true,
fillcolour: 'rgba(162, 177, 198, 0.5)',
medianline: {
color: 'black',
visible: true
}
}
graphs.push(violin_data);
var layout = {
title: `Testing latency of <a href="https://patchwork.freedesktop.org/project/${pw_project_cur}/series">${projects[pw_project_cur].name}</a>'s ${test_name}`,
"yaxis": {
"type": "linear",
"title": "Latency (hours)",
"rangemode": "nonnegative",
"autorange": true,
"zeroline": false,
"zerolinewidth": 1
},
"xaxis": {
"title": "Work weeks (# series tested)",
},
violingap: 0,
violingroupgap: 0,
violinmode: "group",
}
Plotly.newPlot(pw_plot_target, graphs, layout);
}
......@@ -77,6 +77,9 @@ and [Full/Sharded](#full-igt-aka-sharded-runs). They are helpful for
assessing how busy the CI is. See [Queues](/queue/index.html) for
details.
If you are interested in knowning the testing latency's distribution, you
should check out the [dedicated latency page](/latency.html).
### Forcing Tests In BAT And Changing Configuration
**To force some IGT tests** in CI you just need to add an extra patch to your
......
# CI latency
## Testing latency per project and test content
The CI system picks up patches from the different projects/mailing lists, compiles/deploys them, then run tests on it.
This view enables you to visualize the latency between a patch has been sent and when the results were published.
<div class="inline-form">
Select a project / test to get statistics for:
<select id="projects" onchange="pw_test_latency_fetch(this.options[this.selectedIndex].value, 'tests', 'plot', 1);">
<option value="" disabled selected hidden>Please select a project</option>
</select>
<select id="tests" disabled>
<option value="" selected hidden>Test</option>
</select>
<span></span>
</div>
<div id="plot"></div>
<script src='https://cdn.plot.ly/plotly-latest.min.js'></script>
<script type="text/javascript" src="/assets/latency.js"></script>
<script type="text/javascript">
var projects = {
"intel-gfx": {
"name": "Intel GFX",
"tests": {
"Fi.CI.BAT": {"latency_target_hours": 0.5},
"Fi.CI.CHECKPATCH": {"latency_target_hours": 0.5},
"Fi.CI.DOCS": {"latency_target_hours": 0.5},
"Fi.CI.SPARSE": {"latency_target_hours": 0.5},
"Fi.CI.BUILD": {"latency_target_hours": 0.5},
"Fi.CI.IGT": {"latency_target_hours": 6},
}
},
"intel-gfx-trybot": {
"name": "Intel GFX Trybot",
"tests": {
"Fi.CI.BAT": {"latency_target_hours": 6},
"Fi.CI.BUILD": {"latency_target_hours": 6},
"Fi.CI.IGT": {"latency_target_hours": 12},
}
},
"igt": {
"name": "IGT",
"tests": {
"Fi.CI.BAT": {"latency_target_hours": 0.5},
"Fi.CI.BUILD": {"latency_target_hours": 0.5},
"GitLab.Pipeline": {"latency_target_hours": 0.5},
"Fi.CI.IGT": {"latency_target_hours": 6},
}
},
"igt-trybot": {
"name": "IGT trybot",
"tests": {
"Fi.CI.BAT": {"latency_target_hours": 6},
"Fi.CI.BUILD": {"latency_target_hours": 6},
"GitLab.Pipeline": {"latency_target_hours": 0.5},
"Fi.CI.IGT": {"latency_target_hours": 12},
}
},
};
// Add all the available projects
var e = document.getElementById('projects');
for (let p_name in projects) {
var o = document.createElement("option");
o.value = p_name;
o.text = projects[p_name].name;
e.appendChild(o);
}
// If a project has been set in the URL, select it
default_project = get_url_parameter('project', null);
if (default_project !== null) {
pw_test_latency_fetch(default_project, 'tests', 'plot', 1, get_url_parameter('test', undefined));
document.getElementById('projects').value = default_project;
}
</script>
......@@ -94,3 +94,8 @@ is completed, but they execute only if BAT is successful.
Due to technical limitation this is just **an approximation** of the queue.
It is good for assessing the length of the queue, but should not be
considered as completely accurate.
### CI Latency
If you are interested in knowning the testing latency's distribution, you
should check out the [dedicated latency page](/latency.html).
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment