Skip to content

Commit

Permalink
Jmeterbenchmark
Browse files Browse the repository at this point in the history
test jmeter benchmarking

Signed-off-by: ruzell22 <[email protected]>
  • Loading branch information
ruzell22 committed Feb 21, 2024
1 parent 4184cf2 commit 36fd8d9
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 0 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,38 @@ jobs:
restore-keys: |
${{ runner.os }}-yarn-${{ hashFiles('./yarn.lock') }}
- run: ./tools/ci.sh

- name: Ensure .tmp Directory Exists
run: mkdir -p .tmp/benchmark-results/plugin-ledger-connector-besu/

# Download previous benchmark result from cache (if exists)
- name: Download previous benchmark data
uses: actions/[email protected]
with:
path: .tmp/benchmark-results/plugin-ledger-connector-besu/
key: ${{ runner.os }}-benchmark

- name: Run Benchmarks
working-directory: ./packages/cactus-plugin-ledger-connector-besu/
run: yarn run benchmark

- name: Store benchmark result
uses: benchmark-action/[email protected]
with:
tool: 'benchmarkjs'
output-file-path: .tmp/benchmark-results/plugin-ledger-connector-besu/run-plugin-ledger-connector-besu-benchmark.ts.log
github-token: ${{ secrets.GITHUB_TOKEN }}

# Only push the benchmark results to gh-pages website if we are running on the main branch
# We do not want to clutter the benchmark results with intermediate results from PRs that could be drafts
auto-push: ${{ github.ref == 'refs/heads/main' }}

# Show alert with commit comment on detecting possible performance regression
alert-threshold: '5%'
comment-on-alert: true
fail-on-alert: true
alert-comment-cc-users: '@petermetz'

cactus-plugin-ledger-connector-corda:
continue-on-error: false
needs:
Expand Down
1 change: 1 addition & 0 deletions packages/cactus-plugin-ledger-connector-besu/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"dist/*"
],
"scripts": {
"benchmark": "tsx ./src/test/typescript/benchmark/run-plugin-ledger-connector-besu-benchmark.ts .tmp/benchmark-results/plugin-ledger-connector-besu/run-plugin-ledger-connector-besu-benchmark.ts.log",
"codegen": "run-p 'codegen:*'",
"codegen:openapi": "npm run generate-sdk",
"generate-sdk": "run-p 'generate-sdk:*'",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import path from "path";
import { EOL } from "os";
import * as Benchmark from "benchmark";

import test, { Test } from "tape-promise/tape";
import { v4 as uuidv4 } from "uuid";
import { Server as SocketIoServer } from "socket.io";
import { PluginRegistry } from "@hyperledger/cactus-core";
import fse from "fs-extra";
import {
PluginLedgerConnectorBesu,
BesuApiClient,
IPluginLedgerConnectorBesuOptions,
} from "../../../main/typescript/public-api";
import { PluginKeychainMemory } from "@hyperledger/cactus-plugin-keychain-memory";
import {
BesuTestLedger,
pruneDockerAllIfGithubAction,
} from "@hyperledger/cactus-test-tooling";
import KeyEncoder from "key-encoder";
import {
IListenOptions,
KeyFormat,
LogLevelDesc,
Secp256k1Keys,
Servers,
} from "@hyperledger/cactus-common";
import { Constants } from "@hyperledger/cactus-core-api";
import express from "express";
import bodyParser from "body-parser";
import http from "http";
import HelloWorldContractJson from "../../solidity/hello-world-contract/HelloWorld.json";
import { AddressInfo } from "net";
import { BesuApiClientOptions } from "../../../main/typescript/api-client/besu-api-client";

import { installOpenapiValidationMiddleware } from "@hyperledger/cactus-core";
import OAS from "../../../main/json/openapi.json";

const LOG_TAG =
"[packages/cactus-plugin-ledger-connector-besu/src/test/typescript/benchmark/run-plugin-ledger-connector-besu-benchmark.ts]";

const logLevel: LogLevelDesc = "TRACE";
const testCase = "Besu API";

test("BEFORE " + testCase, async (t: Test) => {
const pruning = pruneDockerAllIfGithubAction({ logLevel });
await t.doesNotReject(pruning, "Pruning did not throw OK");
t.end();
});

const createTest = async (t: Test) => {
const keyEncoder: KeyEncoder = new KeyEncoder("secp256k1");
const keychainIdForSigned = uuidv4();
const keychainIdForUnsigned = uuidv4();
const keychainRefForSigned = uuidv4();
const keychainRefForUnsigned = uuidv4();

const besuTestLedger = new BesuTestLedger();
await besuTestLedger.start();
test.onFinish(async () => {
await besuTestLedger.stop();
await besuTestLedger.destroy();
});

const rpcApiHttpHost = await besuTestLedger.getRpcApiHttpHost();
const rpcApiWsHost = await besuTestLedger.getRpcApiWsHost();

const testEthAccount1 = await besuTestLedger.createEthTestAccount();
const testEthAccount2 = await besuTestLedger.createEthTestAccount();
const firstHighNetWorthAccount = besuTestLedger.getGenesisAccountPubKey();

// keychainPlugin for signed transactions
const { privateKey } = Secp256k1Keys.generateKeyPairsBuffer();
const keyHex = privateKey.toString("hex");
const pem = keyEncoder.encodePrivate(keyHex, KeyFormat.Raw, KeyFormat.PEM);
const signedKeychainPlugin = new PluginKeychainMemory({
instanceId: uuidv4(),
keychainId: keychainIdForSigned,
backend: new Map([[keychainRefForSigned, pem]]),
logLevel,
});

// keychainPlugin for unsigned transactions
const keychainEntryValue = testEthAccount1.privateKey;
const unsignedKeychainPlugin = new PluginKeychainMemory({
instanceId: uuidv4(),
keychainId: keychainIdForUnsigned,
backend: new Map([[keychainRefForUnsigned, keychainEntryValue]]),
logLevel,
});
unsignedKeychainPlugin.set(
HelloWorldContractJson.contractName,
JSON.stringify(HelloWorldContractJson),
);

const pluginRegistry = new PluginRegistry({
plugins: [signedKeychainPlugin, unsignedKeychainPlugin],
});

const options: IPluginLedgerConnectorBesuOptions = {
instanceId: uuidv4(),
rpcApiHttpHost,
rpcApiWsHost,
pluginRegistry,
logLevel,
};
const connector = new PluginLedgerConnectorBesu(options);
pluginRegistry.add(connector);

const expressApp = express();
expressApp.use(bodyParser.json({ limit: "250mb" }));
const server = http.createServer(expressApp);

const wsApi = new SocketIoServer(server, {
path: Constants.SocketIoConnectionPathV1,
});

const listenOptions: IListenOptions = {
hostname: "127.0.0.1",
port: 0,
server,
};
const addressInfo = (await Servers.listen(listenOptions)) as AddressInfo;
test.onFinish(async () => await Servers.shutdown(server));
const { address, port } = addressInfo;
const apiHost = `http://${address}:${port}`;
t.comment(
`Metrics URL: ${apiHost}/api/v1/plugins/@hyperledger/cactus-plugin-ledger-connector-besu/get-prometheus-exporter-metrics`,
);

const wsBasePath = apiHost + Constants.SocketIoConnectionPathV1;
t.comment("WS base path: " + wsBasePath);
const besuApiClientOptions = new BesuApiClientOptions({ basePath: apiHost });
const apiClient = new BesuApiClient(besuApiClientOptions);

await installOpenapiValidationMiddleware({
logLevel,
app: expressApp,
apiSpec: OAS,
});

await connector.getOrCreateWebServices();
await connector.registerWebServices(expressApp, wsApi);
};

const main = async (opts: { readonly argv: Readonly<Array<string>> }) => {
const logLevel: LogLevelDesc = "WARN";

const gitRootPath = path.join(
__dirname,
"../../../../../../", // walk back up to the project root
);

console.log("%s gitRootPath=%s", LOG_TAG, gitRootPath);

const DEFAULT_OUTPUT_FILE_RELATIVE_PATH =
".tmp/benchmark-results/plugin-ledger-connector-besu/run-plugin-ledger-connector-besu-benchmark.ts.log";

const relativeOutputFilePath =
opts.argv[2] === undefined
? DEFAULT_OUTPUT_FILE_RELATIVE_PATH
: opts.argv[2];

console.log(
"%s DEFAULT_OUTPUT_FILE_RELATIVE_PATH=%s",
LOG_TAG,
DEFAULT_OUTPUT_FILE_RELATIVE_PATH,
);

console.log("%s opts.argv[2]=%s", LOG_TAG, opts.argv[2]);

console.log("%s relativeOutputFilePath=%s", LOG_TAG, relativeOutputFilePath);

const absoluteOutputFilePath = path.join(gitRootPath, relativeOutputFilePath);

console.log("%s absoluteOutputFilePath=%s", LOG_TAG, absoluteOutputFilePath);

const absoluteOutputDirPath = path.dirname(absoluteOutputFilePath);
console.log("%s absoluteOutputDirPath=%s", LOG_TAG, absoluteOutputDirPath);

await fse.mkdirp(absoluteOutputDirPath);
console.log("%s mkdir -p OK: %s", LOG_TAG, absoluteOutputDirPath);

const { apiServer, httpApi } = await createTest({ logLevel });

Check failure on line 184 in packages/cactus-plugin-ledger-connector-besu/src/test/typescript/benchmark/run-plugin-ledger-connector-besu-benchmark.ts

View workflow job for this annotation

GitHub Actions / nuclei-scan

Property 'apiServer' does not exist on type 'void'.

Check failure on line 184 in packages/cactus-plugin-ledger-connector-besu/src/test/typescript/benchmark/run-plugin-ledger-connector-besu-benchmark.ts

View workflow job for this annotation

GitHub Actions / nuclei-scan

Property 'httpApi' does not exist on type 'void'.

Check failure on line 184 in packages/cactus-plugin-ledger-connector-besu/src/test/typescript/benchmark/run-plugin-ledger-connector-besu-benchmark.ts

View workflow job for this annotation

GitHub Actions / nuclei-scan

Object literal may only specify known properties, and 'logLevel' does not exist in type 'Test'.

Check failure on line 184 in packages/cactus-plugin-ledger-connector-besu/src/test/typescript/benchmark/run-plugin-ledger-connector-besu-benchmark.ts

View workflow job for this annotation

GitHub Actions / publish

Property 'apiServer' does not exist on type 'void'.

Check failure on line 184 in packages/cactus-plugin-ledger-connector-besu/src/test/typescript/benchmark/run-plugin-ledger-connector-besu-benchmark.ts

View workflow job for this annotation

GitHub Actions / publish

Property 'httpApi' does not exist on type 'void'.

Check failure on line 184 in packages/cactus-plugin-ledger-connector-besu/src/test/typescript/benchmark/run-plugin-ledger-connector-besu-benchmark.ts

View workflow job for this annotation

GitHub Actions / publish

Object literal may only specify known properties, and 'logLevel' does not exist in type 'Test'.

Check failure on line 184 in packages/cactus-plugin-ledger-connector-besu/src/test/typescript/benchmark/run-plugin-ledger-connector-besu-benchmark.ts

View workflow job for this annotation

GitHub Actions / build-dev

Property 'apiServer' does not exist on type 'void'.

Check failure on line 184 in packages/cactus-plugin-ledger-connector-besu/src/test/typescript/benchmark/run-plugin-ledger-connector-besu-benchmark.ts

View workflow job for this annotation

GitHub Actions / build-dev

Property 'httpApi' does not exist on type 'void'.

Check failure on line 184 in packages/cactus-plugin-ledger-connector-besu/src/test/typescript/benchmark/run-plugin-ledger-connector-besu-benchmark.ts

View workflow job for this annotation

GitHub Actions / build-dev

Object literal may only specify known properties, and 'logLevel' does not exist in type 'Test'.

const minSamples = 100;
const suite = new Benchmark.Suite({});

const cycles: string[] = [];

await new Promise((resolve, reject) => {
suite
.add("plugin-ledger-connector-besu_HTTP_GET_getOpenApiSpecV1", {
defer: true,
minSamples,
fn: async function (deferred: Benchmark.Deferred) {
await httpApi.getOpenApiSpecV1();
deferred.resolve();
},
})
.on("cycle", (event: { target: unknown }) => {
// Output benchmark result by converting benchmark result to string
// Example line on stdout:
// plugin-ledger-connector-besu_HTTP_GET_getOpenApiSpecV1 x 1,020 ops/sec ±2.25% (177 runs sampled)
const cycle = String(event.target);
console.log("%s Benchmark.js CYCLE: %s", LOG_TAG, cycle);
cycles.push(cycle);
})
.on("complete", function () {
console.log("%s Benchmark.js COMPLETE.", LOG_TAG);
resolve(suite);
})
.on("error", (ex: unknown) => {
console.log("%s Benchmark.js ERROR: %o", LOG_TAG, ex);
reject(ex);
})
.run();
});

const data = cycles.join(EOL);
console.log("%s Writing results...", LOG_TAG);
await fse.writeFile(absoluteOutputFilePath, data, { encoding: "utf-8" });
console.log("%s Wrote results to %s", LOG_TAG, absoluteOutputFilePath);

await apiServer.shutdown();
console.log("%s Shut down API server OK", LOG_TAG);
};

main({ argv: process.argv }).catch((ex: unknown) => {
console.error("%s process crashed with:", LOG_TAG, ex);
process.exit(1);
});

0 comments on commit 36fd8d9

Please sign in to comment.