Skip to content

Commit 817f43a

Browse files
committed
Refine benchmark component alias and template bindings
1 parent 5677cf8 commit 817f43a

7 files changed

Lines changed: 294 additions & 266 deletions

File tree

.github/workflows/benchmarks.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ jobs:
208208
209209
const siteBase = new URL(process.env.BENCHMARK_SITE_URL || 'https://jawk.io/');
210210
const siteRoot = 'target/site';
211+
const resolvedSiteRoot = path.resolve(siteRoot);
211212
const indexPath = path.join(siteRoot, 'benchmarks', 'index.json');
212213
213214
function getText(url) {
@@ -244,11 +245,18 @@ jobs:
244245
return;
245246
}
246247
const normalizedPath = relativePath.replace(/^\/+/, '');
248+
if (normalizedPath.includes('\\') || normalizedPath.split('/').includes('..')) {
249+
return;
250+
}
247251
const content = await getText(new URL(normalizedPath, siteBase));
248252
if (content === null) {
249253
return;
250254
}
251-
const outputPath = path.join(siteRoot, normalizedPath);
255+
const outputPath = path.resolve(resolvedSiteRoot, normalizedPath);
256+
const outputRelativePath = path.relative(resolvedSiteRoot, outputPath);
257+
if (outputRelativePath.startsWith('..') || path.isAbsolute(outputRelativePath)) {
258+
return;
259+
}
252260
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
253261
fs.writeFileSync(outputPath, content);
254262
}

src/main/java/io/jawk/jrt/JRT.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -687,16 +687,24 @@ public static boolean compare2(Object o1, Object o2, int mode) {
687687
if (o1Numeric) {
688688
o1Number = ((Number) o1).doubleValue();
689689
} else if (isComparisonNumber(o1String)) {
690-
o1Number = new BigDecimal(o1String).doubleValue();
691-
o1Numeric = true;
690+
try {
691+
o1Number = new BigDecimal(o1String).doubleValue();
692+
o1Numeric = true;
693+
} catch (NumberFormatException nfe) { // NOPMD - ignore invalid number
694+
o1Number = 0.0;
695+
}
692696
} else {
693697
o1Number = 0.0;
694698
}
695699
if (o2Numeric) {
696700
o2Number = ((Number) o2).doubleValue();
697701
} else if (isComparisonNumber(o2String)) {
698-
o2Number = new BigDecimal(o2String).doubleValue();
699-
o2Numeric = true;
702+
try {
703+
o2Number = new BigDecimal(o2String).doubleValue();
704+
o2Numeric = true;
705+
} catch (NumberFormatException nfe) { // NOPMD - ignore invalid number
706+
o2Number = 0.0;
707+
}
700708
} else {
701709
o2Number = 0.0;
702710
}

src/site/resources/css/site.css

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,9 @@ body.dark {
675675

676676
/* Benchmarks */
677677
.benchmarks-page[ng-cloak],
678-
.benchmarks-page [ng-cloak] {
678+
.benchmarks-page [ng-cloak],
679+
.benchmarks-page[data-ng-cloak],
680+
.benchmarks-page [data-ng-cloak] {
679681
display: none !important;
680682
}
681683

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
* Jawk
3+
* Copyright (C) 2006 - 2026 MetricsHub
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as
7+
* published by the Free Software Foundation, either version 3 of the
8+
* License, or (at your option) any later version.
9+
*/
10+
(function() {
11+
'use strict';
12+
13+
function installBenchmarkSupport(angular) {
14+
var siteModule = angular.module('sentry.site');
15+
var host = document.getElementById('benchmark-application');
16+
if (host) {
17+
host.innerHTML = '<jawk-benchmark-report></jawk-benchmark-report>';
18+
}
19+
20+
siteModule.component('jawkBenchmarkReport', {
21+
controller: ['$http', BenchmarkController],
22+
controllerAs: '$ctrl',
23+
templateUrl: 'templates/benchmarks.html'
24+
});
25+
}
26+
27+
function BenchmarkController($http) {
28+
var $ctrl = this;
29+
var indexUrl = 'benchmarks/index.json';
30+
31+
$ctrl.loading = true;
32+
$ctrl.releaseLoading = false;
33+
$ctrl.error = null;
34+
$ctrl.releaseError = null;
35+
$ctrl.releases = [];
36+
$ctrl.results = [];
37+
$ctrl.environment = null;
38+
39+
$ctrl.metric = function(result) {
40+
return result.primaryMetric || {};
41+
};
42+
43+
$ctrl.shortBenchmarkName = function(benchmark) {
44+
var marker = 'JRTCompare2Benchmark.';
45+
var index;
46+
if (!benchmark) {
47+
return '';
48+
}
49+
index = benchmark.indexOf(marker);
50+
return index >= 0 ? benchmark.substring(index + marker.length) : benchmark;
51+
};
52+
53+
$ctrl.forkCount = function(result) {
54+
var metric = $ctrl.metric(result);
55+
return metric.rawData ? metric.rawData.length : '';
56+
};
57+
58+
$ctrl.releaseKey = function(release) {
59+
return release.versionPath || release.version;
60+
};
61+
62+
$ctrl.releaseLabel = function(release) {
63+
if (!release) {
64+
return '';
65+
}
66+
return release.date ? release.version + ' (' + release.date + ')' : release.version;
67+
};
68+
69+
$ctrl.runnerLabel = function(environment) {
70+
if (!environment || !environment.runner) {
71+
return '';
72+
}
73+
return [environment.runner.os, environment.runner.arch, environment.runner.name].filter(Boolean).join(' / ');
74+
};
75+
76+
$ctrl.systemLabel = function(environment) {
77+
var label;
78+
var system;
79+
if (!environment || !environment.system) {
80+
return '';
81+
}
82+
system = environment.system;
83+
label = [system.platform, system.release, system.arch].filter(Boolean).join(' / ');
84+
if (system.cpuCount) {
85+
label += ' / ' + system.cpuCount + ' CPUs';
86+
}
87+
if (system.cpus && system.cpus.length) {
88+
label += ' / ' + system.cpus.join(', ');
89+
}
90+
return label;
91+
};
92+
93+
$ctrl.loadRelease = function(release) {
94+
if (!release) {
95+
return;
96+
}
97+
98+
$ctrl.releaseLoading = true;
99+
$ctrl.releaseError = null;
100+
$ctrl.results = [];
101+
$ctrl.environment = null;
102+
103+
$http.get(release.jmh, { cache: false }).then(function(response) {
104+
$ctrl.results = response.data || [];
105+
$ctrl.results.sort(function(left, right) {
106+
return left.benchmark.localeCompare(right.benchmark);
107+
});
108+
}, function() {
109+
$ctrl.releaseError = 'Benchmark results could not be loaded for ' + release.version + '.';
110+
}).finally(function() {
111+
$ctrl.releaseLoading = false;
112+
});
113+
114+
if (release.environment) {
115+
$http.get(release.environment, { cache: false }).then(function(response) {
116+
$ctrl.environment = response.data;
117+
});
118+
}
119+
};
120+
121+
$http.get(indexUrl, { cache: false }).then(function(response) {
122+
var data = response.data || {};
123+
var latest = data.latest;
124+
var releases = data.releases || [];
125+
var selected = releases.length ? releases[0] : null;
126+
var index;
127+
128+
$ctrl.releases = releases;
129+
for (index = 0; index < releases.length; index++) {
130+
if (releases[index].version === latest) {
131+
selected = releases[index];
132+
break;
133+
}
134+
}
135+
136+
if (!selected) {
137+
$ctrl.error = 'No published benchmark releases were found in ' + indexUrl + '.';
138+
return;
139+
}
140+
141+
$ctrl.selectedRelease = selected;
142+
$ctrl.loadRelease(selected);
143+
}, function() {
144+
$ctrl.error = 'No benchmark index is published yet. Release benchmarks will create ' + indexUrl + '.';
145+
}).finally(function() {
146+
$ctrl.loading = false;
147+
});
148+
}
149+
150+
function showAngularMissing() {
151+
var host = document.getElementById('benchmark-application');
152+
if (host) {
153+
host.innerHTML = '<div class="alert alert-warning">AngularJS is not available, so benchmark results cannot be loaded dynamically.</div>';
154+
}
155+
}
156+
157+
function installWhenReady() {
158+
if (!window.angular) {
159+
showAngularMissing();
160+
return;
161+
}
162+
installBenchmarkSupport(window.angular);
163+
}
164+
165+
document.addEventListener('DOMContentLoaded', installWhenReady);
166+
}());
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<!--
2+
Jawk
3+
Copyright (C) 2006 - 2026 MetricsHub
4+
5+
This program is free software: you can redistribute it and/or modify
6+
it under the terms of the GNU Lesser General Public License as
7+
published by the Free Software Foundation, either version 3 of the
8+
License, or (at your option) any later version.
9+
-->
10+
<div ng-cloak="">
11+
<div class="alert alert-info" ng-if="$ctrl.loading">
12+
Loading published benchmark index...
13+
</div>
14+
15+
<div class="alert alert-warning" ng-if="$ctrl.error">
16+
{{$ctrl.error}}
17+
</div>
18+
19+
<div ng-if="!$ctrl.loading && $ctrl.releases.length">
20+
<div class="benchmark-toolbar">
21+
<label for="benchmark-release">Release</label>
22+
<select id="benchmark-release" class="form-control" ng-model="$ctrl.selectedRelease"
23+
ng-options="release as $ctrl.releaseLabel(release) for release in $ctrl.releases track by $ctrl.releaseKey(release)"
24+
ng-change="$ctrl.loadRelease($ctrl.selectedRelease)">
25+
</select>
26+
<a class="btn btn-default" ng-href="{{$ctrl.selectedRelease.jmh}}" ng-if="$ctrl.selectedRelease.jmh">
27+
Raw JMH JSON
28+
</a>
29+
<a class="btn btn-default" ng-href="{{$ctrl.selectedRelease.environment}}" ng-if="$ctrl.selectedRelease.environment">
30+
Environment JSON
31+
</a>
32+
</div>
33+
34+
<div class="alert alert-info benchmark-note">
35+
Compare releases only after checking the environment details below. JMH scores depend on JVM version, JVM flags,
36+
operating system, runner load, and CPU model.
37+
</div>
38+
39+
<div class="alert alert-info" ng-if="$ctrl.releaseLoading">
40+
Loading benchmark results...
41+
</div>
42+
43+
<div class="alert alert-warning" ng-if="$ctrl.releaseError">
44+
{{$ctrl.releaseError}}
45+
</div>
46+
47+
<div class="table-responsive" ng-if="$ctrl.results.length">
48+
<table class="table table-striped table-condensed benchmark-table">
49+
<thead>
50+
<tr>
51+
<th>Benchmark</th>
52+
<th>Mode</th>
53+
<th class="benchmark-number">Score</th>
54+
<th class="benchmark-number">Error</th>
55+
<th>Units</th>
56+
<th class="benchmark-number">Forks</th>
57+
</tr>
58+
</thead>
59+
<tbody>
60+
<tr ng-repeat="result in $ctrl.results">
61+
<td><code>{{$ctrl.shortBenchmarkName(result.benchmark)}}</code></td>
62+
<td>{{result.mode}}</td>
63+
<td class="benchmark-number">{{$ctrl.metric(result).score | number:3}}</td>
64+
<td class="benchmark-number">{{$ctrl.metric(result).scoreError | number:3}}</td>
65+
<td>{{$ctrl.metric(result).scoreUnit}}</td>
66+
<td class="benchmark-number">{{$ctrl.forkCount(result)}}</td>
67+
</tr>
68+
</tbody>
69+
</table>
70+
</div>
71+
72+
<h2>Benchmark Environment</h2>
73+
74+
<div class="benchmark-environment" ng-if="$ctrl.environment">
75+
<dl class="dl-horizontal">
76+
<dt>Version</dt>
77+
<dd>{{$ctrl.environment.version || $ctrl.selectedRelease.version}}</dd>
78+
<dt>Commit</dt>
79+
<dd><code>{{$ctrl.environment.commit}}</code></dd>
80+
<dt>Run date</dt>
81+
<dd>{{$ctrl.environment.runDate}}</dd>
82+
<dt>Runner</dt>
83+
<dd>{{$ctrl.runnerLabel($ctrl.environment)}}</dd>
84+
<dt>System</dt>
85+
<dd>{{$ctrl.systemLabel($ctrl.environment)}}</dd>
86+
<dt>JMH pattern</dt>
87+
<dd><code>{{$ctrl.environment.benchmarkPattern}}</code></dd>
88+
<dt>JMH arguments</dt>
89+
<dd><code>{{$ctrl.environment.jmhArgs}}</code></dd>
90+
<dt>Workflow run</dt>
91+
<dd><a ng-href="{{$ctrl.environment.workflowRunUrl}}">{{$ctrl.environment.workflowRunUrl}}</a></dd>
92+
</dl>
93+
94+
<h3>Java</h3>
95+
<pre class="benchmark-environment-output">{{$ctrl.environment.javaVersion}}</pre>
96+
97+
<h3>Maven</h3>
98+
<pre class="benchmark-environment-output">{{$ctrl.environment.mavenVersion}}</pre>
99+
</div>
100+
</div>
101+
</div>

0 commit comments

Comments
 (0)