From df5e8f744b143e9da652c0f1b78d6fe7bac3ee33 Mon Sep 17 00:00:00 2001 From: Jesse Wierzbinski Date: Wed, 29 Nov 2023 18:16:58 -1000 Subject: [PATCH] feat: Add timeline benchmark --- README.md | 15 +++++++++++ benchmarks/timelines.ts | 56 +++++++++++++++++++++++++++++++++++++++++ index.ts | 3 ++- package.json | 1 + 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 benchmarks/timelines.ts diff --git a/README.md b/README.md index d54ddb74..6d3a627a 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,25 @@ This project aims to be a fully featured social network, with a focus on privacy - [x] Full regex-based filters for posts, users and media - [x] Custom emoji support - [x] Automatic image conversion to WebP or other formats +- [x] Scripting-compatible CLI with JSON and CSV outputs - [ ] Moderation tools - [ ] Full Mastodon API support - [ ] Outbound federation +## Benchmarks + +> **Note**: These benchmarks are not representative of real-world performance, and are only meant to be used as a rough guide. + +### Timeline Benchmarks + +You may run the following command to benchmark the `/api/v1/timelines/home` endpoint: + +```bash +TOKEN=token_here bun benchmark:timeline +``` + +The `request_count` variable is optional and defaults to 100. `TOKEN` is your personal user token, used to login to the API. + ## How do I run it? ### Requirements diff --git a/benchmarks/timelines.ts b/benchmarks/timelines.ts new file mode 100644 index 00000000..2804f691 --- /dev/null +++ b/benchmarks/timelines.ts @@ -0,0 +1,56 @@ +/** + * Usage: TOKEN=your_token_here bun benchmark:timeline + */ + +import { getConfig } from "@config"; +import chalk from "chalk"; + +const config = getConfig(); + +const token = process.env.TOKEN; +const requestCount = Number(process.argv[2]) || 100; + +if (!token) { + console.log( + `${chalk.red( + "✗" + )} No token provided. Provide one via the TOKEN environment variable.` + ); + process.exit(1); +} + +const fetchTimeline = () => + fetch(`${config.http.base_url}/api/v1/timelines/home`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }).then(res => res.ok); + +const timeNow = performance.now(); + +const requests = Array.from({ length: requestCount }, () => fetchTimeline()); + +Promise.all(requests) + .then(results => { + const timeTaken = performance.now() - timeNow; + if (results.every(t => t)) { + console.log(`${chalk.green("✓")} All requests succeeded`); + } else { + console.log( + `${chalk.red("✗")} ${ + results.filter(t => !t).length + } requests failed` + ); + } + console.log( + `${chalk.green("✓")} ${ + requests.length + } requests fulfilled in ${chalk.bold( + (timeTaken / 1000).toFixed(5) + )}s` + ); + }) + .catch(err => { + console.log(`${chalk.red("✗")} ${err}`); + process.exit(1); + }); diff --git a/index.ts b/index.ts index b1aadd86..ce7ababe 100644 --- a/index.ts +++ b/index.ts @@ -12,6 +12,7 @@ import { client } from "~database/datasource"; import type { PrismaClientInitializationError } from "@prisma/client/runtime/library"; import { HookTypes, Server } from "~plugins/types"; +const timeAtStart = performance.now(); const server = new Server(); const router = new Bun.FileSystemRouter({ @@ -171,7 +172,7 @@ console.log( `${chalk.green(`✓`)} ${chalk.bold( `Lysand started at ${chalk.blue( `${config.http.bind}:${config.http.bind_port}` - )}` + )} in ${chalk.gray((performance.now() - timeAtStart).toFixed(0))}ms` )}` ); diff --git a/package.json b/package.json index 23c4985f..90da5362 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "lint": "eslint --config .eslintrc.cjs --ext .ts .", "prisma": "bun run prisma.ts", "generate": "bun prisma generate", + "benchmark:timeline": "bun run benchmarks/timelines.ts", "cli": "bun run cli.ts" }, "trustedDependencies": [