diff --git a/frameworks/fletch/.dart_tool/package_config.json b/frameworks/fletch/.dart_tool/package_config.json new file mode 100644 index 00000000..b54b4942 --- /dev/null +++ b/frameworks/fletch/.dart_tool/package_config.json @@ -0,0 +1,274 @@ +{ + "configVersion": 2, + "packages": [ + { + "name": "args", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/args-2.7.0", + "packageUri": "lib/", + "languageVersion": "3.3" + }, + { + "name": "async", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/async-2.13.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "boolean_selector", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/boolean_selector-2.1.2", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "buffer", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/buffer-1.2.3", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "charcode", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/charcode-1.4.0", + "packageUri": "lib/", + "languageVersion": "3.0" + }, + { + "name": "clock", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/clock-1.1.2", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "code_assets", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/code_assets-1.0.0", + "packageUri": "lib/", + "languageVersion": "3.9" + }, + { + "name": "collection", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/collection-1.19.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "crypto", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/crypto-3.0.7", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "ffi", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/ffi-2.2.0", + "packageUri": "lib/", + "languageVersion": "3.7" + }, + { + "name": "file", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/file-7.0.1", + "packageUri": "lib/", + "languageVersion": "3.0" + }, + { + "name": "fixnum", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/fixnum-1.1.1", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "fletch", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/fletch-2.2.0", + "packageUri": "lib/", + "languageVersion": "3.6" + }, + { + "name": "get_it", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/get_it-9.2.1", + "packageUri": "lib/", + "languageVersion": "3.0" + }, + { + "name": "glob", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/glob-2.1.3", + "packageUri": "lib/", + "languageVersion": "3.3" + }, + { + "name": "hooks", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/hooks-1.0.2", + "packageUri": "lib/", + "languageVersion": "3.10" + }, + { + "name": "http", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/http-1.6.0", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "http_parser", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/http_parser-4.1.2", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "logger", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/logger-2.7.0", + "packageUri": "lib/", + "languageVersion": "2.17" + }, + { + "name": "logging", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/logging-1.3.0", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "matcher", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/matcher-0.12.19", + "packageUri": "lib/", + "languageVersion": "3.7" + }, + { + "name": "meta", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/meta-1.18.2", + "packageUri": "lib/", + "languageVersion": "3.5" + }, + { + "name": "mime", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/mime-2.0.0", + "packageUri": "lib/", + "languageVersion": "3.2" + }, + { + "name": "native_toolchain_c", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/native_toolchain_c-0.17.6", + "packageUri": "lib/", + "languageVersion": "3.10" + }, + { + "name": "path", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/path-1.9.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "petitparser", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/petitparser-7.0.2", + "packageUri": "lib/", + "languageVersion": "3.8" + }, + { + "name": "pool", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/pool-1.5.2", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "postgres", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/postgres-3.5.9", + "packageUri": "lib/", + "languageVersion": "3.9" + }, + { + "name": "pub_semver", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/pub_semver-2.2.0", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "quiver", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/quiver-3.2.2", + "packageUri": "lib/", + "languageVersion": "2.17" + }, + { + "name": "source_span", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/source_span-1.10.2", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "sqlite3", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/sqlite3-3.2.0", + "packageUri": "lib/", + "languageVersion": "3.9" + }, + { + "name": "stack_trace", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/stack_trace-1.12.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "stream_channel", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/stream_channel-2.1.4", + "packageUri": "lib/", + "languageVersion": "3.3" + }, + { + "name": "string_scanner", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/string_scanner-1.4.1", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "term_glyph", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/term_glyph-1.2.2", + "packageUri": "lib/", + "languageVersion": "3.1" + }, + { + "name": "test_api", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/test_api-0.7.11", + "packageUri": "lib/", + "languageVersion": "3.7" + }, + { + "name": "typed_data", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/typed_data-1.4.0", + "packageUri": "lib/", + "languageVersion": "3.5" + }, + { + "name": "uri", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/uri-1.0.0", + "packageUri": "lib/", + "languageVersion": "2.12" + }, + { + "name": "uuid", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/uuid-4.5.3", + "packageUri": "lib/", + "languageVersion": "3.0" + }, + { + "name": "web", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/web-1.1.1", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "xml", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/xml-6.6.1", + "packageUri": "lib/", + "languageVersion": "3.8" + }, + { + "name": "yaml", + "rootUri": "file:///Users/kartik/.pub-cache/hosted/pub.dev/yaml-3.1.3", + "packageUri": "lib/", + "languageVersion": "3.4" + }, + { + "name": "httparena_fletch", + "rootUri": "../", + "packageUri": "lib/", + "languageVersion": "3.6" + } + ], + "generator": "pub", + "generatorVersion": "3.11.4", + "flutterRoot": "file:///Users/kartik/Downloads/flutter", + "flutterVersion": "3.41.6", + "pubCache": "file:///Users/kartik/.pub-cache" +} diff --git a/frameworks/fletch/.dart_tool/package_graph.json b/frameworks/fletch/.dart_tool/package_graph.json new file mode 100644 index 00000000..92538e38 --- /dev/null +++ b/frameworks/fletch/.dart_tool/package_graph.json @@ -0,0 +1,370 @@ +{ + "roots": [ + "httparena_fletch" + ], + "packages": [ + { + "name": "httparena_fletch", + "version": "1.0.0", + "dependencies": [ + "fletch", + "logger", + "postgres", + "sqlite3" + ], + "devDependencies": [] + }, + { + "name": "sqlite3", + "version": "3.2.0", + "dependencies": [ + "code_assets", + "collection", + "crypto", + "ffi", + "hooks", + "meta", + "native_toolchain_c", + "path", + "typed_data", + "web" + ] + }, + { + "name": "fletch", + "version": "2.2.0", + "dependencies": [ + "args", + "async", + "crypto", + "get_it", + "http", + "logger", + "meta", + "mime", + "uri", + "uuid", + "xml" + ] + }, + { + "name": "code_assets", + "version": "1.0.0", + "dependencies": [ + "collection", + "hooks" + ] + }, + { + "name": "collection", + "version": "1.19.1", + "dependencies": [] + }, + { + "name": "uri", + "version": "1.0.0", + "dependencies": [ + "matcher", + "quiver" + ] + }, + { + "name": "mime", + "version": "2.0.0", + "dependencies": [] + }, + { + "name": "typed_data", + "version": "1.4.0", + "dependencies": [ + "collection" + ] + }, + { + "name": "native_toolchain_c", + "version": "0.17.6", + "dependencies": [ + "code_assets", + "glob", + "hooks", + "logging", + "meta", + "pub_semver" + ] + }, + { + "name": "pub_semver", + "version": "2.2.0", + "dependencies": [ + "collection" + ] + }, + { + "name": "logging", + "version": "1.3.0", + "dependencies": [] + }, + { + "name": "crypto", + "version": "3.0.7", + "dependencies": [ + "typed_data" + ] + }, + { + "name": "get_it", + "version": "9.2.1", + "dependencies": [ + "async", + "collection", + "meta" + ] + }, + { + "name": "web", + "version": "1.1.1", + "dependencies": [] + }, + { + "name": "hooks", + "version": "1.0.2", + "dependencies": [ + "collection", + "crypto", + "logging", + "meta", + "pub_semver", + "yaml" + ] + }, + { + "name": "yaml", + "version": "3.1.3", + "dependencies": [ + "collection", + "source_span", + "string_scanner" + ] + }, + { + "name": "xml", + "version": "6.6.1", + "dependencies": [ + "collection", + "meta", + "petitparser" + ] + }, + { + "name": "uuid", + "version": "4.5.3", + "dependencies": [ + "crypto", + "fixnum" + ] + }, + { + "name": "fixnum", + "version": "1.1.1", + "dependencies": [] + }, + { + "name": "glob", + "version": "2.1.3", + "dependencies": [ + "async", + "collection", + "file", + "path", + "string_scanner" + ] + }, + { + "name": "petitparser", + "version": "7.0.2", + "dependencies": [ + "collection", + "meta" + ] + }, + { + "name": "async", + "version": "2.13.1", + "dependencies": [ + "collection", + "meta" + ] + }, + { + "name": "args", + "version": "2.7.0", + "dependencies": [] + }, + { + "name": "string_scanner", + "version": "1.4.1", + "dependencies": [ + "source_span" + ] + }, + { + "name": "file", + "version": "7.0.1", + "dependencies": [ + "meta", + "path" + ] + }, + { + "name": "path", + "version": "1.9.1", + "dependencies": [] + }, + { + "name": "logger", + "version": "2.7.0", + "dependencies": [ + "clock", + "meta" + ] + }, + { + "name": "clock", + "version": "1.1.2", + "dependencies": [] + }, + { + "name": "meta", + "version": "1.18.2", + "dependencies": [] + }, + { + "name": "quiver", + "version": "3.2.2", + "dependencies": [ + "matcher" + ] + }, + { + "name": "ffi", + "version": "2.2.0", + "dependencies": [] + }, + { + "name": "http", + "version": "1.6.0", + "dependencies": [ + "async", + "http_parser", + "meta", + "web" + ] + }, + { + "name": "http_parser", + "version": "4.1.2", + "dependencies": [ + "collection", + "source_span", + "string_scanner", + "typed_data" + ] + }, + { + "name": "source_span", + "version": "1.10.2", + "dependencies": [ + "collection", + "path", + "term_glyph" + ] + }, + { + "name": "term_glyph", + "version": "1.2.2", + "dependencies": [] + }, + { + "name": "matcher", + "version": "0.12.19", + "dependencies": [ + "async", + "meta", + "stack_trace", + "term_glyph", + "test_api" + ] + }, + { + "name": "stack_trace", + "version": "1.12.1", + "dependencies": [ + "path" + ] + }, + { + "name": "test_api", + "version": "0.7.11", + "dependencies": [ + "async", + "boolean_selector", + "collection", + "meta", + "source_span", + "stack_trace", + "stream_channel", + "string_scanner", + "term_glyph" + ] + }, + { + "name": "boolean_selector", + "version": "2.1.2", + "dependencies": [ + "source_span", + "string_scanner" + ] + }, + { + "name": "stream_channel", + "version": "2.1.4", + "dependencies": [ + "async" + ] + }, + { + "name": "postgres", + "version": "3.5.9", + "dependencies": [ + "async", + "buffer", + "charcode", + "collection", + "crypto", + "meta", + "pool", + "stack_trace", + "stream_channel" + ] + }, + { + "name": "charcode", + "version": "1.4.0", + "dependencies": [] + }, + { + "name": "buffer", + "version": "1.2.3", + "dependencies": [] + }, + { + "name": "pool", + "version": "1.5.2", + "dependencies": [ + "async", + "stack_trace" + ] + } + ], + "configVersion": 1 +} \ No newline at end of file diff --git a/frameworks/fletch/.dockerignore b/frameworks/fletch/.dockerignore new file mode 100644 index 00000000..05d02950 --- /dev/null +++ b/frameworks/fletch/.dockerignore @@ -0,0 +1,2 @@ +.dart_tool/ +pubspec.lock diff --git a/frameworks/fletch/Dockerfile b/frameworks/fletch/Dockerfile new file mode 100644 index 00000000..aab47a4a --- /dev/null +++ b/frameworks/fletch/Dockerfile @@ -0,0 +1,25 @@ +# Stage 1 — AOT compile the Dart server +FROM dart:stable AS build + +WORKDIR /app +COPY pubspec.yaml ./ +RUN dart pub get + +COPY . . +RUN dart build cli --target bin/server.dart --output /app/build + +# Stage 2 — Minimal runtime image +FROM debian:bookworm-slim + +# The Dart sqlite3 FFI loader looks for libsqlite3.so (unversioned), so we +# install the -dev package to ensure that soname symlink exists. +RUN apt-get update \ + && apt-get install -y --no-install-recommends libsqlite3-dev \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=build /app/build/bundle /server +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +EXPOSE 8080 +CMD ["/entrypoint.sh"] diff --git a/frameworks/fletch/bin/server.dart b/frameworks/fletch/bin/server.dart new file mode 100644 index 00000000..db41e196 --- /dev/null +++ b/frameworks/fletch/bin/server.dart @@ -0,0 +1,357 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'dart:isolate'; +import 'dart:typed_data'; + +import 'package:fletch/fletch.dart'; +import 'package:logger/logger.dart'; +import 'package:postgres/postgres.dart'; +import 'package:sqlite3/sqlite3.dart'; + +const _mimeTypes = { + '.css': 'text/css', + '.js': 'application/javascript', + '.html': 'text/html', + '.woff2': 'font/woff2', + '.svg': 'image/svg+xml', + '.webp': 'image/webp', + '.json': 'application/json', +}; + +// Pre-computed once; reused on every request that needs an empty result. +final _emptyJson = Uint8List.fromList(utf8.encode('{"items":[],"count":0}')); + +class _StaticFile { + final Uint8List data; + final String contentType; + const _StaticFile(this.data, this.contentType); +} + +Future main(List args) async { + // Prefer the worker count passed via entrypoint.sh (derived from `nproc`, + // which respects the cgroup CPU quota set by --cpus=N). Fall back to + // Platform.numberOfProcessors when running outside Docker. + final n = args.isNotEmpty + ? (int.tryParse(args[0]) ?? Platform.numberOfProcessors) + : Platform.numberOfProcessors; + for (var i = 1; i < n; i++) { + await Isolate.spawn(_run, null); + } + await _run(null); +} + +Future _run(dynamic _) async { + final jsonDataset = _loadDataset('/data/dataset.json'); + final compressionDataset = _loadDataset('/data/dataset-large.json'); + final staticFiles = _loadStaticFiles(); + final sqliteDb = _openSqlite(); + + // Prepared statement — avoids re-parsing SQL on every /db request. + final sqliteStmt = sqliteDb?.prepare( + 'SELECT id, name, category, price, quantity, active, tags,' + ' rating_score, rating_count' + ' FROM items WHERE price BETWEEN ? AND ? LIMIT 50', + ); + + // Postgres pool — populated after listen() so startup is never blocked. + Pool? pgPool; + Future? pgPoolConnectInFlight; + DateTime? pgLastConnectAttempt; + const pgRetryInterval = Duration(milliseconds: 500); + + Future ensurePgPool() async { + final current = pgPool; + if (current != null) return current; + + final inFlight = pgPoolConnectInFlight; + if (inFlight != null) return inFlight; + + final now = DateTime.now(); + final lastAttempt = pgLastConnectAttempt; + if (lastAttempt != null && now.difference(lastAttempt) < pgRetryInterval) { + return null; + } + pgLastConnectAttempt = now; + + final connectFuture = _openPostgresPool().then((pool) { + if (pool != null) pgPool = pool; + return pool; + }).whenComplete(() { + pgPoolConnectInFlight = null; + }); + pgPoolConnectInFlight = connectFuture; + return connectFuture; + } + + Future resetPgPool() async { + final oldPool = pgPool; + pgPool = null; + if (oldPool != null) { + try { + await oldPool.close(); + } catch (_) {} + } + } + + final app = Fletch( + requestTimeout: null, + secureCookies: false, + sessionSecret: 'httparena-bench-secret-key-fletch32!', + maxBodySize: 100 * 1024 * 1024, + maxFileSize: 100 * 1024 * 1024, + // Cookie parsing is unused in the benchmark; skip that middleware hop. + useCookieParser: false, + logger: Logger(level: Level.off), + ); + + app.get('/pipeline', (req, res) { + res.text('ok'); + }); + + app.get('/baseline11', (req, res) { + var sum = 0; + for (final v in req.query.values) { + final n = int.tryParse(v); + if (n != null) sum += n; + } + res.text('$sum'); + }); + + app.post('/baseline11', (req, res) async { + var sum = 0; + for (final v in req.query.values) { + final n = int.tryParse(v); + if (n != null) sum += n; + } + final body = await req.body; + if (body != null) { + final s = body is String + ? body.trim() + : utf8.decode(body as List).trim(); + final n = int.tryParse(s); + if (n != null) sum += n; + } + res.text('$sum'); + }); + + app.get('/json', (req, res) { + if (jsonDataset == null) { + res.bytes(_emptyJson, contentType: 'application/json'); + return; + } + final items = jsonDataset.map(_mapItem).toList(); + res.bytes( + utf8.encode(jsonEncode({'items': items, 'count': items.length})), + contentType: 'application/json', + ); + }); + + // Use Content-Length header when available — avoids buffering the entire + // upload body just to count bytes, which matters for large payloads. + app.post('/upload', (req, res) async { + final cl = req.httpRequest.contentLength; + if (cl >= 0) { + res.text('$cl'); + return; + } + // Fallback for chunked transfers: buffer and count. + final body = await req.body; + int size = 0; + if (body is Uint8List) { + size = body.length; + } else if (body is String) { + size = utf8.encode(body).length; + } else if (body is List) { + size = body.length; + } + res.text('$size'); + }); + + app.get('/compression', (req, res) { + if (compressionDataset == null) { + res.bytes(Uint8List.fromList(GZipCodec(level: 1).encode(_emptyJson)), + contentType: 'application/json'); + res.setHeader('Content-Encoding', 'gzip'); + return; + } + final items = compressionDataset.map(_mapItem).toList(); + final jsonBytes = utf8.encode(jsonEncode({'items': items, 'count': items.length})); + final gzipBytes = Uint8List.fromList(GZipCodec(level: 1).encode(jsonBytes)); + res.bytes(gzipBytes, contentType: 'application/json'); + res.setHeader('Content-Encoding', 'gzip'); + }); + + app.get('/static/:filename', (req, res) { + final sf = staticFiles[req.params['filename']!]; + if (sf == null) { + res.setStatus(404); + } else { + res.bytes(sf.data, contentType: sf.contentType); + } + }); + + app.get('/db', (req, res) { + if (sqliteStmt == null) { + stderr.writeln('[db] sqliteStmt is null — sqlite3 may not have loaded'); + res.bytes(_emptyJson, contentType: 'application/json'); + return; + } + final minVal = double.tryParse(req.query['min'] ?? '') ?? 10.0; + final maxVal = double.tryParse(req.query['max'] ?? '') ?? 50.0; + try { + final rows = sqliteStmt.select([minVal, maxVal]); + final items = rows + .map((row) => { + 'id': row['id'], + 'name': row['name'], + 'category': row['category'], + 'price': row['price'], + 'quantity': row['quantity'], + 'active': row['active'] == 1, + 'tags': jsonDecode(row['tags'] as String), + 'rating': { + 'score': row['rating_score'], + 'count': row['rating_count'], + }, + }) + .toList(); + res.bytes( + utf8.encode(jsonEncode({'items': items, 'count': items.length})), + contentType: 'application/json', + ); + } catch (e, st) { + stderr.writeln('[db] error: $e\n$st'); + res.bytes(_emptyJson, contentType: 'application/json'); + } + }); + + app.get('/async-db', (req, res) async { + final pool = await ensurePgPool(); + if (pool == null) { + res.bytes(_emptyJson, contentType: 'application/json'); + return; + } + final minVal = double.tryParse(req.query['min'] ?? '') ?? 10.0; + final maxVal = double.tryParse(req.query['max'] ?? '') ?? 50.0; + try { + final result = await pool.execute( + r'SELECT id, name, category, price, quantity, active, tags,' + r' rating_score, rating_count' + r' FROM items WHERE price BETWEEN $1 AND $2 LIMIT 50', + parameters: [minVal, maxVal], + ); + final items = result.map((row) { + final cols = row.toColumnMap(); + final tagsRaw = cols['tags']; + final tags = + tagsRaw is List ? tagsRaw : jsonDecode(tagsRaw as String); + return { + 'id': cols['id'], + 'name': cols['name'], + 'category': cols['category'], + 'price': cols['price'], + 'quantity': cols['quantity'], + 'active': cols['active'], + 'tags': tags, + 'rating': { + 'score': cols['rating_score'], + 'count': cols['rating_count'], + }, + }; + }).toList(); + res.bytes( + utf8.encode(jsonEncode({'items': items, 'count': items.length})), + contentType: 'application/json', + ); + } catch (_) { + await resetPgPool(); + res.bytes(_emptyJson, contentType: 'application/json'); + } + }); + + // Bind first — server is reachable immediately. + await app.listen(8080, shared: true); + + // Kick off async-db pool warmup, but keep lazy retries in request path. + unawaited(ensurePgPool()); +} + +// --------------------------------------------------------------------------- +// Data helpers +// --------------------------------------------------------------------------- + +List? _loadDataset(String path) { + try { + return jsonDecode(File(path).readAsStringSync()) as List; + } catch (_) { + return null; + } +} + +Map _mapItem(dynamic d) => { + 'id': d['id'], + 'name': d['name'], + 'category': d['category'], + 'price': d['price'], + 'quantity': d['quantity'], + 'active': d['active'], + 'tags': d['tags'], + 'rating': d['rating'], + 'total': + ((d['price'] as num) * (d['quantity'] as num) * 100).round() / 100, + }; + +Map _loadStaticFiles() { + final result = {}; + try { + for (final entity in Directory('/data/static').listSync()) { + if (entity is! File) continue; + final name = entity.uri.pathSegments.last; + final ext = name.contains('.') ? '.${name.split('.').last}' : ''; + result[name] = _StaticFile( + entity.readAsBytesSync(), + _mimeTypes[ext] ?? 'application/octet-stream', + ); + } + } catch (_) {} + return result; +} + +Database? _openSqlite() { + try { + return sqlite3.open('/data/benchmark.db', mode: OpenMode.readOnly); + } catch (e) { + stderr.writeln('[sqlite] failed to open: $e'); + return null; + } +} + +Future _openPostgresPool() async { + final dbUrl = Platform.environment['DATABASE_URL']; + if (dbUrl == null) return null; + try { + final uri = Uri.parse(dbUrl); + final userInfo = uri.userInfo.split(':'); + final endpoint = Endpoint( + host: uri.host, + port: uri.port > 0 ? uri.port : 5432, + database: uri.path.substring(1), + username: userInfo[0], + password: userInfo.length > 1 ? userInfo[1] : '', + ); + // 4 connections per isolate; with N isolates total = 4N concurrent queries. + final pool = Pool.withEndpoints( + [endpoint], + settings: const PoolSettings( + sslMode: SslMode.disable, + maxConnectionCount: 4, + ), + ); + // Warm up one connection to catch auth/config errors early. + await pool.execute('SELECT 1'); + return pool; + } catch (_) { + return null; + } +} diff --git a/frameworks/fletch/entrypoint.sh b/frameworks/fletch/entrypoint.sh new file mode 100644 index 00000000..05d77632 --- /dev/null +++ b/frameworks/fletch/entrypoint.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# nproc on Linux reads the cgroup CPU quota, so it returns the value set by +# --cpus=N rather than the host's total CPU count. This ensures the Dart +# server spawns exactly as many isolates as the container is allowed to use. +exec /server/bin/server "$(nproc)" diff --git a/frameworks/fletch/meta.json b/frameworks/fletch/meta.json new file mode 100644 index 00000000..f9f94dbd --- /dev/null +++ b/frameworks/fletch/meta.json @@ -0,0 +1,21 @@ +{ + "display_name": "Fletch", + "language": "Dart", + "engine": "dart:io", + "type": "framework", + "description": "Express-inspired HTTP framework for Dart with radix-tree routing, middleware chains, signed sessions, and built-in DI.", + "repo": "https://github.com/kartikey321/fletch", + "enabled": true, + "tests": [ + "baseline", + "pipelined", + "limited-conn", + "json", + "upload", + "compression", + "noisy", + "mixed", + "static", + "async-db" + ] +} diff --git a/frameworks/fletch/pubspec.lock b/frameworks/fletch/pubspec.lock new file mode 100644 index 00000000..37258a7c --- /dev/null +++ b/frameworks/fletch/pubspec.lock @@ -0,0 +1,349 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 + url: "https://pub.dev" + source: hosted + version: "2.13.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + buffer: + dependency: transitive + description: + name: buffer + sha256: "389da2ec2c16283c8787e0adaede82b1842102f8c8aae2f49003a766c5c6b3d1" + url: "https://pub.dev" + source: hosted + version: "1.2.3" + charcode: + dependency: transitive + description: + name: charcode + sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a + url: "https://pub.dev" + source: hosted + version: "1.4.0" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + ffi: + dependency: transitive + description: + name: ffi + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + fletch: + dependency: "direct main" + description: + name: fletch + sha256: "373f6be6c32e253eee43bfde712e2b22a484acb97d989b6eb0e6ee0e9916c796" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + get_it: + dependency: transitive + description: + name: get_it + sha256: "568d62f0e68666fb5d95519743b3c24a34c7f19d834b0658c46e26d778461f66" + url: "https://pub.dev" + source: hosted + version: "9.2.1" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + hooks: + dependency: transitive + description: + name: hooks + sha256: e79ed1e8e1929bc6ecb6ec85f0cb519c887aa5b423705ded0d0f2d9226def388 + url: "https://pub.dev" + source: hosted + version: "1.0.2" + http: + dependency: transitive + description: + name: http + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + logger: + dependency: "direct main" + description: + name: logger + sha256: "25aee487596a6257655a1e091ec2ae66bc30e7af663592cc3a27e6591e05035c" + url: "https://pub.dev" + source: hosted + version: "2.7.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + url: "https://pub.dev" + source: hosted + version: "0.12.19" + meta: + dependency: transitive + description: + name: meta + sha256: df0c643f44ad098eb37988027a8e2b2b5a031fd3977f06bbfd3a76637e8df739 + url: "https://pub.dev" + source: hosted + version: "1.18.2" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + native_toolchain_c: + dependency: transitive + description: + name: native_toolchain_c + sha256: "6ba77bb18063eebe9de401f5e6437e95e1438af0a87a3a39084fbd37c90df572" + url: "https://pub.dev" + source: hosted + version: "0.17.6" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" + url: "https://pub.dev" + source: hosted + version: "7.0.2" + pool: + dependency: transitive + description: + name: pool + sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" + url: "https://pub.dev" + source: hosted + version: "1.5.2" + postgres: + dependency: "direct main" + description: + name: postgres + sha256: fefbbfe749c6130e5096588b9c4459173684c695952cd7636ab19be76f255469 + url: "https://pub.dev" + source: hosted + version: "3.5.9" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + quiver: + dependency: transitive + description: + name: quiver + sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + source_span: + dependency: transitive + description: + name: source_span + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" + url: "https://pub.dev" + source: hosted + version: "1.10.2" + sqlite3: + dependency: "direct main" + description: + name: sqlite3 + sha256: caa693ad15a587a2b4fde093b728131a1827903872171089dedb16f7665d3a91 + url: "https://pub.dev" + source: hosted + version: "3.2.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e" + url: "https://pub.dev" + source: hosted + version: "0.7.11" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + uri: + dependency: transitive + description: + name: uri + sha256: "889eea21e953187c6099802b7b4cf5219ba8f3518f604a1033064d45b1b8268a" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + uuid: + dependency: transitive + description: + name: uuid + sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" + url: "https://pub.dev" + source: hosted + version: "4.5.3" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + xml: + dependency: transitive + description: + name: xml + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" + url: "https://pub.dev" + source: hosted + version: "6.6.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" +sdks: + dart: ">=3.10.0 <4.0.0" diff --git a/frameworks/fletch/pubspec.yaml b/frameworks/fletch/pubspec.yaml new file mode 100644 index 00000000..03d10bf3 --- /dev/null +++ b/frameworks/fletch/pubspec.yaml @@ -0,0 +1,13 @@ +name: httparena_fletch +description: Fletch HTTP framework — HttpArena benchmark server +version: 1.0.0 +publish_to: none + +environment: + sdk: '>=3.10.0 <4.0.0' + +dependencies: + fletch: ^2.2.0 + postgres: ^3.0.0 + sqlite3: ^3.2.0 + logger: ^2.5.0 diff --git a/site/data/async-db-1024.json b/site/data/async-db-1024.json index 2d9166d9..4d72a7bb 100644 --- a/site/data/async-db-1024.json +++ b/site/data/async-db-1024.json @@ -758,5 +758,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 3817, + "avg_latency": "211.29ms", + "p99_latency": "905.60ms", + "cpu": "867.0%", + "memory": "2.5GiB", + "connections": 1024, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "30.29MB/s", + "input_bw": "", + "reconnects": 0, + "status_2xx": 19086, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/async-db-512.json b/site/data/async-db-512.json index e04fd4f9..94995207 100644 --- a/site/data/async-db-512.json +++ b/site/data/async-db-512.json @@ -758,5 +758,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 4873, + "avg_latency": "99.72ms", + "p99_latency": "444.50ms", + "cpu": "1105.6%", + "memory": "1.9GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "38.68MB/s", + "input_bw": "", + "reconnects": 0, + "status_2xx": 24369, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/baseline-16384.json b/site/data/baseline-16384.json index fb91f371..3b029c50 100644 --- a/site/data/baseline-16384.json +++ b/site/data/baseline-16384.json @@ -1098,5 +1098,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 158019, + "avg_latency": "27.42ms", + "p99_latency": "138.20ms", + "cpu": "1227.9%", + "memory": "1.4GiB", + "connections": 16384, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "29.38MB/s", + "input_bw": "12.21MB/s", + "reconnects": 0, + "status_2xx": 790095, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/baseline-4096.json b/site/data/baseline-4096.json index d7891939..4ac71606 100644 --- a/site/data/baseline-4096.json +++ b/site/data/baseline-4096.json @@ -1098,5 +1098,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 177116, + "avg_latency": "8.35ms", + "p99_latency": "12.60ms", + "cpu": "1353.5%", + "memory": "1.4GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "32.93MB/s", + "input_bw": "13.68MB/s", + "reconnects": 0, + "status_2xx": 885583, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/baseline-512.json b/site/data/baseline-512.json index 79f6462b..9c963630 100644 --- a/site/data/baseline-512.json +++ b/site/data/baseline-512.json @@ -1098,5 +1098,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 180487, + "avg_latency": "2.31ms", + "p99_latency": "3.85ms", + "cpu": "1374.3%", + "memory": "1.3GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "33.55MB/s", + "input_bw": "13.94MB/s", + "reconnects": 0, + "status_2xx": 902437, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/compression-16384.json b/site/data/compression-16384.json index 2d110808..eaf6ba2f 100644 --- a/site/data/compression-16384.json +++ b/site/data/compression-16384.json @@ -866,5 +866,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 126, + "avg_latency": "1.31s", + "p99_latency": "4.25s", + "cpu": "708.3%", + "memory": "1023.0MiB", + "connections": 16384, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "26.56MB/s", + "input_bw": "9.11KB/s", + "reconnects": 0, + "status_2xx": 632, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/compression-4096.json b/site/data/compression-4096.json index c0e8d2c5..1f55c95b 100644 --- a/site/data/compression-4096.json +++ b/site/data/compression-4096.json @@ -866,5 +866,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 140, + "avg_latency": "1.30s", + "p99_latency": "3.89s", + "cpu": "783.4%", + "memory": "3.9GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "29.46MB/s", + "input_bw": "10.12KB/s", + "reconnects": 0, + "status_2xx": 701, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/current.json b/site/data/current.json index 07d26ef3..1cf676bc 100644 --- a/site/data/current.json +++ b/site/data/current.json @@ -1,5 +1,5 @@ { - "date": "2026-03-29", + "date": "2026-03-30", "cpu": "AMD Ryzen Threadripper PRO 3995WX 64-Cores", "cores": "64", "threads": "128", @@ -7,7 +7,7 @@ "os": "Ubuntu 24.04.4 LTS", "kernel": "6.17.0-19-generic", "docker": "29.3.0", - "commit": "1e1e2ab", + "commit": "82e5d96", "governor": "performance", "docker_runtime": "runc", "threads_per_core": "2", diff --git a/site/data/frameworks.json b/site/data/frameworks.json index 0e8f8869..20eeb22c 100644 --- a/site/data/frameworks.json +++ b/site/data/frameworks.json @@ -1,71 +1,70 @@ { - "actix": {"dir": "actix", "description": "Actix-web 4 with rustls for HTTP/2 support, compiled with -O3 and thin LTO.", "repo": "https://github.com/actix/actix-web", "type": "framework", "engine": "actix"}, - "actix-websocket": {"dir": "actix-websocket", "description": "Actix-web WebSocket echo server", "repo": "https://github.com/actix/actix-web", "type": "framework", "engine": "Actix"}, - "aspnet-grpc": {"dir": "aspnet-grpc", "description": "ASP.NET Core gRPC server using .NET 10 preview with Kestrel.", "repo": "https://github.com/dotnet/aspnetcore", "type": "framework", "engine": "Kestrel"}, - "aspnet-minimal": {"dir": "aspnet-minimal", "description": "Minimal ASP.NET Core server using .NET 10 preview with Kestrel and minimal API routing.", "repo": "https://github.com/dotnet/aspnetcore", "type": "framework", "engine": "Kestrel"}, - "aspnet-websocket": {"dir": "aspnet-websocket", "description": "ASP.NET Core WebSocket echo server using .NET 10 preview with Kestrel and minimal API.", "repo": "https://github.com/dotnet/aspnetcore", "type": "framework", "engine": "Kestrel"}, - "blitz": {"dir": "blitz", "description": "Custom Zig HTTP server with dual epoll/io_uring backends. Zero-copy parsing, pre-computed responses, pipeline batching.", "repo": "https://github.com/BennyFranciscus/blitz", "type": "engine", "engine": "io_uring"}, - "bun": {"dir": "bun", "description": "Bun's built-in HTTP server using JavaScriptCore engine with multi-core clustering.", "repo": "https://github.com/oven-sh/bun", "type": "framework", "engine": "JSC"}, - "bun-websocket": {"dir": "bun-websocket", "description": "Bun WebSocket echo server", "repo": "https://github.com/oven-sh/bun", "type": "framework", "engine": "Bun"}, - "caddy": {"dir": "caddy", "description": "Caddy web server with a custom handler module for benchmark endpoints, native HTTP/2 support.", "repo": "https://github.com/caddyserver/caddy", "type": "engine", "engine": "caddy"}, - "chi": {"dir": "chi", "description": "Chi is a lightweight, idiomatic and composable router for building Go HTTP services, built on top of net/http.", "repo": "https://github.com/go-chi/chi", "type": "framework", "engine": "chi"}, - "deno": {"dir": "deno", "description": "Deno HTTP server using deno serve --parallel with zero-dependency native fetch handler.", "repo": "https://github.com/denoland/deno", "type": "framework", "engine": "V8"}, - "deno-websocket": {"dir": "deno-websocket", "description": "Deno WebSocket echo server", "repo": "https://github.com/denoland/deno", "type": "framework", "engine": "Deno"}, - "Django": {"dir": "django", "description": "Django web framework on Gunicorn with sync workers, one worker per CPU core.", "repo": "https://github.com/django/django", "type": "framework", "engine": "gunicorn"}, - "drogon": {"dir": "drogon", "description": "Drogon C++ framework using HttpController with async callbacks, mimalloc allocator, and -flto optimization.", "repo": "https://github.com/drogonframework/drogon", "type": "framework", "engine": "drogon"}, - "echo": {"dir": "echo", "description": "Echo is a high performance, extensible, minimalist Go web framework with optimized HTTP router, middleware support, and data binding.", "repo": "https://github.com/labstack/echo", "type": "framework", "engine": "echo"}, - "Elysia": {"dir": "elysia", "description": "Ergonomic TypeScript framework built for Bun with end-to-end type safety and excellent DX.", "repo": "https://github.com/elysiajs/elysia", "type": "framework", "engine": "Bun"}, - "Express": {"dir": "express", "description": "Fast, unopinionated, minimalist web framework for Node.js. The most widely used backend framework in the JavaScript ecosystem.", "repo": "https://github.com/expressjs/express", "type": "framework", "engine": "V8"}, - "FastAPI": {"dir": "fastapi", "description": "FastAPI async web framework on Uvicorn (uvloop), multi-worker via gunicorn.", "repo": "https://github.com/fastapi/fastapi", "type": "framework", "engine": "uvicorn"}, - "Fastify": {"dir": "fastify", "description": "Fast and low-overhead Node.js web framework built for developer experience and performance.", "repo": "https://github.com/fastify/fastify", "type": "framework", "engine": "V8"}, - "FastPySGI-WSGI": {"dir": "fastpysgi", "description": "An ultra fast WSGI/ASGI server for Python", "repo": "https://github.com/remittor/fastpysgi", "type": "engine", "engine": "libuv"}, - "FastPySGI-ASGI": {"dir": "fastpysgi-asgi", "description": "An ultra fast WSGI/ASGI server for Python", "repo": "https://github.com/remittor/fastpysgi", "type": "engine", "engine": "libuv"}, - "fiber": {"dir": "fiber", "description": "Fiber is an Express-inspired Go web framework built on fasthttp, featuring zero-allocation routing and extreme performance.", "repo": "https://github.com/gofiber/fiber", "type": "framework", "engine": "fiber"}, - "flask": {"dir": "flask", "description": "Flask web framework on Gunicorn with sync workers, one worker per CPU core.", "repo": "https://github.com/pallets/flask", "type": "framework", "engine": "gunicorn"}, - "GenHTTP": {"dir": "genhttp", "description": "Lightweight, embeddable and modular C# web server.", "repo": "https://github.com/Kaliumhexacyanoferrat/GenHTTP", "type": "framework", "engine": "GenHTTP"}, - "GenHTTP-WS": {"dir": "genhttp-websocket", "description": "GenHTTP WebSocket echo server using the functional API with zero-allocation frame handling.", "repo": "https://github.com/Kaliumhexacyanoferrat/GenHTTP", "type": "framework", "engine": "GenHTTP"}, - "gin": {"dir": "gin", "description": "Gin is a Go web framework with a martini-like API, featuring the fastest HTTP router (httprouter) and zero-allocation routing.", "repo": "https://github.com/gin-gonic/gin", "type": "framework", "engine": "gin"}, - "gleam-mist": {"dir": "gleam-mist", "description": "Mist HTTP server for Gleam on the BEAM VM — first Gleam and first BEAM entry in HttpArena.", "repo": "https://github.com/rawhat/mist", "type": "framework", "engine": "BEAM"}, - "go-fasthttp": {"dir": "go-fasthttp", "description": "High-performance Go HTTP server using fasthttp with zero-allocation design and buffer reuse.", "repo": "https://github.com/valyala/fasthttp", "type": "framework", "engine": "fasthttp"}, - "go-websocket": {"dir": "go-websocket", "description": "Go WebSocket echo server using gobwas/ws", "repo": "https://github.com/gobwas/ws", "type": "framework", "engine": "net/http"}, - "grpc-go": {"dir": "grpc-go", "description": "Go gRPC server using google.golang.org/grpc.", "repo": "https://github.com/grpc/grpc-go", "type": "framework", "engine": "grpc-go"}, - "h2o": {"dir": "h2o", "description": "High-performance C HTTP server using libh2o with multi-threaded event loops and native HTTP/2 support.", "repo": "https://github.com/h2o/h2o", "type": "engine", "engine": "h2o"}, - "h2o-mruby": {"dir": "h2o-mruby", "description": "h2o config-based server with mruby handlers and native HTTP/3 (QUIC) support.", "repo": "https://github.com/h2o/h2o", "type": "framework", "engine": "h2o"}, - "hono (node)": {"dir": "hono", "description": "Ultrafast web framework built on Web Standards, runs on any JS runtime.", "repo": "https://github.com/honojs/hono", "type": "framework", "engine": "Node"}, - "Hono (Bun)": {"dir": "hono-bun", "description": "Ultrafast Web Standards framework running natively on Bun — no adapter overhead.", "repo": "https://github.com/honojs/hono", "type": "framework", "engine": "JSC"}, - "hummingbird": {"dir": "humming-bird", "description": "Lightweight, flexible HTTP server framework written in Swift, built on SwiftNIO with minimal dependencies.", "repo": "https://github.com/hummingbird-project/hummingbird", "type": "framework", "engine": "Hummingbird"}, - "hyper": {"dir": "hyper", "description": "Low-level HTTP library for Rust, built on tokio with multi-threaded async runtime.", "repo": "https://github.com/hyperium/hyper", "type": "engine", "engine": "hyper"}, - "kemal": {"dir": "kemal", "description": "Kemal web framework for Crystal, compiled with --release optimizations.", "repo": "https://github.com/kemalcr/kemal", "type": "framework", "engine": "Kemal"}, - "Koa": {"dir": "koa", "description": "Expressive middleware framework for Node.js by the Express team, using async/await.", "repo": "https://github.com/koajs/koa", "type": "framework", "engine": "V8"}, - "ktor": {"dir": "ktor", "description": "JetBrains Ktor 3.x on Netty with Kotlin coroutines, kotlinx.serialization, JDK 21.", "repo": "https://github.com/ktorio/ktor", "type": "framework", "engine": "Netty"}, - "lithium": {"dir": "lithium", "description": "Lithium C++ HTTP framework with compile-time reflection, boost::context coroutines, and -O3 -march=native -flto.", "repo": "https://github.com/matt-42/lithium", "type": "framework", "engine": "li/http"}, - "may-minihttp": {"dir": "may-minihttp", "description": "Mini HTTP server built on May stackful coroutines. Uses cooperative scheduling with coroutine-per-connection model for high concurrency.", "repo": "https://github.com/Xudong-Huang/may_minihttp", "type": "engine", "engine": "may-minihttp"}, - "nginx": {"dir": "nginx", "description": "Nginx with a custom C handler module, compiled with -O3 -march=native.", "repo": "https://github.com/nginx/nginx", "type": "engine", "engine": "nginx"}, - "nginx-openresty": {"dir": "nginx-openresty", "description": "OpenResty (Nginx + LuaJIT) with Lua content handlers for all benchmark endpoints.", "repo": "https://github.com/openresty/openresty", "type": "framework", "engine": "openresty"}, - "ngx-php": {"dir": "ngx-php", "description": "Embedded PHP scripting language module for nginx.", "repo": "https://github.com/rryqszq4/ngx-php", "type": "framework", "engine": "nginx"}, - "node": {"dir": "node", "description": "Bare Node.js HTTP server using the cluster module for multi-core scaling.", "repo": "https://github.com/nodejs/node", "type": "framework", "engine": "V8"}, - "node-websocket": {"dir": "node-websocket", "description": "Node.js WebSocket echo server using ws package", "repo": "https://github.com/websockets/ws", "type": "framework", "engine": "V8"}, - "ntex-iouring": {"dir": "ntex-iouring", "description": "ntex web framework with neon-uring runtime (io_uring), compiled with -O3 and thin LTO.", "repo": "https://github.com/ntex-rs/ntex", "type": "framework", "engine": "io_uring"}, - "ntex-tokio": {"dir": "ntex-tokio", "description": "ntex web framework with Tokio runtime, compiled with -O3 and thin LTO.", "repo": "https://github.com/ntex-rs/ntex", "type": "framework", "engine": "Tokio"}, - "phoenix": {"dir": "phoenix", "description": "Phoenix 1.7 on Cowboy — the most popular Elixir web framework. First Elixir entry in HttpArena.", "repo": "https://github.com/phoenixframework/phoenix", "type": "framework", "engine": "BEAM"}, - "prologue": {"dir": "prologue", "description": "Prologue web framework for Nim — compiles to native C with powerful routing and middleware support.", "repo": "https://github.com/planety/prologue", "type": "framework", "engine": "asynchserver"}, - "quarkus-jvm": {"dir": "quarkus-jvm", "description": "Quarkus with RESTEasy Reactive on Vert.x/Netty, JDK 21, optimized JVM tuning.", "repo": "https://github.com/quarkusio/quarkus", "type": "framework", "engine": "Netty"}, - "quarkus-jvm-grpc": {"dir": "quarkus-jvm-grpc", "description": "Quarkus gRPC server using quarkus-grpc on Vert.x with h2c, JDK 21, optimized JVM tuning.", "repo": "https://github.com/quarkusio/quarkus", "type": "framework", "engine": "Vert.x (gRPC)"}, - "Rails": {"dir": "rails", "description": "Ruby on Rails (API mode) on Puma, multi-worker with one worker per CPU core.", "repo": "https://github.com/rails/rails", "type": "framework", "engine": "puma"}, - "ringzero": {"dir": "ringzero", "description": "Custom C HTTP server built on io_uring with a multi-reactor architecture. No epoll, no thread-per-connection.", "repo": "https://github.com/MDA2AV/ringzero", "type": "engine", "engine": "io_uring"}, - "rocket": {"dir": "rocket", "description": "Rocket 0.5 on Tokio with Rustls for HTTP/2, compiled with -O3 and thin LTO.", "repo": "https://github.com/SergioBenitez/Rocket", "type": "framework", "engine": "rocket"}, - "Roda": {"dir": "roda", "description": "Roda routing tree web toolkit", "repo": "https://github.com/jeremyevans/roda", "type": "framework", "engine": "puma"}, - "rust-epoll": {"dir": "rust-epoll", "description": "Zero-dependency Rust HTTP engine using raw epoll syscalls, one-thread-per-core with SO_REUSEPORT.", "repo": "", "type": "engine", "engine": "epoll"}, - "salvo": {"dir": "salvo", "description": "Salvo web framework with Quinn HTTP/3 support on Tokio runtime, compiled with -O3 and thin LTO.", "repo": "https://github.com/salvo-rs/salvo", "type": "framework", "engine": "Salvo"}, - "Sinatra": {"dir": "sinatra", "description": "Sinatra DSL web framework on Puma, multi-threaded with one worker per CPU core.", "repo": "https://github.com/sinatra/sinatra", "type": "framework", "engine": "puma"}, - "spring-jvm": {"dir": "spring-jvm", "description": "Spring Boot with embedded Tomcat on JDK 21 (HotSpot JVM with ZGC).", "repo": "https://github.com/spring-projects/spring-boot", "type": "framework", "engine": "Tomcat"}, - "spring-jvm-grpc": {"dir": "spring-jvm-grpc", "description": "Spring Boot gRPC server using grpc-spring-boot-starter with Netty transport on JDK 24.", "repo": "https://github.com/grpc-ecosystem/grpc-spring", "type": "framework", "engine": "Netty (gRPC)"}, - "Starlette": {"dir": "starlette", "description": "Starlette ASGI framework on Uvicorn (uvloop), multi-worker via gunicorn. The foundation FastAPI is built on.", "repo": "https://github.com/encode/starlette", "type": "framework", "engine": "uvicorn"}, - "tonic-grpc": {"dir": "tonic-grpc", "description": "Rust gRPC server using tonic, a native Rust gRPC implementation built on top of hyper and tower.", "repo": "https://github.com/hyperium/tonic", "type": "framework", "engine": "Tonic"}, - "ulfius": {"dir": "ulfius", "description": "Ulfius C REST framework built on GNU Libmicrohttpd with Jansson JSON. Lightweight with small memory footprint, designed for embedded systems.", "repo": "https://github.com/babelouest/ulfius", "type": "framework", "engine": "libmicrohttpd"}, - "ultimate-express": {"dir": "ultimate-express", "description": "ultimate-express (Express API on uWebSockets.js) with single-process threading.", "repo": "https://github.com/dimdenGD/ultimate-express", "type": "framework", "engine": "uWebSockets"}, - "uWebSockets.js": {"dir": "uwebsockets", "description": "Native C++ HTTP/WebSocket server exposed as a Node.js addon. Uses µSockets event loop with epoll, bypassing Node's HTTP stack entirely.", "repo": "https://github.com/uNetworking/uWebSockets.js", "type": "engine", "engine": "uWebSockets"}, - "vertx": {"dir": "vertx", "description": "Eclipse Vert.x 4.5 — reactive toolkit on Netty with event-loop threading, JDK 21.", "repo": "https://github.com/eclipse-vertx/vert.x", "type": "engine", "engine": "Netty"}, - "workerman": {"dir": "workerman", "description": "Workerman with PHP content handlers for all benchmark endpoints.", "repo": "https://github.com/walkor/Workerman", "type": "framework", "engine": "workerman"}, - "workerman-websocket": {"dir": "workerman-websocket", "description": "Workerman WebSocket echo server", "repo": "https://github.com/walkor/Workerman", "type": "framework", "engine": "Workerman"} + "actix": {"description": "Actix-web 4 with rustls for HTTP/2 support, compiled with -O3 and thin LTO.", "repo": "https://github.com/actix/actix-web", "type": "framework", "engine": "actix"}, + "actix-websocket": {"description": "Actix-web WebSocket echo server", "repo": "https://github.com/actix/actix-web", "type": "framework", "engine": "Actix"}, + "aspnet-grpc": {"description": "ASP.NET Core gRPC server using .NET 10 preview with Kestrel.", "repo": "https://github.com/dotnet/aspnetcore", "type": "framework", "engine": "Kestrel"}, + "aspnet-minimal": {"description": "Minimal ASP.NET Core server using .NET 10 preview with Kestrel and minimal API routing.", "repo": "https://github.com/dotnet/aspnetcore", "type": "framework", "engine": "Kestrel"}, + "aspnet-websocket": {"description": "ASP.NET Core WebSocket echo server using .NET 10 preview with Kestrel and minimal API.", "repo": "https://github.com/dotnet/aspnetcore", "type": "framework", "engine": "Kestrel"}, + "blitz": {"description": "Custom Zig HTTP server with dual epoll/io_uring backends. Zero-copy parsing, pre-computed responses, pipeline batching.", "repo": "https://github.com/BennyFranciscus/blitz", "type": "engine", "engine": "io_uring"}, + "bun": {"description": "Bun's built-in HTTP server using JavaScriptCore engine with multi-core clustering.", "repo": "https://github.com/oven-sh/bun", "type": "framework", "engine": "JSC"}, + "bun-websocket": {"description": "Bun WebSocket echo server", "repo": "https://github.com/oven-sh/bun", "type": "framework", "engine": "Bun"}, + "caddy": {"description": "Caddy web server with a custom handler module for benchmark endpoints, native HTTP/2 support.", "repo": "https://github.com/caddyserver/caddy", "type": "engine", "engine": "caddy"}, + "chi": {"description": "Chi is a lightweight, idiomatic and composable router for building Go HTTP services, built on top of net/http.", "repo": "https://github.com/go-chi/chi", "type": "framework", "engine": "chi"}, + "deno": {"description": "Deno HTTP server using deno serve --parallel with zero-dependency native fetch handler.", "repo": "https://github.com/denoland/deno", "type": "framework", "engine": "V8"}, + "deno-websocket": {"description": "Deno WebSocket echo server", "repo": "https://github.com/denoland/deno", "type": "framework", "engine": "Deno"}, + "Django": {"description": "Django web framework on Gunicorn with sync workers, one worker per CPU core.", "repo": "https://github.com/django/django", "type": "framework", "engine": "gunicorn"}, + "drogon": {"description": "Drogon C++ framework using HttpController with async callbacks, mimalloc allocator, and -flto optimization.", "repo": "https://github.com/drogonframework/drogon", "type": "framework", "engine": "drogon"}, + "echo": {"description": "Echo is a high performance, extensible, minimalist Go web framework with optimized HTTP router, middleware support, and data binding.", "repo": "https://github.com/labstack/echo", "type": "framework", "engine": "echo"}, + "Elysia": {"description": "Ergonomic TypeScript framework built for Bun with end-to-end type safety and excellent DX.", "repo": "https://github.com/elysiajs/elysia", "type": "framework", "engine": "Bun"}, + "Express": {"description": "Fast, unopinionated, minimalist web framework for Node.js. The most widely used backend framework in the JavaScript ecosystem.", "repo": "https://github.com/expressjs/express", "type": "framework", "engine": "V8"}, + "FastAPI": {"description": "FastAPI async web framework on Uvicorn (uvloop), multi-worker via gunicorn.", "repo": "https://github.com/fastapi/fastapi", "type": "framework", "engine": "uvicorn"}, + "Fastify": {"description": "Fast and low-overhead Node.js web framework built for developer experience and performance.", "repo": "https://github.com/fastify/fastify", "type": "framework", "engine": "V8"}, + "FastPySGI-WSGI": {"description": "An ultra fast WSGI/ASGI server for Python", "repo": "https://github.com/remittor/fastpysgi", "type": "engine", "engine": "libuv"}, + "FastPySGI-ASGI": {"description": "An ultra fast WSGI/ASGI server for Python", "repo": "https://github.com/remittor/fastpysgi", "type": "engine", "engine": "libuv"}, + "fiber": {"description": "Fiber is an Express-inspired Go web framework built on fasthttp, featuring zero-allocation routing and extreme performance.", "repo": "https://github.com/gofiber/fiber", "type": "framework", "engine": "fiber"}, + "flask": {"description": "Flask web framework on Gunicorn with sync workers, one worker per CPU core.", "repo": "https://github.com/pallets/flask", "type": "framework", "engine": "gunicorn"}, + "Fletch": {"description": "Express-inspired HTTP framework for Dart with radix-tree routing, middleware chains, signed sessions, and built-in DI.", "repo": "https://github.com/kartikey321/fletch", "type": "framework", "engine": "dart:io"}, + "GenHTTP": {"description": "Lightweight, embeddable and modular C# web server.", "repo": "https://github.com/Kaliumhexacyanoferrat/GenHTTP", "type": "framework", "engine": "GenHTTP"}, + "GenHTTP-WS": {"description": "GenHTTP WebSocket echo server using the functional API with zero-allocation frame handling.", "repo": "https://github.com/Kaliumhexacyanoferrat/GenHTTP", "type": "framework", "engine": "GenHTTP"}, + "gin": {"description": "Gin is a Go web framework with a martini-like API, featuring the fastest HTTP router (httprouter) and zero-allocation routing.", "repo": "https://github.com/gin-gonic/gin", "type": "framework", "engine": "gin"}, + "gleam-mist": {"description": "Mist HTTP server for Gleam on the BEAM VM — first Gleam and first BEAM entry in HttpArena.", "repo": "https://github.com/rawhat/mist", "type": "framework", "engine": "BEAM"}, + "go-fasthttp": {"description": "High-performance Go HTTP server using fasthttp with zero-allocation design and buffer reuse.", "repo": "https://github.com/valyala/fasthttp", "type": "framework", "engine": "fasthttp"}, + "go-websocket": {"description": "Go WebSocket echo server using gobwas/ws", "repo": "https://github.com/gobwas/ws", "type": "framework", "engine": "net/http"}, + "grpc-go": {"description": "Go gRPC server using google.golang.org/grpc.", "repo": "https://github.com/grpc/grpc-go", "type": "framework", "engine": "grpc-go"}, + "h2o": {"description": "High-performance C HTTP server using libh2o with multi-threaded event loops and native HTTP/2 support.", "repo": "https://github.com/h2o/h2o", "type": "engine", "engine": "h2o"}, + "h2o-mruby": {"description": "h2o config-based server with mruby handlers and native HTTP/3 (QUIC) support.", "repo": "https://github.com/h2o/h2o", "type": "framework", "engine": "h2o"}, + "hono (node)": {"description": "Ultrafast web framework built on Web Standards, runs on any JS runtime.", "repo": "https://github.com/honojs/hono", "type": "framework", "engine": "Node"}, + "Hono (Bun)": {"description": "Ultrafast Web Standards framework running natively on Bun — no adapter overhead.", "repo": "https://github.com/honojs/hono", "type": "framework", "engine": "JSC"}, + "hummingbird": {"description": "Lightweight, flexible HTTP server framework written in Swift, built on SwiftNIO with minimal dependencies.", "repo": "https://github.com/hummingbird-project/hummingbird", "type": "framework", "engine": "Hummingbird"}, + "hyper": {"description": "Low-level HTTP library for Rust, built on tokio with multi-threaded async runtime.", "repo": "https://github.com/hyperium/hyper", "type": "engine", "engine": "hyper"}, + "kemal": {"description": "Kemal web framework for Crystal, compiled with --release optimizations.", "repo": "https://github.com/kemalcr/kemal", "type": "framework", "engine": "Kemal"}, + "Koa": {"description": "Expressive middleware framework for Node.js by the Express team, using async/await.", "repo": "https://github.com/koajs/koa", "type": "framework", "engine": "V8"}, + "ktor": {"description": "JetBrains Ktor 3.x on Netty with Kotlin coroutines, kotlinx.serialization, JDK 21.", "repo": "https://github.com/ktorio/ktor", "type": "framework", "engine": "Netty"}, + "lithium": {"description": "Lithium C++ HTTP framework with compile-time reflection, boost::context coroutines, and -O3 -march=native -flto.", "repo": "https://github.com/matt-42/lithium", "type": "framework", "engine": "li/http"}, + "may-minihttp": {"description": "Mini HTTP server built on May stackful coroutines. Uses cooperative scheduling with coroutine-per-connection model for high concurrency.", "repo": "https://github.com/Xudong-Huang/may_minihttp", "type": "engine", "engine": "may-minihttp"}, + "nginx": {"description": "Nginx with a custom C handler module, compiled with -O3 -march=native.", "repo": "https://github.com/nginx/nginx", "type": "engine", "engine": "nginx"}, + "nginx-openresty": {"description": "OpenResty (Nginx + LuaJIT) with Lua content handlers for all benchmark endpoints.", "repo": "https://github.com/openresty/openresty", "type": "framework", "engine": "openresty"}, + "ngx-php": {"description": "Embedded PHP scripting language module for nginx.", "repo": "https://github.com/rryqszq4/ngx-php", "type": "framework", "engine": "nginx"}, + "node": {"description": "Bare Node.js HTTP server using the cluster module for multi-core scaling.", "repo": "https://github.com/nodejs/node", "type": "framework", "engine": "V8"}, + "node-websocket": {"description": "Node.js WebSocket echo server using ws package", "repo": "https://github.com/websockets/ws", "type": "framework", "engine": "V8"}, + "ntex-iouring": {"description": "ntex web framework with neon-uring runtime (io_uring), compiled with -O3 and thin LTO.", "repo": "https://github.com/ntex-rs/ntex", "type": "framework", "engine": "io_uring"}, + "ntex-tokio": {"description": "ntex web framework with Tokio runtime, compiled with -O3 and thin LTO.", "repo": "https://github.com/ntex-rs/ntex", "type": "framework", "engine": "Tokio"}, + "phoenix": {"description": "Phoenix 1.7 on Cowboy — the most popular Elixir web framework. First Elixir entry in HttpArena.", "repo": "https://github.com/phoenixframework/phoenix", "type": "framework", "engine": "BEAM"}, + "prologue": {"description": "Prologue web framework for Nim — compiles to native C with powerful routing and middleware support.", "repo": "https://github.com/planety/prologue", "type": "framework", "engine": "asynchserver"}, + "quarkus-jvm": {"description": "Quarkus with RESTEasy Reactive on Vert.x/Netty, JDK 21, optimized JVM tuning.", "repo": "https://github.com/quarkusio/quarkus", "type": "framework", "engine": "Netty"}, + "quarkus-jvm-grpc": {"description": "Quarkus gRPC server using quarkus-grpc on Vert.x with h2c, JDK 21, optimized JVM tuning.", "repo": "https://github.com/quarkusio/quarkus", "type": "framework", "engine": "Vert.x (gRPC)"}, + "Rails": {"description": "Ruby on Rails (API mode) on Puma, multi-worker with one worker per CPU core.", "repo": "https://github.com/rails/rails", "type": "framework", "engine": "puma"}, + "ringzero": {"description": "Custom C HTTP server built on io_uring with a multi-reactor architecture. No epoll, no thread-per-connection.", "repo": "https://github.com/MDA2AV/ringzero", "type": "engine", "engine": "io_uring"}, + "rocket": {"description": "Rocket 0.5 on Tokio with Rustls for HTTP/2, compiled with -O3 and thin LTO.", "repo": "https://github.com/SergioBenitez/Rocket", "type": "framework", "engine": "rocket"}, + "rust-epoll": {"description": "Zero-dependency Rust HTTP engine using raw epoll syscalls, one-thread-per-core with SO_REUSEPORT.", "repo": "", "type": "engine", "engine": "epoll"}, + "salvo": {"description": "Salvo web framework with Quinn HTTP/3 support on Tokio runtime, compiled with -O3 and thin LTO.", "repo": "https://github.com/salvo-rs/salvo", "type": "framework", "engine": "Salvo"}, + "Sinatra": {"description": "Sinatra DSL web framework on Puma, multi-threaded with one worker per CPU core.", "repo": "https://github.com/sinatra/sinatra", "type": "framework", "engine": "puma"}, + "spring-jvm": {"description": "Spring Boot with embedded Tomcat on JDK 21 (HotSpot JVM with ZGC).", "repo": "https://github.com/spring-projects/spring-boot", "type": "framework", "engine": "Tomcat"}, + "spring-jvm-grpc": {"description": "Spring Boot gRPC server using grpc-spring-boot-starter with Netty transport on JDK 24.", "repo": "https://github.com/grpc-ecosystem/grpc-spring", "type": "framework", "engine": "Netty (gRPC)"}, + "Starlette": {"description": "Starlette ASGI framework on Uvicorn (uvloop), multi-worker via gunicorn. The foundation FastAPI is built on.", "repo": "https://github.com/encode/starlette", "type": "framework", "engine": "uvicorn"}, + "tonic-grpc": {"description": "Rust gRPC server using tonic, a native Rust gRPC implementation built on top of hyper and tower.", "repo": "https://github.com/hyperium/tonic", "type": "framework", "engine": "Tonic"}, + "ulfius": {"description": "Ulfius C REST framework built on GNU Libmicrohttpd with Jansson JSON. Lightweight with small memory footprint, designed for embedded systems.", "repo": "https://github.com/babelouest/ulfius", "type": "framework", "engine": "libmicrohttpd"}, + "ultimate-express": {"description": "ultimate-express (Express API on uWebSockets.js) with single-process threading.", "repo": "https://github.com/dimdenGD/ultimate-express", "type": "framework", "engine": "uWebSockets"}, + "vertx": {"description": "Eclipse Vert.x 4.5 — reactive toolkit on Netty with event-loop threading, JDK 21.", "repo": "https://github.com/eclipse-vertx/vert.x", "type": "engine", "engine": "Netty"}, + "workerman": {"description": "Workerman with PHP content handlers for all benchmark endpoints.", "repo": "https://github.com/walkor/Workerman", "type": "framework", "engine": "workerman"}, + "workerman-websocket": {"description": "Workerman WebSocket echo server", "repo": "https://github.com/walkor/Workerman", "type": "framework", "engine": "Workerman"} } diff --git a/site/data/json-16384.json b/site/data/json-16384.json index 9f6f481f..3fda748c 100644 --- a/site/data/json-16384.json +++ b/site/data/json-16384.json @@ -894,5 +894,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 30174, + "avg_latency": "98.01ms", + "p99_latency": "961.10ms", + "cpu": "1196.1%", + "memory": "1.4GiB", + "connections": 16384, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "245.98MB/s", + "input_bw": "", + "reconnects": 0, + "status_2xx": 150874, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/json-4096.json b/site/data/json-4096.json index 9b3b8135..195d29aa 100644 --- a/site/data/json-4096.json +++ b/site/data/json-4096.json @@ -894,5 +894,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 37808, + "avg_latency": "33.00ms", + "p99_latency": "323.20ms", + "cpu": "1346.5%", + "memory": "1.3GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "308.22MB/s", + "input_bw": "", + "reconnects": 0, + "status_2xx": 189044, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/limited-conn-4096.json b/site/data/limited-conn-4096.json index b7626326..878b7b60 100644 --- a/site/data/limited-conn-4096.json +++ b/site/data/limited-conn-4096.json @@ -1083,5 +1083,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 127671, + "avg_latency": "6.86ms", + "p99_latency": "12.90ms", + "cpu": "1176.2%", + "memory": "1.2GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "25.93MB/s", + "input_bw": "9.86MB/s", + "reconnects": 69417, + "status_2xx": 638356, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/limited-conn-512.json b/site/data/limited-conn-512.json index e2c26c6a..20ee0fac 100644 --- a/site/data/limited-conn-512.json +++ b/site/data/limited-conn-512.json @@ -1083,5 +1083,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 144092, + "avg_latency": "2.74ms", + "p99_latency": "3.64ms", + "cpu": "1401.7%", + "memory": "1.1GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "29.41MB/s", + "input_bw": "11.13MB/s", + "reconnects": 79450, + "status_2xx": 720462, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/mixed-16384.json b/site/data/mixed-16384.json index 67d08022..c60d10b7 100644 --- a/site/data/mixed-16384.json +++ b/site/data/mixed-16384.json @@ -1078,5 +1078,32 @@ "tpl_compression": 85553, "tpl_static": 95221, "tpl_async_db": 2 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 611, + "avg_latency": "1.15s", + "p99_latency": "5.00s", + "cpu": "854.6%", + "memory": "9.9GiB", + "connections": 16384, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "31.95MB/s", + "input_bw": "43.68MB/s", + "reconnects": 2060, + "status_2xx": 9168, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0, + "tpl_baseline": 2983, + "tpl_json": 576, + "tpl_db": 573, + "tpl_upload": 546, + "tpl_compression": 2154, + "tpl_static": 1133, + "tpl_async_db": 1203 } ] \ No newline at end of file diff --git a/site/data/mixed-4096.json b/site/data/mixed-4096.json index 075521f7..d1099647 100644 --- a/site/data/mixed-4096.json +++ b/site/data/mixed-4096.json @@ -1078,5 +1078,32 @@ "tpl_compression": 94430, "tpl_static": 106061, "tpl_async_db": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 724, + "avg_latency": "974.94ms", + "p99_latency": "5.00s", + "cpu": "863.3%", + "memory": "11.2GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "31.05MB/s", + "input_bw": "51.76MB/s", + "reconnects": 2253, + "status_2xx": 10872, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0, + "tpl_baseline": 3833, + "tpl_json": 731, + "tpl_db": 750, + "tpl_upload": 733, + "tpl_compression": 2055, + "tpl_static": 1417, + "tpl_async_db": 1353 } ] \ No newline at end of file diff --git a/site/data/noisy-16384.json b/site/data/noisy-16384.json index 164f8f43..76fd3069 100644 --- a/site/data/noisy-16384.json +++ b/site/data/noisy-16384.json @@ -845,5 +845,25 @@ "status_3xx": 0, "status_4xx": 3863291, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 106777, + "avg_latency": "18.54ms", + "p99_latency": "39.10ms", + "cpu": "1105.5%", + "memory": "2.0GiB", + "connections": 16384, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "29.19MB/s", + "input_bw": "10.79MB/s", + "reconnects": 1905, + "status_2xx": 533885, + "status_3xx": 0, + "status_4xx": 179468, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/noisy-4096.json b/site/data/noisy-4096.json index d50326f2..0f000863 100644 --- a/site/data/noisy-4096.json +++ b/site/data/noisy-4096.json @@ -845,5 +845,25 @@ "status_3xx": 0, "status_4xx": 2271170, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 131098, + "avg_latency": "2.93ms", + "p99_latency": "6.16ms", + "cpu": "1349.1%", + "memory": "1.4GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "35.71MB/s", + "input_bw": "13.25MB/s", + "reconnects": 237, + "status_2xx": 655490, + "status_3xx": 0, + "status_4xx": 217806, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/noisy-512.json b/site/data/noisy-512.json index cb44bf95..f88df2ca 100644 --- a/site/data/noisy-512.json +++ b/site/data/noisy-512.json @@ -845,5 +845,25 @@ "status_3xx": 0, "status_4xx": 2213021, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 108469, + "avg_latency": "2.52ms", + "p99_latency": "3.61ms", + "cpu": "1233.7%", + "memory": "1.6GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "30.43MB/s", + "input_bw": "10.97MB/s", + "reconnects": 34, + "status_2xx": 542349, + "status_3xx": 0, + "status_4xx": 197138, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/pipelined-16384.json b/site/data/pipelined-16384.json index 0bcbd072..1bd9526d 100644 --- a/site/data/pipelined-16384.json +++ b/site/data/pipelined-16384.json @@ -1085,5 +1085,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 267269, + "avg_latency": "81.11ms", + "p99_latency": "2.20s", + "cpu": "1310.2%", + "memory": "1.2GiB", + "connections": 16384, + "threads": 64, + "duration": "5s", + "pipeline": 16, + "bandwidth": "49.70MB/s", + "input_bw": "", + "reconnects": 0, + "status_2xx": 1336346, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/pipelined-4096.json b/site/data/pipelined-4096.json index 9d5a2def..be9beccc 100644 --- a/site/data/pipelined-4096.json +++ b/site/data/pipelined-4096.json @@ -1085,5 +1085,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 276937, + "avg_latency": "31.58ms", + "p99_latency": "523.40ms", + "cpu": "1368.9%", + "memory": "1.1GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 16, + "bandwidth": "51.51MB/s", + "input_bw": "", + "reconnects": 0, + "status_2xx": 1384688, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/pipelined-512.json b/site/data/pipelined-512.json index 08b5d4b9..ef67401f 100644 --- a/site/data/pipelined-512.json +++ b/site/data/pipelined-512.json @@ -1085,5 +1085,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 274481, + "avg_latency": "22.02ms", + "p99_latency": "371.10ms", + "cpu": "1373.3%", + "memory": "1.1GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 16, + "bandwidth": "51.04MB/s", + "input_bw": "", + "reconnects": 0, + "status_2xx": 1372407, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/static-16384.json b/site/data/static-16384.json index b191a4b6..ca3c318a 100644 --- a/site/data/static-16384.json +++ b/site/data/static-16384.json @@ -798,5 +798,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 147628, + "avg_latency": "20.51ms", + "p99_latency": "135.50ms", + "cpu": "1327.7%", + "memory": "1.2GiB", + "connections": 16384, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "2.29GB/s", + "input_bw": "8.02MB/s", + "reconnects": 0, + "status_2xx": 738141, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/static-4096.json b/site/data/static-4096.json index 27815067..44f9e34c 100644 --- a/site/data/static-4096.json +++ b/site/data/static-4096.json @@ -798,5 +798,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 172174, + "avg_latency": "7.39ms", + "p99_latency": "14.10ms", + "cpu": "1337.5%", + "memory": "1.4GiB", + "connections": 4096, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "2.72GB/s", + "input_bw": "9.36MB/s", + "reconnects": 0, + "status_2xx": 860871, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/upload-256.json b/site/data/upload-256.json index bcd2bcaa..79105623 100644 --- a/site/data/upload-256.json +++ b/site/data/upload-256.json @@ -858,5 +858,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 100, + "avg_latency": "1.34s", + "p99_latency": "4.88s", + "cpu": "467.8%", + "memory": "7.9GiB", + "connections": 256, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "19.62KB/s", + "input_bw": "1.95GB/s", + "reconnects": 0, + "status_2xx": 500, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/upload-512.json b/site/data/upload-512.json index ef8a6dca..89c53842 100644 --- a/site/data/upload-512.json +++ b/site/data/upload-512.json @@ -858,5 +858,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 97, + "avg_latency": "1.62s", + "p99_latency": "5.00s", + "cpu": "442.9%", + "memory": "8.0GiB", + "connections": 512, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "19.11KB/s", + "input_bw": "1.89GB/s", + "reconnects": 0, + "status_2xx": 487, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/data/upload-64.json b/site/data/upload-64.json index c24b923d..0360c427 100644 --- a/site/data/upload-64.json +++ b/site/data/upload-64.json @@ -858,5 +858,25 @@ "status_3xx": 0, "status_4xx": 0, "status_5xx": 0 + }, + { + "framework": "Fletch", + "language": "Dart", + "rps": 145, + "avg_latency": "427.12ms", + "p99_latency": "1.62s", + "cpu": "595.7%", + "memory": "6.3GiB", + "connections": 64, + "threads": 64, + "duration": "5s", + "pipeline": 1, + "bandwidth": "28.53KB/s", + "input_bw": "2.83GB/s", + "reconnects": 0, + "status_2xx": 727, + "status_3xx": 0, + "status_4xx": 0, + "status_5xx": 0 } ] \ No newline at end of file diff --git a/site/static/logs/async-db/1024/fletch.log b/site/static/logs/async-db/1024/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/async-db/512/fletch.log b/site/static/logs/async-db/512/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/baseline/16384/fletch.log b/site/static/logs/baseline/16384/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/baseline/4096/fletch.log b/site/static/logs/baseline/4096/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/baseline/512/fletch.log b/site/static/logs/baseline/512/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/compression/16384/fletch.log b/site/static/logs/compression/16384/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/compression/4096/fletch.log b/site/static/logs/compression/4096/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/json/16384/fletch.log b/site/static/logs/json/16384/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/json/4096/fletch.log b/site/static/logs/json/4096/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/limited-conn/4096/fletch.log b/site/static/logs/limited-conn/4096/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/limited-conn/512/fletch.log b/site/static/logs/limited-conn/512/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/mixed/16384/fletch.log b/site/static/logs/mixed/16384/fletch.log new file mode 100644 index 00000000..3f056aa0 --- /dev/null +++ b/site/static/logs/mixed/16384/fletch.log @@ -0,0 +1,7 @@ +evacuation failed +evacuation failed +evacuation failed +evacuation failed +evacuation failed +evacuation failed +evacuation failed diff --git a/site/static/logs/mixed/4096/fletch.log b/site/static/logs/mixed/4096/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/noisy/16384/fletch.log b/site/static/logs/noisy/16384/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/noisy/4096/fletch.log b/site/static/logs/noisy/4096/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/noisy/512/fletch.log b/site/static/logs/noisy/512/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/pipelined/16384/fletch.log b/site/static/logs/pipelined/16384/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/pipelined/4096/fletch.log b/site/static/logs/pipelined/4096/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/pipelined/512/fletch.log b/site/static/logs/pipelined/512/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/static/16384/fletch.log b/site/static/logs/static/16384/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/static/4096/fletch.log b/site/static/logs/static/4096/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/upload/256/fletch.log b/site/static/logs/upload/256/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/upload/512/fletch.log b/site/static/logs/upload/512/fletch.log new file mode 100644 index 00000000..e69de29b diff --git a/site/static/logs/upload/64/fletch.log b/site/static/logs/upload/64/fletch.log new file mode 100644 index 00000000..e69de29b