Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Benchmark tool support to fetch data from custom apiEndpoint #2583

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2022 The Parca Authors
// 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.

import React from 'react';
import ProfileIcicleGraph from '..';
import {Provider} from 'react-redux';
import {store} from '@parca/store';
import parcaGraphData from './benchdata/parca-12h.json';
import {Flamegraph} from '@parca/client';

const {store: reduxStore} = store();

const parcaGraph = parcaGraphData as Flamegraph;

export default function ({callback = () => {}}): React.ReactElement {
return (
<div ref={callback}>
<Provider store={reduxStore}>
<ProfileIcicleGraph
loading={false}
graph={parcaGraph}
sampleUnit={parcaGraph.unit}
curPath={[]}
setNewCurPath={() => {}}
/>
</Provider>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2022 The Parca Authors
// 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.

import React from 'react';
import ProfileIcicleGraph from '..';
import {Provider} from 'react-redux';
import {store} from '@parca/store';
import parcaGraphData from './benchdata/parca-15m.json';
import {Flamegraph} from '@parca/client';

const {store: reduxStore} = store();

const parcaGraph = parcaGraphData as Flamegraph;

export default function ({callback = () => {}}): React.ReactElement {
return (
<div ref={callback}>
<Provider store={reduxStore}>
<ProfileIcicleGraph
loading={false}
graph={parcaGraph}
sampleUnit={parcaGraph.unit}
curPath={[]}
setNewCurPath={() => {}}
/>
</Provider>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,21 @@ import React from 'react';
import ProfileIcicleGraph from '..';
import {Provider} from 'react-redux';
import {store} from '@parca/store';
import parca10mGraphData from './benchdata/parca-10m.json';
import parcaGraphData from './benchdata/parca-1d.json';
import {Flamegraph} from '@parca/client';

const {store: reduxStore} = store();

const parca10mGraph = parca10mGraphData as Flamegraph;
const parcaGraph = parcaGraphData as Flamegraph;

export default function ({callback = () => {}}): React.ReactElement {
return (
<div ref={callback}>
<Provider store={reduxStore}>
<ProfileIcicleGraph
graph={parca10mGraph}
sampleUnit={parca10mGraph.unit}
loading={false}
graph={parcaGraph}
sampleUnit={parcaGraph.unit}
curPath={[]}
setNewCurPath={() => {}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,21 @@ import React from 'react';
import ProfileIcicleGraph from '..';
import {Provider} from 'react-redux';
import {store} from '@parca/store';
import parca20mGraphData from './benchdata/parca-20m.json';
import parcaGraphData from './benchdata/parca-1h.json';
import {Flamegraph} from '@parca/client';

const {store: reduxStore} = store();

const parca20mGraph = parca20mGraphData as Flamegraph;
const parcaGraph = parcaGraphData as Flamegraph;

export default function ({callback = () => {}}): React.ReactElement {
return (
<div ref={callback}>
<Provider store={reduxStore}>
<ProfileIcicleGraph
graph={parca20mGraph}
sampleUnit={parca20mGraph.unit}
loading={false}
graph={parcaGraph}
sampleUnit={parcaGraph.unit}
curPath={[]}
setNewCurPath={() => {}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,24 @@
// limitations under the License.

import React from 'react';
import ProfileIcicleGraph from '../';
import ProfileIcicleGraph from '..';
import {Provider} from 'react-redux';
import {store} from '@parca/store';
import parcaGraphData from './benchdata/parca-3d.json';
import {Flamegraph} from '@parca/client';
import parca1mGraphData from './benchdata/parca-1m.json';

const {store: reduxStore} = store();

const parca1mGraph = parca1mGraphData as Flamegraph;
const parcaGraph = parcaGraphData as Flamegraph;

export default function ({callback = () => {}}): React.ReactElement {
return (
<div ref={callback}>
<Provider store={reduxStore}>
<ProfileIcicleGraph
graph={parca1mGraph}
sampleUnit={parca1mGraph.unit}
loading={false}
graph={parcaGraph}
sampleUnit={parcaGraph.unit}
curPath={[]}
setNewCurPath={() => {}}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2022 The Parca Authors
// 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.

import React from 'react';
import ProfileIcicleGraph from '..';
import {Provider} from 'react-redux';
import {store} from '@parca/store';
import parcaGraphData from './benchdata/parca-6h.json';
import {Flamegraph} from '@parca/client';

const {store: reduxStore} = store();

const parcaGraph = parcaGraphData as Flamegraph;

export default function ({callback = () => {}}): React.ReactElement {
return (
<div ref={callback}>
<Provider store={reduxStore}>
<ProfileIcicleGraph
loading={false}
graph={parcaGraph}
sampleUnit={parcaGraph.unit}
curPath={[]}
setNewCurPath={() => {}}
/>
</Provider>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import commandLineArgs from 'command-line-args';

const optionDefinitions = [{name: 'apiEndpoint', type: String}];
const options = commandLineArgs(optionDefinitions);

export const getApiEndPoint = () => {
return options.apiEndpoint ?? 'https://demo.parca.dev';
};

export const getGrpcMetadata = () => {
return {meta: JSON.parse(process.env.GRPC_METADATA ?? '{}')};
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ const fs = require('fs-extra');
const path = require('path');
// const {fileURLToPath} = require('url');
const fetch = require('node-fetch');
const {getApiEndPoint, getGrpcMetadata} = require('./common');

globalThis.fetch = fetch;
globalThis.Headers = fetch.Headers;
const DIR_NAME = __dirname; // path.dirname(fileURLToPath(import.meta.url));

const apiEndpoint = 'https://demo.parca.dev';
const apiEndpoint = getApiEndPoint();

const queryClient = new client.QueryServiceClient(
new GrpcWebFetchTransport({
Expand All @@ -35,18 +36,21 @@ const populateDataIfNeeded = async (from, filename) => {
if (Object.keys(await readFile(filePath)).length > 0) {
return;
}
const {response} = await queryClient.query({
options: {
oneofKind: 'merge',
merge: {
start: client.Timestamp.fromDate(from),
end: client.Timestamp.fromDate(new Date()),
query: 'parca_agent_cpu:samples:count:cpu:nanoseconds:delta{container="parca"}',
const {response} = await queryClient.query(
{
options: {
oneofKind: 'merge',
merge: {
start: client.Timestamp.fromDate(from),
end: client.Timestamp.fromDate(new Date()),
query: 'parca_agent_cpu:samples:count:cpu:nanoseconds:delta{}',
},
},
reportType: client.QueryRequest_ReportType.FLAMEGRAPH_TABLE,
mode: client.QueryRequest_Mode.MERGE,
},
reportType: client.QueryRequest_ReportType.FLAMEGRAPH_TABLE,
mode: client.QueryRequest_Mode.MERGE,
});
getGrpcMetadata()
);
if (response.report.oneofKind !== 'flamegraph') {
throw new Error('Expected flamegraph report');
}
Expand All @@ -68,9 +72,12 @@ const readFile = async filename => {

const run = async () => {
await Promise.all([
populateDataIfNeeded(new Date(new Date().getTime() - 1000 * 60), 'parca-1m.json'),
populateDataIfNeeded(new Date(new Date().getTime() - 1000 * 60 * 10), 'parca-10m.json'),
populateDataIfNeeded(new Date(new Date().getTime() - 1000 * 60 * 20), 'parca-20m.json'),
populateDataIfNeeded(new Date(new Date().getTime() - 1000 * 60 * 15), 'parca-15m.json'),
populateDataIfNeeded(new Date(new Date().getTime() - 1000 * 60 * 60), 'parca-1h.json'),
populateDataIfNeeded(new Date(new Date().getTime() - 1000 * 60 * 60 * 6), 'parca-6h.json'),
populateDataIfNeeded(new Date(new Date().getTime() - 1000 * 60 * 60 * 12), 'parca-12h.json'),
populateDataIfNeeded(new Date(new Date().getTime() - 1000 * 60 * 60 * 24), 'parca-1d.json'),
populateDataIfNeeded(new Date(new Date().getTime() - 1000 * 60 * 60 * 24 * 3), 'parca-3d.json'),
]);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ const fs = require('fs-extra');
const path = require('path');
// const {fileURLToPath} = require('url');
const fetch = require('node-fetch');
const {
getApiEndPoint,
getGrpcMetadata,
} = require('../../../ProfileIcicleGraph/benchmarks/benchdata/common');

globalThis.fetch = fetch;
globalThis.Headers = fetch.Headers;
const DIR_NAME = __dirname; // path.dirname(fileURLToPath(import.meta.url));

const apiEndpoint = 'https://demo.parca.dev';
const apiEndpoint = getApiEndPoint();

const queryClient = new client.QueryServiceClient(
new GrpcWebFetchTransport({
Expand All @@ -35,18 +39,21 @@ const populateDataIfNeeded = async (from, filename) => {
if (Object.keys(await readFile(filePath)).length > 0) {
return;
}
const {response} = await queryClient.query({
options: {
oneofKind: 'merge',
merge: {
start: client.Timestamp.fromDate(from),
end: client.Timestamp.fromDate(new Date()),
query: 'parca_agent_cpu:samples:count:cpu:nanoseconds:delta{container="parca"}',
const {response} = await queryClient.query(
{
options: {
oneofKind: 'merge',
merge: {
start: client.Timestamp.fromDate(from),
end: client.Timestamp.fromDate(new Date()),
query: 'parca_agent_cpu:samples:count:cpu:nanoseconds:delta{container="parca"}',
},
},
reportType: client.QueryRequest_ReportType.TOP,
mode: client.QueryRequest_Mode.MERGE,
},
reportType: client.QueryRequest_ReportType.TOP,
mode: client.QueryRequest_Mode.MERGE,
});
getGrpcMetadata()
);
if (response.report.oneofKind !== 'top') {
throw new Error('Expected topTable report');
}
Expand Down
42 changes: 42 additions & 0 deletions ui/scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Benchmark Runner

It is a simple benchmark tool that loads the given React component in the browser and measures the time it takes to render the component. It also has support for running dataPopulation scripts that can be used to populate the data from the remote api that the components need to render.

## Usage

```bash
$ yarn benchmark
```

## Options

```bash
yarn benchmark --pattern "ProfileIcicleGraph*"
```

To run only the benchmarks that match the given pattern.

```bash
yarn benchmark --pattern "ProfileIcicleGraph*" --name flamegraphBefore
```

To run only the benchmarks that match the given pattern and save the result with the given name.

```bash
yarn benchmark --pattern "ProfileIcicleGraph*" --compare "flamegraphBefore"
```

To run only the benchmarks that match the given pattern and compare them to the given result name.

```bash
yarn benchmark --apiEndpoint='https://api.example.com'
```

To run the dataPopulation script against a different API endpoint.

```bash
export GRPC_METADATA='{"key":"value","authorization":"Bearer ...."}'
yarn benchmark --apiEndpoint='https://api.example.com'
```

To run the dataPopulation script against a different API endpoint with custom headers.
15 changes: 10 additions & 5 deletions ui/scripts/run-benchmark.mts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const optionDefinitions = [
{name: 'debug', alias: 'd', type: Boolean},
{name: 'compare', alias: 'c', type: String},
{name: 'pattern', alias: 'p', type: String, defaultValue: '*'},
{name: 'apiEndpoint', type: String},
];
const options = commandLineArgs(optionDefinitions);
const IS_DEBUG = process.env.DEBUG === 'true' || options.debug === true;
Expand Down Expand Up @@ -163,11 +164,15 @@ const populateBenchmarkData = async (): Promise<void> => {
try {
stopwatch.start();
spinner.start(`Running data population script: ${file}`);
const {stdout} = await execa('babel-node', [
'--config-file',
path.join(DIR_NAME, '../babel.config.cjs'),
path.join(DIR_NAME, `../${file}`),
]);
const {stdout} = await execa(
'babel-node',
[
'--config-file',
path.join(DIR_NAME, '../babel.config.cjs'),
path.join(DIR_NAME, `../${file}`),
options.apiEndpoint != null ? `--apiEndpoint=${options.apiEndpoint}` : '',
].filter(Boolean)
);
console.log('stdout', stdout);
spinner.succeed(`Data population script: ${file} completed ${stopwatch.stopAndReset()}ms`);
} catch (error) {
Expand Down