Skip to content

Commit 8743020

Browse files
committed
feat: add ColdBox performance analysis suite (BE vs stable 8.1)
Adds tests/perf-harness/ — a complete performance benchmarking suite that compares the bleeding-edge ColdBox development branch against stable 8.1 across four CFML engines: BoxLang, BoxLang-CFML, Adobe CF 2025, Lucee 7. Structure: - app/ — shared ColdBox harness app (handlers, views, models, interceptors, perf-module HMVC module) - be-app/ — bootstrap that maps /coldbox to the repo root (BE branch) - stable-app/ — bootstrap that maps /coldbox to installed ColdBox 8.1 - PerformanceSuite.cfc — CommandBox task runner orchestrating all tests - reports/ — output directory for generated HTML + Markdown reports Test scenarios (5 per version): health — routing only, no DI, no view (baseline) simple-view — view rendering + layout pipeline json-api — WireBox DI + JSON renderData complex-view — multi-model injection + view data loops module — HMVC module routing + module-scoped DI Measurements: cold start — server restart + cleared bytecode cache, first response app bootstrap — ColdBox onApplicationStart re-init timing warm latency — min/avg/P95/P99 over N iterations per scenario throughput — sequential RPS over configurable duration Reports: perf-report-{ts}.md — Markdown with comparison tables + deltas perf-report-{ts}.html — HTML with Chart.js bar charts + Bootstrap tables New box.json scripts: perf:run — full suite (all engines, both versions) perf:run:quick — fast single-engine run without cold start perf:be — BE version only perf:stable — stable version only perf:lucee — Lucee 7 engine only perf:adobe — Adobe CF 2025 engine only Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A9URDbRHAkreUvNUjFdmfG
1 parent e173c11 commit 8743020

20 files changed

Lines changed: 1357 additions & 1 deletion

File tree

box.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@
7575
"log:lucee":"server log coldbox-lucee@5 --follow",
7676
"log:boxlang":"server log coldbox-boxlang-cfml@1 --follow",
7777
"log:boxlangprime":"server log coldbox-boxlang@1 --follow",
78-
"log:adobe":"server log coldbox-adobe@2025 --follow"
78+
"log:adobe":"server log coldbox-adobe@2025 --follow",
79+
"perf:run":"task run tests/perf-harness/PerformanceSuite.cfc",
80+
"perf:run:quick":"task run tests/perf-harness/PerformanceSuite.cfc engines=boxlang-cfml iterations=10 warmup=3 coldStart=false",
81+
"perf:be":"task run tests/perf-harness/PerformanceSuite.cfc versions=be",
82+
"perf:stable":"task run tests/perf-harness/PerformanceSuite.cfc versions=stable",
83+
"perf:lucee":"task run tests/perf-harness/PerformanceSuite.cfc engines=lucee-7",
84+
"perf:adobe":"task run tests/perf-harness/PerformanceSuite.cfc engines=adobe-2025"
7985
}
8086
}

tests/perf-harness/PerformanceSuite.cfc

Lines changed: 847 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Shared ColdBox configuration for performance harness.
3+
* appName and appKey are overridden per-version in be-app/config and stable-app/config.
4+
*/
5+
component {
6+
7+
function configure(){
8+
variables.coldbox = {
9+
appName : "ColdBoxPerfHarness",
10+
eventName : "event",
11+
reinitPassword : "",
12+
reinitKey : "fwreinit",
13+
handlersIndexAutoReload : false,
14+
debugMode : false,
15+
defaultEvent : "Main.index",
16+
requestStartHandler : "",
17+
requestEndHandler : "",
18+
applicationStartHandler : "",
19+
applicationEndHandler : "",
20+
sessionStartHandler : "",
21+
sessionEndHandler : "",
22+
missingTemplateHandler : "",
23+
applicationHelper : "",
24+
viewsHelper : "",
25+
modulesExternalLocation : [],
26+
viewsExternalLocation : "",
27+
layoutsExternalLocation : "",
28+
handlersExternalLocation: "",
29+
requestContextDecorator : "",
30+
exceptionHandler : "",
31+
invalidEventHandler : "",
32+
customErrorTemplate : "",
33+
handlerCaching : true,
34+
eventCaching : false,
35+
proxyReturnCollection : false
36+
};
37+
38+
variables.layoutSettings = {
39+
defaultLayout : "Main.cfm",
40+
defaultView : ""
41+
};
42+
43+
variables.modules = {
44+
autoReload : false,
45+
include : [ "perf-module" ],
46+
exclude : []
47+
};
48+
49+
variables.interceptors = [
50+
{ class : "#appMapping#.interceptors.PerfInterceptor" }
51+
];
52+
53+
variables.logBox = {
54+
appenders : {
55+
console : { class : "ConsoleAppender" }
56+
},
57+
root : { levelmax : "WARN", appenders : "*" }
58+
};
59+
}
60+
61+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Performance harness router — five measurable test scenarios.
3+
*/
4+
component {
5+
6+
function configure(){
7+
// Health check — minimal response, no DI, no view
8+
route( "/perf/health" ).to( "Main.health" )
9+
10+
// Simple view — renders view + layout
11+
route( "/perf/view" ).to( "Main.index" )
12+
13+
// JSON API — DI injection + renderData
14+
route( "/perf/api" ).to( "Api.list" )
15+
16+
// Complex view — multiple model injections + data loop
17+
route( "/perf/complex" ).to( "Main.complex" )
18+
19+
// Module request — full HMVC module routing
20+
route( "/perf/module" ).to( "perf-module:Items.index" )
21+
22+
// Default convention routing
23+
route( "/:handler/:action?" ).end()
24+
}
25+
26+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* REST API handler — tests DI + JSON serialization pipeline.
3+
*/
4+
component extends="coldbox.system.EventHandler" {
5+
6+
property name="userService" inject="UserService";
7+
8+
// JSON list — injects UserService and renders JSON
9+
function list( event, rc, prc ){
10+
var data = {
11+
status : "success",
12+
count : 10,
13+
engine : server.keyExists( "coldfusion" ) ? "Adobe CF" : ( server.keyExists( "lucee" ) ? "Lucee" : "BoxLang" ),
14+
users : userService.getUsers( 10 ),
15+
metadata : {
16+
generated : now(),
17+
framework : "ColdBox"
18+
}
19+
}
20+
event.renderData( type="json", data=data )
21+
}
22+
23+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* Main handler for performance test scenarios.
3+
*/
4+
component extends="coldbox.system.EventHandler" {
5+
6+
property name="userService" inject="UserService";
7+
property name="productService" inject="ProductService";
8+
9+
// Baseline — no DI usage, no view, minimal processing
10+
function health( event, rc, prc ){
11+
return "ok"
12+
}
13+
14+
// Simple view — renders main/index with layout
15+
function index( event, rc, prc ){
16+
prc.message = "ColdBox Performance Harness"
17+
prc.timestamp = now()
18+
prc.version = getColdBoxSetting( "version", "unknown" )
19+
event.setView( "main/index" )
20+
}
21+
22+
// Complex view — resolves two model dependencies, loops data
23+
function complex( event, rc, prc ){
24+
prc.users = userService.getUsers( 10 )
25+
prc.products = productService.getProducts( 5 )
26+
event.setView( "main/complex" )
27+
}
28+
29+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* Records per-request timing into the PRC scope for debugging.
3+
*/
4+
component {
5+
6+
void function configure(){
7+
}
8+
9+
void function preProcess( event, data, rc, prc ){
10+
arguments.prc._perfStart = getTickCount()
11+
}
12+
13+
void function postProcess( event, data, rc, prc ){
14+
if( arguments.prc.keyExists( "_perfStart" ) ){
15+
arguments.prc._perfElapsed = getTickCount() - arguments.prc._perfStart
16+
}
17+
}
18+
19+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>ColdBox Perf Harness</title>
7+
<style>
8+
body { font-family: system-ui, sans-serif; margin: 2rem; color: #333; }
9+
h2 { color: #0066cc; }
10+
ul { line-height: 1.8; }
11+
</style>
12+
</head>
13+
<body>
14+
<cfoutput>
15+
<header>
16+
<h1>ColdBox Performance Harness</h1>
17+
</header>
18+
<main>
19+
#renderView()#
20+
</main>
21+
</cfoutput>
22+
</body>
23+
</html>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* Product service singleton — provides test product data.
3+
*/
4+
component singleton {
5+
6+
variables.CATEGORIES = [ "Electronics", "Clothing", "Books", "Food", "Tools" ]
7+
8+
function getProducts( numeric count=5 ){
9+
var result = []
10+
for( var i = 1; i <= arguments.count; i++ ){
11+
result.append({
12+
id : i,
13+
name : "Product #i#",
14+
sku : "SKU-#numberFormat( i, "00000" )#",
15+
price : precisionEvaluate( i * 9.99 ),
16+
category : variables.CATEGORIES[ ( ( i - 1 ) mod variables.CATEGORIES.len() ) + 1 ],
17+
inStock : ( i mod 4 != 0 ),
18+
tags : [ "tag#i#", "perf", "test" ]
19+
})
20+
}
21+
return result
22+
}
23+
24+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* User service singleton — provides test user data.
3+
*/
4+
component singleton {
5+
6+
function getUsers( numeric count=10 ){
7+
var result = []
8+
for( var i = 1; i <= arguments.count; i++ ){
9+
result.append({
10+
id : i,
11+
firstName : "User",
12+
lastName : "Number#i#",
13+
email : "user#i#@perf.test",
14+
role : ( i mod 3 == 0 ) ? "admin" : "user",
15+
active : true,
16+
createdAt : now()
17+
})
18+
}
19+
return result
20+
}
21+
22+
function getUserById( required numeric id ){
23+
return {
24+
id : arguments.id,
25+
firstName : "User",
26+
lastName : "Number#arguments.id#",
27+
email : "user#arguments.id#@perf.test",
28+
role : "user",
29+
active : true,
30+
createdAt : now()
31+
}
32+
}
33+
34+
}

0 commit comments

Comments
 (0)