Skip to content

Commit bc144e1

Browse files
authored
New Workload: prismjs source code highlighting (#149)
Measure startup of prismjs [1] syntax highlighting for various source formats. [1] https://prismjs.com/
1 parent 1d33e47 commit bc144e1

29 files changed

+3188
-0
lines changed

JetStreamDriver.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2586,6 +2586,47 @@ let BENCHMARKS = [
25862586
];
25872587

25882588

2589+
const PRISM_JS_FILES = [
2590+
"./startup-helper/StartupBenchmark.js",
2591+
"./prismjs/benchmark.js",
2592+
];
2593+
const PRISM_JS_PRELOADS = {
2594+
SAMPLE_CPP: "./prismjs/data/sample.cpp",
2595+
SAMPLE_CSS: "./prismjs/data/sample.css",
2596+
SAMPLE_HTML: "./prismjs/data/sample.html",
2597+
SAMPLE_JS: "./prismjs/data/sample.js",
2598+
SAMPLE_JSON: "./prismjs/data/sample.json",
2599+
SAMPLE_MD: "./prismjs/data/sample.md",
2600+
SAMPLE_PY: "./prismjs/data/sample.py",
2601+
SAMPLE_SQL: "./prismjs/data/sample.sql",
2602+
SAMPLE_TS: "./prismjs/data/sample.TS",
2603+
};
2604+
const PRISM_JS_TAGS = ["parser", "regexp", "startup", "prismjs"];
2605+
BENCHMARKS.push(
2606+
new AsyncBenchmark({
2607+
name: "prismjs-startup-es6",
2608+
files: PRISM_JS_FILES,
2609+
preload: {
2610+
// Use non-minified bundle for better local profiling.
2611+
// BUNDLE: "./prismjs/dist/bundle.es6.js",
2612+
BUNDLE: "./prismjs/dist/bundle.es6.min.js",
2613+
...PRISM_JS_PRELOADS,
2614+
},
2615+
tags: ["Default", ...PRISM_JS_TAGS, "es6"],
2616+
}),
2617+
new AsyncBenchmark({
2618+
name: "prismjs-startup-es5",
2619+
files: PRISM_JS_FILES,
2620+
preload: {
2621+
// Use non-minified bundle for better local profiling.
2622+
// BUNDLE: "./prismjs/dist/bundle.es5.js",
2623+
BUNDLE: "./prismjs/dist/bundle.es5.min.js",
2624+
...PRISM_JS_PRELOADS,
2625+
},
2626+
tags: [...PRISM_JS_TAGS, "es5"],
2627+
}),
2628+
);
2629+
25892630
const INTL_TESTS = [
25902631
"DateTimeFormat",
25912632
"ListFormat",

prismjs/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# prism.js test for JetStream
2+
3+
Measures the performance of the prism.js library by parsing and formatting sample files.
4+
5+
## Build Instructions
6+
7+
```bash
8+
# install required node packages.
9+
npm ci
10+
# build the workload, output is ./dist
11+
npm run build
12+
```

prismjs/benchmark-node.mjs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import fs from "fs";
2+
import path from "path";
3+
import { fileURLToPath } from "url";
4+
import { runTest } from "./src/test.mjs";
5+
6+
const __filename = fileURLToPath(import.meta.url);
7+
const __dirname = path.dirname(__filename);
8+
9+
const samples = [
10+
{ file: "data/sample.html", lang: "markup" },
11+
{ file: "data/sample.js", lang: "javascript" },
12+
{ file: "data/sample.css", lang: "css" },
13+
{ file: "data/sample.cpp", lang: "cpp" },
14+
{ file: "data/sample.md", lang: "markdown" },
15+
{ file: "data/sample.json", lang: "json" },
16+
{ file: "data/sample.sql", lang: "sql" },
17+
{ file: "data/sample.py", lang: "python" },
18+
{ file: "data/sample.ts", lang: "typescript" },
19+
];
20+
21+
const samplesWithContent = samples.map((sample) => {
22+
const content = fs.readFileSync(path.join(__dirname, sample.file), "utf8");
23+
return { ...sample, content };
24+
});
25+
26+
const startTime = process.hrtime.bigint();
27+
const results = runTest(samplesWithContent);
28+
const endTime = process.hrtime.bigint();
29+
30+
const duration = Number(endTime - startTime) / 1e6; // milliseconds
31+
32+
for (const result of results) {
33+
console.log(`Output size: ${result.html.length} characters`);
34+
}
35+
36+
console.log(
37+
`\nTotal highlighting time for all files: ${duration.toFixed(2)}ms`
38+
);

prismjs/benchmark.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright (C) 2025 Apple Inc. All rights reserved.
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions
6+
* are met:
7+
* 1. Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
*
13+
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14+
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21+
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24+
*/
25+
26+
const EXPECTED_ASSERTION_COUNT = 1213680;
27+
28+
class Benchmark extends StartupBenchmark {
29+
lastResult;
30+
totalHash = 0xdeadbeef;
31+
samples = [];
32+
33+
constructor({iterationCount}) {
34+
super({
35+
iterationCount,
36+
expectedCacheCommentCount: 71,
37+
sourceCodeReuseCount: 1,
38+
});
39+
}
40+
41+
async init() {
42+
await Promise.all([
43+
super.init(),
44+
this.loadData("cpp", JetStream.preload.SAMPLE_CPP, -1086372285),
45+
this.loadData("css", JetStream.preload.SAMPLE_CSS, 1173668337),
46+
this.loadData("markup", JetStream.preload.SAMPLE_HTML, -270772291),
47+
this.loadData("js", JetStream.preload.SAMPLE_JS, -838545229),
48+
this.loadData("markdown", JetStream.preload.SAMPLE_MD, 5859883),
49+
this.loadData("sql", JetStream.preload.SAMPLE_SQL, 5859941),
50+
this.loadData("json", JetStream.preload.SAMPLE_JSON, 5859883),
51+
this.loadData("typescript", JetStream.preload.SAMPLE_TS, 133251625),
52+
]);
53+
}
54+
55+
async loadData(lang, file, hash) {
56+
const sample = { lang, hash };
57+
// Push eagerly to have deterministic order.
58+
this.samples.push(sample);
59+
sample.content = await JetStream.getString(file);
60+
// Warm up quickHash and force good string representation.
61+
this.quickHash(sample.content);
62+
console.assert(sample.content.length > 0);
63+
}
64+
65+
runIteration(iteration) {
66+
// Module is loaded into PrismJSBenchmark
67+
let PrismJSBenchmark;
68+
eval(this.iterationSourceCodes[iteration]);
69+
this.lastResult = PrismJSBenchmark.runTest(this.samples);
70+
71+
for (const result of this.lastResult) {
72+
result.hash = this.quickHash(result.html);
73+
this.totalHash ^= result.hash;
74+
}
75+
}
76+
77+
validate() {
78+
console.assert(this.lastResult.length == this.samples.length);
79+
for (let i = 0; i < this.samples.length; i++) {
80+
const sample = this.samples[i];
81+
const result = this.lastResult[i];
82+
console.assert(result.html.length > 0);
83+
console.assert(
84+
result.hash == sample.hash,
85+
`Invalid result.hash = ${result.hash}, expected ${sample.hash}`
86+
);
87+
}
88+
}
89+
}

prismjs/data/sample.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <iostream>
2+
#include <vector>
3+
#include <string>
4+
#include <algorithm>
5+
6+
class MyClass {
7+
public:
8+
MyClass(const std::string& name) : name_(name) {}
9+
10+
void printName() const {
11+
std::cout << "Name: " << name_ << std::endl;
12+
}
13+
14+
private:
15+
std::string name_;
16+
};
17+
18+
template<typename T>
19+
void printVector(const std::vector<T>& vec) {
20+
for (const auto& item : vec) {
21+
std::cout << item << " ";
22+
}
23+
std::cout << std::endl;
24+
}
25+
26+
int main() {
27+
std::cout << "Hello, C++ World!" << std::endl;
28+
29+
std::vector<int> numbers = {1, 2, 3, 4, 5};
30+
printVector(numbers);
31+
32+
std::vector<std::string> strings = {"apple", "banana", "cherry"};
33+
printVector(strings);
34+
35+
std::sort(strings.begin(), strings.end());
36+
printVector(strings);
37+
38+
MyClass obj("Test Object");
39+
obj.printName();
40+
41+
return 0;
42+
}

prismjs/data/sample.css

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/* Large CSS file for testing */
2+
3+
body {
4+
font-family: Arial, sans-serif;
5+
line-height: 1.6;
6+
color: #333;
7+
}
8+
9+
.container {
10+
width: 90%;
11+
margin: 0 auto;
12+
padding: 20px;
13+
}
14+
15+
.header {
16+
background: #f4f4f4;
17+
padding: 1rem;
18+
border-bottom: 1px solid #ddd;
19+
}
20+
21+
.header h1 {
22+
margin: 0;
23+
}
24+
25+
.nav {
26+
background: #333;
27+
color: #fff;
28+
padding: 0.5rem;
29+
}
30+
31+
.nav ul {
32+
padding: 0;
33+
list-style: none;
34+
}
35+
36+
.nav ul li {
37+
display: inline;
38+
margin-right: 20px;
39+
}
40+
41+
.nav a {
42+
color: #fff;
43+
text-decoration: none;
44+
}
45+
46+
.main {
47+
padding: 1rem 0;
48+
}
49+
50+
.footer {
51+
background: #333;
52+
color: #fff;
53+
text-align: center;
54+
padding: 1rem;
55+
margin-top: 20px;
56+
}
57+
58+
.btn {
59+
display: inline-block;
60+
background: #5cb85c;
61+
color: #fff;
62+
padding: 10px 20px;
63+
border: none;
64+
cursor: pointer;
65+
}
66+
67+
.btn:hover {
68+
background: #4cae4c;
69+
}
70+
71+
.grid {
72+
display: grid;
73+
grid-template-columns: repeat(4, 1fr);
74+
gap: 1rem;
75+
}
76+
77+
.card {
78+
border: 1px solid #ccc;
79+
padding: 1rem;
80+
box-shadow: 2px 2px 5px rgba(0,0,0,0.1);
81+
}
82+
83+
.table {
84+
width: 100%;
85+
border-collapse: collapse;
86+
}
87+
88+
.table th, .table td {
89+
border: 1px solid #ddd;
90+
padding: 8px;
91+
}
92+
93+
.table th {
94+
background-color: #f2f2f2;
95+
}
96+
97+
.form-group {
98+
margin-bottom: 15px;
99+
}
100+
101+
.form-group label {
102+
display: block;
103+
margin-bottom: 5px;
104+
}
105+
106+
.form-group input {
107+
width: 100%;
108+
padding: 8px;
109+
border: 1px solid #ccc;
110+
}
111+
112+
.alert {
113+
padding: 15px;
114+
margin-bottom: 20px;
115+
border: 1px solid transparent;
116+
border-radius: 4px;
117+
}
118+
119+
.alert-success {
120+
color: #3c763d;
121+
background-color: #dff0d8;
122+
border-color: #d6e9c6;
123+
}
124+
125+
.alert-danger {
126+
color: #a94442;
127+
background-color: #f2dede;
128+
border-color: #ebccd1;
129+
}

0 commit comments

Comments
 (0)