From c524755acdeb1f31b6abd37b1ace71d345bed346 Mon Sep 17 00:00:00 2001 From: chad Date: Mon, 19 Jun 2023 17:26:10 -0500 Subject: [PATCH 01/27] feat: implement perf protocol co-authored-by: Marco Munizaga --- .github/workflows/perf-test.yml | 37 +++++++ packages/perf/.gitignore | 5 + packages/perf/LICENSE | 4 + packages/perf/LICENSE-APACHE | 5 + packages/perf/LICENSE-MIT | 19 ++++ packages/perf/package.json | 48 +++++++++ packages/perf/src/constants.ts | 6 ++ packages/perf/src/index.ts | 165 ++++++++++++++++++++++++++++++ packages/perf/src/printResults.ts | 41 ++++++++ packages/perf/test/index.spec.ts | 123 ++++++++++++++++++++++ packages/perf/tsconfig.json | 10 ++ 11 files changed, 463 insertions(+) create mode 100644 .github/workflows/perf-test.yml create mode 100644 packages/perf/.gitignore create mode 100644 packages/perf/LICENSE create mode 100644 packages/perf/LICENSE-APACHE create mode 100644 packages/perf/LICENSE-MIT create mode 100644 packages/perf/package.json create mode 100644 packages/perf/src/constants.ts create mode 100644 packages/perf/src/index.ts create mode 100644 packages/perf/src/printResults.ts create mode 100644 packages/perf/test/index.spec.ts create mode 100644 packages/perf/tsconfig.json diff --git a/.github/workflows/perf-test.yml b/.github/workflows/perf-test.yml new file mode 100644 index 0000000000..e46c99c283 --- /dev/null +++ b/.github/workflows/perf-test.yml @@ -0,0 +1,37 @@ +name: Generate Performance Report + +on: + push: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install dependencies + working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }} + run: npm ci + + - name: Generate Report + run: npm run test + + - name: Exit with Error + working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }} + run: | + if grep -q "color:red" ./Perfreport.md; then + exit 1 + else + exit 0 + fi + shell: bash + + - uses: actions/upload-artifact@v3 + with: + name: perf-output + path: | + ${{ steps.find-workdir.outputs.WORK_DIR }}/Perfreport.md diff --git a/packages/perf/.gitignore b/packages/perf/.gitignore new file mode 100644 index 0000000000..29d65d0df2 --- /dev/null +++ b/packages/perf/.gitignore @@ -0,0 +1,5 @@ +perfReport.md + +node_modules/ + +dist/ \ No newline at end of file diff --git a/packages/perf/LICENSE b/packages/perf/LICENSE new file mode 100644 index 0000000000..20ce483c86 --- /dev/null +++ b/packages/perf/LICENSE @@ -0,0 +1,4 @@ +This project is dual licensed under MIT and Apache-2.0. + +MIT: https://www.opensource.org/licenses/mit +Apache-2.0: https://www.apache.org/licenses/license-2.0 diff --git a/packages/perf/LICENSE-APACHE b/packages/perf/LICENSE-APACHE new file mode 100644 index 0000000000..14478a3b60 --- /dev/null +++ b/packages/perf/LICENSE-APACHE @@ -0,0 +1,5 @@ +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. diff --git a/packages/perf/LICENSE-MIT b/packages/perf/LICENSE-MIT new file mode 100644 index 0000000000..72dc60d84b --- /dev/null +++ b/packages/perf/LICENSE-MIT @@ -0,0 +1,19 @@ +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/packages/perf/package.json b/packages/perf/package.json new file mode 100644 index 0000000000..b0807c3113 --- /dev/null +++ b/packages/perf/package.json @@ -0,0 +1,48 @@ +{ + "name": "perf-protocol", + "version": "1.0.0", + "description": "Performance Tests", + "type": "module", + "author": "@maschad / @marcopolo", + "license": "MIT", + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "eslintConfig": { + "extends": "ipfs", + "parserOptions": { + "sourceType": "module" + } + }, + "scripts": { + "build": "aegir build", + "test": "aegir test", + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check -i protons" + }, + "dependencies": { + "@libp2p/interface-connection-gater": "3.0.1", + "@libp2p/interface-connection-manager": "3.0.1", + "@libp2p/interface-mocks": "12.0.1", + "@libp2p/interface-peer-id": "2.0.2", + "@libp2p/interface-registrar": "^2.0.12", + "@libp2p/interface-transport": "4.0.3", + "@libp2p/interfaces": "3.3.2", + "@libp2p/logger": "^2.1.1", + "@libp2p/peer-id-factory": "2.0.4", + "@libp2p/peer-store": "8.2.1", + "any-signal": "^4.1.1", + "datastore-core": "9.2.0" + }, + "devDependencies": { + "aegir": "^39.0.10", + "sinon-ts": "1.0.0" + }, + "typedoc": { + "entryPoint": "./src/index.ts" + } +} diff --git a/packages/perf/src/constants.ts b/packages/perf/src/constants.ts new file mode 100644 index 0000000000..c62f4dd8a8 --- /dev/null +++ b/packages/perf/src/constants.ts @@ -0,0 +1,6 @@ +export const MAX_INBOUND_STREAMS = 1 << 10 +export const MAX_OUTBOUND_STREAMS = 1 << 10 +export const PROTOCOL_NAME = '/perf/1.0.0' + +export const TIMEOUT = 10000 +export const WRITE_BLOCK_SIZE = BigInt(64 << 10) diff --git a/packages/perf/src/index.ts b/packages/perf/src/index.ts new file mode 100644 index 0000000000..79e8065d30 --- /dev/null +++ b/packages/perf/src/index.ts @@ -0,0 +1,165 @@ +import { logger } from '@libp2p/logger' +import { anySignal } from 'any-signal' +import { MAX_INBOUND_STREAMS, PROTOCOL_NAME, TIMEOUT, WRITE_BLOCK_SIZE } from './constants.js' +import type { ConnectionManager } from '@libp2p/interface-connection-manager' +import type { PeerId } from '@libp2p/interface-peer-id' +import type { IncomingStreamData, Registrar } from '@libp2p/interface-registrar' +import type { AbortOptions, Startable } from '@libp2p/interfaces' + +const log = logger('libp2p:perf') + +export interface PerfService { + perf: (peer: PeerId, sendBytes: bigint, recvBytes: bigint, options?: AbortOptions) => Promise + measureDownloadBandwidth: (peer: PeerId, size: bigint) => Promise + measureUploadBandwidth: (peer: PeerId, size: bigint) => Promise +} + +export interface PerfServiceInit { + protocolName?: string + maxInboundStreams?: number + maxOutboundStreams?: number + timeout?: number + writeBlockSize?: bigint +} + +export interface PerfServiceComponents { + registrar: Registrar + connectionManager: ConnectionManager +} + +export class DefaultPerfService implements Startable, PerfService { + public readonly protocol: string + private readonly components: PerfServiceComponents + private started: boolean + private readonly databuf: ArrayBuffer + private readonly maxInboundStreams: number + private readonly maxOutboundStreams: number + private readonly timeout: number + private readonly writeBlockSize: bigint + + constructor (components: PerfServiceComponents, init: PerfServiceInit) { + this.components = components + this.started = false + this.protocol = init.protocolName ?? PROTOCOL_NAME + this.databuf = new ArrayBuffer(Number(init.writeBlockSize ?? WRITE_BLOCK_SIZE)) + this.maxInboundStreams = init.maxInboundStreams ?? MAX_INBOUND_STREAMS + this.maxOutboundStreams = init.maxOutboundStreams ?? MAX_INBOUND_STREAMS + this.timeout = init.timeout ?? TIMEOUT + this.writeBlockSize = init.writeBlockSize ?? WRITE_BLOCK_SIZE + } + + async start (): Promise { + await this.components.registrar.handle(this.protocol, (data: IncomingStreamData) => { void this.handleMessage(data) }, { + maxInboundStreams: this.maxInboundStreams, + maxOutboundStreams: this.maxOutboundStreams + }) + this.started = true + } + + async stop (): Promise { + await this.components.registrar.unhandle(this.protocol) + this.started = false + } + + isStarted (): boolean { + return this.started + } + + async handleMessage (data: IncomingStreamData): Promise { + const { stream } = data + + const writeBlockSize = this.writeBlockSize + + let bytesToSendBack: bigint | null = null + + for await (const buf of stream.source) { + if (bytesToSendBack === null) { + bytesToSendBack = BigInt(buf.getBigUint64(0, false)) + } + // Ingest all the bufs and wait for the read side to close + } + + const uint8Buf = new Uint8Array(this.databuf) + + if (bytesToSendBack === null) { + throw new Error('bytesToSendBack was null') + } + + await stream.sink(async function * () { + while (bytesToSendBack > 0n) { + let toSend: bigint = writeBlockSize + if (toSend > bytesToSendBack) { + toSend = bytesToSendBack + } + bytesToSendBack = bytesToSendBack - toSend + yield uint8Buf.subarray(0, Number(toSend)) + } + }()) + } + + async perf (peer: PeerId, sendBytes: bigint, recvBytes: bigint, options: AbortOptions = {}): Promise { + log('opening stream on protocol %s to %p', this.protocol, peer) + + const uint8Buf = new Uint8Array(this.databuf) + + const writeBlockSize = this.writeBlockSize + + const connection = await this.components.connectionManager.openConnection(peer, options) + + const signal = anySignal([AbortSignal.timeout(this.timeout), options?.signal]) + const stream = await connection.newStream([this.protocol], { + signal + }) + + // Convert sendBytes to uint64 big endian buffer + const view = new DataView(this.databuf) + view.setBigInt64(0, recvBytes, false) + + log.trace('sending %i bytes to %p', sendBytes, peer) + + await stream.sink((async function * () { + // Send the number of bytes to receive + yield uint8Buf.subarray(0, 8) + // Send the number of bytes to send + while (sendBytes > 0n) { + let toSend: bigint = writeBlockSize + if (toSend > sendBytes) { + toSend = sendBytes + } + sendBytes = sendBytes - toSend + yield uint8Buf.subarray(0, Number(toSend)) + } + })()) + + // Read the received bytes + let actualRecvdBytes = BigInt(0) + for await (const buf of stream.source) { + actualRecvdBytes += BigInt(buf.length) + } + + if (actualRecvdBytes !== recvBytes) { + throw new Error(`Expected to receive ${recvBytes} bytes, but received ${actualRecvdBytes}`) + } + + log('performed %s to %p', this.protocol, peer) + stream.close() + } + + // measureDownloadBandwidth returns the measured bandwidth in bits per second + async measureDownloadBandwidth (peer: PeerId, size: bigint): Promise { + const now = Date.now() + await this.perf(peer, 0n, size) + return Number((8000n * size) / BigInt(Date.now() - now)) + } + + // measureUploadBandwidth returns the measured bandwidth in bit per second + async measureUploadBandwidth (peer: PeerId, size: bigint): Promise { + const now = Date.now() + await this.perf(peer, size, 0n) + return Number((8000n * size) / BigInt(Date.now() - now)) + } +} + +export function perfService (init: PerfServiceInit = {}): (components: PerfServiceComponents) => PerfService { + return (components) => new DefaultPerfService(components, init) +} diff --git a/packages/perf/src/printResults.ts b/packages/perf/src/printResults.ts new file mode 100644 index 0000000000..9bb6b29ac7 --- /dev/null +++ b/packages/perf/src/printResults.ts @@ -0,0 +1,41 @@ +export function generatePerformanceOutput(currentDownloadSpeed: number, previousDownloadSpeed: number, currentUploadSpeed: number, previousUploadSpeed: number): string { + + const uploadProgress = (currentUploadSpeed - previousUploadSpeed) / previousUploadSpeed; + const downloadProgress = (currentDownloadSpeed - previousDownloadSpeed) / previousDownloadSpeed; + + let markdownContent = ` + # Bandwidth Test Results + + ## Download Bandwidth + + The download bandwidth measured during the test was: ${currentDownloadSpeed} kiB/s. + + `; + + if (downloadProgress > 0) { + markdownContent += ` The download bandwidth has improved by ${downloadProgress}% since the last test. `; + } else if (uploadProgress < 0) { + markdownContent += ` The download bandwidth has decreased by ${downloadProgress}% since the last test. `; + } else { + markdownContent += `The download bandwidth has not changed since the last test.`; + } + + ` + ## Upload Bandwidth + + The upload bandwidth measured during the test was: ${currentUploadSpeed} kiB/s. + `; + + if (uploadProgress > 0) { + markdownContent += `The upload bandwidth has improved by ${uploadProgress}% since the last test. `; + } else if (uploadProgress < 0) { + markdownContent += `The upload bandwidth has decreased by ${uploadProgress}% since the last test.`; + } else { + markdownContent += ` The upload bandwidth has not changed since the last test. `; + } + + + return markdownContent; + +} + diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts new file mode 100644 index 0000000000..afbb720466 --- /dev/null +++ b/packages/perf/test/index.spec.ts @@ -0,0 +1,123 @@ +/* eslint-env mocha */ + +import * as fs from 'fs' + +import { connectionPair, mockRegistrar, mockUpgrader } from '@libp2p/interface-mocks' +import { EventEmitter } from '@libp2p/interfaces/events' +import { start, stop } from '@libp2p/interfaces/startable' +import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { PersistentPeerStore } from '@libp2p/peer-store' +import { expect } from 'aegir/chai' +import { MemoryDatastore } from 'datastore-core' +import { stubInterface } from 'sinon-ts' +import { defaultComponents, type Components } from '../../libp2p/dist/src/components.js' +import { DefaultConnectionManager } from '../../libp2p/dist/src/connection-manager' +import { perfService, type PerfServiceInit } from '../src/index.js' +import type { ConnectionGater } from '@libp2p/interface-connection-gater' +import type { TransportManager } from '@libp2p/interface-transport' +import { generatePerformanceOutput } from '../src/printResults.js' + +const defaultInit: PerfServiceInit = { + protocolName: '/perf/1.0.0', + maxInboundStreams: 1 << 10, + maxOutboundStreams: 1 << 10, + timeout: 1000, + writeBlockSize: BigInt(64 << 10) +} + +async function createComponents (index: number): Promise { + const peerId = await createEd25519PeerId() + + const events = new EventEmitter() + + const components = defaultComponents({ + peerId, + registrar: mockRegistrar(), + upgrader: mockUpgrader(), + datastore: new MemoryDatastore(), + transportManager: stubInterface(), + connectionGater: stubInterface(), + events + }) + + components.peerStore = new PersistentPeerStore(components) + components.connectionManager = new DefaultConnectionManager(components, { + minConnections: 50, + maxConnections: 1000, + autoDialInterval: 1000, + inboundUpgradeTimeout: 1000 + }) + + return components +} + +describe('perf', () => { + let localComponents: Components + let remoteComponents: Components + + beforeEach(async () => { + localComponents = await createComponents(0) + remoteComponents = await createComponents(1) + + await Promise.all([ + start(localComponents), + start(remoteComponents) + ]) + }) + + afterEach(async () => { + await Promise.all([ + stop(localComponents), + stop(remoteComponents) + ]) + }) + + it('should run perf', async () => { + const client = perfService(defaultInit)(localComponents) + const server = perfService(defaultInit)(remoteComponents) + + await start(client) + await start(server) + + // simulate connection between nodes + const [localToRemote, remoteToLocal] = connectionPair(localComponents, remoteComponents) + localComponents.events.safeDispatchEvent('connection:open', { detail: localToRemote }) + remoteComponents.events.safeDispatchEvent('connection:open', { detail: remoteToLocal }) + + // Run Perf + await expect(client.perf(remoteComponents.peerId, 1n << 10n, 1n << 10n)).to.eventually.be.fulfilled() + }) + + it('should output benchmark', async () => { + const client = perfService(defaultInit)(localComponents) + const server = perfService(defaultInit)(remoteComponents) + + await start(client) + await start(server) + + // simulate connection between nodes + const [localToRemote, remoteToLocal] = connectionPair(localComponents, remoteComponents) + localComponents.events.safeDispatchEvent('connection:open', { detail: localToRemote }) + remoteComponents.events.safeDispatchEvent('connection:open', { detail: remoteToLocal }) + + // Run Perf + const downloadBandwidth = await client.measureDownloadBandwidth(remoteComponents.peerId, 10n << 20n) >> 10 + // eslint-disable-next-line no-console + console.log('Download bandwidth: ', downloadBandwidth , ' kiB/s') + + const uploadBandwidth = await client.measureDownloadBandwidth(remoteComponents.peerId, 10n << 20n) >> 10 + // eslint-disable-next-line no-console + console.log('Upload bandwidth: ', uploadBandwidth, ' kiB/s') + + const { previousDownloadBandwidth, previousUploadBandwidth } = JSON.parse(fs.readFileSync('../perf.txt', 'utf8')) + + const markdownContent = generatePerformanceOutput(downloadBandwidth, previousDownloadBandwidth, uploadBandwidth, previousUploadBandwidth) + + fs.writeFileSync('../perf.txt', JSON.stringify({ + previousDownloadBandwidth: downloadBandwidth , + previousUploadBandwidth: uploadBandwidth + })) + + fs.writeFileSync('../perfReport.md', markdownContent) + }) +}) diff --git a/packages/perf/tsconfig.json b/packages/perf/tsconfig.json new file mode 100644 index 0000000000..13a3599639 --- /dev/null +++ b/packages/perf/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src", + "test" + ] +} From 0898dd0887cfc2216bc2c8b3610789b128d2af81 Mon Sep 17 00:00:00 2001 From: chad Date: Tue, 20 Jun 2023 22:13:19 -0500 Subject: [PATCH 02/27] test: only runs test in node environment --- .github/workflows/perf-test.yml | 12 +----- packages/libp2p/README.md | 72 +++++++++++++++---------------- packages/libp2p/package.json | 8 ++++ packages/perf/README.md | 24 +++++++++++ packages/perf/package.json | 31 +++++++++---- packages/perf/previousPerf.txt | 1 + packages/perf/src/index.ts | 9 ++-- packages/perf/src/printResults.ts | 18 ++++---- packages/perf/test/index.spec.ts | 47 +++++++++++++------- packages/perf/tsconfig.json | 5 +++ 10 files changed, 142 insertions(+), 85 deletions(-) create mode 100644 packages/perf/README.md create mode 100644 packages/perf/previousPerf.txt diff --git a/.github/workflows/perf-test.yml b/.github/workflows/perf-test.yml index e46c99c283..21ea355b1f 100644 --- a/.github/workflows/perf-test.yml +++ b/.github/workflows/perf-test.yml @@ -20,18 +20,8 @@ jobs: - name: Generate Report run: npm run test - - name: Exit with Error - working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }} - run: | - if grep -q "color:red" ./Perfreport.md; then - exit 1 - else - exit 0 - fi - shell: bash - - uses: actions/upload-artifact@v3 with: name: perf-output path: | - ${{ steps.find-workdir.outputs.WORK_DIR }}/Perfreport.md + ${{ steps.find-workdir.outputs.WORK_DIR }}/perfReport.md diff --git a/packages/libp2p/README.md b/packages/libp2p/README.md index 554db067e3..817342f1dd 100644 --- a/packages/libp2p/README.md +++ b/packages/libp2p/README.md @@ -142,43 +142,43 @@ List of packages currently in existence for libp2p > This table is generated using the module `package-table` with `package-table --data=package-list.json`. -| Package | Version | Deps | CI | Coverage | -| ---------|---------|---------|---------|--------- | -| **libp2p** | -| [`libp2p`](//github.com/libp2p/js-libp2p) | [![npm](https://img.shields.io/npm/v/libp2p.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/libp2p?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/libp2p) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) | -| [`@libp2p/interface`](//github.com/libp2p/js-libp2p-interfaces) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Finterface-libp2p.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-interfaces/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Finterface-libp2p?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Finterface-libp2p) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-interfaces/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-interfaces/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-interfaces/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-interfaces) | -| **transports** | -| [`@libp2p/tcp`](//github.com/libp2p/js-libp2p-tcp) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Ftcp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-tcp/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Ftcp?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Ftcp) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-tcp/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-tcp/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-tcp/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-tcp) | -| [`@libp2p/webrtc`](//github.com/libp2p/js-libp2p-webrtc) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fwebrtc.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fwebrtc?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fwebrtc) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-webrtc/js-test-and-release.yml?branch=main&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc) | -| [`@libp2p/websockets`](//github.com/libp2p/js-libp2p-websockets) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fwebsockets.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fwebsockets?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fwebsockets) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-websockets/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-websockets/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-websockets) | -| [`@libp2p/webtransport`](//github.com/libp2p/js-libp2p-webtransport) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fwebtransport.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webtransport/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fwebtransport?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fwebtransport) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-webtransport/js-test-and-release.yml?branch=main&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-webtransport/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webtransport/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webtransport) | -| **secure channels** | -| [`@chainsafe/libp2p-noise`](//github.com/ChainSafe/js-libp2p-noise) | [![npm](https://img.shields.io/npm/v/%40chainsafe%2Flibp2p-noise.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/js-libp2p-noise/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40chainsafe%2Flibp2p-noise?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40chainsafe%2Flibp2p-noise) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/ChainSafe/js-libp2p-noise/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/ChainSafe/js-libp2p-noise/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/ChainSafe/js-libp2p-noise/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/js-libp2p-noise) | -| **stream multiplexers** | -| [`@libp2p/mplex`](//github.com/libp2p/js-libp2p-mplex) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fmplex.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-mplex/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fmplex?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fmplex) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-mplex/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-mplex/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-mplex/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-mplex) | -| [`@chainsafe/libp2p-yamux`](//github.com/ChainSafe/js-libp2p-yamux) | [![npm](https://img.shields.io/npm/v/%40chainsafe%2Flibp2p-yamux.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/js-libp2p-yamux/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40chainsafe%2Flibp2p-yamux?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40chainsafe%2Flibp2p-yamux) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/ChainSafe/js-libp2p-yamux/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/ChainSafe/js-libp2p-yamux/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/ChainSafe/js-libp2p-yamux/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/js-libp2p-yamux) | -| **peer discovery** | -| [`@libp2p/bootstrap`](//github.com/libp2p/js-libp2p-bootstrap) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fbootstrap.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-bootstrap/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fbootstrap?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fbootstrap) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-bootstrap/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-bootstrap/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-bootstrap/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-bootstrap) | -| [`@libp2p/kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fkad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fkad-dht?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fkad-dht) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-kad-dht/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | -| [`@libp2p/mdns`](//github.com/libp2p/js-libp2p-mdns) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fmdns.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-mdns/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fmdns?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fmdns) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-mdns/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-mdns/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-mdns/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-mdns) | -| [`@chainsafe/discv5`](//github.com/ChainSafe/discv5) | [![npm](https://img.shields.io/npm/v/%40chainsafe%2Fdiscv5.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/discv5/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40chainsafe%2Fdiscv5?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40chainsafe%2Fdiscv5) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/ChainSafe/discv5/test_and_release.yml?branch=master&label=ci&style=flat-square)](//github.com/ChainSafe/discv5/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/ChainSafe/discv5/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/discv5) | -| **content routing** | -| [`@libp2p/reframe-content-routing`](//github.com/libp2p/js-reframe-content-routing) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Freframe-content-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-reframe-content-routing/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Freframe-content-routing?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Freframe-content-routing) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-reframe-content-routing/js-test-and-release.yml?branch=main&label=ci&style=flat-square)](//github.com/libp2p/js-reframe-content-routing/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-reframe-content-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-reframe-content-routing) | -| [`@libp2p/ipni-content-routing`](//github.com/libp2p/js-ipni-content-routing) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fipni-content-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-ipni-content-routing/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fipni-content-routing?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fipni-content-routing) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-ipni-content-routing/js-test-and-release.yml?branch=main&label=ci&style=flat-square)](//github.com/libp2p/js-ipni-content-routing/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-ipni-content-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-ipni-content-routing) | +| Package | Version | Deps | CI | Coverage | +| ---------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **libp2p** | +| [`libp2p`](//github.com/libp2p/js-libp2p) | [![npm](https://img.shields.io/npm/v/libp2p.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/libp2p?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/libp2p) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) | +| [`@libp2p/interface`](//github.com/libp2p/js-libp2p-interfaces) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Finterface-libp2p.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-interfaces/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Finterface-libp2p?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Finterface-libp2p) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-interfaces/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-interfaces/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-interfaces/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-interfaces) | +| **transports** | +| [`@libp2p/tcp`](//github.com/libp2p/js-libp2p-tcp) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Ftcp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-tcp/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Ftcp?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Ftcp) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-tcp/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-tcp/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-tcp/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-tcp) | +| [`@libp2p/webrtc`](//github.com/libp2p/js-libp2p-webrtc) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fwebrtc.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fwebrtc?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fwebrtc) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-webrtc/js-test-and-release.yml?branch=main&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc) | +| [`@libp2p/websockets`](//github.com/libp2p/js-libp2p-websockets) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fwebsockets.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fwebsockets?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fwebsockets) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-websockets/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-websockets/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-websockets) | +| [`@libp2p/webtransport`](//github.com/libp2p/js-libp2p-webtransport) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fwebtransport.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webtransport/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fwebtransport?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fwebtransport) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-webtransport/js-test-and-release.yml?branch=main&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-webtransport/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webtransport/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webtransport) | +| **secure channels** | +| [`@chainsafe/libp2p-noise`](//github.com/ChainSafe/js-libp2p-noise) | [![npm](https://img.shields.io/npm/v/%40chainsafe%2Flibp2p-noise.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/js-libp2p-noise/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40chainsafe%2Flibp2p-noise?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40chainsafe%2Flibp2p-noise) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/ChainSafe/js-libp2p-noise/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/ChainSafe/js-libp2p-noise/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/ChainSafe/js-libp2p-noise/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/js-libp2p-noise) | +| **stream multiplexers** | +| [`@libp2p/mplex`](//github.com/libp2p/js-libp2p-mplex) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fmplex.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-mplex/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fmplex?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fmplex) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-mplex/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-mplex/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-mplex/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-mplex) | +| [`@chainsafe/libp2p-yamux`](//github.com/ChainSafe/js-libp2p-yamux) | [![npm](https://img.shields.io/npm/v/%40chainsafe%2Flibp2p-yamux.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/js-libp2p-yamux/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40chainsafe%2Flibp2p-yamux?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40chainsafe%2Flibp2p-yamux) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/ChainSafe/js-libp2p-yamux/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/ChainSafe/js-libp2p-yamux/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/ChainSafe/js-libp2p-yamux/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/js-libp2p-yamux) | +| **peer discovery** | +| [`@libp2p/bootstrap`](//github.com/libp2p/js-libp2p-bootstrap) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fbootstrap.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-bootstrap/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fbootstrap?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fbootstrap) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-bootstrap/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-bootstrap/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-bootstrap/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-bootstrap) | +| [`@libp2p/kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fkad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fkad-dht?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fkad-dht) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-kad-dht/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | +| [`@libp2p/mdns`](//github.com/libp2p/js-libp2p-mdns) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fmdns.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-mdns/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fmdns?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fmdns) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-mdns/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-mdns/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-mdns/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-mdns) | +| [`@chainsafe/discv5`](//github.com/ChainSafe/discv5) | [![npm](https://img.shields.io/npm/v/%40chainsafe%2Fdiscv5.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/discv5/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40chainsafe%2Fdiscv5?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40chainsafe%2Fdiscv5) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/ChainSafe/discv5/test_and_release.yml?branch=master&label=ci&style=flat-square)](//github.com/ChainSafe/discv5/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/ChainSafe/discv5/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/discv5) | +| **content routing** | +| [`@libp2p/reframe-content-routing`](//github.com/libp2p/js-reframe-content-routing) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Freframe-content-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-reframe-content-routing/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Freframe-content-routing?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Freframe-content-routing) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-reframe-content-routing/js-test-and-release.yml?branch=main&label=ci&style=flat-square)](//github.com/libp2p/js-reframe-content-routing/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-reframe-content-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-reframe-content-routing) | +| [`@libp2p/ipni-content-routing`](//github.com/libp2p/js-ipni-content-routing) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fipni-content-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-ipni-content-routing/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fipni-content-routing?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fipni-content-routing) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-ipni-content-routing/js-test-and-release.yml?branch=main&label=ci&style=flat-square)](//github.com/libp2p/js-ipni-content-routing/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-ipni-content-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-ipni-content-routing) | | [`@libp2p/delegated-content-routing`](//github.com/libp2p/js-libp2p-delegated-content-routing) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fdelegated-content-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-content-routing/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fdelegated-content-routing?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fdelegated-content-routing) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-delegated-content-routing/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-content-routing/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-delegated-content-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-delegated-content-routing) | -| [`@libp2p/kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fkad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fkad-dht?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fkad-dht) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-kad-dht/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | -| **peer routing** | -| [`@libp2p/delegated-peer-routing`](//github.com/libp2p/js-libp2p-delegated-peer-routing) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fdelegated-peer-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-peer-routing/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fdelegated-peer-routing?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fdelegated-peer-routing) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-delegated-peer-routing/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-peer-routing/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing) | -| [`@libp2p/kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fkad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fkad-dht?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fkad-dht) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-kad-dht/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | -| **utilities** | -| [`@libp2p/crypto`](//github.com/libp2p/js-libp2p-crypto) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fcrypto.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-crypto/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fcrypto?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fcrypto) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-crypto/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-crypto/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-crypto/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-crypto) | -| **data types** | -| [`@libp2p/peer-id`](//github.com/libp2p/js-libp2p-peer-id) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fpeer-id.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-peer-id/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fpeer-id?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fpeer-id) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-peer-id/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-peer-id/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-peer-id/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-peer-id) | -| [`@libp2p/record`](//github.com/libp2p/js-libp2p-record) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Frecord.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-record/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Frecord?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Frecord) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-record/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-record/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-record/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-record) | -| [`@libp2p/peer-record`](//github.com/libp2p/js-libp2p-peer-record) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fpeer-record.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-peer-record/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fpeer-record?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fpeer-record) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-peer-record/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-peer-record/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-peer-record/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-peer-record) | -| **pubsub** | -| [`@ChainSafe/libp2p-gossipsub`](//github.com/ChainSafe/js-libp2p-gossipsub) | [![npm](https://img.shields.io/npm/v/%40ChainSafe%2Flibp2p-gossipsub.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/js-libp2p-gossipsub/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40ChainSafe%2Flibp2p-gossipsub?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40ChainSafe%2Flibp2p-gossipsub) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/ChainSafe/js-libp2p-gossipsub/main.yml?branch=master&label=ci&style=flat-square)](//github.com/ChainSafe/js-libp2p-gossipsub/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/ChainSafe/js-libp2p-gossipsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/js-libp2p-gossipsub) | -| [`@libp2p/floodsub`](//github.com/libp2p/js-libp2p-floodsub) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Ffloodsub.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-floodsub/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Ffloodsub?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Ffloodsub) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-floodsub/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-floodsub/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-floodsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-floodsub) | +| [`@libp2p/kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fkad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fkad-dht?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fkad-dht) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-kad-dht/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | +| **peer routing** | +| [`@libp2p/delegated-peer-routing`](//github.com/libp2p/js-libp2p-delegated-peer-routing) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fdelegated-peer-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-peer-routing/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fdelegated-peer-routing?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fdelegated-peer-routing) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-delegated-peer-routing/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-peer-routing/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing) | +| [`@libp2p/kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fkad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fkad-dht?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fkad-dht) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-kad-dht/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | +| **utilities** | +| [`@libp2p/crypto`](//github.com/libp2p/js-libp2p-crypto) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fcrypto.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-crypto/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fcrypto?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fcrypto) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-crypto/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-crypto/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-crypto/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-crypto) | +| **data types** | +| [`@libp2p/peer-id`](//github.com/libp2p/js-libp2p-peer-id) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fpeer-id.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-peer-id/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fpeer-id?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fpeer-id) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-peer-id/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-peer-id/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-peer-id/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-peer-id) | +| [`@libp2p/record`](//github.com/libp2p/js-libp2p-record) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Frecord.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-record/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Frecord?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Frecord) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-record/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-record/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-record/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-record) | +| [`@libp2p/peer-record`](//github.com/libp2p/js-libp2p-peer-record) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fpeer-record.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-peer-record/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fpeer-record?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Fpeer-record) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-peer-record/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-peer-record/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-peer-record/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-peer-record) | +| **pubsub** | +| [`@ChainSafe/libp2p-gossipsub`](//github.com/ChainSafe/js-libp2p-gossipsub) | [![npm](https://img.shields.io/npm/v/%40ChainSafe%2Flibp2p-gossipsub.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/js-libp2p-gossipsub/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40ChainSafe%2Flibp2p-gossipsub?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40ChainSafe%2Flibp2p-gossipsub) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/ChainSafe/js-libp2p-gossipsub/main.yml?branch=master&label=ci&style=flat-square)](//github.com/ChainSafe/js-libp2p-gossipsub/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/ChainSafe/js-libp2p-gossipsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/js-libp2p-gossipsub) | +| [`@libp2p/floodsub`](//github.com/libp2p/js-libp2p-floodsub) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Ffloodsub.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-floodsub/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Ffloodsub?logo=Libraries.io&logoColor=white&style=flat-square)](//libraries.io/npm/%40libp2p%2Ffloodsub) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-floodsub/js-test-and-release.yml?branch=master&label=ci&style=flat-square)](//github.com/libp2p/js-libp2p-floodsub/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-floodsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-floodsub) | ## Used by diff --git a/packages/libp2p/package.json b/packages/libp2p/package.json index 2ceeebe910..bab3361cb9 100644 --- a/packages/libp2p/package.json +++ b/packages/libp2p/package.json @@ -56,6 +56,14 @@ "types": "./dist/src/circuit-relay/index.d.ts", "import": "./dist/src/circuit-relay/index.js" }, + "./components": { + "types": "./dist/src/components.d.ts", + "import": "./dist/src/components.js" + }, + "./connection-manager": { + "types": "./dist/src/connection-manager/index.d.ts", + "import": "./dist/src/connection-manager/index.js" + }, "./fetch": { "types": "./dist/src/fetch/index.d.ts", "import": "./dist/src/fetch/index.js" diff --git a/packages/perf/README.md b/packages/perf/README.md new file mode 100644 index 0000000000..f017c3df69 --- /dev/null +++ b/packages/perf/README.md @@ -0,0 +1,24 @@ +# @libp2p/perf + +[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) +[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io) +[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=master\&style=flat-square)](https://github.com/libp2p/js-libp2p/actions/workflows/main.yml?query=branch%3Amaster) + +> Implementation of the [Perf Protocol](https://github.com/libp2p/specs/blob/master/perf/perf.md) + +## API Docs + +- + + +## License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](LICENSE-MIT) / ) + +## Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/packages/perf/package.json b/packages/perf/package.json index b0807c3113..8678dd4183 100644 --- a/packages/perf/package.json +++ b/packages/perf/package.json @@ -1,10 +1,18 @@ { - "name": "perf-protocol", + "name": "@libp2p/perf", "version": "1.0.0", - "description": "Performance Tests", + "description": "Implementation of Perf Protocol", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p/tree/master/packages/perf#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p/issues" + }, "type": "module", "author": "@maschad / @marcopolo", - "license": "MIT", "files": [ "src", "dist", @@ -19,24 +27,29 @@ }, "scripts": { "build": "aegir build", - "test": "aegir test", + "test": "aegir test -t node --cov", "clean": "aegir clean", "lint": "aegir lint", + "test:chrome": "aegir test -t browser --cov", + "test:chrome-webworker": "aegir test -t webworker", + "test:firefox": "aegir test -t browser -- --browser firefox", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "test:node": "aegir test -t node --cov", "dep-check": "aegir dep-check -i protons" }, "dependencies": { + "@libp2p/interface": "^0.0.1", + "@libp2p/interface-compliance-tests": "^3.0.7", "@libp2p/interface-connection-gater": "3.0.1", - "@libp2p/interface-connection-manager": "3.0.1", - "@libp2p/interface-mocks": "12.0.1", + "@libp2p/interface-internal": "^0.0.1", "@libp2p/interface-peer-id": "2.0.2", - "@libp2p/interface-registrar": "^2.0.12", - "@libp2p/interface-transport": "4.0.3", "@libp2p/interfaces": "3.3.2", "@libp2p/logger": "^2.1.1", "@libp2p/peer-id-factory": "2.0.4", "@libp2p/peer-store": "8.2.1", "any-signal": "^4.1.1", - "datastore-core": "9.2.0" + "datastore-core": "9.2.0", + "libp2p": "^0.45.9" }, "devDependencies": { "aegir": "^39.0.10", diff --git a/packages/perf/previousPerf.txt b/packages/perf/previousPerf.txt new file mode 100644 index 0000000000..e9c0bb3e93 --- /dev/null +++ b/packages/perf/previousPerf.txt @@ -0,0 +1 @@ +{"previousDownloadBandwidth":113619,"previousUploadBandwidth":111002} \ No newline at end of file diff --git a/packages/perf/src/index.ts b/packages/perf/src/index.ts index 79e8065d30..f2de852f51 100644 --- a/packages/perf/src/index.ts +++ b/packages/perf/src/index.ts @@ -1,10 +1,11 @@ import { logger } from '@libp2p/logger' import { anySignal } from 'any-signal' import { MAX_INBOUND_STREAMS, PROTOCOL_NAME, TIMEOUT, WRITE_BLOCK_SIZE } from './constants.js' -import type { ConnectionManager } from '@libp2p/interface-connection-manager' +import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager' import type { PeerId } from '@libp2p/interface-peer-id' -import type { IncomingStreamData, Registrar } from '@libp2p/interface-registrar' -import type { AbortOptions, Startable } from '@libp2p/interfaces' +import type { IncomingStreamData, Registrar } from '@libp2p/interface-internal/registrar' +import type {Startable } from '@libp2p/interface/startable' +import type { AbortOptions } from '@libp2p/interfaces' const log = logger('libp2p:perf') @@ -115,7 +116,7 @@ export class DefaultPerfService implements Startable, PerfService { const view = new DataView(this.databuf) view.setBigInt64(0, recvBytes, false) - log.trace('sending %i bytes to %p', sendBytes, peer) + log('sending %i bytes to %p', sendBytes, peer) await stream.sink((async function * () { // Send the number of bytes to receive diff --git a/packages/perf/src/printResults.ts b/packages/perf/src/printResults.ts index 9bb6b29ac7..785b008811 100644 --- a/packages/perf/src/printResults.ts +++ b/packages/perf/src/printResults.ts @@ -13,29 +13,29 @@ export function generatePerformanceOutput(currentDownloadSpeed: number, previous `; if (downloadProgress > 0) { - markdownContent += ` The download bandwidth has improved by ${downloadProgress}% since the last test. `; - } else if (uploadProgress < 0) { - markdownContent += ` The download bandwidth has decreased by ${downloadProgress}% since the last test. `; + markdownContent += `:white_check_mark: The download bandwidth has improved by ${downloadProgress}% since the last test. :white_check_mark:`; + } else if (downloadProgress < 0) { + markdownContent += `:x: The download bandwidth has decreased by ${downloadProgress}% since the last test. :x:`; } else { markdownContent += `The download bandwidth has not changed since the last test.`; } - ` + markdownContent += ` + ## Upload Bandwidth The upload bandwidth measured during the test was: ${currentUploadSpeed} kiB/s. `; if (uploadProgress > 0) { - markdownContent += `The upload bandwidth has improved by ${uploadProgress}% since the last test. `; + markdownContent += `:white_check_mark: The upload bandwidth has improved by ${uploadProgress}% since the last test. :white_check_mark:`; } else if (uploadProgress < 0) { - markdownContent += `The upload bandwidth has decreased by ${uploadProgress}% since the last test.`; + markdownContent += `:x: The upload bandwidth has decreased by ${uploadProgress}% since the last test. :x:`; } else { - markdownContent += ` The upload bandwidth has not changed since the last test. `; + markdownContent += `The upload bandwidth has not changed since the last test.`; } - - return markdownContent; + return markdownContent.replace(/\t/g, ''); } diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index afbb720466..9b5b7fe2b2 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -1,31 +1,34 @@ /* eslint-env mocha */ import * as fs from 'fs' +import * as path from 'path' +import { fileURLToPath } from 'url' -import { connectionPair, mockRegistrar, mockUpgrader } from '@libp2p/interface-mocks' -import { EventEmitter } from '@libp2p/interfaces/events' -import { start, stop } from '@libp2p/interfaces/startable' +import { connectionPair, mockConnectionGater, mockRegistrar, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' +import { EventEmitter } from '@libp2p/interface/events' +import { start, stop } from '@libp2p/interface/startable' import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { PersistentPeerStore } from '@libp2p/peer-store' -import { expect } from 'aegir/chai' +import { assert, expect } from 'aegir/chai' import { MemoryDatastore } from 'datastore-core' import { stubInterface } from 'sinon-ts' -import { defaultComponents, type Components } from '../../libp2p/dist/src/components.js' -import { DefaultConnectionManager } from '../../libp2p/dist/src/connection-manager' + import { perfService, type PerfServiceInit } from '../src/index.js' -import type { ConnectionGater } from '@libp2p/interface-connection-gater' -import type { TransportManager } from '@libp2p/interface-transport' +import type { TransportManager } from '@libp2p/interface-internal/transport-manager' import { generatePerformanceOutput } from '../src/printResults.js' +import { defaultComponents, type Components } from 'libp2p/components' +import { DefaultConnectionManager } from 'libp2p/connection-manager' + const defaultInit: PerfServiceInit = { protocolName: '/perf/1.0.0', maxInboundStreams: 1 << 10, maxOutboundStreams: 1 << 10, - timeout: 1000, + timeout: 10000, writeBlockSize: BigInt(64 << 10) } -async function createComponents (index: number): Promise { +async function createComponents (): Promise { const peerId = await createEd25519PeerId() const events = new EventEmitter() @@ -36,7 +39,7 @@ async function createComponents (index: number): Promise { upgrader: mockUpgrader(), datastore: new MemoryDatastore(), transportManager: stubInterface(), - connectionGater: stubInterface(), + connectionGater: mockConnectionGater(), events }) @@ -56,8 +59,8 @@ describe('perf', () => { let remoteComponents: Components beforeEach(async () => { - localComponents = await createComponents(0) - remoteComponents = await createComponents(1) + localComponents = await createComponents() + remoteComponents = await createComponents() await Promise.all([ start(localComponents), @@ -109,15 +112,27 @@ describe('perf', () => { // eslint-disable-next-line no-console console.log('Upload bandwidth: ', uploadBandwidth, ' kiB/s') - const { previousDownloadBandwidth, previousUploadBandwidth } = JSON.parse(fs.readFileSync('../perf.txt', 'utf8')) + const __dirname = path.dirname(fileURLToPath(import.meta.url)) + + const prevPerfFilePath = path.resolve(__dirname, '../..', 'previousPerf.txt'); + const fileReportPath = path.resolve(__dirname, '../..', 'perfReport.md'); + + const { previousDownloadBandwidth, previousUploadBandwidth } = JSON.parse(fs.readFileSync(prevPerfFilePath, 'utf8')) const markdownContent = generatePerformanceOutput(downloadBandwidth, previousDownloadBandwidth, uploadBandwidth, previousUploadBandwidth) - fs.writeFileSync('../perf.txt', JSON.stringify({ + fs.writeFileSync(prevPerfFilePath, JSON.stringify({ previousDownloadBandwidth: downloadBandwidth , previousUploadBandwidth: uploadBandwidth })) - fs.writeFileSync('../perfReport.md', markdownContent) + + fs.writeFileSync(fileReportPath, markdownContent) + + const uploadProgress = (uploadBandwidth - previousUploadBandwidth) / previousUploadBandwidth; + const downloadProgress = (downloadBandwidth - previousDownloadBandwidth) / previousDownloadBandwidth; + + assert(downloadProgress > -0.2, 'Download bandwidth decreased by more than 20%') + assert(uploadProgress >= -0.2, 'Upload bandwidth decreased by more than 20%') }) }) diff --git a/packages/perf/tsconfig.json b/packages/perf/tsconfig.json index 13a3599639..2a0bd0091c 100644 --- a/packages/perf/tsconfig.json +++ b/packages/perf/tsconfig.json @@ -6,5 +6,10 @@ "include": [ "src", "test" + ], + "references": [ + { + "path": "../libp2p" + } ] } From 2458fbce0b65fdf62533fe70c05edbe63b7a1902 Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 21 Jun 2023 12:19:28 -0500 Subject: [PATCH 03/27] test: use CI to output test results --- .github/workflows/perf-test.yml | 85 +++++++++++++++++++++++++------ packages/perf/.gitignore | 2 - packages/perf/package.json | 2 +- packages/perf/previousPerf.json | 1 + packages/perf/previousPerf.txt | 1 - packages/perf/src/printResults.ts | 41 --------------- packages/perf/test/index.spec.ts | 31 +---------- 7 files changed, 73 insertions(+), 90 deletions(-) create mode 100644 packages/perf/previousPerf.json delete mode 100644 packages/perf/previousPerf.txt delete mode 100644 packages/perf/src/printResults.ts diff --git a/.github/workflows/perf-test.yml b/.github/workflows/perf-test.yml index 21ea355b1f..0e6c1fb265 100644 --- a/.github/workflows/perf-test.yml +++ b/.github/workflows/perf-test.yml @@ -1,27 +1,80 @@ -name: Generate Performance Report - +name: Performance Test on: push: branches: - - main + - master + pull_request: + branches: + - "**" jobs: - build: + performance_test: runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + - uses: actions/checkout@v3 + with: + directories: | + ./packages/perf/node_modules + + - name: Build perf + run: (cd pacakges/perf && npm i && npm run build) - - name: Install dependencies - working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }} - run: npm ci + - name: Run tests and capture console output + run: | + npm run test > test_output.txt + echo '::set-output name=test_output::$(cat test_output.txt)' - - name: Generate Report - run: npm run test + - name: Read previous performance data + id: read_previous_data + run: | + previous_data=$(cat previousPerf.json) + echo "::set-output name=previous_data::$previous_data" - - uses: actions/upload-artifact@v3 + - name: Extract bandwidth from test output + id: extract_bandwidth + run: | + test_output=$(cat test_output.txt) + upload_bandwidth=$(echo "$test_output" | grep -o 'Upload bandwidth: [0-9]*') + upload_bandwidth=${upload_bandwidth#*: } + download_bandwidth=$(echo "$test_output" | grep -o 'Download bandwidth: [0-9]*') + download_bandwidth=${download_bandwidth#*: } + echo "::set-output name=upload_bandwidth::$upload_bandwidth" + echo "::set-output name=download_bandwidth::$download_bandwidth" + + - name: Compare bandwidths with previous data + id: compare_bandwidths + run: | + previous_download_bandwidth=${{ steps.read_previous_data.outputs.previous_data | fromJson | .previousDownloadBandwidth }} + previous_upload_bandwidth=${{ steps.read_previous_data.outputs.previous_data | fromJson | .previousUploadBandwidth }} + current_upload_bandwidth=${{ steps.extract_bandwidth.outputs.upload_bandwidth }} + current_download_bandwidth=${{ steps.extract_bandwidth.outputs.download_bandwidth }} + if (( $(bc <<< "$current_upload_bandwidth <= 0.8 * $previous_upload_bandwidth") )) || (( $(bc <<< "$current_download_bandwidth <= 0.8 * $previous_download_bandwidth") )); then + echo "::set-output name=bandwidth_comparison::fail" + else + echo "::set-output name=bandwidth_comparison::pass" + fi + + - name: Save current performance data + id: save_performance_data + run: | + current_upload_bandwidth=${{ steps.extract_bandwidth.outputs.upload_bandwidth }} + current_download_bandwidth=${{ steps.extract_bandwidth.outputs.download_bandwidth }} + echo "{\"previousDownloadBandwidth\": $current_download_bandwidth, \"previousUploadBandwidth\": $current_upload_bandwidth}" > previousPerf.json + + - name: Commit and push changes + uses: stefanzweifel/git-auto-commit-action@v4 with: - name: perf-output - path: | - ${{ steps.find-workdir.outputs.WORK_DIR }}/perfReport.md + commit_message: Update performance data + file_pattern: previousPerf.txt + branch: ${{ github.ref }} + + - name: Check CI job status + run: | + bandwidth_comparison=${{ steps.compare_bandwidth.outputs.bandwidth_comparison }} + if [ "$bandwidth_comparison" == "fail" ]; then + echo "Performance test failed: bandwidth descreased by more than 20%." + exit 1 + else + echo "Performance test passed." + fi diff --git a/packages/perf/.gitignore b/packages/perf/.gitignore index 29d65d0df2..a4b426ea95 100644 --- a/packages/perf/.gitignore +++ b/packages/perf/.gitignore @@ -1,5 +1,3 @@ -perfReport.md - node_modules/ dist/ \ No newline at end of file diff --git a/packages/perf/package.json b/packages/perf/package.json index 8678dd4183..b148d62549 100644 --- a/packages/perf/package.json +++ b/packages/perf/package.json @@ -27,7 +27,7 @@ }, "scripts": { "build": "aegir build", - "test": "aegir test -t node --cov", + "test": "aegir test", "clean": "aegir clean", "lint": "aegir lint", "test:chrome": "aegir test -t browser --cov", diff --git a/packages/perf/previousPerf.json b/packages/perf/previousPerf.json new file mode 100644 index 0000000000..f7bb5b4918 --- /dev/null +++ b/packages/perf/previousPerf.json @@ -0,0 +1 @@ +{ "previousDownloadBandwidth": 107084, "previousUploadBandwidth": 119069 } diff --git a/packages/perf/previousPerf.txt b/packages/perf/previousPerf.txt deleted file mode 100644 index e9c0bb3e93..0000000000 --- a/packages/perf/previousPerf.txt +++ /dev/null @@ -1 +0,0 @@ -{"previousDownloadBandwidth":113619,"previousUploadBandwidth":111002} \ No newline at end of file diff --git a/packages/perf/src/printResults.ts b/packages/perf/src/printResults.ts deleted file mode 100644 index 785b008811..0000000000 --- a/packages/perf/src/printResults.ts +++ /dev/null @@ -1,41 +0,0 @@ -export function generatePerformanceOutput(currentDownloadSpeed: number, previousDownloadSpeed: number, currentUploadSpeed: number, previousUploadSpeed: number): string { - - const uploadProgress = (currentUploadSpeed - previousUploadSpeed) / previousUploadSpeed; - const downloadProgress = (currentDownloadSpeed - previousDownloadSpeed) / previousDownloadSpeed; - - let markdownContent = ` - # Bandwidth Test Results - - ## Download Bandwidth - - The download bandwidth measured during the test was: ${currentDownloadSpeed} kiB/s. - - `; - - if (downloadProgress > 0) { - markdownContent += `:white_check_mark: The download bandwidth has improved by ${downloadProgress}% since the last test. :white_check_mark:`; - } else if (downloadProgress < 0) { - markdownContent += `:x: The download bandwidth has decreased by ${downloadProgress}% since the last test. :x:`; - } else { - markdownContent += `The download bandwidth has not changed since the last test.`; - } - - markdownContent += ` - - ## Upload Bandwidth - - The upload bandwidth measured during the test was: ${currentUploadSpeed} kiB/s. - `; - - if (uploadProgress > 0) { - markdownContent += `:white_check_mark: The upload bandwidth has improved by ${uploadProgress}% since the last test. :white_check_mark:`; - } else if (uploadProgress < 0) { - markdownContent += `:x: The upload bandwidth has decreased by ${uploadProgress}% since the last test. :x:`; - } else { - markdownContent += `The upload bandwidth has not changed since the last test.`; - } - - return markdownContent.replace(/\t/g, ''); - -} - diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index 9b5b7fe2b2..8a9e950af1 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -1,21 +1,16 @@ /* eslint-env mocha */ -import * as fs from 'fs' -import * as path from 'path' -import { fileURLToPath } from 'url' - import { connectionPair, mockConnectionGater, mockRegistrar, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' import { EventEmitter } from '@libp2p/interface/events' import { start, stop } from '@libp2p/interface/startable' import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { PersistentPeerStore } from '@libp2p/peer-store' -import { assert, expect } from 'aegir/chai' +import { expect } from 'aegir/chai' import { MemoryDatastore } from 'datastore-core' import { stubInterface } from 'sinon-ts' import { perfService, type PerfServiceInit } from '../src/index.js' import type { TransportManager } from '@libp2p/interface-internal/transport-manager' -import { generatePerformanceOutput } from '../src/printResults.js' import { defaultComponents, type Components } from 'libp2p/components' import { DefaultConnectionManager } from 'libp2p/connection-manager' @@ -111,28 +106,6 @@ describe('perf', () => { const uploadBandwidth = await client.measureDownloadBandwidth(remoteComponents.peerId, 10n << 20n) >> 10 // eslint-disable-next-line no-console console.log('Upload bandwidth: ', uploadBandwidth, ' kiB/s') - - const __dirname = path.dirname(fileURLToPath(import.meta.url)) - - const prevPerfFilePath = path.resolve(__dirname, '../..', 'previousPerf.txt'); - const fileReportPath = path.resolve(__dirname, '../..', 'perfReport.md'); - - const { previousDownloadBandwidth, previousUploadBandwidth } = JSON.parse(fs.readFileSync(prevPerfFilePath, 'utf8')) - - const markdownContent = generatePerformanceOutput(downloadBandwidth, previousDownloadBandwidth, uploadBandwidth, previousUploadBandwidth) - - fs.writeFileSync(prevPerfFilePath, JSON.stringify({ - previousDownloadBandwidth: downloadBandwidth , - previousUploadBandwidth: uploadBandwidth - })) - - - fs.writeFileSync(fileReportPath, markdownContent) - - const uploadProgress = (uploadBandwidth - previousUploadBandwidth) / previousUploadBandwidth; - const downloadProgress = (downloadBandwidth - previousDownloadBandwidth) / previousDownloadBandwidth; - - assert(downloadProgress > -0.2, 'Download bandwidth decreased by more than 20%') - assert(uploadProgress >= -0.2, 'Upload bandwidth decreased by more than 20%') }) + }) From 8aee800ed2fad8b9fef02ef26bc47df259c0b1d0 Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 21 Jun 2023 12:49:07 -0500 Subject: [PATCH 04/27] chore: linting fixes + remove unused deps --- packages/perf/package.json | 1 - packages/perf/src/index.ts | 4 ++-- packages/perf/test/index.spec.ts | 11 ++++------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/perf/package.json b/packages/perf/package.json index b148d62549..473ebbccaa 100644 --- a/packages/perf/package.json +++ b/packages/perf/package.json @@ -40,7 +40,6 @@ "dependencies": { "@libp2p/interface": "^0.0.1", "@libp2p/interface-compliance-tests": "^3.0.7", - "@libp2p/interface-connection-gater": "3.0.1", "@libp2p/interface-internal": "^0.0.1", "@libp2p/interface-peer-id": "2.0.2", "@libp2p/interfaces": "3.3.2", diff --git a/packages/perf/src/index.ts b/packages/perf/src/index.ts index f2de852f51..4ac0a86c77 100644 --- a/packages/perf/src/index.ts +++ b/packages/perf/src/index.ts @@ -1,10 +1,10 @@ import { logger } from '@libp2p/logger' import { anySignal } from 'any-signal' import { MAX_INBOUND_STREAMS, PROTOCOL_NAME, TIMEOUT, WRITE_BLOCK_SIZE } from './constants.js' +import type { Startable } from '@libp2p/interface/startable' import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager' -import type { PeerId } from '@libp2p/interface-peer-id' import type { IncomingStreamData, Registrar } from '@libp2p/interface-internal/registrar' -import type {Startable } from '@libp2p/interface/startable' +import type { PeerId } from '@libp2p/interface-peer-id' import type { AbortOptions } from '@libp2p/interfaces' const log = logger('libp2p:perf') diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index 8a9e950af1..c8809b60a6 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -1,19 +1,17 @@ /* eslint-env mocha */ -import { connectionPair, mockConnectionGater, mockRegistrar, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' import { EventEmitter } from '@libp2p/interface/events' import { start, stop } from '@libp2p/interface/startable' +import { connectionPair, mockConnectionGater, mockRegistrar, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { PersistentPeerStore } from '@libp2p/peer-store' import { expect } from 'aegir/chai' import { MemoryDatastore } from 'datastore-core' +import { defaultComponents, type Components } from 'libp2p/components' +import { DefaultConnectionManager } from 'libp2p/connection-manager' import { stubInterface } from 'sinon-ts' - import { perfService, type PerfServiceInit } from '../src/index.js' import type { TransportManager } from '@libp2p/interface-internal/transport-manager' -import { defaultComponents, type Components } from 'libp2p/components' -import { DefaultConnectionManager } from 'libp2p/connection-manager' - const defaultInit: PerfServiceInit = { protocolName: '/perf/1.0.0', @@ -101,11 +99,10 @@ describe('perf', () => { // Run Perf const downloadBandwidth = await client.measureDownloadBandwidth(remoteComponents.peerId, 10n << 20n) >> 10 // eslint-disable-next-line no-console - console.log('Download bandwidth: ', downloadBandwidth , ' kiB/s') + console.log('Download bandwidth: ', downloadBandwidth, ' kiB/s') const uploadBandwidth = await client.measureDownloadBandwidth(remoteComponents.peerId, 10n << 20n) >> 10 // eslint-disable-next-line no-console console.log('Upload bandwidth: ', uploadBandwidth, ' kiB/s') }) - }) From 8ea1870eb851d924e4365d57edc21e0f3ab8d4cd Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 21 Jun 2023 15:28:31 -0500 Subject: [PATCH 05/27] test: updated workflow --- .github/workflows/perf-test.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/perf-test.yml b/.github/workflows/perf-test.yml index 0e6c1fb265..405cc7be15 100644 --- a/.github/workflows/perf-test.yml +++ b/.github/workflows/perf-test.yml @@ -45,8 +45,9 @@ jobs: - name: Compare bandwidths with previous data id: compare_bandwidths run: | - previous_download_bandwidth=${{ steps.read_previous_data.outputs.previous_data | fromJson | .previousDownloadBandwidth }} - previous_upload_bandwidth=${{ steps.read_previous_data.outputs.previous_data | fromJson | .previousUploadBandwidth }} + previous_data="${{ steps.read_previous_data.outputs.previous_data }}" + previous_download_bandwidth=$(echo "$previous_data" | jq -r '.previousDownloadBandwidth') + previous_upload_bandwidth=$(echo "$previous_data" | jq -r '.previousUploadBandwidth') current_upload_bandwidth=${{ steps.extract_bandwidth.outputs.upload_bandwidth }} current_download_bandwidth=${{ steps.extract_bandwidth.outputs.download_bandwidth }} if (( $(bc <<< "$current_upload_bandwidth <= 0.8 * $previous_upload_bandwidth") )) || (( $(bc <<< "$current_download_bandwidth <= 0.8 * $previous_download_bandwidth") )); then From 4de5595774be355184776ac039f754cbd5d6c97f Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 22 Jun 2023 19:02:39 -0500 Subject: [PATCH 06/27] ci: updated workflow to fail if bandwidth drops below 20% --- .github/workflows/perf-test.yml | 31 ++++++++++++++++++++++++------- packages/perf/test/index.spec.ts | 4 ++-- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/.github/workflows/perf-test.yml b/.github/workflows/perf-test.yml index 405cc7be15..a0e603d4b5 100644 --- a/.github/workflows/perf-test.yml +++ b/.github/workflows/perf-test.yml @@ -9,30 +9,43 @@ on: jobs: performance_test: + name: Run performance tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: actions/checkout@v3 + - uses: ipfs/aegir/actions/cache-node-modules@master with: directories: | ./packages/perf/node_modules + - name: Install playwright dependencies + uses: ipfs/aegir/actions/cache-node-modules@master + - run: npx playwright install-deps + - name: Build perf - run: (cd pacakges/perf && npm i && npm run build) + working-directory: packages/perf + run: (npm i && npm run build) - name: Run tests and capture console output + working-directory: packages/perf run: | npm run test > test_output.txt echo '::set-output name=test_output::$(cat test_output.txt)' - name: Read previous performance data id: read_previous_data + working-directory: packages/perf run: | previous_data=$(cat previousPerf.json) echo "::set-output name=previous_data::$previous_data" + previous_download_bandwidth=$(echo "$previous_data" | jq -r '.previousDownloadBandwidth') + previous_upload_bandwidth=$(echo "$previous_data" | jq -r '.previousUploadBandwidth') + echo "::set-output name=previous_download_bandwidth::$previous_download_bandwidth" + echo "::set-output name=previous_upload_bandwidth::$previous_upload_bandwidth" - name: Extract bandwidth from test output id: extract_bandwidth + working-directory: packages/perf run: | test_output=$(cat test_output.txt) upload_bandwidth=$(echo "$test_output" | grep -o 'Upload bandwidth: [0-9]*') @@ -42,14 +55,17 @@ jobs: echo "::set-output name=upload_bandwidth::$upload_bandwidth" echo "::set-output name=download_bandwidth::$download_bandwidth" + - name: Install bc for floating point arithmetic + run: sudo apt-get update && sudo apt-get install -y bc + - name: Compare bandwidths with previous data id: compare_bandwidths + working-directory: packages/perf run: | - previous_data="${{ steps.read_previous_data.outputs.previous_data }}" - previous_download_bandwidth=$(echo "$previous_data" | jq -r '.previousDownloadBandwidth') - previous_upload_bandwidth=$(echo "$previous_data" | jq -r '.previousUploadBandwidth') current_upload_bandwidth=${{ steps.extract_bandwidth.outputs.upload_bandwidth }} current_download_bandwidth=${{ steps.extract_bandwidth.outputs.download_bandwidth }} + previous_upload_bandwidth=${{ steps.read_previous_data.outputs.previous_upload_bandwidth }} + previous_download_bandwidth=${{ steps.read_previous_data.outputs.previous_download_bandwidth }} if (( $(bc <<< "$current_upload_bandwidth <= 0.8 * $previous_upload_bandwidth") )) || (( $(bc <<< "$current_download_bandwidth <= 0.8 * $previous_download_bandwidth") )); then echo "::set-output name=bandwidth_comparison::fail" else @@ -58,6 +74,7 @@ jobs: - name: Save current performance data id: save_performance_data + working-directory: packages/perf run: | current_upload_bandwidth=${{ steps.extract_bandwidth.outputs.upload_bandwidth }} current_download_bandwidth=${{ steps.extract_bandwidth.outputs.download_bandwidth }} @@ -67,12 +84,12 @@ jobs: uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: Update performance data - file_pattern: previousPerf.txt + file_pattern: previousPerf.json branch: ${{ github.ref }} - name: Check CI job status run: | - bandwidth_comparison=${{ steps.compare_bandwidth.outputs.bandwidth_comparison }} + bandwidth_comparison=${{ steps.compare_bandwidths.outputs.bandwidth_comparison }} if [ "$bandwidth_comparison" == "fail" ]; then echo "Performance test failed: bandwidth descreased by more than 20%." exit 1 diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index c8809b60a6..e0680985c5 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -99,10 +99,10 @@ describe('perf', () => { // Run Perf const downloadBandwidth = await client.measureDownloadBandwidth(remoteComponents.peerId, 10n << 20n) >> 10 // eslint-disable-next-line no-console - console.log('Download bandwidth: ', downloadBandwidth, ' kiB/s') + console.log('Download bandwidth:', downloadBandwidth, 'kiB/s') const uploadBandwidth = await client.measureDownloadBandwidth(remoteComponents.peerId, 10n << 20n) >> 10 // eslint-disable-next-line no-console - console.log('Upload bandwidth: ', uploadBandwidth, ' kiB/s') + console.log('Upload bandwidth:', uploadBandwidth, 'kiB/s') }) }) From 9a7f9d835cb1b56d391cd7e527a4cd528ff1eee0 Mon Sep 17 00:00:00 2001 From: chad Date: Tue, 27 Jun 2023 15:29:10 -0500 Subject: [PATCH 07/27] ci: updated job to generate report for performance data --- .github/workflows/perf-test.yml | 146 ++++++++++++++++++++--------- packages/perf/package.json | 3 +- packages/perf/previousPerf.json | 6 +- packages/perf/src/renderResults.ts | 55 +++++++++++ 4 files changed, 162 insertions(+), 48 deletions(-) create mode 100644 packages/perf/src/renderResults.ts diff --git a/.github/workflows/perf-test.yml b/.github/workflows/perf-test.yml index a0e603d4b5..94429e733f 100644 --- a/.github/workflows/perf-test.yml +++ b/.github/workflows/perf-test.yml @@ -15,8 +15,7 @@ jobs: - uses: actions/checkout@v3 - uses: ipfs/aegir/actions/cache-node-modules@master with: - directories: | - ./packages/perf/node_modules + directories: ./packages/perf/node_modules - name: Install playwright dependencies uses: ipfs/aegir/actions/cache-node-modules@master @@ -26,59 +25,111 @@ jobs: working-directory: packages/perf run: (npm i && npm run build) - - name: Run tests and capture console output + - name: Run tests and store in test_output working-directory: packages/perf run: | npm run test > test_output.txt - echo '::set-output name=test_output::$(cat test_output.txt)' - - - name: Read previous performance data - id: read_previous_data - working-directory: packages/perf - run: | - previous_data=$(cat previousPerf.json) - echo "::set-output name=previous_data::$previous_data" - previous_download_bandwidth=$(echo "$previous_data" | jq -r '.previousDownloadBandwidth') - previous_upload_bandwidth=$(echo "$previous_data" | jq -r '.previousUploadBandwidth') - echo "::set-output name=previous_download_bandwidth::$previous_download_bandwidth" - echo "::set-output name=previous_upload_bandwidth::$previous_upload_bandwidth" - name: Extract bandwidth from test output id: extract_bandwidth working-directory: packages/perf + shell: bash run: | - test_output=$(cat test_output.txt) - upload_bandwidth=$(echo "$test_output" | grep -o 'Upload bandwidth: [0-9]*') - upload_bandwidth=${upload_bandwidth#*: } - download_bandwidth=$(echo "$test_output" | grep -o 'Download bandwidth: [0-9]*') - download_bandwidth=${download_bandwidth#*: } - echo "::set-output name=upload_bandwidth::$upload_bandwidth" - echo "::set-output name=download_bandwidth::$download_bandwidth" - - - name: Install bc for floating point arithmetic - run: sudo apt-get update && sudo apt-get install -y bc - - - name: Compare bandwidths with previous data - id: compare_bandwidths - working-directory: packages/perf - run: | - current_upload_bandwidth=${{ steps.extract_bandwidth.outputs.upload_bandwidth }} - current_download_bandwidth=${{ steps.extract_bandwidth.outputs.download_bandwidth }} - previous_upload_bandwidth=${{ steps.read_previous_data.outputs.previous_upload_bandwidth }} - previous_download_bandwidth=${{ steps.read_previous_data.outputs.previous_download_bandwidth }} - if (( $(bc <<< "$current_upload_bandwidth <= 0.8 * $previous_upload_bandwidth") )) || (( $(bc <<< "$current_download_bandwidth <= 0.8 * $previous_download_bandwidth") )); then - echo "::set-output name=bandwidth_comparison::fail" - else - echo "::set-output name=bandwidth_comparison::pass" + bandwidth_file="test_output.txt" + bandwidth_object="{" + + # Function to assign bandwidth values to the object + assign_bandwidth() { + local environment=$1 + local current_upload_bandwidth=$2 + local current_download_bandwidth=$3 + + if [[ ${#bandwidth_object} -gt 1 ]]; then + bandwidth_object+=", " + fi + + bandwidth_object+="\"$environment\": { \"currentUploadBandwidth\": $current_upload_bandwidth, \"currentDownloadBandwidth\": $current_download_bandwidth }" + } + + # Read the bandwidth values from the file + upload_count=0 + download_count=0 + + upload_bandwidths=() + download_bandwidths=() + + while IFS= read -r line; do + if [[ $line == *"Upload bandwidth"* ]]; then + current_upload_bandwidth=$(grep -o 'Upload bandwidth: [0-9]*' <<< "$line" | grep -o '[0-9]*') + upload_count=$((upload_count + 1)) + elif [[ $line == *"Download bandwidth"* ]]; then + current_download_bandwidth=$(grep -o 'Download bandwidth: [0-9]*' <<< "$line" | grep -o '[0-9]*') + download_count=$((download_count + 1)) + fi + + if [[ $upload_count -eq 1 && $download_count -eq 1 ]]; then + upload_bandwidths[0]=$current_upload_bandwidth + download_bandwidths[0]=$current_download_bandwidth + elif [[ $upload_count -eq 2 && $download_count -eq 2 ]]; then + upload_bandwidths[1]=$current_upload_bandwidth + download_bandwidths[1]=$current_download_bandwidth + elif [[ $upload_count -eq 3 && $download_count -eq 3 ]]; then + upload_bandwidths[2]=$current_upload_bandwidth + download_bandwidths[2]=$current_download_bandwidth + break # Exit the loop after processing the third instance + fi + done < "$bandwidth_file" + + # Construct the bandwidth object + assign_bandwidth "node" "${upload_bandwidths[0]}" "${download_bandwidths[0]}" + assign_bandwidth "browser" "${upload_bandwidths[1]}" "${download_bandwidths[1]}" + assign_bandwidth "webworker" "${upload_bandwidths[2]}" "${download_bandwidths[2]}" + + # Remove trailing comma if there are values in the object + if [[ ${#bandwidth_object} -gt 1 ]]; then + bandwidth_object="${bandwidth_object#, }" fi + bandwidth_object+="}" + + current_bandwidths=$bandwidth_object + + echo "::set-output name=current_bandwidths::$current_bandwidths" + + # Read the previous bandwidth values from the file + previous_bandwidths=$(cat previousPerf.json | jq -r '.') + + # Iterate over the current bandwidth object and merge with previous values + merged_object=$(jq --argjson previous "$previous_bandwidths" '. as $current | reduce keys[] as $key ({}; .[$key] = ($current[$key] + $previous[$key]))' <<< "$current_bandwidths") + + # Set the merged bandwidth object as environment variable + EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) + echo "BANDWIDTH_TEST_RESULTS<<$EOF" >> "$GITHUB_ENV" + echo $merged_object >> "$GITHUB_ENV" + echo "$EOF" >> "$GITHUB_ENV" + + - name: Generate Test Report + id: generate_report + working-directory: packages/perf + run: npm run renderResults > test_report.md + + - name: Upload Test Report + id: upload_report + uses: actions/upload-artifact@v2 + with: + name: test_report + path: packages/perf/test_report.md + - name: Save current performance data id: save_performance_data working-directory: packages/perf run: | - current_upload_bandwidth=${{ steps.extract_bandwidth.outputs.upload_bandwidth }} - current_download_bandwidth=${{ steps.extract_bandwidth.outputs.download_bandwidth }} - echo "{\"previousDownloadBandwidth\": $current_download_bandwidth, \"previousUploadBandwidth\": $current_upload_bandwidth}" > previousPerf.json + current_bandwidths=$(echo "${{ steps.extract_bandwidth.outputs.current_bandwidths }}"" | jq -r '.') + # Parse the input object using jq, modify the keys, and store the result in a new variable + updated_object=$(echo "$current_bandwidths" | jq 'map_values(.previousUploadBandwidth = .currentUploadBandwidth | del(.currentUploadBandwidth) | .previousDownloadBandwidth = .currentDownloadBandwidth | del(.currentDownloadBandwidth))') + + # Output the updated object + echo $updated_object > previousPerf.json - name: Commit and push changes uses: stefanzweifel/git-auto-commit-action@v4 @@ -88,11 +139,14 @@ jobs: branch: ${{ github.ref }} - name: Check CI job status + id: check_ci + working-directory: packages/perf run: | - bandwidth_comparison=${{ steps.compare_bandwidths.outputs.bandwidth_comparison }} - if [ "$bandwidth_comparison" == "fail" ]; then - echo "Performance test failed: bandwidth descreased by more than 20%." - exit 1 + # Check if the file contains the "❌ " symbol + if grep -q "❌ " test_report.md; then + echo "Failure: Test report contains the ❌ symbol." + exit 1 # Exit with a non-zero status code for failure else - echo "Performance test passed." + echo "Success: Test report does not contain the ❌ symbol." + exit 0 # Exit with a zero status code for pass fi diff --git a/packages/perf/package.json b/packages/perf/package.json index 473ebbccaa..411066281c 100644 --- a/packages/perf/package.json +++ b/packages/perf/package.json @@ -35,7 +35,8 @@ "test:firefox": "aegir test -t browser -- --browser firefox", "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", "test:node": "aegir test -t node --cov", - "dep-check": "aegir dep-check -i protons" + "dep-check": "aegir dep-check", + "renderResults": "node dist/src/renderResults.js" }, "dependencies": { "@libp2p/interface": "^0.0.1", diff --git a/packages/perf/previousPerf.json b/packages/perf/previousPerf.json index f7bb5b4918..57184429b0 100644 --- a/packages/perf/previousPerf.json +++ b/packages/perf/previousPerf.json @@ -1 +1,5 @@ -{ "previousDownloadBandwidth": 107084, "previousUploadBandwidth": 119069 } +{ + "node": { "previousDownloadBandwidth": 125644, "previousUploadBandwidth": 127204 }, + "browser": { "previousDownloadBandwidth": 123003, "previousUploadBandwidth": 122268 }, + "webworker": { "previousDownloadBandwidth": 120825, "previousUploadBandwidth": 124121 } +} diff --git a/packages/perf/src/renderResults.ts b/packages/perf/src/renderResults.ts new file mode 100644 index 0000000000..556ceea1f2 --- /dev/null +++ b/packages/perf/src/renderResults.ts @@ -0,0 +1,55 @@ +interface TestResult { + previousUploadBandwidth: number; + currentUploadBandwidth: number; + previousDownloadBandwidth: number; + currentDownloadBandwidth: number; +} + +interface TestEnvironment { + name: string; + results: TestResult; +} + +export function generateMarkdownTable(environments: TestEnvironment[]): string { + const headerRow = + "| Environment | Previous Upload Bandwidth | Current Upload Bandwidth | Upload Bandwidth Comparison | Previous Download Bandwidth | Current Download Bandwidth | Download Bandwidth Comparison |\n"; + const separatorRow = + "|-------------|--------------------------|-------------------------|-----------------------------|-----------------------------|----------------------------|-----------------------------|\n"; + let bodyRows = ""; + + environments.forEach((environment) => { + const { name, results } = environment; + const { + previousUploadBandwidth, + currentUploadBandwidth, + previousDownloadBandwidth, + currentDownloadBandwidth, + } = results; + + const uploadComparison = currentUploadBandwidth <= 0.8 * previousUploadBandwidth ? "❌" : "✅"; + const downloadComparison = currentDownloadBandwidth <= 0.8 * previousDownloadBandwidth ? "❌" : "✅"; + + const row = `| ${name} | ${previousUploadBandwidth} | ${currentUploadBandwidth} ${uploadComparison} | ${previousDownloadBandwidth} | ${currentDownloadBandwidth} ${downloadComparison} |\n`; + bodyRows += row; + }); + + return `${headerRow}${separatorRow}${bodyRows}`; +} + +const testEnvironments: TestEnvironment[] = []; + +const jsonObject = JSON.parse(process.env.BANDWIDTH_TEST_RESULTS ?? ''); + +for (const name in jsonObject) { + if (Object.prototype.hasOwnProperty.call(jsonObject, name)) { + const testResult = jsonObject[name]; + const testEnvironment: TestEnvironment = { + name: name, + results: testResult, + }; + testEnvironments.push(testEnvironment); + } +} + +const markdownTable = generateMarkdownTable(testEnvironments); +console.log(markdownTable); \ No newline at end of file From 9bed517f337b4accd39cd40227f1ba033fecb188 Mon Sep 17 00:00:00 2001 From: chad Date: Tue, 27 Jun 2023 21:42:34 -0500 Subject: [PATCH 08/27] chore: linting + updated ci job --- .github/workflows/perf-test.yml | 8 +++- packages/perf/previousPerf.json | 6 +-- packages/perf/src/renderResults.ts | 64 ++++++++++++++---------------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/.github/workflows/perf-test.yml b/.github/workflows/perf-test.yml index 94429e733f..f38e55b0c8 100644 --- a/.github/workflows/perf-test.yml +++ b/.github/workflows/perf-test.yml @@ -115,16 +115,20 @@ jobs: - name: Upload Test Report id: upload_report - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: test_report path: packages/perf/test_report.md + - name: Show Report Output + working-directory: packages/perf + run: cat test_report.md >> $GITHUB_STEP_SUMMARY + - name: Save current performance data id: save_performance_data working-directory: packages/perf run: | - current_bandwidths=$(echo "${{ steps.extract_bandwidth.outputs.current_bandwidths }}"" | jq -r '.') + current_bandwidths=$(echo "${{ steps.extract_bandwidth.outputs.current_bandwidths }}" | jq -r '.') # Parse the input object using jq, modify the keys, and store the result in a new variable updated_object=$(echo "$current_bandwidths" | jq 'map_values(.previousUploadBandwidth = .currentUploadBandwidth | del(.currentUploadBandwidth) | .previousDownloadBandwidth = .currentDownloadBandwidth | del(.currentDownloadBandwidth))') diff --git a/packages/perf/previousPerf.json b/packages/perf/previousPerf.json index 57184429b0..4e1d9c3e8e 100644 --- a/packages/perf/previousPerf.json +++ b/packages/perf/previousPerf.json @@ -1,5 +1,5 @@ { - "node": { "previousDownloadBandwidth": 125644, "previousUploadBandwidth": 127204 }, - "browser": { "previousDownloadBandwidth": 123003, "previousUploadBandwidth": 122268 }, - "webworker": { "previousDownloadBandwidth": 120825, "previousUploadBandwidth": 124121 } + "node": { "currentUploadBandwidth": 97407, "currentDownloadBandwidth": 94924 }, + "browser": { "currentUploadBandwidth": 98343, "currentDownloadBandwidth": 95700 }, + "webworker": { "currentUploadBandwidth": 94814, "currentDownloadBandwidth": 92879 } } diff --git a/packages/perf/src/renderResults.ts b/packages/perf/src/renderResults.ts index 556ceea1f2..3b4af9a0fc 100644 --- a/packages/perf/src/renderResults.ts +++ b/packages/perf/src/renderResults.ts @@ -1,55 +1,51 @@ interface TestResult { - previousUploadBandwidth: number; - currentUploadBandwidth: number; - previousDownloadBandwidth: number; - currentDownloadBandwidth: number; + previousUploadBandwidth: number + currentUploadBandwidth: number + previousDownloadBandwidth: number + currentDownloadBandwidth: number } interface TestEnvironment { - name: string; - results: TestResult; + name: string + results: TestResult } -export function generateMarkdownTable(environments: TestEnvironment[]): string { +export function generateMarkdownTable (environments: TestEnvironment[]): string { const headerRow = - "| Environment | Previous Upload Bandwidth | Current Upload Bandwidth | Upload Bandwidth Comparison | Previous Download Bandwidth | Current Download Bandwidth | Download Bandwidth Comparison |\n"; + '| Environment | Previous Upload Bandwidth | Current Upload Bandwidth | Upload Bandwidth Comparison | Previous Download Bandwidth | Current Download Bandwidth | Download Bandwidth Comparison |\n' const separatorRow = - "|-------------|--------------------------|-------------------------|-----------------------------|-----------------------------|----------------------------|-----------------------------|\n"; - let bodyRows = ""; + '|-------------|--------------------------|-------------------------|-----------------------------|-----------------------------|----------------------------|-----------------------------|\n' + let bodyRows = '' environments.forEach((environment) => { - const { name, results } = environment; - const { - previousUploadBandwidth, - currentUploadBandwidth, - previousDownloadBandwidth, - currentDownloadBandwidth, - } = results; - - const uploadComparison = currentUploadBandwidth <= 0.8 * previousUploadBandwidth ? "❌" : "✅"; - const downloadComparison = currentDownloadBandwidth <= 0.8 * previousDownloadBandwidth ? "❌" : "✅"; - - const row = `| ${name} | ${previousUploadBandwidth} | ${currentUploadBandwidth} ${uploadComparison} | ${previousDownloadBandwidth} | ${currentDownloadBandwidth} ${downloadComparison} |\n`; - bodyRows += row; - }); - - return `${headerRow}${separatorRow}${bodyRows}`; + const { name, results } = environment + const { previousUploadBandwidth, currentUploadBandwidth, previousDownloadBandwidth, currentDownloadBandwidth } = results + + const uploadComparison = currentUploadBandwidth <= 0.8 * previousUploadBandwidth ? '❌' : '✅' + const downloadComparison = currentDownloadBandwidth <= 0.8 * previousDownloadBandwidth ? '❌' : '✅' + + const row = `| ${name} | ${previousUploadBandwidth} | ${currentUploadBandwidth} ${uploadComparison} | ${previousDownloadBandwidth} | ${currentDownloadBandwidth} ${downloadComparison} |\n` + bodyRows += row + }) + + return `${headerRow}${separatorRow}${bodyRows}` } -const testEnvironments: TestEnvironment[] = []; +const testEnvironments: TestEnvironment[] = [] -const jsonObject = JSON.parse(process.env.BANDWIDTH_TEST_RESULTS ?? ''); +const jsonObject = JSON.parse(process.env.BANDWIDTH_TEST_RESULTS ?? '') for (const name in jsonObject) { if (Object.prototype.hasOwnProperty.call(jsonObject, name)) { - const testResult = jsonObject[name]; + const testResult = jsonObject[name] const testEnvironment: TestEnvironment = { name: name, - results: testResult, - }; - testEnvironments.push(testEnvironment); + results: testResult + } + testEnvironments.push(testEnvironment) } } -const markdownTable = generateMarkdownTable(testEnvironments); -console.log(markdownTable); \ No newline at end of file +const markdownTable = generateMarkdownTable(testEnvironments) +// eslint-disable-next-line no-console +console.log(markdownTable) From c1b262f9e45467cd0bb4fed414128d4628146b34 Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 28 Jun 2023 12:01:18 -0500 Subject: [PATCH 09/27] ci: updated saving performance data --- .github/workflows/perf-test.yml | 18 +++++++++++------- packages/perf/previousPerf.json | 6 +++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/workflows/perf-test.yml b/.github/workflows/perf-test.yml index f38e55b0c8..772ba6235e 100644 --- a/.github/workflows/perf-test.yml +++ b/.github/workflows/perf-test.yml @@ -31,7 +31,7 @@ jobs: npm run test > test_output.txt - name: Extract bandwidth from test output - id: extract_bandwidth + id: extract_bandwidths working-directory: packages/perf shell: bash run: | @@ -127,13 +127,17 @@ jobs: - name: Save current performance data id: save_performance_data working-directory: packages/perf + shell: bash run: | - current_bandwidths=$(echo "${{ steps.extract_bandwidth.outputs.current_bandwidths }}" | jq -r '.') + current_bandwidths=$(echo '${{ steps.extract_bandwidths.outputs.current_bandwidths }}' | jq -r '.') + # Parse the input object using jq, modify the keys, and store the result in a new variable updated_object=$(echo "$current_bandwidths" | jq 'map_values(.previousUploadBandwidth = .currentUploadBandwidth | del(.currentUploadBandwidth) | .previousDownloadBandwidth = .currentDownloadBandwidth | del(.currentDownloadBandwidth))') + echo "updated object: $updated_object" + # Output the updated object - echo $updated_object > previousPerf.json + echo "$updated_object" > previousPerf.json - name: Commit and push changes uses: stefanzweifel/git-auto-commit-action@v4 @@ -146,11 +150,11 @@ jobs: id: check_ci working-directory: packages/perf run: | - # Check if the file contains the "❌ " symbol - if grep -q "❌ " test_report.md; then - echo "Failure: Test report contains the ❌ symbol." + # Check if the file contains the "❌" symbol + if grep -q "❌" test_report.md; then + echo "Failure: There was a performance degradation of over 20%." exit 1 # Exit with a non-zero status code for failure else - echo "Success: Test report does not contain the ❌ symbol." + echo "Success: Performance benchmarks passed." exit 0 # Exit with a zero status code for pass fi diff --git a/packages/perf/previousPerf.json b/packages/perf/previousPerf.json index 4e1d9c3e8e..b64fae6eaa 100644 --- a/packages/perf/previousPerf.json +++ b/packages/perf/previousPerf.json @@ -1,5 +1,5 @@ { - "node": { "currentUploadBandwidth": 97407, "currentDownloadBandwidth": 94924 }, - "browser": { "currentUploadBandwidth": 98343, "currentDownloadBandwidth": 95700 }, - "webworker": { "currentUploadBandwidth": 94814, "currentDownloadBandwidth": 92879 } + "browser": { "previousUploadBandwidth": 98343, "previousDownloadBandwidth": 95700 }, + "node": { "previousUploadBandwidth": 97407, "previousDownloadBandwidth": 94924 }, + "webworker": { "previousUploadBandwidth": 94814, "previousDownloadBandwidth": 92879 } } From fe79a728fd0b44095451cff42faff0e7b41d844f Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 28 Jun 2023 14:08:02 -0500 Subject: [PATCH 10/27] ci: update rendering --- packages/perf/src/renderResults.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/perf/src/renderResults.ts b/packages/perf/src/renderResults.ts index 3b4af9a0fc..e811962abc 100644 --- a/packages/perf/src/renderResults.ts +++ b/packages/perf/src/renderResults.ts @@ -24,7 +24,7 @@ export function generateMarkdownTable (environments: TestEnvironment[]): string const uploadComparison = currentUploadBandwidth <= 0.8 * previousUploadBandwidth ? '❌' : '✅' const downloadComparison = currentDownloadBandwidth <= 0.8 * previousDownloadBandwidth ? '❌' : '✅' - const row = `| ${name} | ${previousUploadBandwidth} | ${currentUploadBandwidth} ${uploadComparison} | ${previousDownloadBandwidth} | ${currentDownloadBandwidth} ${downloadComparison} |\n` + const row = `| ${name} | ${previousUploadBandwidth} | ${currentUploadBandwidth} | ${uploadComparison} | ${previousDownloadBandwidth} | ${currentDownloadBandwidth} | ${downloadComparison} |\n` bodyRows += row }) From 9dd024850875dbdf68fd8c5a8d00d227380815f2 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 29 Jun 2023 11:21:31 -0500 Subject: [PATCH 11/27] test: update perf test to take an average of 5 runs + standardize bytes --- packages/perf/src/renderResults.ts | 4 ++-- packages/perf/test/index.spec.ts | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/perf/src/renderResults.ts b/packages/perf/src/renderResults.ts index e811962abc..7565aeed5d 100644 --- a/packages/perf/src/renderResults.ts +++ b/packages/perf/src/renderResults.ts @@ -21,8 +21,8 @@ export function generateMarkdownTable (environments: TestEnvironment[]): string const { name, results } = environment const { previousUploadBandwidth, currentUploadBandwidth, previousDownloadBandwidth, currentDownloadBandwidth } = results - const uploadComparison = currentUploadBandwidth <= 0.8 * previousUploadBandwidth ? '❌' : '✅' - const downloadComparison = currentDownloadBandwidth <= 0.8 * previousDownloadBandwidth ? '❌' : '✅' + const uploadComparison = currentUploadBandwidth <= 0.95 * previousUploadBandwidth ? '❌' : '✅' + const downloadComparison = currentDownloadBandwidth <= 0.95 * previousDownloadBandwidth ? '❌' : '✅' const row = `| ${name} | ${previousUploadBandwidth} | ${currentUploadBandwidth} | ${uploadComparison} | ${previousDownloadBandwidth} | ${currentDownloadBandwidth} | ${downloadComparison} |\n` bodyRows += row diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index e0680985c5..f4705a78d6 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -81,7 +81,7 @@ describe('perf', () => { remoteComponents.events.safeDispatchEvent('connection:open', { detail: remoteToLocal }) // Run Perf - await expect(client.perf(remoteComponents.peerId, 1n << 10n, 1n << 10n)).to.eventually.be.fulfilled() + await expect(client.perf(remoteComponents.peerId, 1024n, 1024n)).to.eventually.be.fulfilled() }) it('should output benchmark', async () => { @@ -96,13 +96,19 @@ describe('perf', () => { localComponents.events.safeDispatchEvent('connection:open', { detail: localToRemote }) remoteComponents.events.safeDispatchEvent('connection:open', { detail: remoteToLocal }) - // Run Perf - const downloadBandwidth = await client.measureDownloadBandwidth(remoteComponents.peerId, 10n << 20n) >> 10 + let downloadBandwidth = 0 + let uploadBandwidth = 0 + + for (let i = 1; i < 5; i++) { + // Run Perf + downloadBandwidth += await client.measureDownloadBandwidth(remoteComponents.peerId, 10485760n) + uploadBandwidth += await client.measureUploadBandwidth(remoteComponents.peerId, 10485760n) + } + // eslint-disable-next-line no-console - console.log('Download bandwidth:', downloadBandwidth, 'kiB/s') + console.log('Upload bandwidth:', Math.floor(downloadBandwidth / 5), 'B/s') - const uploadBandwidth = await client.measureDownloadBandwidth(remoteComponents.peerId, 10n << 20n) >> 10 // eslint-disable-next-line no-console - console.log('Upload bandwidth:', uploadBandwidth, 'kiB/s') + console.log('Download bandwidth:', Math.floor(uploadBandwidth / 5), 'B/s') }) }) From 666142407b25ebbf25cec88684714dad5aa557f0 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 29 Jun 2023 11:37:45 -0500 Subject: [PATCH 12/27] ci: Added units to output matrix --- packages/perf/src/renderResults.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/perf/src/renderResults.ts b/packages/perf/src/renderResults.ts index 7565aeed5d..7489a72fa3 100644 --- a/packages/perf/src/renderResults.ts +++ b/packages/perf/src/renderResults.ts @@ -24,7 +24,7 @@ export function generateMarkdownTable (environments: TestEnvironment[]): string const uploadComparison = currentUploadBandwidth <= 0.95 * previousUploadBandwidth ? '❌' : '✅' const downloadComparison = currentDownloadBandwidth <= 0.95 * previousDownloadBandwidth ? '❌' : '✅' - const row = `| ${name} | ${previousUploadBandwidth} | ${currentUploadBandwidth} | ${uploadComparison} | ${previousDownloadBandwidth} | ${currentDownloadBandwidth} | ${downloadComparison} |\n` + const row = `| ${name} | ${previousUploadBandwidth} B/s | ${currentUploadBandwidth} B/s | ${uploadComparison} | ${previousDownloadBandwidth} B/s | ${currentDownloadBandwidth} B/s| ${downloadComparison} |\n` bodyRows += row }) From 79cbe1953f6f3aa36f7ed5c55caa222c10f32620 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 29 Jun 2023 11:51:07 -0500 Subject: [PATCH 13/27] test: updated previous bandwidths --- packages/perf/previousPerf.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/perf/previousPerf.json b/packages/perf/previousPerf.json index b64fae6eaa..a330174350 100644 --- a/packages/perf/previousPerf.json +++ b/packages/perf/previousPerf.json @@ -1,5 +1,5 @@ { - "browser": { "previousUploadBandwidth": 98343, "previousDownloadBandwidth": 95700 }, - "node": { "previousUploadBandwidth": 97407, "previousDownloadBandwidth": 94924 }, - "webworker": { "previousUploadBandwidth": 94814, "previousDownloadBandwidth": 92879 } + "browser": { "previousUploadBandwidth": 87900055, "previousDownloadBandwidth": 87736073 }, + "node": { "previousUploadBandwidth": 93373758, "previousDownloadBandwidth": 93798254 }, + "webworker": { "previousUploadBandwidth": 85991114, "previousDownloadBandwidth": 85401884 } } From 118703ab6d648ea9ac0d8c854c3b99a5a89f516a Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 29 Jun 2023 13:53:11 -0500 Subject: [PATCH 14/27] ci: updated save performance action --- .github/workflows/perf-test.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/perf-test.yml b/.github/workflows/perf-test.yml index 772ba6235e..b59ba762ef 100644 --- a/.github/workflows/perf-test.yml +++ b/.github/workflows/perf-test.yml @@ -134,16 +134,14 @@ jobs: # Parse the input object using jq, modify the keys, and store the result in a new variable updated_object=$(echo "$current_bandwidths" | jq 'map_values(.previousUploadBandwidth = .currentUploadBandwidth | del(.currentUploadBandwidth) | .previousDownloadBandwidth = .currentDownloadBandwidth | del(.currentDownloadBandwidth))') - echo "updated object: $updated_object" - # Output the updated object - echo "$updated_object" > previousPerf.json + echo $updated_object > previousPerf.json - name: Commit and push changes uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: Update performance data - file_pattern: previousPerf.json + file_pattern: "*.json" branch: ${{ github.ref }} - name: Check CI job status @@ -152,7 +150,7 @@ jobs: run: | # Check if the file contains the "❌" symbol if grep -q "❌" test_report.md; then - echo "Failure: There was a performance degradation of over 20%." + echo "Failure: There was a performance degradation of over 5%." exit 1 # Exit with a non-zero status code for failure else echo "Success: Performance benchmarks passed." From 7eb1a796df786e84d592399e7e5b80e5f7afaaff Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 26 Jul 2023 10:06:28 -0500 Subject: [PATCH 15/27] wip --- packages/perf/src/main.ts | 136 +++++++++++++++++++++++++++++++ packages/perf/test/index.spec.ts | 50 ++---------- 2 files changed, 141 insertions(+), 45 deletions(-) create mode 100644 packages/perf/src/main.ts diff --git a/packages/perf/src/main.ts b/packages/perf/src/main.ts new file mode 100644 index 0000000000..b7c93ca992 --- /dev/null +++ b/packages/perf/src/main.ts @@ -0,0 +1,136 @@ +import { mockRegistrar, mockUpgrader, mockConnectionGater, connectionPair } from '@libp2p/interface-compliance-tests/src/mocks' +import type { TransportManager } from '@libp2p/interface-internal/src/transport-manager' +import { EventEmitter } from '@libp2p/interface/src/events' +import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { PersistentPeerStore } from '@libp2p/peer-store' +import { MemoryDatastore } from 'datastore-core' +import { DefaultAddressManager } from 'libp2p/src/address-manager' +import { type Components, defaultComponents } from 'libp2p/src/components' +import { DefaultConnectionManager } from 'libp2p/src/connection-manager' +import { stubInterface } from 'sinon-ts' +import yargs from 'yargs' +import { multiaddr } from '@multiformats/multiaddr' +import type { Multiaddr } from '@multiformats/multiaddr' +import { perfService, type PerfServiceInit } from '.' +import { start } from '@libp2p/interface/src/startable' + + +export const defaultInit: PerfServiceInit = { + protocolName: '/perf/1.0.0', + maxInboundStreams: 1 << 10, + maxOutboundStreams: 1 << 10, + timeout: 10000, + writeBlockSize: BigInt(64 << 10) +} + +const argv = yargs + .options({ + 'run-server': { + type: 'boolean', + demandOption: true, + default: false, + description: 'Whether to run as a server', + }, + 'server-ip-address': { + type: 'string', + demandOption: false, + description: 'Server IP address', + default: '', + }, + 'transport': { + type: 'string', + demandOption: false, + description: 'Transport to use', + default: 'tcp' + }, + 'upload-bytes': { + type: 'number', + demandOption: false, + description: 'Number of bytes to upload', + default: 0 + }, + 'download-bytes': { + type: 'number', + demandOption: false, + description: 'Number of bytes to download', + default: 0 + }, + }) + .command('help', 'Print usage information', yargs.help) + .parseSync() + +export async function main(runServer: boolean, serverIpAddress: string, transport: string, uploadBytes: number, downloadBytes: number): void { + const listenAddrs: Multiaddr[] = [] + + if (runServer === true) { + const { host, port } = splitHostPort(serverIpAddress) + // #TODO: right now we only support tcp + listenAddrs.push(multiaddr(`/ip4/${host}/tcp/${port}`)) + } + + const localComponents = await createComponents(listenAddrs) + const remoteComponents = await createComponents() + + const client = perfService(defaultInit)(localComponents) + const server = perfService(defaultInit)(remoteComponents) + + await start(client) + await start(server) + + const startTime = Date.now() + + const [localToRemote, remoteToLocal] = connectionPair(localComponents, remoteComponents) + localComponents.events.safeDispatchEvent('connection:open', { detail: localToRemote }) + remoteComponents.events.safeDispatchEvent('connection:open', { detail: remoteToLocal }) + + await client.perf(remoteComponents.peerId, BigInt(uploadBytes), BigInt(downloadBytes)) + + const endTime = Date.now() + + console.log('latency: ' + JSON.stringify({ latency: endTime - startTime})) +} + +function splitHostPort(urlString: string): { host: string, port?: string } { + try { + const url = new URL(urlString); + return { + host: url.hostname, + port: url.port || undefined, + }; + } catch (error) { + throw Error('Invalid server address'); + } +} + + +export async function createComponents (listenMaddrs: Multiaddr[] = []): Promise { + const peerId = await createEd25519PeerId() + + const events = new EventEmitter() + + const components = defaultComponents({ + peerId, + registrar: mockRegistrar(), + upgrader: mockUpgrader(), + datastore: new MemoryDatastore(), + transportManager: stubInterface(), + connectionGater: mockConnectionGater(), + events + }) + + components.peerStore = new PersistentPeerStore(components) + components.connectionManager = new DefaultConnectionManager(components, { + minConnections: 50, + maxConnections: 1000, + autoDialInterval: 1000, + inboundUpgradeTimeout: 1000 + }) + + components.addressManager = new DefaultAddressManager(components, { + announce: listenMaddrs.map(ma => ma.toString()) + }) + + return components +} + +main(argv['run-server'], argv['server-ip-address'], argv['transport'], argv['upload-bytes'], argv['download-bytes']) \ No newline at end of file diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index f4705a78d6..cd0d333475 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -1,51 +1,11 @@ /* eslint-env mocha */ -import { EventEmitter } from '@libp2p/interface/events' import { start, stop } from '@libp2p/interface/startable' -import { connectionPair, mockConnectionGater, mockRegistrar, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' -import { PersistentPeerStore } from '@libp2p/peer-store' +import { connectionPair } from '@libp2p/interface-compliance-tests/mocks' import { expect } from 'aegir/chai' -import { MemoryDatastore } from 'datastore-core' -import { defaultComponents, type Components } from 'libp2p/components' -import { DefaultConnectionManager } from 'libp2p/connection-manager' -import { stubInterface } from 'sinon-ts' -import { perfService, type PerfServiceInit } from '../src/index.js' -import type { TransportManager } from '@libp2p/interface-internal/transport-manager' - -const defaultInit: PerfServiceInit = { - protocolName: '/perf/1.0.0', - maxInboundStreams: 1 << 10, - maxOutboundStreams: 1 << 10, - timeout: 10000, - writeBlockSize: BigInt(64 << 10) -} - -async function createComponents (): Promise { - const peerId = await createEd25519PeerId() - - const events = new EventEmitter() - - const components = defaultComponents({ - peerId, - registrar: mockRegistrar(), - upgrader: mockUpgrader(), - datastore: new MemoryDatastore(), - transportManager: stubInterface(), - connectionGater: mockConnectionGater(), - events - }) - - components.peerStore = new PersistentPeerStore(components) - components.connectionManager = new DefaultConnectionManager(components, { - minConnections: 50, - maxConnections: 1000, - autoDialInterval: 1000, - inboundUpgradeTimeout: 1000 - }) - - return components -} +import { type Components } from 'libp2p/components' +import { perfService } from '../src/index.js' +import { createComponents, defaultInit } from '../src/main.js' describe('perf', () => { let localComponents: Components @@ -84,7 +44,7 @@ describe('perf', () => { await expect(client.perf(remoteComponents.peerId, 1024n, 1024n)).to.eventually.be.fulfilled() }) - it('should output benchmark', async () => { + it('should output bandwidth', async () => { const client = perfService(defaultInit)(localComponents) const server = perfService(defaultInit)(remoteComponents) From b1d89bda6c7952b7d60f560894aadc1544cc53ce Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 26 Jul 2023 14:16:25 -0500 Subject: [PATCH 16/27] feat: added perf test and output to JSON --- packages/perf/src/index.ts | 2 +- packages/perf/src/main.ts | 68 ++++++++++++++++---------------- packages/perf/test/index.spec.ts | 2 +- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/packages/perf/src/index.ts b/packages/perf/src/index.ts index 4ac0a86c77..8ed9261a86 100644 --- a/packages/perf/src/index.ts +++ b/packages/perf/src/index.ts @@ -143,7 +143,7 @@ export class DefaultPerfService implements Startable, PerfService { } log('performed %s to %p', this.protocol, peer) - stream.close() + await stream.close() } // measureDownloadBandwidth returns the measured bandwidth in bits per second diff --git a/packages/perf/src/main.ts b/packages/perf/src/main.ts index b7c93ca992..4aa3b2a378 100644 --- a/packages/perf/src/main.ts +++ b/packages/perf/src/main.ts @@ -25,41 +25,41 @@ export const defaultInit: PerfServiceInit = { const argv = yargs .options({ - 'run-server': { - type: 'boolean', - demandOption: true, - default: false, - description: 'Whether to run as a server', - }, - 'server-ip-address': { - type: 'string', - demandOption: false, - description: 'Server IP address', - default: '', - }, - 'transport': { - type: 'string', - demandOption: false, - description: 'Transport to use', - default: 'tcp' - }, - 'upload-bytes': { - type: 'number', - demandOption: false, - description: 'Number of bytes to upload', - default: 0 - }, - 'download-bytes': { - type: 'number', - demandOption: false, - description: 'Number of bytes to download', - default: 0 - }, + 'run-server': { + type: 'boolean', + demandOption: true, + default: false, + description: 'Whether to run as a server', + }, + 'server-ip-address': { + type: 'string', + demandOption: false, + description: 'Server IP address', + default: '', + }, + 'transport': { + type: 'string', + demandOption: false, + description: 'Transport to use', + default: 'tcp' + }, + 'upload-bytes': { + type: 'number', + demandOption: false, + description: 'Number of bytes to upload', + default: 0 + }, + 'download-bytes': { + type: 'number', + demandOption: false, + description: 'Number of bytes to download', + default: 0 + }, }) .command('help', 'Print usage information', yargs.help) .parseSync() -export async function main(runServer: boolean, serverIpAddress: string, transport: string, uploadBytes: number, downloadBytes: number): void { +export async function main(runServer: boolean, serverIpAddress: string, transport: string, uploadBytes: number, downloadBytes: number): Promise { const listenAddrs: Multiaddr[] = [] if (runServer === true) { @@ -72,10 +72,10 @@ export async function main(runServer: boolean, serverIpAddress: string, transpor const remoteComponents = await createComponents() const client = perfService(defaultInit)(localComponents) - const server = perfService(defaultInit)(remoteComponents) + const server = perfService(defaultInit)(remoteComponents) - await start(client) - await start(server) + await start(client) + await start(server) const startTime = Date.now() diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index cd0d333475..e0ee3a22fd 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -3,7 +3,7 @@ import { start, stop } from '@libp2p/interface/startable' import { connectionPair } from '@libp2p/interface-compliance-tests/mocks' import { expect } from 'aegir/chai' -import { type Components } from 'libp2p/components' +import type { Components } from 'libp2p/components' import { perfService } from '../src/index.js' import { createComponents, defaultInit } from '../src/main.js' From ccd5f26b98b8cf2bea5f85f96f4f597eed6a3af9 Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 26 Jul 2023 18:21:08 -0500 Subject: [PATCH 17/27] chore: linting fixes --- packages/perf/package.json | 1 + packages/perf/src/main.ts | 141 ++++++++++++++++--------------- packages/perf/test/index.spec.ts | 4 +- 3 files changed, 75 insertions(+), 71 deletions(-) diff --git a/packages/perf/package.json b/packages/perf/package.json index 411066281c..f0076bae95 100644 --- a/packages/perf/package.json +++ b/packages/perf/package.json @@ -26,6 +26,7 @@ } }, "scripts": { + "start": "node dist/src/main.js", "build": "aegir build", "test": "aegir test", "clean": "aegir clean", diff --git a/packages/perf/src/main.ts b/packages/perf/src/main.ts index 4aa3b2a378..fb9d17ed80 100644 --- a/packages/perf/src/main.ts +++ b/packages/perf/src/main.ts @@ -1,19 +1,18 @@ -import { mockRegistrar, mockUpgrader, mockConnectionGater, connectionPair } from '@libp2p/interface-compliance-tests/src/mocks' -import type { TransportManager } from '@libp2p/interface-internal/src/transport-manager' -import { EventEmitter } from '@libp2p/interface/src/events' +import { EventEmitter } from '@libp2p/interface/events' +import { start } from '@libp2p/interface/startable' +import { mockRegistrar, mockUpgrader, mockConnectionGater, connectionPair } from '@libp2p/interface-compliance-tests/mocks' import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { PersistentPeerStore } from '@libp2p/peer-store' +import { multiaddr } from '@multiformats/multiaddr' import { MemoryDatastore } from 'datastore-core' import { DefaultAddressManager } from 'libp2p/src/address-manager' import { type Components, defaultComponents } from 'libp2p/src/components' import { DefaultConnectionManager } from 'libp2p/src/connection-manager' import { stubInterface } from 'sinon-ts' import yargs from 'yargs' -import { multiaddr } from '@multiformats/multiaddr' -import type { Multiaddr } from '@multiformats/multiaddr' import { perfService, type PerfServiceInit } from '.' -import { start } from '@libp2p/interface/src/startable' - +import type { TransportManager } from '@libp2p/interface-internal/transport-manager' +import type { Multiaddr } from '@multiformats/multiaddr' export const defaultInit: PerfServiceInit = { protocolName: '/perf/1.0.0', @@ -24,85 +23,85 @@ export const defaultInit: PerfServiceInit = { } const argv = yargs - .options({ - 'run-server': { - type: 'boolean', - demandOption: true, - default: false, - description: 'Whether to run as a server', - }, - 'server-ip-address': { - type: 'string', - demandOption: false, - description: 'Server IP address', - default: '', - }, - 'transport': { - type: 'string', - demandOption: false, - description: 'Transport to use', - default: 'tcp' - }, - 'upload-bytes': { - type: 'number', - demandOption: false, - description: 'Number of bytes to upload', - default: 0 - }, - 'download-bytes': { - type: 'number', - demandOption: false, - description: 'Number of bytes to download', - default: 0 - }, - }) - .command('help', 'Print usage information', yargs.help) - .parseSync() - -export async function main(runServer: boolean, serverIpAddress: string, transport: string, uploadBytes: number, downloadBytes: number): Promise { - const listenAddrs: Multiaddr[] = [] - - if (runServer === true) { - const { host, port } = splitHostPort(serverIpAddress) - // #TODO: right now we only support tcp - listenAddrs.push(multiaddr(`/ip4/${host}/tcp/${port}`)) - } - - const localComponents = await createComponents(listenAddrs) - const remoteComponents = await createComponents() - - const client = perfService(defaultInit)(localComponents) + .options({ + 'run-server': { + type: 'boolean', + demandOption: true, + default: false, + description: 'Whether to run as a server' + }, + 'server-ip-address': { + type: 'string', + demandOption: false, + description: 'Server IP address', + default: '' + }, + transport: { + type: 'string', + demandOption: false, + description: 'Transport to use', + default: 'tcp' + }, + 'upload-bytes': { + type: 'number', + demandOption: false, + description: 'Number of bytes to upload', + default: 0 + }, + 'download-bytes': { + type: 'number', + demandOption: false, + description: 'Number of bytes to download', + default: 0 + } + }) + .command('help', 'Print usage information', yargs.help) + .parseSync() + +export async function main (runServer: boolean, serverIpAddress: string, transport: string, uploadBytes: number, downloadBytes: number): Promise { + const listenAddrs: Multiaddr[] = [] + + if (runServer) { + const { host, port } = splitHostPort(serverIpAddress) + // #TODO: right now we only support tcp + listenAddrs.push(multiaddr(`/ip4/${host}/tcp/${port}`)) + } + + const localComponents = await createComponents(listenAddrs) + const remoteComponents = await createComponents() + + const client = perfService(defaultInit)(localComponents) const server = perfService(defaultInit)(remoteComponents) await start(client) await start(server) - const startTime = Date.now() + const startTime = Date.now() - const [localToRemote, remoteToLocal] = connectionPair(localComponents, remoteComponents) - localComponents.events.safeDispatchEvent('connection:open', { detail: localToRemote }) - remoteComponents.events.safeDispatchEvent('connection:open', { detail: remoteToLocal }) + const [localToRemote, remoteToLocal] = connectionPair(localComponents, remoteComponents) + localComponents.events.safeDispatchEvent('connection:open', { detail: localToRemote }) + remoteComponents.events.safeDispatchEvent('connection:open', { detail: remoteToLocal }) - await client.perf(remoteComponents.peerId, BigInt(uploadBytes), BigInt(downloadBytes)) + await client.perf(remoteComponents.peerId, BigInt(uploadBytes), BigInt(downloadBytes)) - const endTime = Date.now() + const endTime = Date.now() - console.log('latency: ' + JSON.stringify({ latency: endTime - startTime})) + // eslint-disable-next-line no-console + console.log('latency: ' + JSON.stringify({ latency: endTime - startTime })) } -function splitHostPort(urlString: string): { host: string, port?: string } { +function splitHostPort (urlString: string): { host: string, port?: string } { try { - const url = new URL(urlString); + const url = new URL(urlString) return { host: url.hostname, - port: url.port || undefined, - }; + port: url.port + } } catch (error) { - throw Error('Invalid server address'); + throw Error('Invalid server address') } } - export async function createComponents (listenMaddrs: Multiaddr[] = []): Promise { const peerId = await createEd25519PeerId() @@ -133,4 +132,8 @@ export async function createComponents (listenMaddrs: Multiaddr[] = []): Promise return components } -main(argv['run-server'], argv['server-ip-address'], argv['transport'], argv['upload-bytes'], argv['download-bytes']) \ No newline at end of file +main(argv['run-server'], argv['server-ip-address'], argv.transport, argv['upload-bytes'], argv['download-bytes']).catch((err) => { + // eslint-disable-next-line no-console + console.error(err) + process.exit(1) +}) diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index e0ee3a22fd..8758c2c0db 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -3,9 +3,9 @@ import { start, stop } from '@libp2p/interface/startable' import { connectionPair } from '@libp2p/interface-compliance-tests/mocks' import { expect } from 'aegir/chai' -import type { Components } from 'libp2p/components' -import { perfService } from '../src/index.js' +import { perfService } from '../src/index.js' import { createComponents, defaultInit } from '../src/main.js' +import type { Components } from 'libp2p/components' describe('perf', () => { let localComponents: Components From 7f9c716395c6b3f9046dfc47d7ffe2af596d8e80 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 27 Jul 2023 23:20:29 -0500 Subject: [PATCH 18/27] deps(dev): upgrade aegir --- packages/perf/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/perf/package.json b/packages/perf/package.json index f0076bae95..fb880b070c 100644 --- a/packages/perf/package.json +++ b/packages/perf/package.json @@ -53,7 +53,7 @@ "libp2p": "^0.45.9" }, "devDependencies": { - "aegir": "^39.0.10", + "aegir": "^40.0.2", "sinon-ts": "1.0.0" }, "typedoc": { From 35c79a40d7b2d9fc1bfc9a38df729f3785204706 Mon Sep 17 00:00:00 2001 From: chad Date: Fri, 28 Jul 2023 11:43:19 -0500 Subject: [PATCH 19/27] deps: install missing deps --- packages/perf/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/perf/package.json b/packages/perf/package.json index fb880b070c..062e1093a5 100644 --- a/packages/perf/package.json +++ b/packages/perf/package.json @@ -48,9 +48,11 @@ "@libp2p/logger": "^2.1.1", "@libp2p/peer-id-factory": "2.0.4", "@libp2p/peer-store": "8.2.1", + "@multiformats/multiaddr": "^12.1.3", "any-signal": "^4.1.1", "datastore-core": "9.2.0", - "libp2p": "^0.45.9" + "libp2p": "^0.45.9", + "yargs": "^17.7.2" }, "devDependencies": { "aegir": "^40.0.2", From 8ba8db32926de830078c100551c939c746e2966d Mon Sep 17 00:00:00 2001 From: chad Date: Sun, 30 Jul 2023 12:15:19 -0500 Subject: [PATCH 20/27] refactor: refactored main runner --- packages/libp2p/package.json | 4 +++ packages/perf/src/index.ts | 8 +++++ packages/perf/src/main.ts | 52 ++------------------------------ packages/perf/test/index.spec.ts | 46 +++++++++++++++++++++++++--- 4 files changed, 57 insertions(+), 53 deletions(-) diff --git a/packages/libp2p/package.json b/packages/libp2p/package.json index 0de9617d03..b5e89939d3 100644 --- a/packages/libp2p/package.json +++ b/packages/libp2p/package.json @@ -52,6 +52,10 @@ "types": "./dist/src/autonat/index.d.ts", "import": "./dist/src/autonat/index.js" }, + "./address-manager": { + "types": "./dist/src/address-manager/index.d.ts", + "import": "./dist/src/address-manager/index.js" + }, "./circuit-relay": { "types": "./dist/src/circuit-relay/index.d.ts", "import": "./dist/src/circuit-relay/index.js" diff --git a/packages/perf/src/index.ts b/packages/perf/src/index.ts index 8ed9261a86..a52a4b2e1b 100644 --- a/packages/perf/src/index.ts +++ b/packages/perf/src/index.ts @@ -9,6 +9,14 @@ import type { AbortOptions } from '@libp2p/interfaces' const log = logger('libp2p:perf') +export const defaultInit: PerfServiceInit = { + protocolName: '/perf/1.0.0', + maxInboundStreams: 1 << 10, + maxOutboundStreams: 1 << 10, + timeout: 10000, + writeBlockSize: BigInt(64 << 10) +} + export interface PerfService { perf: (peer: PeerId, sendBytes: bigint, recvBytes: bigint, options?: AbortOptions) => Promise measureDownloadBandwidth: (peer: PeerId, size: bigint) => Promise diff --git a/packages/perf/src/main.ts b/packages/perf/src/main.ts index fb9d17ed80..4881874624 100644 --- a/packages/perf/src/main.ts +++ b/packages/perf/src/main.ts @@ -1,27 +1,11 @@ -import { EventEmitter } from '@libp2p/interface/events' import { start } from '@libp2p/interface/startable' -import { mockRegistrar, mockUpgrader, mockConnectionGater, connectionPair } from '@libp2p/interface-compliance-tests/mocks' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' -import { PersistentPeerStore } from '@libp2p/peer-store' +import { connectionPair } from '@libp2p/interface-compliance-tests/mocks' import { multiaddr } from '@multiformats/multiaddr' -import { MemoryDatastore } from 'datastore-core' -import { DefaultAddressManager } from 'libp2p/src/address-manager' -import { type Components, defaultComponents } from 'libp2p/src/components' -import { DefaultConnectionManager } from 'libp2p/src/connection-manager' -import { stubInterface } from 'sinon-ts' import yargs from 'yargs' -import { perfService, type PerfServiceInit } from '.' -import type { TransportManager } from '@libp2p/interface-internal/transport-manager' +import { defaultInit, perfService } from '../src/index.js' +import { createComponents } from '../test/index.spec.js' import type { Multiaddr } from '@multiformats/multiaddr' -export const defaultInit: PerfServiceInit = { - protocolName: '/perf/1.0.0', - maxInboundStreams: 1 << 10, - maxOutboundStreams: 1 << 10, - timeout: 10000, - writeBlockSize: BigInt(64 << 10) -} - const argv = yargs .options({ 'run-server': { @@ -102,36 +86,6 @@ function splitHostPort (urlString: string): { host: string, port?: string } { } } -export async function createComponents (listenMaddrs: Multiaddr[] = []): Promise { - const peerId = await createEd25519PeerId() - - const events = new EventEmitter() - - const components = defaultComponents({ - peerId, - registrar: mockRegistrar(), - upgrader: mockUpgrader(), - datastore: new MemoryDatastore(), - transportManager: stubInterface(), - connectionGater: mockConnectionGater(), - events - }) - - components.peerStore = new PersistentPeerStore(components) - components.connectionManager = new DefaultConnectionManager(components, { - minConnections: 50, - maxConnections: 1000, - autoDialInterval: 1000, - inboundUpgradeTimeout: 1000 - }) - - components.addressManager = new DefaultAddressManager(components, { - announce: listenMaddrs.map(ma => ma.toString()) - }) - - return components -} - main(argv['run-server'], argv['server-ip-address'], argv.transport, argv['upload-bytes'], argv['download-bytes']).catch((err) => { // eslint-disable-next-line no-console console.error(err) diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index 8758c2c0db..aecaa61664 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -1,11 +1,49 @@ /* eslint-env mocha */ +import { EventEmitter } from '@libp2p/interface/events' import { start, stop } from '@libp2p/interface/startable' -import { connectionPair } from '@libp2p/interface-compliance-tests/mocks' +import { connectionPair, mockConnectionGater, mockRegistrar, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' +import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { PersistentPeerStore } from '@libp2p/peer-store' import { expect } from 'aegir/chai' -import { perfService } from '../src/index.js' -import { createComponents, defaultInit } from '../src/main.js' -import type { Components } from 'libp2p/components' +import { MemoryDatastore } from 'datastore-core' +import { DefaultAddressManager } from 'libp2p/address-manager' +import { type Components, defaultComponents } from 'libp2p/components' +import { DefaultConnectionManager } from 'libp2p/connection-manager' +import { stubInterface } from 'sinon-ts' +import { defaultInit, perfService } from '../src/index.js' +import type { TransportManager } from '@libp2p/interface-internal/transport-manager' +import type { Multiaddr } from '@multiformats/multiaddr' + +export async function createComponents (listenMaddrs: Multiaddr[] = []): Promise { + const peerId = await createEd25519PeerId() + + const events = new EventEmitter() + + const components = defaultComponents({ + peerId, + registrar: mockRegistrar(), + upgrader: mockUpgrader(), + datastore: new MemoryDatastore(), + transportManager: stubInterface(), + connectionGater: mockConnectionGater(), + events + }) + + components.peerStore = new PersistentPeerStore(components) + components.connectionManager = new DefaultConnectionManager(components, { + minConnections: 50, + maxConnections: 1000, + autoDialInterval: 1000, + inboundUpgradeTimeout: 1000 + }) + + components.addressManager = new DefaultAddressManager(components, { + announce: listenMaddrs.map(ma => ma.toString()) + }) + + return components +} describe('perf', () => { let localComponents: Components From f9b91cbed9a9834ddb06fa473b76e745db90a87a Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 2 Aug 2023 18:23:58 -0500 Subject: [PATCH 21/27] feat: updated main to use fake peer id for client mode perf --- packages/perf/package.json | 3 ++ packages/perf/src/main.ts | 80 +++++++++++++++++++++----------- packages/perf/test/index.spec.ts | 5 -- 3 files changed, 57 insertions(+), 31 deletions(-) diff --git a/packages/perf/package.json b/packages/perf/package.json index 062e1093a5..dcf8314908 100644 --- a/packages/perf/package.json +++ b/packages/perf/package.json @@ -40,14 +40,17 @@ "renderResults": "node dist/src/renderResults.js" }, "dependencies": { + "@chainsafe/libp2p-yamux": "^4.0.2", "@libp2p/interface": "^0.0.1", "@libp2p/interface-compliance-tests": "^3.0.7", "@libp2p/interface-internal": "^0.0.1", "@libp2p/interface-peer-id": "2.0.2", "@libp2p/interfaces": "3.3.2", "@libp2p/logger": "^2.1.1", + "@libp2p/peer-id": "^2.0.3", "@libp2p/peer-id-factory": "2.0.4", "@libp2p/peer-store": "8.2.1", + "@libp2p/tcp": "^7.0.3", "@multiformats/multiaddr": "^12.1.3", "any-signal": "^4.1.1", "datastore-core": "9.2.0", diff --git a/packages/perf/src/main.ts b/packages/perf/src/main.ts index 4881874624..a761e43b65 100644 --- a/packages/perf/src/main.ts +++ b/packages/perf/src/main.ts @@ -1,12 +1,16 @@ -import { start } from '@libp2p/interface/startable' -import { connectionPair } from '@libp2p/interface-compliance-tests/mocks' +import { yamux } from '@chainsafe/libp2p-yamux' +import { peerIdFromString } from '@libp2p/peer-id' +import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { tcp } from '@libp2p/tcp' import { multiaddr } from '@multiformats/multiaddr' +import { createLibp2p } from 'libp2p' +import { plaintext } from 'libp2p/insecure' import yargs from 'yargs' +import { hideBin } from 'yargs/helpers' import { defaultInit, perfService } from '../src/index.js' -import { createComponents } from '../test/index.spec.js' -import type { Multiaddr } from '@multiformats/multiaddr' +import type { PeerId } from '@libp2p/interface-peer-id' -const argv = yargs +const argv = yargs(hideBin(process.argv)) .options({ 'run-server': { type: 'boolean', @@ -14,7 +18,7 @@ const argv = yargs default: false, description: 'Whether to run as a server' }, - 'server-ip-address': { + 'server-address': { type: 'string', demandOption: false, description: 'Server IP address', @@ -43,50 +47,74 @@ const argv = yargs .parseSync() export async function main (runServer: boolean, serverIpAddress: string, transport: string, uploadBytes: number, downloadBytes: number): Promise { - const listenAddrs: Multiaddr[] = [] + let peerId: PeerId - if (runServer) { - const { host, port } = splitHostPort(serverIpAddress) - // #TODO: right now we only support tcp - listenAddrs.push(multiaddr(`/ip4/${host}/tcp/${port}`)) + const listenAddrs: string[] = [] + + const { host, port } = splitHostPort(serverIpAddress) + // #TODO: right now we only support tcp + const tcpMultiaddr = multiaddr(`/ip4/${host}/tcp/${port}`) + + const config = { + transports: [tcp()], + streamMuxers: [yamux()], + connectionEncryption: [ + plaintext() + ], + services: { + perf: perfService(defaultInit) + } } - const localComponents = await createComponents(listenAddrs) - const remoteComponents = await createComponents() + if (runServer) { + peerId = await createEd25519PeerId() + listenAddrs.push(`${tcpMultiaddr.toString()}/p2p/${peerId.toString()}`) - const client = perfService(defaultInit)(localComponents) - const server = perfService(defaultInit)(remoteComponents) + Object.assign(config, { + peerId, + addresses: { + listen: listenAddrs + } + }) + } else { + peerId = peerIdFromString('12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN') + } + + const node = await createLibp2p(config) - await start(client) - await start(server) + await node.start() const startTime = Date.now() - const [localToRemote, remoteToLocal] = connectionPair(localComponents, remoteComponents) - localComponents.events.safeDispatchEvent('connection:open', { detail: localToRemote }) - remoteComponents.events.safeDispatchEvent('connection:open', { detail: remoteToLocal }) + if (!runServer) { + await node.dial(multiaddr(`${tcpMultiaddr.toString()}/p2p/${peerId.toString()}`)) + } - await client.perf(remoteComponents.peerId, BigInt(uploadBytes), BigInt(downloadBytes)) + await node.services.perf.perf(peerId, BigInt(uploadBytes), BigInt(downloadBytes)) const endTime = Date.now() + await node.stop() + // eslint-disable-next-line no-console console.log('latency: ' + JSON.stringify({ latency: endTime - startTime })) } -function splitHostPort (urlString: string): { host: string, port?: string } { +function splitHostPort (address: string): { host: string, port?: string } { try { - const url = new URL(urlString) + const parts = address.split(':') + const host = parts[0] + const port = parts[1] return { - host: url.hostname, - port: url.port + host, + port } } catch (error) { throw Error('Invalid server address') } } -main(argv['run-server'], argv['server-ip-address'], argv.transport, argv['upload-bytes'], argv['download-bytes']).catch((err) => { +main(argv['run-server'], argv['server-address'], argv.transport, argv['upload-bytes'], argv['download-bytes']).catch((err) => { // eslint-disable-next-line no-console console.error(err) process.exit(1) diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index aecaa61664..b65c1f5f32 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -7,7 +7,6 @@ import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { PersistentPeerStore } from '@libp2p/peer-store' import { expect } from 'aegir/chai' import { MemoryDatastore } from 'datastore-core' -import { DefaultAddressManager } from 'libp2p/address-manager' import { type Components, defaultComponents } from 'libp2p/components' import { DefaultConnectionManager } from 'libp2p/connection-manager' import { stubInterface } from 'sinon-ts' @@ -38,10 +37,6 @@ export async function createComponents (listenMaddrs: Multiaddr[] = []): Promise inboundUpgradeTimeout: 1000 }) - components.addressManager = new DefaultAddressManager(components, { - announce: listenMaddrs.map(ma => ma.toString()) - }) - return components } From 68dfd6888453e57e850fa75fc980fa5db68c522e Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 3 Aug 2023 22:34:23 -0500 Subject: [PATCH 22/27] feat: fixed issue with run server + added stable peer id --- packages/perf/package.json | 5 ++-- packages/perf/src/index.ts | 42 +++++++++++++++----------------- packages/perf/src/main.ts | 38 +++++++++++++++++++---------- packages/perf/test/index.spec.ts | 10 +++----- 4 files changed, 52 insertions(+), 43 deletions(-) diff --git a/packages/perf/package.json b/packages/perf/package.json index dcf8314908..396ac9d344 100644 --- a/packages/perf/package.json +++ b/packages/perf/package.json @@ -41,13 +41,12 @@ }, "dependencies": { "@chainsafe/libp2p-yamux": "^4.0.2", + "@libp2p/crypto": "^1.0.17", "@libp2p/interface": "^0.0.1", "@libp2p/interface-compliance-tests": "^3.0.7", "@libp2p/interface-internal": "^0.0.1", - "@libp2p/interface-peer-id": "2.0.2", "@libp2p/interfaces": "3.3.2", "@libp2p/logger": "^2.1.1", - "@libp2p/peer-id": "^2.0.3", "@libp2p/peer-id-factory": "2.0.4", "@libp2p/peer-store": "8.2.1", "@libp2p/tcp": "^7.0.3", @@ -55,6 +54,8 @@ "any-signal": "^4.1.1", "datastore-core": "9.2.0", "libp2p": "^0.45.9", + "p-wait-for": "^5.0.2", + "uint8arrays": "^4.0.6", "yargs": "^17.7.2" }, "devDependencies": { diff --git a/packages/perf/src/index.ts b/packages/perf/src/index.ts index a52a4b2e1b..2c449800cf 100644 --- a/packages/perf/src/index.ts +++ b/packages/perf/src/index.ts @@ -4,8 +4,8 @@ import { MAX_INBOUND_STREAMS, PROTOCOL_NAME, TIMEOUT, WRITE_BLOCK_SIZE } from '. import type { Startable } from '@libp2p/interface/startable' import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager' import type { IncomingStreamData, Registrar } from '@libp2p/interface-internal/registrar' -import type { PeerId } from '@libp2p/interface-peer-id' import type { AbortOptions } from '@libp2p/interfaces' +import type { Connection } from '@libp2p/interface/src/connection/index.js' const log = logger('libp2p:perf') @@ -18,9 +18,9 @@ export const defaultInit: PerfServiceInit = { } export interface PerfService { - perf: (peer: PeerId, sendBytes: bigint, recvBytes: bigint, options?: AbortOptions) => Promise - measureDownloadBandwidth: (peer: PeerId, size: bigint) => Promise - measureUploadBandwidth: (peer: PeerId, size: bigint) => Promise + perf: (connection: Connection, sendBytes: bigint, recvBytes: bigint, options?: AbortOptions) => Promise + // measureDownloadBandwidth: (peer: PeerId, size: bigint) => Promise + // measureUploadBandwidth: (peer: PeerId, size: bigint) => Promise } export interface PerfServiceInit { @@ -106,15 +106,13 @@ export class DefaultPerfService implements Startable, PerfService { }()) } - async perf (peer: PeerId, sendBytes: bigint, recvBytes: bigint, options: AbortOptions = {}): Promise { - log('opening stream on protocol %s to %p', this.protocol, peer) + async perf (connection: Connection, sendBytes: bigint, recvBytes: bigint, options: AbortOptions = {}): Promise { + log('opening stream on protocol %s to %p', this.protocol, connection.remotePeer) const uint8Buf = new Uint8Array(this.databuf) const writeBlockSize = this.writeBlockSize - const connection = await this.components.connectionManager.openConnection(peer, options) - const signal = anySignal([AbortSignal.timeout(this.timeout), options?.signal]) const stream = await connection.newStream([this.protocol], { signal @@ -124,7 +122,7 @@ export class DefaultPerfService implements Startable, PerfService { const view = new DataView(this.databuf) view.setBigInt64(0, recvBytes, false) - log('sending %i bytes to %p', sendBytes, peer) + log('sending %i bytes to %p', sendBytes, connection.remotePeer) await stream.sink((async function * () { // Send the number of bytes to receive @@ -150,23 +148,23 @@ export class DefaultPerfService implements Startable, PerfService { throw new Error(`Expected to receive ${recvBytes} bytes, but received ${actualRecvdBytes}`) } - log('performed %s to %p', this.protocol, peer) + log('performed %s to %p', this.protocol, connection.remotePeer) await stream.close() } // measureDownloadBandwidth returns the measured bandwidth in bits per second - async measureDownloadBandwidth (peer: PeerId, size: bigint): Promise { - const now = Date.now() - await this.perf(peer, 0n, size) - return Number((8000n * size) / BigInt(Date.now() - now)) - } - - // measureUploadBandwidth returns the measured bandwidth in bit per second - async measureUploadBandwidth (peer: PeerId, size: bigint): Promise { - const now = Date.now() - await this.perf(peer, size, 0n) - return Number((8000n * size) / BigInt(Date.now() - now)) - } + // async measureDownloadBandwidth (peer: PeerId, size: bigint): Promise { + // const now = Date.now() + // await this.perf(connection, 0n, size) + // return Number((8000n * size) / BigInt(Date.now() - now)) + // } + + // // measureUploadBandwidth returns the measured bandwidth in bit per second + // async measureUploadBandwidth (peer: PeerId, size: bigint): Promise { + // const now = Date.now() + // await this.perf(peer, size, 0n) + // return Number((8000n * size) / BigInt(Date.now() - now)) + // } } export function perfService (init: PerfServiceInit = {}): (components: PerfServiceComponents) => PerfService { diff --git a/packages/perf/src/main.ts b/packages/perf/src/main.ts index a761e43b65..d928049f03 100644 --- a/packages/perf/src/main.ts +++ b/packages/perf/src/main.ts @@ -1,6 +1,5 @@ import { yamux } from '@chainsafe/libp2p-yamux' -import { peerIdFromString } from '@libp2p/peer-id' -import { createEd25519PeerId } from '@libp2p/peer-id-factory' +import { createFromPrivKey } from '@libp2p/peer-id-factory' import { tcp } from '@libp2p/tcp' import { multiaddr } from '@multiformats/multiaddr' import { createLibp2p } from 'libp2p' @@ -8,7 +7,11 @@ import { plaintext } from 'libp2p/insecure' import yargs from 'yargs' import { hideBin } from 'yargs/helpers' import { defaultInit, perfService } from '../src/index.js' -import type { PeerId } from '@libp2p/interface-peer-id' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { unmarshalPrivateKey } from '@libp2p/crypto/keys' +import type { Connection } from '@libp2p/interface/connection' +import pWaitFor from 'p-wait-for' + const argv = yargs(hideBin(process.argv)) .options({ @@ -47,8 +50,6 @@ const argv = yargs(hideBin(process.argv)) .parseSync() export async function main (runServer: boolean, serverIpAddress: string, transport: string, uploadBytes: number, downloadBytes: number): Promise { - let peerId: PeerId - const listenAddrs: string[] = [] const { host, port } = splitHostPort(serverIpAddress) @@ -66,9 +67,14 @@ export async function main (runServer: boolean, serverIpAddress: string, transpo } } - if (runServer) { - peerId = await createEd25519PeerId() - listenAddrs.push(`${tcpMultiaddr.toString()}/p2p/${peerId.toString()}`) + const testPrivKey = 'CAASpgkwggSiAgEAAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAECggEAZtju/bcKvKFPz0mkHiaJcpycy9STKphorpCT83srBVQi59CdFU6Mj+aL/xt0kCPMVigJw8P3/YCEJ9J+rS8BsoWE+xWUEsJvtXoT7vzPHaAtM3ci1HZd302Mz1+GgS8Epdx+7F5p80XAFLDUnELzOzKftvWGZmWfSeDnslwVONkL/1VAzwKy7Ce6hk4SxRE7l2NE2OklSHOzCGU1f78ZzVYKSnS5Ag9YrGjOAmTOXDbKNKN/qIorAQ1bovzGoCwx3iGIatQKFOxyVCyO1PsJYT7JO+kZbhBWRRE+L7l+ppPER9bdLFxs1t5CrKc078h+wuUr05S1P1JjXk68pk3+kQKBgQDeK8AR11373Mzib6uzpjGzgNRMzdYNuExWjxyxAzz53NAR7zrPHvXvfIqjDScLJ4NcRO2TddhXAfZoOPVH5k4PJHKLBPKuXZpWlookCAyENY7+Pd55S8r+a+MusrMagYNljb5WbVTgN8cgdpim9lbbIFlpN6SZaVjLQL3J8TWH6wKBgQDSChzItkqWX11CNstJ9zJyUE20I7LrpyBJNgG1gtvz3ZMUQCn3PxxHtQzN9n1P0mSSYs+jBKPuoSyYLt1wwe10/lpgL4rkKWU3/m1Myt0tveJ9WcqHh6tzcAbb/fXpUFT/o4SWDimWkPkuCb+8j//2yiXk0a/T2f36zKMuZvujqQKBgC6B7BAQDG2H2B/ijofp12ejJU36nL98gAZyqOfpLJ+FeMz4TlBDQ+phIMhnHXA5UkdDapQ+zA3SrFk+6yGk9Vw4Hf46B+82SvOrSbmnMa+PYqKYIvUzR4gg34rL/7AhwnbEyD5hXq4dHwMNsIDq+l2elPjwm/U9V0gdAl2+r50HAoGALtsKqMvhv8HucAMBPrLikhXP/8um8mMKFMrzfqZ+otxfHzlhI0L08Bo3jQrb0Z7ByNY6M8epOmbCKADsbWcVre/AAY0ZkuSZK/CaOXNX/AhMKmKJh8qAOPRY02LIJRBCpfS4czEdnfUhYV/TYiFNnKRj57PPYZdTzUsxa/yVTmECgYBr7slQEjb5Onn5mZnGDh+72BxLNdgwBkhO0OCdpdISqk0F0Pxby22DFOKXZEpiyI9XYP1C8wPiJsShGm2yEwBPWXnrrZNWczaVuCbXHrZkWQogBDG3HGXNdU4MAWCyiYlyinIBpPpoAJZSzpGLmWbMWh28+RJS6AQX6KHrK1o2uw==' + const encoded = uint8ArrayFromString(testPrivKey, 'base64pad') + const privateKey = await unmarshalPrivateKey(encoded) + const peerId = await createFromPrivKey(privateKey) + const tcpMultiaddrAddress = `${tcpMultiaddr.toString()}/p2p/${peerId.toString()}` + + if (runServer === true) { + listenAddrs.push(tcpMultiaddrAddress) Object.assign(config, { peerId, @@ -76,8 +82,6 @@ export async function main (runServer: boolean, serverIpAddress: string, transpo listen: listenAddrs } }) - } else { - peerId = peerIdFromString('12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN') } const node = await createLibp2p(config) @@ -86,11 +90,19 @@ export async function main (runServer: boolean, serverIpAddress: string, transpo const startTime = Date.now() - if (!runServer) { - await node.dial(multiaddr(`${tcpMultiaddr.toString()}/p2p/${peerId.toString()}`)) + let connection: any = null + + if (runServer === true) { + node.addEventListener('connection:open', (eventInfo) => { + connection = eventInfo.detail + }) + } else { + connection = await node.dial(multiaddr(tcpMultiaddrAddress)) } - await node.services.perf.perf(peerId, BigInt(uploadBytes), BigInt(downloadBytes)) + await pWaitFor(() => connection != null) + + await node.services.perf.perf(connection as Connection, BigInt(uploadBytes), BigInt(downloadBytes)) const endTime = Date.now() diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index b65c1f5f32..833424f143 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -5,16 +5,14 @@ import { start, stop } from '@libp2p/interface/startable' import { connectionPair, mockConnectionGater, mockRegistrar, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { PersistentPeerStore } from '@libp2p/peer-store' -import { expect } from 'aegir/chai' import { MemoryDatastore } from 'datastore-core' import { type Components, defaultComponents } from 'libp2p/components' import { DefaultConnectionManager } from 'libp2p/connection-manager' import { stubInterface } from 'sinon-ts' import { defaultInit, perfService } from '../src/index.js' import type { TransportManager } from '@libp2p/interface-internal/transport-manager' -import type { Multiaddr } from '@multiformats/multiaddr' -export async function createComponents (listenMaddrs: Multiaddr[] = []): Promise { +export async function createComponents (): Promise { const peerId = await createEd25519PeerId() const events = new EventEmitter() @@ -74,7 +72,7 @@ describe('perf', () => { remoteComponents.events.safeDispatchEvent('connection:open', { detail: remoteToLocal }) // Run Perf - await expect(client.perf(remoteComponents.peerId, 1024n, 1024n)).to.eventually.be.fulfilled() + // await expect(client.perf(remoteComponents.peerId, 1024n, 1024n)).to.eventually.be.fulfilled() }) it('should output bandwidth', async () => { @@ -94,8 +92,8 @@ describe('perf', () => { for (let i = 1; i < 5; i++) { // Run Perf - downloadBandwidth += await client.measureDownloadBandwidth(remoteComponents.peerId, 10485760n) - uploadBandwidth += await client.measureUploadBandwidth(remoteComponents.peerId, 10485760n) + // downloadBandwidth += await client.measureDownloadBandwidth(remoteComponents.peerId, 10485760n) + // uploadBandwidth += await client.measureUploadBandwidth(remoteComponents.peerId, 10485760n) } // eslint-disable-next-line no-console From 0bff620a43859424a50b54cfed5bbeddc98397fd Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 3 Aug 2023 22:44:01 -0500 Subject: [PATCH 23/27] refactor: Updated tests + perf signature + linting --- packages/perf/src/index.ts | 30 +++++++++++++++--------------- packages/perf/src/main.ts | 13 ++++++------- packages/perf/test/index.spec.ts | 9 +++++---- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/packages/perf/src/index.ts b/packages/perf/src/index.ts index 2c449800cf..d19e802f23 100644 --- a/packages/perf/src/index.ts +++ b/packages/perf/src/index.ts @@ -1,11 +1,11 @@ import { logger } from '@libp2p/logger' import { anySignal } from 'any-signal' import { MAX_INBOUND_STREAMS, PROTOCOL_NAME, TIMEOUT, WRITE_BLOCK_SIZE } from './constants.js' +import type { Connection } from '@libp2p/interface/src/connection/index.js' import type { Startable } from '@libp2p/interface/startable' import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager' import type { IncomingStreamData, Registrar } from '@libp2p/interface-internal/registrar' import type { AbortOptions } from '@libp2p/interfaces' -import type { Connection } from '@libp2p/interface/src/connection/index.js' const log = logger('libp2p:perf') @@ -19,8 +19,8 @@ export const defaultInit: PerfServiceInit = { export interface PerfService { perf: (connection: Connection, sendBytes: bigint, recvBytes: bigint, options?: AbortOptions) => Promise - // measureDownloadBandwidth: (peer: PeerId, size: bigint) => Promise - // measureUploadBandwidth: (peer: PeerId, size: bigint) => Promise + measureDownloadBandwidth: (connection: Connection, size: bigint) => Promise + measureUploadBandwidth: (connection: Connection, size: bigint) => Promise } export interface PerfServiceInit { @@ -153,18 +153,18 @@ export class DefaultPerfService implements Startable, PerfService { } // measureDownloadBandwidth returns the measured bandwidth in bits per second - // async measureDownloadBandwidth (peer: PeerId, size: bigint): Promise { - // const now = Date.now() - // await this.perf(connection, 0n, size) - // return Number((8000n * size) / BigInt(Date.now() - now)) - // } - - // // measureUploadBandwidth returns the measured bandwidth in bit per second - // async measureUploadBandwidth (peer: PeerId, size: bigint): Promise { - // const now = Date.now() - // await this.perf(peer, size, 0n) - // return Number((8000n * size) / BigInt(Date.now() - now)) - // } + async measureDownloadBandwidth (connection: Connection, size: bigint): Promise { + const now = Date.now() + await this.perf(connection, 0n, size) + return Number((8000n * size) / BigInt(Date.now() - now)) + } + + // measureUploadBandwidth returns the measured bandwidth in bit per second + async measureUploadBandwidth (connection: Connection, size: bigint): Promise { + const now = Date.now() + await this.perf(connection, size, 0n) + return Number((8000n * size) / BigInt(Date.now() - now)) + } } export function perfService (init: PerfServiceInit = {}): (components: PerfServiceComponents) => PerfService { diff --git a/packages/perf/src/main.ts b/packages/perf/src/main.ts index d928049f03..ee45ef33f0 100644 --- a/packages/perf/src/main.ts +++ b/packages/perf/src/main.ts @@ -1,17 +1,16 @@ import { yamux } from '@chainsafe/libp2p-yamux' +import { unmarshalPrivateKey } from '@libp2p/crypto/keys' import { createFromPrivKey } from '@libp2p/peer-id-factory' import { tcp } from '@libp2p/tcp' import { multiaddr } from '@multiformats/multiaddr' import { createLibp2p } from 'libp2p' import { plaintext } from 'libp2p/insecure' +import pWaitFor from 'p-wait-for' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' import yargs from 'yargs' import { hideBin } from 'yargs/helpers' import { defaultInit, perfService } from '../src/index.js' -import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' -import { unmarshalPrivateKey } from '@libp2p/crypto/keys' import type { Connection } from '@libp2p/interface/connection' -import pWaitFor from 'p-wait-for' - const argv = yargs(hideBin(process.argv)) .options({ @@ -73,7 +72,7 @@ export async function main (runServer: boolean, serverIpAddress: string, transpo const peerId = await createFromPrivKey(privateKey) const tcpMultiaddrAddress = `${tcpMultiaddr.toString()}/p2p/${peerId.toString()}` - if (runServer === true) { + if (runServer) { listenAddrs.push(tcpMultiaddrAddress) Object.assign(config, { @@ -92,12 +91,12 @@ export async function main (runServer: boolean, serverIpAddress: string, transpo let connection: any = null - if (runServer === true) { + if (runServer) { node.addEventListener('connection:open', (eventInfo) => { connection = eventInfo.detail }) } else { - connection = await node.dial(multiaddr(tcpMultiaddrAddress)) + connection = await node.dial(multiaddr(tcpMultiaddrAddress)) } await pWaitFor(() => connection != null) diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index 833424f143..0ac9b64ac3 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -5,6 +5,7 @@ import { start, stop } from '@libp2p/interface/startable' import { connectionPair, mockConnectionGater, mockRegistrar, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { PersistentPeerStore } from '@libp2p/peer-store' +import { expect } from 'aegir/chai' import { MemoryDatastore } from 'datastore-core' import { type Components, defaultComponents } from 'libp2p/components' import { DefaultConnectionManager } from 'libp2p/connection-manager' @@ -72,7 +73,7 @@ describe('perf', () => { remoteComponents.events.safeDispatchEvent('connection:open', { detail: remoteToLocal }) // Run Perf - // await expect(client.perf(remoteComponents.peerId, 1024n, 1024n)).to.eventually.be.fulfilled() + await expect(client.perf(localToRemote, 1024n, 1024n)).to.eventually.be.fulfilled() }) it('should output bandwidth', async () => { @@ -90,10 +91,10 @@ describe('perf', () => { let downloadBandwidth = 0 let uploadBandwidth = 0 - for (let i = 1; i < 5; i++) { + for (let i = 0; i < 5; i++) { // Run Perf - // downloadBandwidth += await client.measureDownloadBandwidth(remoteComponents.peerId, 10485760n) - // uploadBandwidth += await client.measureUploadBandwidth(remoteComponents.peerId, 10485760n) + downloadBandwidth += await client.measureDownloadBandwidth(localToRemote, 10485760n) + uploadBandwidth += await client.measureUploadBandwidth(localToRemote, 10485760n) } // eslint-disable-next-line no-console From fb914fd5eed6685bec7e056cc58f3a3b4ba03ac8 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 3 Aug 2023 23:03:31 -0500 Subject: [PATCH 24/27] deps: updated deps --- packages/perf/package.json | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/perf/package.json b/packages/perf/package.json index 396ac9d344..f1e75ce190 100644 --- a/packages/perf/package.json +++ b/packages/perf/package.json @@ -40,26 +40,26 @@ "renderResults": "node dist/src/renderResults.js" }, "dependencies": { - "@chainsafe/libp2p-yamux": "^4.0.2", - "@libp2p/crypto": "^1.0.17", - "@libp2p/interface": "^0.0.1", - "@libp2p/interface-compliance-tests": "^3.0.7", - "@libp2p/interface-internal": "^0.0.1", + "@chainsafe/libp2p-yamux": "^5.0.0", + "@libp2p/crypto": "^2.0.0", + "@libp2p/interface": "^0.1.0", + "@libp2p/interface-compliance-tests": "^4.0.0", + "@libp2p/interface-internal": "^0.1.0", "@libp2p/interfaces": "3.3.2", - "@libp2p/logger": "^2.1.1", - "@libp2p/peer-id-factory": "2.0.4", - "@libp2p/peer-store": "8.2.1", - "@libp2p/tcp": "^7.0.3", - "@multiformats/multiaddr": "^12.1.3", + "@libp2p/logger": "^3.0.0", + "@libp2p/peer-id-factory": "3.0.0", + "@libp2p/peer-store": "9.0.0", + "@libp2p/tcp": "^8.0.0", + "@multiformats/multiaddr": "^12.1.5", "any-signal": "^4.1.1", - "datastore-core": "9.2.0", - "libp2p": "^0.45.9", + "datastore-core": "9.2.2", + "libp2p": "^0.46.1", "p-wait-for": "^5.0.2", "uint8arrays": "^4.0.6", "yargs": "^17.7.2" }, "devDependencies": { - "aegir": "^40.0.2", + "aegir": "^40.0.8", "sinon-ts": "1.0.0" }, "typedoc": { From a28ff46530afa5adc1c6fbb88f7d279ce06989cd Mon Sep 17 00:00:00 2001 From: chad Date: Sat, 5 Aug 2023 14:06:44 -0500 Subject: [PATCH 25/27] feat: address perf review comments --- .github/workflows/perf-test.yml | 158 ----------------------------- packages/libp2p/package.json | 12 --- packages/perf/.gitignore | 3 - packages/perf/package.json | 8 +- packages/perf/previousPerf.json | 5 - packages/perf/src/constants.ts | 2 - packages/perf/src/index.ts | 134 +++++++++++++++--------- packages/perf/src/main.ts | 6 +- packages/perf/src/renderResults.ts | 51 ---------- packages/perf/test/index.spec.ts | 68 ++++++------- 10 files changed, 122 insertions(+), 325 deletions(-) delete mode 100644 .github/workflows/perf-test.yml delete mode 100644 packages/perf/.gitignore delete mode 100644 packages/perf/previousPerf.json delete mode 100644 packages/perf/src/renderResults.ts diff --git a/.github/workflows/perf-test.yml b/.github/workflows/perf-test.yml deleted file mode 100644 index b59ba762ef..0000000000 --- a/.github/workflows/perf-test.yml +++ /dev/null @@ -1,158 +0,0 @@ -name: Performance Test -on: - push: - branches: - - master - pull_request: - branches: - - "**" - -jobs: - performance_test: - name: Run performance tests - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: ipfs/aegir/actions/cache-node-modules@master - with: - directories: ./packages/perf/node_modules - - - name: Install playwright dependencies - uses: ipfs/aegir/actions/cache-node-modules@master - - run: npx playwright install-deps - - - name: Build perf - working-directory: packages/perf - run: (npm i && npm run build) - - - name: Run tests and store in test_output - working-directory: packages/perf - run: | - npm run test > test_output.txt - - - name: Extract bandwidth from test output - id: extract_bandwidths - working-directory: packages/perf - shell: bash - run: | - bandwidth_file="test_output.txt" - bandwidth_object="{" - - # Function to assign bandwidth values to the object - assign_bandwidth() { - local environment=$1 - local current_upload_bandwidth=$2 - local current_download_bandwidth=$3 - - if [[ ${#bandwidth_object} -gt 1 ]]; then - bandwidth_object+=", " - fi - - bandwidth_object+="\"$environment\": { \"currentUploadBandwidth\": $current_upload_bandwidth, \"currentDownloadBandwidth\": $current_download_bandwidth }" - } - - # Read the bandwidth values from the file - upload_count=0 - download_count=0 - - upload_bandwidths=() - download_bandwidths=() - - while IFS= read -r line; do - if [[ $line == *"Upload bandwidth"* ]]; then - current_upload_bandwidth=$(grep -o 'Upload bandwidth: [0-9]*' <<< "$line" | grep -o '[0-9]*') - upload_count=$((upload_count + 1)) - elif [[ $line == *"Download bandwidth"* ]]; then - current_download_bandwidth=$(grep -o 'Download bandwidth: [0-9]*' <<< "$line" | grep -o '[0-9]*') - download_count=$((download_count + 1)) - fi - - if [[ $upload_count -eq 1 && $download_count -eq 1 ]]; then - upload_bandwidths[0]=$current_upload_bandwidth - download_bandwidths[0]=$current_download_bandwidth - elif [[ $upload_count -eq 2 && $download_count -eq 2 ]]; then - upload_bandwidths[1]=$current_upload_bandwidth - download_bandwidths[1]=$current_download_bandwidth - elif [[ $upload_count -eq 3 && $download_count -eq 3 ]]; then - upload_bandwidths[2]=$current_upload_bandwidth - download_bandwidths[2]=$current_download_bandwidth - break # Exit the loop after processing the third instance - fi - done < "$bandwidth_file" - - # Construct the bandwidth object - assign_bandwidth "node" "${upload_bandwidths[0]}" "${download_bandwidths[0]}" - assign_bandwidth "browser" "${upload_bandwidths[1]}" "${download_bandwidths[1]}" - assign_bandwidth "webworker" "${upload_bandwidths[2]}" "${download_bandwidths[2]}" - - # Remove trailing comma if there are values in the object - if [[ ${#bandwidth_object} -gt 1 ]]; then - bandwidth_object="${bandwidth_object#, }" - fi - - bandwidth_object+="}" - - current_bandwidths=$bandwidth_object - - echo "::set-output name=current_bandwidths::$current_bandwidths" - - # Read the previous bandwidth values from the file - previous_bandwidths=$(cat previousPerf.json | jq -r '.') - - # Iterate over the current bandwidth object and merge with previous values - merged_object=$(jq --argjson previous "$previous_bandwidths" '. as $current | reduce keys[] as $key ({}; .[$key] = ($current[$key] + $previous[$key]))' <<< "$current_bandwidths") - - # Set the merged bandwidth object as environment variable - EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) - echo "BANDWIDTH_TEST_RESULTS<<$EOF" >> "$GITHUB_ENV" - echo $merged_object >> "$GITHUB_ENV" - echo "$EOF" >> "$GITHUB_ENV" - - - name: Generate Test Report - id: generate_report - working-directory: packages/perf - run: npm run renderResults > test_report.md - - - name: Upload Test Report - id: upload_report - uses: actions/upload-artifact@v3 - with: - name: test_report - path: packages/perf/test_report.md - - - name: Show Report Output - working-directory: packages/perf - run: cat test_report.md >> $GITHUB_STEP_SUMMARY - - - name: Save current performance data - id: save_performance_data - working-directory: packages/perf - shell: bash - run: | - current_bandwidths=$(echo '${{ steps.extract_bandwidths.outputs.current_bandwidths }}' | jq -r '.') - - # Parse the input object using jq, modify the keys, and store the result in a new variable - updated_object=$(echo "$current_bandwidths" | jq 'map_values(.previousUploadBandwidth = .currentUploadBandwidth | del(.currentUploadBandwidth) | .previousDownloadBandwidth = .currentDownloadBandwidth | del(.currentDownloadBandwidth))') - - # Output the updated object - echo $updated_object > previousPerf.json - - - name: Commit and push changes - uses: stefanzweifel/git-auto-commit-action@v4 - with: - commit_message: Update performance data - file_pattern: "*.json" - branch: ${{ github.ref }} - - - name: Check CI job status - id: check_ci - working-directory: packages/perf - run: | - # Check if the file contains the "❌" symbol - if grep -q "❌" test_report.md; then - echo "Failure: There was a performance degradation of over 5%." - exit 1 # Exit with a non-zero status code for failure - else - echo "Success: Performance benchmarks passed." - exit 0 # Exit with a zero status code for pass - fi diff --git a/packages/libp2p/package.json b/packages/libp2p/package.json index 63c9acaa64..1813f14a8c 100644 --- a/packages/libp2p/package.json +++ b/packages/libp2p/package.json @@ -52,22 +52,10 @@ "types": "./dist/src/autonat/index.d.ts", "import": "./dist/src/autonat/index.js" }, - "./address-manager": { - "types": "./dist/src/address-manager/index.d.ts", - "import": "./dist/src/address-manager/index.js" - }, "./circuit-relay": { "types": "./dist/src/circuit-relay/index.d.ts", "import": "./dist/src/circuit-relay/index.js" }, - "./components": { - "types": "./dist/src/components.d.ts", - "import": "./dist/src/components.js" - }, - "./connection-manager": { - "types": "./dist/src/connection-manager/index.d.ts", - "import": "./dist/src/connection-manager/index.js" - }, "./fetch": { "types": "./dist/src/fetch/index.d.ts", "import": "./dist/src/fetch/index.js" diff --git a/packages/perf/.gitignore b/packages/perf/.gitignore deleted file mode 100644 index a4b426ea95..0000000000 --- a/packages/perf/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules/ - -dist/ \ No newline at end of file diff --git a/packages/perf/package.json b/packages/perf/package.json index f1e75ce190..a8e1c23312 100644 --- a/packages/perf/package.json +++ b/packages/perf/package.json @@ -48,21 +48,15 @@ "@libp2p/interfaces": "3.3.2", "@libp2p/logger": "^3.0.0", "@libp2p/peer-id-factory": "3.0.0", - "@libp2p/peer-store": "9.0.0", "@libp2p/tcp": "^8.0.0", "@multiformats/multiaddr": "^12.1.5", "any-signal": "^4.1.1", - "datastore-core": "9.2.2", "libp2p": "^0.46.1", "p-wait-for": "^5.0.2", "uint8arrays": "^4.0.6", "yargs": "^17.7.2" }, "devDependencies": { - "aegir": "^40.0.8", - "sinon-ts": "1.0.0" - }, - "typedoc": { - "entryPoint": "./src/index.ts" + "aegir": "^40.0.8" } } diff --git a/packages/perf/previousPerf.json b/packages/perf/previousPerf.json deleted file mode 100644 index a330174350..0000000000 --- a/packages/perf/previousPerf.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "browser": { "previousUploadBandwidth": 87900055, "previousDownloadBandwidth": 87736073 }, - "node": { "previousUploadBandwidth": 93373758, "previousDownloadBandwidth": 93798254 }, - "webworker": { "previousUploadBandwidth": 85991114, "previousDownloadBandwidth": 85401884 } -} diff --git a/packages/perf/src/constants.ts b/packages/perf/src/constants.ts index c62f4dd8a8..8a93316424 100644 --- a/packages/perf/src/constants.ts +++ b/packages/perf/src/constants.ts @@ -1,6 +1,4 @@ export const MAX_INBOUND_STREAMS = 1 << 10 export const MAX_OUTBOUND_STREAMS = 1 << 10 export const PROTOCOL_NAME = '/perf/1.0.0' - -export const TIMEOUT = 10000 export const WRITE_BLOCK_SIZE = BigInt(64 << 10) diff --git a/packages/perf/src/index.ts b/packages/perf/src/index.ts index d19e802f23..6eed9b6639 100644 --- a/packages/perf/src/index.ts +++ b/packages/perf/src/index.ts @@ -1,6 +1,47 @@ +/** + * @packageDocumentation + * + * The `performanceService` implements the [perf protocol](https://github.com/libp2p/specs/blob/master/perf/perf.md), which is used to measure performance within and across libp2p implementations + * addresses. + * + * @example + * + * ```typescript + * import { createLibp2p } from 'libp2p' + * import { circuitRelayTransport } from 'libp2p/circuit-relay' + * + * const node = await createLibp2p({ + * service: [ + * perfService() + * ] + * }) + * ``` + * + * The `measurePerformance` function can be used to measure the latency and throughput of a connection. + * server. This will not work in browsers. + * + * @example + * + * ```typescript + * import { createLibp2p } from 'libp2p' + * import { circuitRelayServer } from 'libp2p/circuit-relay' + * + * const node = await createLibp2p({ + * services: [ + * perf: perfService() + * ] + * }) + * + * const connection = await node.dial(multiaddr(multiaddrAddress)) + * + * await node.services.perf.measurePerformance(connection, BigInt(uploadBytes), BigInt(downloadBytes)) + * + * ``` + */ + import { logger } from '@libp2p/logger' import { anySignal } from 'any-signal' -import { MAX_INBOUND_STREAMS, PROTOCOL_NAME, TIMEOUT, WRITE_BLOCK_SIZE } from './constants.js' +import { MAX_INBOUND_STREAMS, PROTOCOL_NAME, WRITE_BLOCK_SIZE } from './constants.js' import type { Connection } from '@libp2p/interface/src/connection/index.js' import type { Startable } from '@libp2p/interface/startable' import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager' @@ -18,9 +59,7 @@ export const defaultInit: PerfServiceInit = { } export interface PerfService { - perf: (connection: Connection, sendBytes: bigint, recvBytes: bigint, options?: AbortOptions) => Promise - measureDownloadBandwidth: (connection: Connection, size: bigint) => Promise - measureUploadBandwidth: (connection: Connection, size: bigint) => Promise + measurePerformance: (startTime: number, connection: Connection, sendBytes: bigint, recvBytes: bigint, options?: AbortOptions) => Promise } export interface PerfServiceInit { @@ -36,29 +75,31 @@ export interface PerfServiceComponents { connectionManager: ConnectionManager } -export class DefaultPerfService implements Startable, PerfService { +class DefaultPerfService implements Startable, PerfService { public readonly protocol: string private readonly components: PerfServiceComponents private started: boolean private readonly databuf: ArrayBuffer private readonly maxInboundStreams: number private readonly maxOutboundStreams: number - private readonly timeout: number private readonly writeBlockSize: bigint constructor (components: PerfServiceComponents, init: PerfServiceInit) { this.components = components this.started = false this.protocol = init.protocolName ?? PROTOCOL_NAME - this.databuf = new ArrayBuffer(Number(init.writeBlockSize ?? WRITE_BLOCK_SIZE)) + this.writeBlockSize = init.writeBlockSize ?? WRITE_BLOCK_SIZE + this.databuf = new ArrayBuffer(Number(init.writeBlockSize)) this.maxInboundStreams = init.maxInboundStreams ?? MAX_INBOUND_STREAMS this.maxOutboundStreams = init.maxOutboundStreams ?? MAX_INBOUND_STREAMS - this.timeout = init.timeout ?? TIMEOUT - this.writeBlockSize = init.writeBlockSize ?? WRITE_BLOCK_SIZE } async start (): Promise { - await this.components.registrar.handle(this.protocol, (data: IncomingStreamData) => { void this.handleMessage(data) }, { + await this.components.registrar.handle(this.protocol, (data: IncomingStreamData) => { + void this.handleMessage(data).catch((err) => { + log.error('error handling perf protocol message', err) + }) + }, { maxInboundStreams: this.maxInboundStreams, maxOutboundStreams: this.maxOutboundStreams }) @@ -91,7 +132,7 @@ export class DefaultPerfService implements Startable, PerfService { const uint8Buf = new Uint8Array(this.databuf) if (bytesToSendBack === null) { - throw new Error('bytesToSendBack was null') + throw new Error('bytesToSendBack was not set') } await stream.sink(async function * () { @@ -106,14 +147,15 @@ export class DefaultPerfService implements Startable, PerfService { }()) } - async perf (connection: Connection, sendBytes: bigint, recvBytes: bigint, options: AbortOptions = {}): Promise { + async measurePerformance (startTime: number, connection: Connection, sendBytes: bigint, recvBytes: bigint, options: AbortOptions = {}): Promise { log('opening stream on protocol %s to %p', this.protocol, connection.remotePeer) const uint8Buf = new Uint8Array(this.databuf) const writeBlockSize = this.writeBlockSize - const signal = anySignal([AbortSignal.timeout(this.timeout), options?.signal]) + const signal = anySignal([options?.signal]) + const stream = await connection.newStream([this.protocol], { signal }) @@ -123,47 +165,41 @@ export class DefaultPerfService implements Startable, PerfService { view.setBigInt64(0, recvBytes, false) log('sending %i bytes to %p', sendBytes, connection.remotePeer) - - await stream.sink((async function * () { - // Send the number of bytes to receive - yield uint8Buf.subarray(0, 8) - // Send the number of bytes to send - while (sendBytes > 0n) { - let toSend: bigint = writeBlockSize - if (toSend > sendBytes) { - toSend = sendBytes + try { + await stream.sink((async function * () { + // Send the number of bytes to receive + yield uint8Buf.subarray(0, 8) + // Send the number of bytes to send + while (sendBytes > 0n) { + let toSend: bigint = writeBlockSize + if (toSend > sendBytes) { + toSend = sendBytes + } + sendBytes = sendBytes - toSend + yield uint8Buf.subarray(0, Number(toSend)) } - sendBytes = sendBytes - toSend - yield uint8Buf.subarray(0, Number(toSend)) - } - })()) + })()) - // Read the received bytes - let actualRecvdBytes = BigInt(0) - for await (const buf of stream.source) { - actualRecvdBytes += BigInt(buf.length) - } + // Read the received bytes + let actualRecvdBytes = BigInt(0) + for await (const buf of stream.source) { + actualRecvdBytes += BigInt(buf.length) + } - if (actualRecvdBytes !== recvBytes) { - throw new Error(`Expected to receive ${recvBytes} bytes, but received ${actualRecvdBytes}`) + if (actualRecvdBytes !== recvBytes) { + throw new Error(`Expected to receive ${recvBytes} bytes, but received ${actualRecvdBytes}`) + } + } catch (err) { + log('error sending %i bytes to %p: %s', sendBytes, connection.remotePeer, err) + throw err + } finally { + log('performed %s to %p', this.protocol, connection.remotePeer) + signal.clear() + await stream.close() } - log('performed %s to %p', this.protocol, connection.remotePeer) - await stream.close() - } - - // measureDownloadBandwidth returns the measured bandwidth in bits per second - async measureDownloadBandwidth (connection: Connection, size: bigint): Promise { - const now = Date.now() - await this.perf(connection, 0n, size) - return Number((8000n * size) / BigInt(Date.now() - now)) - } - - // measureUploadBandwidth returns the measured bandwidth in bit per second - async measureUploadBandwidth (connection: Connection, size: bigint): Promise { - const now = Date.now() - await this.perf(connection, size, 0n) - return Number((8000n * size) / BigInt(Date.now() - now)) + // Return the latency + return Date.now() - startTime } } diff --git a/packages/perf/src/main.ts b/packages/perf/src/main.ts index ee45ef33f0..33c96e6a92 100644 --- a/packages/perf/src/main.ts +++ b/packages/perf/src/main.ts @@ -101,14 +101,12 @@ export async function main (runServer: boolean, serverIpAddress: string, transpo await pWaitFor(() => connection != null) - await node.services.perf.perf(connection as Connection, BigInt(uploadBytes), BigInt(downloadBytes)) - - const endTime = Date.now() + const duration = await node.services.perf.measurePerformance(startTime, connection as Connection, BigInt(uploadBytes), BigInt(downloadBytes)) await node.stop() // eslint-disable-next-line no-console - console.log('latency: ' + JSON.stringify({ latency: endTime - startTime })) + console.log('latency: ' + JSON.stringify({ latency: duration })) } function splitHostPort (address: string): { host: string, port?: string } { diff --git a/packages/perf/src/renderResults.ts b/packages/perf/src/renderResults.ts deleted file mode 100644 index 7489a72fa3..0000000000 --- a/packages/perf/src/renderResults.ts +++ /dev/null @@ -1,51 +0,0 @@ -interface TestResult { - previousUploadBandwidth: number - currentUploadBandwidth: number - previousDownloadBandwidth: number - currentDownloadBandwidth: number -} - -interface TestEnvironment { - name: string - results: TestResult -} - -export function generateMarkdownTable (environments: TestEnvironment[]): string { - const headerRow = - '| Environment | Previous Upload Bandwidth | Current Upload Bandwidth | Upload Bandwidth Comparison | Previous Download Bandwidth | Current Download Bandwidth | Download Bandwidth Comparison |\n' - const separatorRow = - '|-------------|--------------------------|-------------------------|-----------------------------|-----------------------------|----------------------------|-----------------------------|\n' - let bodyRows = '' - - environments.forEach((environment) => { - const { name, results } = environment - const { previousUploadBandwidth, currentUploadBandwidth, previousDownloadBandwidth, currentDownloadBandwidth } = results - - const uploadComparison = currentUploadBandwidth <= 0.95 * previousUploadBandwidth ? '❌' : '✅' - const downloadComparison = currentDownloadBandwidth <= 0.95 * previousDownloadBandwidth ? '❌' : '✅' - - const row = `| ${name} | ${previousUploadBandwidth} B/s | ${currentUploadBandwidth} B/s | ${uploadComparison} | ${previousDownloadBandwidth} B/s | ${currentDownloadBandwidth} B/s| ${downloadComparison} |\n` - bodyRows += row - }) - - return `${headerRow}${separatorRow}${bodyRows}` -} - -const testEnvironments: TestEnvironment[] = [] - -const jsonObject = JSON.parse(process.env.BANDWIDTH_TEST_RESULTS ?? '') - -for (const name in jsonObject) { - if (Object.prototype.hasOwnProperty.call(jsonObject, name)) { - const testResult = jsonObject[name] - const testEnvironment: TestEnvironment = { - name: name, - results: testResult - } - testEnvironments.push(testEnvironment) - } -} - -const markdownTable = generateMarkdownTable(testEnvironments) -// eslint-disable-next-line no-console -console.log(markdownTable) diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index 0ac9b64ac3..d5758d941a 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -2,46 +2,27 @@ import { EventEmitter } from '@libp2p/interface/events' import { start, stop } from '@libp2p/interface/startable' -import { connectionPair, mockConnectionGater, mockRegistrar, mockUpgrader } from '@libp2p/interface-compliance-tests/mocks' +import { connectionPair, mockRegistrar, type MockNetworkComponents, mockConnectionManager } from '@libp2p/interface-compliance-tests/mocks' import { createEd25519PeerId } from '@libp2p/peer-id-factory' -import { PersistentPeerStore } from '@libp2p/peer-store' import { expect } from 'aegir/chai' -import { MemoryDatastore } from 'datastore-core' -import { type Components, defaultComponents } from 'libp2p/components' -import { DefaultConnectionManager } from 'libp2p/connection-manager' -import { stubInterface } from 'sinon-ts' -import { defaultInit, perfService } from '../src/index.js' -import type { TransportManager } from '@libp2p/interface-internal/transport-manager' +import { defaultInit, perfService, type PerfService } from '../src/index.js' +import type { Connection } from '@libp2p/interface/connection' -export async function createComponents (): Promise { - const peerId = await createEd25519PeerId() - - const events = new EventEmitter() - - const components = defaultComponents({ - peerId, +export async function createComponents (): Promise { + const components: any = { + peerId: await createEd25519PeerId(), registrar: mockRegistrar(), - upgrader: mockUpgrader(), - datastore: new MemoryDatastore(), - transportManager: stubInterface(), - connectionGater: mockConnectionGater(), - events - }) + events: new EventEmitter() + } - components.peerStore = new PersistentPeerStore(components) - components.connectionManager = new DefaultConnectionManager(components, { - minConnections: 50, - maxConnections: 1000, - autoDialInterval: 1000, - inboundUpgradeTimeout: 1000 - }) + components.connectionManager = mockConnectionManager(components) - return components + return components as MockNetworkComponents } describe('perf', () => { - let localComponents: Components - let remoteComponents: Components + let localComponents: MockNetworkComponents + let remoteComponents: MockNetworkComponents beforeEach(async () => { localComponents = await createComponents() @@ -72,8 +53,10 @@ describe('perf', () => { localComponents.events.safeDispatchEvent('connection:open', { detail: localToRemote }) remoteComponents.events.safeDispatchEvent('connection:open', { detail: remoteToLocal }) + const startTime = Date.now() + // Run Perf - await expect(client.perf(localToRemote, 1024n, 1024n)).to.eventually.be.fulfilled() + await expect(client.measurePerformance(startTime, localToRemote, 1024n, 1024n)).to.eventually.be.fulfilled() }) it('should output bandwidth', async () => { @@ -93,8 +76,8 @@ describe('perf', () => { for (let i = 0; i < 5; i++) { // Run Perf - downloadBandwidth += await client.measureDownloadBandwidth(localToRemote, 10485760n) - uploadBandwidth += await client.measureUploadBandwidth(localToRemote, 10485760n) + downloadBandwidth += await measureDownloadBandwidth(localToRemote, 10485760n, client) + uploadBandwidth += await measureUploadBandwidth(localToRemote, 10485760n, client) } // eslint-disable-next-line no-console @@ -102,5 +85,22 @@ describe('perf', () => { // eslint-disable-next-line no-console console.log('Download bandwidth:', Math.floor(uploadBandwidth / 5), 'B/s') + + expect(downloadBandwidth).to.be.greaterThan(0) + expect(uploadBandwidth).to.be.greaterThan(0) }) + + // measureDownloadBandwidth returns the measured bandwidth in bytes per second B/s + async function measureDownloadBandwidth (connection: Connection, size: bigint, client: PerfService): Promise { + const startTime = Date.now() + const duration = await client.measurePerformance(startTime, connection, 0n, size) + return Number((8000n * size) / BigInt(duration)) + } + + // measureUploadBandwidth returns the measured bandwidth in bytes per second B/s + async function measureUploadBandwidth (connection: Connection, size: bigint, client: PerfService): Promise { + const startTime = Date.now() + const duration = await client.measurePerformance(startTime, connection, size, 0n) + return Number((8000n * size) / BigInt(duration)) + } }) From 5e62a7b852d6fb0d728424bf09ad30b53e448422 Mon Sep 17 00:00:00 2001 From: chad Date: Tue, 8 Aug 2023 09:46:45 -0500 Subject: [PATCH 26/27] refactor: removed maxInbound and outbound streams on handler + bandwidth tests --- packages/perf/package.json | 1 - packages/perf/src/constants.ts | 2 -- packages/perf/src/index.ts | 22 ++------------- packages/perf/test/index.spec.ts | 48 +------------------------------- 4 files changed, 4 insertions(+), 69 deletions(-) diff --git a/packages/perf/package.json b/packages/perf/package.json index a8e1c23312..079caa77ce 100644 --- a/packages/perf/package.json +++ b/packages/perf/package.json @@ -50,7 +50,6 @@ "@libp2p/peer-id-factory": "3.0.0", "@libp2p/tcp": "^8.0.0", "@multiformats/multiaddr": "^12.1.5", - "any-signal": "^4.1.1", "libp2p": "^0.46.1", "p-wait-for": "^5.0.2", "uint8arrays": "^4.0.6", diff --git a/packages/perf/src/constants.ts b/packages/perf/src/constants.ts index 8a93316424..a2e514d6f8 100644 --- a/packages/perf/src/constants.ts +++ b/packages/perf/src/constants.ts @@ -1,4 +1,2 @@ -export const MAX_INBOUND_STREAMS = 1 << 10 -export const MAX_OUTBOUND_STREAMS = 1 << 10 export const PROTOCOL_NAME = '/perf/1.0.0' export const WRITE_BLOCK_SIZE = BigInt(64 << 10) diff --git a/packages/perf/src/index.ts b/packages/perf/src/index.ts index 6eed9b6639..88ed19286e 100644 --- a/packages/perf/src/index.ts +++ b/packages/perf/src/index.ts @@ -40,9 +40,8 @@ */ import { logger } from '@libp2p/logger' -import { anySignal } from 'any-signal' -import { MAX_INBOUND_STREAMS, PROTOCOL_NAME, WRITE_BLOCK_SIZE } from './constants.js' -import type { Connection } from '@libp2p/interface/src/connection/index.js' +import { PROTOCOL_NAME, WRITE_BLOCK_SIZE } from './constants.js' +import type { Connection } from '@libp2p/interface/connection' import type { Startable } from '@libp2p/interface/startable' import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager' import type { IncomingStreamData, Registrar } from '@libp2p/interface-internal/registrar' @@ -52,9 +51,6 @@ const log = logger('libp2p:perf') export const defaultInit: PerfServiceInit = { protocolName: '/perf/1.0.0', - maxInboundStreams: 1 << 10, - maxOutboundStreams: 1 << 10, - timeout: 10000, writeBlockSize: BigInt(64 << 10) } @@ -80,8 +76,6 @@ class DefaultPerfService implements Startable, PerfService { private readonly components: PerfServiceComponents private started: boolean private readonly databuf: ArrayBuffer - private readonly maxInboundStreams: number - private readonly maxOutboundStreams: number private readonly writeBlockSize: bigint constructor (components: PerfServiceComponents, init: PerfServiceInit) { @@ -90,8 +84,6 @@ class DefaultPerfService implements Startable, PerfService { this.protocol = init.protocolName ?? PROTOCOL_NAME this.writeBlockSize = init.writeBlockSize ?? WRITE_BLOCK_SIZE this.databuf = new ArrayBuffer(Number(init.writeBlockSize)) - this.maxInboundStreams = init.maxInboundStreams ?? MAX_INBOUND_STREAMS - this.maxOutboundStreams = init.maxOutboundStreams ?? MAX_INBOUND_STREAMS } async start (): Promise { @@ -99,9 +91,6 @@ class DefaultPerfService implements Startable, PerfService { void this.handleMessage(data).catch((err) => { log.error('error handling perf protocol message', err) }) - }, { - maxInboundStreams: this.maxInboundStreams, - maxOutboundStreams: this.maxOutboundStreams }) this.started = true } @@ -154,11 +143,7 @@ class DefaultPerfService implements Startable, PerfService { const writeBlockSize = this.writeBlockSize - const signal = anySignal([options?.signal]) - - const stream = await connection.newStream([this.protocol], { - signal - }) + const stream = await connection.newStream([this.protocol]) // Convert sendBytes to uint64 big endian buffer const view = new DataView(this.databuf) @@ -194,7 +179,6 @@ class DefaultPerfService implements Startable, PerfService { throw err } finally { log('performed %s to %p', this.protocol, connection.remotePeer) - signal.clear() await stream.close() } diff --git a/packages/perf/test/index.spec.ts b/packages/perf/test/index.spec.ts index d5758d941a..83fd6c310f 100644 --- a/packages/perf/test/index.spec.ts +++ b/packages/perf/test/index.spec.ts @@ -5,8 +5,7 @@ import { start, stop } from '@libp2p/interface/startable' import { connectionPair, mockRegistrar, type MockNetworkComponents, mockConnectionManager } from '@libp2p/interface-compliance-tests/mocks' import { createEd25519PeerId } from '@libp2p/peer-id-factory' import { expect } from 'aegir/chai' -import { defaultInit, perfService, type PerfService } from '../src/index.js' -import type { Connection } from '@libp2p/interface/connection' +import { defaultInit, perfService } from '../src/index.js' export async function createComponents (): Promise { const components: any = { @@ -58,49 +57,4 @@ describe('perf', () => { // Run Perf await expect(client.measurePerformance(startTime, localToRemote, 1024n, 1024n)).to.eventually.be.fulfilled() }) - - it('should output bandwidth', async () => { - const client = perfService(defaultInit)(localComponents) - const server = perfService(defaultInit)(remoteComponents) - - await start(client) - await start(server) - - // simulate connection between nodes - const [localToRemote, remoteToLocal] = connectionPair(localComponents, remoteComponents) - localComponents.events.safeDispatchEvent('connection:open', { detail: localToRemote }) - remoteComponents.events.safeDispatchEvent('connection:open', { detail: remoteToLocal }) - - let downloadBandwidth = 0 - let uploadBandwidth = 0 - - for (let i = 0; i < 5; i++) { - // Run Perf - downloadBandwidth += await measureDownloadBandwidth(localToRemote, 10485760n, client) - uploadBandwidth += await measureUploadBandwidth(localToRemote, 10485760n, client) - } - - // eslint-disable-next-line no-console - console.log('Upload bandwidth:', Math.floor(downloadBandwidth / 5), 'B/s') - - // eslint-disable-next-line no-console - console.log('Download bandwidth:', Math.floor(uploadBandwidth / 5), 'B/s') - - expect(downloadBandwidth).to.be.greaterThan(0) - expect(uploadBandwidth).to.be.greaterThan(0) - }) - - // measureDownloadBandwidth returns the measured bandwidth in bytes per second B/s - async function measureDownloadBandwidth (connection: Connection, size: bigint, client: PerfService): Promise { - const startTime = Date.now() - const duration = await client.measurePerformance(startTime, connection, 0n, size) - return Number((8000n * size) / BigInt(duration)) - } - - // measureUploadBandwidth returns the measured bandwidth in bytes per second B/s - async function measureUploadBandwidth (connection: Connection, size: bigint, client: PerfService): Promise { - const startTime = Date.now() - const duration = await client.measurePerformance(startTime, connection, size, 0n) - return Number((8000n * size) / BigInt(duration)) - } }) From 0a4eae5c7ac8593a4da43a2a154824df1aa2f5b9 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 10 Aug 2023 14:39:51 -0500 Subject: [PATCH 27/27] refactor: rename to protocol-perf + update package documentation --- packages/{perf => protocol-perf}/LICENSE | 0 packages/{perf => protocol-perf}/LICENSE-APACHE | 0 packages/{perf => protocol-perf}/LICENSE-MIT | 0 packages/{perf => protocol-perf}/README.md | 0 packages/{perf => protocol-perf}/package.json | 6 ++++++ packages/{perf => protocol-perf}/src/constants.ts | 0 packages/{perf => protocol-perf}/src/index.ts | 8 +++++--- packages/{perf => protocol-perf}/src/main.ts | 0 packages/{perf => protocol-perf}/test/index.spec.ts | 0 packages/{perf => protocol-perf}/tsconfig.json | 0 10 files changed, 11 insertions(+), 3 deletions(-) rename packages/{perf => protocol-perf}/LICENSE (100%) rename packages/{perf => protocol-perf}/LICENSE-APACHE (100%) rename packages/{perf => protocol-perf}/LICENSE-MIT (100%) rename packages/{perf => protocol-perf}/README.md (100%) rename packages/{perf => protocol-perf}/package.json (93%) rename packages/{perf => protocol-perf}/src/constants.ts (100%) rename packages/{perf => protocol-perf}/src/index.ts (95%) rename packages/{perf => protocol-perf}/src/main.ts (100%) rename packages/{perf => protocol-perf}/test/index.spec.ts (100%) rename packages/{perf => protocol-perf}/tsconfig.json (100%) diff --git a/packages/perf/LICENSE b/packages/protocol-perf/LICENSE similarity index 100% rename from packages/perf/LICENSE rename to packages/protocol-perf/LICENSE diff --git a/packages/perf/LICENSE-APACHE b/packages/protocol-perf/LICENSE-APACHE similarity index 100% rename from packages/perf/LICENSE-APACHE rename to packages/protocol-perf/LICENSE-APACHE diff --git a/packages/perf/LICENSE-MIT b/packages/protocol-perf/LICENSE-MIT similarity index 100% rename from packages/perf/LICENSE-MIT rename to packages/protocol-perf/LICENSE-MIT diff --git a/packages/perf/README.md b/packages/protocol-perf/README.md similarity index 100% rename from packages/perf/README.md rename to packages/protocol-perf/README.md diff --git a/packages/perf/package.json b/packages/protocol-perf/package.json similarity index 93% rename from packages/perf/package.json rename to packages/protocol-perf/package.json index 079caa77ce..d005e71690 100644 --- a/packages/perf/package.json +++ b/packages/protocol-perf/package.json @@ -19,6 +19,12 @@ "!dist/test", "!**/*.tsbuildinfo" ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + } + }, "eslintConfig": { "extends": "ipfs", "parserOptions": { diff --git a/packages/perf/src/constants.ts b/packages/protocol-perf/src/constants.ts similarity index 100% rename from packages/perf/src/constants.ts rename to packages/protocol-perf/src/constants.ts diff --git a/packages/perf/src/index.ts b/packages/protocol-perf/src/index.ts similarity index 95% rename from packages/perf/src/index.ts rename to packages/protocol-perf/src/index.ts index 88ed19286e..15713cd6ec 100644 --- a/packages/perf/src/index.ts +++ b/packages/protocol-perf/src/index.ts @@ -8,7 +8,7 @@ * * ```typescript * import { createLibp2p } from 'libp2p' - * import { circuitRelayTransport } from 'libp2p/circuit-relay' + * import { perfService } from '@libp2p/perf' * * const node = await createLibp2p({ * service: [ @@ -24,7 +24,7 @@ * * ```typescript * import { createLibp2p } from 'libp2p' - * import { circuitRelayServer } from 'libp2p/circuit-relay' + * import { perfService } from 'libp2p/perf' * * const node = await createLibp2p({ * services: [ @@ -34,7 +34,9 @@ * * const connection = await node.dial(multiaddr(multiaddrAddress)) * - * await node.services.perf.measurePerformance(connection, BigInt(uploadBytes), BigInt(downloadBytes)) + * const startTime = Date.now() + * + * await node.services.perf.measurePerformance(startTime, connection, BigInt(uploadBytes), BigInt(downloadBytes)) * * ``` */ diff --git a/packages/perf/src/main.ts b/packages/protocol-perf/src/main.ts similarity index 100% rename from packages/perf/src/main.ts rename to packages/protocol-perf/src/main.ts diff --git a/packages/perf/test/index.spec.ts b/packages/protocol-perf/test/index.spec.ts similarity index 100% rename from packages/perf/test/index.spec.ts rename to packages/protocol-perf/test/index.spec.ts diff --git a/packages/perf/tsconfig.json b/packages/protocol-perf/tsconfig.json similarity index 100% rename from packages/perf/tsconfig.json rename to packages/protocol-perf/tsconfig.json