Skip to content

Commit

Permalink
feat(report) : add statistics in averaged summary (#178)
Browse files Browse the repository at this point in the history
* refactor: group round function, add default parameter to roundToDecimal

* feat: add getStandardDeviation

* feat: add getMinMax

* refactor: splitting reporting.ts by stat

* feat: dedicated file, add function getRamStats

* feat: dedicated file, add getHighCpuStats

* feat: dedicated file, add getCpuStats

* feat: dedicated file, add getFpsStats

* feat: dedicated file, add getRuntimeStats

* (KO) chore: update imports

* feat: Report has public function getStats

* feat: to display stats in averaged summary

* feat: to pass SummaryStats

* feat: display stats only when average is displayed

* fix(HighCpu): should use measure as averageTotalHighCpu

* snapshot: changes since we use lodash round function now

* feat(HighCpu): add getStatsByThread

* feat(HighCpu): display stats by thread
  • Loading branch information
bam-charlesbo committed Dec 5, 2023
1 parent e4c9f40 commit d718057
Show file tree
Hide file tree
Showing 20 changed files with 2,214 additions and 319 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -418,9 +418,6 @@ exports[`flashlight measure interactive it displays measures: Web app with measu
class="cursor-default overflow-hidden transition-[height] duration-300"
style="height: 0px;"
>
<div
class="h-2"
/>
<div
class="text-neutral-400 text-sm"
>
Expand Down Expand Up @@ -487,9 +484,6 @@ exports[`flashlight measure interactive it displays measures: Web app with measu
class="cursor-default overflow-hidden transition-[height] duration-300"
style="height: 0px;"
>
<div
class="h-2"
/>
<div
class="text-neutral-400 text-sm"
>
Expand Down Expand Up @@ -564,9 +558,6 @@ exports[`flashlight measure interactive it displays measures: Web app with measu
class="cursor-default overflow-hidden transition-[height] duration-300"
style="height: 0px;"
>
<div
class="h-2"
/>
<div
class="text-neutral-400 text-sm"
>
Expand Down Expand Up @@ -641,9 +632,6 @@ exports[`flashlight measure interactive it displays measures: Web app with measu
class="cursor-default overflow-hidden transition-[height] duration-300"
style="height: 0px;"
>
<div
class="h-2"
/>
<div
class="text-neutral-400 text-sm"
>
Expand Down Expand Up @@ -720,9 +708,6 @@ exports[`flashlight measure interactive it displays measures: Web app with measu
class="cursor-default overflow-hidden transition-[height] duration-300"
style="height: 0px;"
>
<div
class="h-2"
/>
<div
class="text-neutral-400 text-sm"
>
Expand Down Expand Up @@ -3460,9 +3445,6 @@ exports[`flashlight measure interactive it displays measures: Web app with no me
class="cursor-default overflow-hidden transition-[height] duration-300"
style="height: 0px;"
>
<div
class="h-2"
/>
<div
class="text-neutral-400 text-sm"
>
Expand Down Expand Up @@ -3529,9 +3511,6 @@ exports[`flashlight measure interactive it displays measures: Web app with no me
class="cursor-default overflow-hidden transition-[height] duration-300"
style="height: 0px;"
>
<div
class="h-2"
/>
<div
class="text-neutral-400 text-sm"
>
Expand Down Expand Up @@ -3606,9 +3585,6 @@ exports[`flashlight measure interactive it displays measures: Web app with no me
class="cursor-default overflow-hidden transition-[height] duration-300"
style="height: 0px;"
>
<div
class="h-2"
/>
<div
class="text-neutral-400 text-sm"
>
Expand Down Expand Up @@ -3679,9 +3655,6 @@ exports[`flashlight measure interactive it displays measures: Web app with no me
class="cursor-default overflow-hidden transition-[height] duration-300"
style="height: 0px;"
>
<div
class="h-2"
/>
<div
class="text-neutral-400 text-sm"
>
Expand Down Expand Up @@ -3753,9 +3726,6 @@ exports[`flashlight measure interactive it displays measures: Web app with no me
class="cursor-default overflow-hidden transition-[height] duration-300"
style="height: 0px;"
>
<div
class="h-2"
/>
<div
class="text-neutral-400 text-sm"
>
Expand Down
4 changes: 2 additions & 2 deletions packages/core/reporter/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export * from "./reporting/averageIterations";
export * from "./reporting/getScore";
export * from "./reporting/reporting";
export * from "./reporting/Report";
export * from "./utils/sanitizeProcessName";
export * from "./utils/roundToDecimal";
export * from "./utils/round";
export * from "./reporting/cpu";
26 changes: 18 additions & 8 deletions packages/core/reporter/src/reporting/Report.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { TestCaseResult, AveragedTestCaseResult } from "@perf-profiler/types";
import { roundToDecimal } from "../utils/roundToDecimal";
import { roundToDecimal } from "../utils/round";
import { averageTestCaseResult } from "./averageIterations";
import {
getAverageCpuUsage,
getAverageCpuUsagePerProcess,
getAverageFPSUsage,
getAverageRAMUsage,
getAverageTotalHighCPUUsage,
} from "./reporting";
import { getScore } from "./getScore";
import { getAverageCpuUsage, getAverageCpuUsagePerProcess, getCpuStats } from "./cpu";
import { getAverageFPSUsage, getFpsStats } from "./fps";
import { getAverageTotalHighCPUUsage, getHighCpuStats } from "./highCpu";
import { getAverageRAMUsage, getRamStats } from "./ram";
import { getRuntimeStats } from "./runtime";

interface ReportMetrics {
runtime: number;
Expand Down Expand Up @@ -101,4 +99,16 @@ export class Report {
public getAverageMetrics() {
return this.averageMetrics;
}

public getStats() {
const iterations = this.result.iterations;

return {
cpu: getCpuStats(iterations, this.averageMetrics.cpu),
fps: getFpsStats(iterations, this.averageMetrics.fps),
highCpu: getHighCpuStats(iterations, this.averagedResult.averageHighCpuUsage),
ram: getRamStats(iterations, this.averageMetrics.ram),
runtime: getRuntimeStats(iterations, this.averageMetrics.runtime),
};
}
}
6 changes: 2 additions & 4 deletions packages/core/reporter/src/reporting/averageIterations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
TestCaseResult,
} from "@perf-profiler/types";
import { mapValues } from "lodash";
import { getHighCpuUsageStats } from "./reporting";
import { getHighCpuUsage } from "./highCpu";

const range = (n: number) =>
Array(n)
Expand Down Expand Up @@ -66,9 +66,7 @@ export const averageIterations = (results: TestCaseIterationResult[]): TestCaseI
};

export const averageHighCpuUsage = (results: TestCaseIterationResult[], cpuUsageThreshold = 90) => {
return averageMaps(
results.map((result) => getHighCpuUsageStats(result.measures, cpuUsageThreshold))
);
return averageMaps(results.map((result) => getHighCpuUsage(result.measures, cpuUsageThreshold)));
};

export const averageTestCaseResult = (result: TestCaseResult): AveragedTestCaseResult => {
Expand Down
60 changes: 60 additions & 0 deletions packages/core/reporter/src/reporting/cpu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Measure, TestCaseIterationResult } from "@perf-profiler/types";
import _, { round } from "lodash";
import { getMinMax } from "../utils/getMinMax";
import { getStandardDeviation } from "../utils/getStandardDeviation";
import { roundToDecimal } from "../utils/round";

const _getAverageCpuUsagePerProcess = (measures: Measure[]) =>
_(measures)
.map((measure) => measure.cpu)
.map(({ perName }) =>
Object.keys(perName).map((processName) => ({
processName,
cpuUsage: perName[processName],
}))
)
.flatten()
.groupBy((measure) => measure.processName)
.map((measure, processName) => ({
processName,
cpuUsage: _.sumBy(measure, (measure) => measure.cpuUsage) / measures.length,
}))
.orderBy((measure) => measure.cpuUsage, "desc")
.value();

export const getAverageCpuUsagePerProcess = (measures: Measure[]) =>
_getAverageCpuUsagePerProcess(measures).map((measure) => ({
...measure,
cpuUsage: round(measure.cpuUsage, 1),
}));

export const getAverageCpuUsage = (measures: Measure[]) =>
_getAverageCpuUsagePerProcess(measures).reduce<number>((sum, { cpuUsage }) => sum + cpuUsage, 0);

export const getStandardDeviationCPU = (
iterations: TestCaseIterationResult[],
averageCpu: number
): {
deviation: number;
deviationRange: [number, number];
} => {
const averageCpuUsages = iterations.map((iteration) => getAverageCpuUsage(iteration.measures));
return getStandardDeviation({
values: averageCpuUsages,
average: averageCpu,
});
};

export const getMinMaxCPU = (iterations: TestCaseIterationResult[]): [number, number] => {
const averageCpuUsages = iterations.map((iteration) => getAverageCpuUsage(iteration.measures));
return getMinMax(averageCpuUsages);
};

export const getCpuStats = (iterations: TestCaseIterationResult[], averageCpu: number) => {
const standardDeviation = getStandardDeviationCPU(iterations, averageCpu);
return {
minMaxRange: getMinMaxCPU(iterations),
deviationRange: standardDeviation.deviationRange,
variationCoefficient: roundToDecimal((standardDeviation.deviation / averageCpu) * 100),
};
};
40 changes: 40 additions & 0 deletions packages/core/reporter/src/reporting/fps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Measure, TestCaseIterationResult } from "@perf-profiler/types";
import { getMinMax } from "../utils/getMinMax";
import { getStandardDeviation } from "../utils/getStandardDeviation";
import { roundToDecimal } from "../utils/round";
import { average } from "./averageIterations";

export const getAverageFPSUsage = (measures: Measure[]) =>
average(measures.map((measure) => measure.fps));

export const getStandardDeviationFPS = (
iterations: TestCaseIterationResult[],
averageFps: number
) => {
const averageFpsUsages: number[] = [];
iterations.forEach((iteration) => {
const value = getAverageFPSUsage(iteration.measures);
value && averageFpsUsages.push(value);
});
return getStandardDeviation({ values: averageFpsUsages, average: averageFps });
};

const getMinMaxFPS = (iterations: TestCaseIterationResult[]): [number, number] => {
const averageFpsUsages: number[] = [];
iterations.forEach((iteration) => {
const value = getAverageFPSUsage(iteration.measures);
value && averageFpsUsages.push(value);
});
return getMinMax(averageFpsUsages);
};

export const getFpsStats = (iterations: TestCaseIterationResult[], averageFps?: number) => {
if (!averageFps) return undefined;

const standardDeviation = getStandardDeviationFPS(iterations, averageFps);
return {
minMaxRange: getMinMaxFPS(iterations),
deviationRange: standardDeviation.deviationRange,
variationCoefficient: roundToDecimal((standardDeviation.deviation / averageFps) * 100),
};
};
3 changes: 2 additions & 1 deletion packages/core/reporter/src/reporting/getScore.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { AveragedTestCaseResult, POLLING_INTERVAL } from "@perf-profiler/types";
import { round } from "lodash";
import { getAverageCpuUsage, getAverageFPSUsage } from "./reporting";
import { average } from "./averageIterations";
import { getAverageCpuUsage } from "./cpu";
import { getAverageFPSUsage } from "./fps";

/**
* From https://www.mathcelebrity.com/3ptquad.php?p1=50%2C100&p2=200%2C50&p3=300%2C15&pl=Calculate+Equation
Expand Down
89 changes: 89 additions & 0 deletions packages/core/reporter/src/reporting/highCpu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import {
Measure,
POLLING_INTERVAL,
TestCaseIterationResult,
AveragedTestCaseResult,
} from "@perf-profiler/types";
import _ from "lodash";
import { getMinMax } from "../utils/getMinMax";
import { getStandardDeviation } from "../utils/getStandardDeviation";
import { roundToDecimal } from "../utils/round";

export const getHighCpuUsage = (measures: Measure[], cpuUsageThreshold: number | undefined = 90) =>
_(measures)
.map((measure) => measure.cpu)
.map(({ perName }) =>
Object.keys(perName).map((processName) => ({
processName,
cpuUsage: perName[processName],
}))
)
.flatten()
.filter((measure) => measure.cpuUsage > cpuUsageThreshold)
.groupBy((measure) => measure.processName)
.mapValues((measures) => measures.length * POLLING_INTERVAL)
.value();

export const getAverageTotalHighCPUUsage = (highCpuProcesses: { [processName: string]: number }) =>
Object.keys(highCpuProcesses).reduce((sum, name) => sum + highCpuProcesses[name], 0);

const getStatsByThread = (iterations: TestCaseIterationResult[]) => {
const threads: { [threadName: string]: number[] } = {};
iterations.forEach((iteration) => {
const measure = getHighCpuUsage(iteration.measures);
Object.keys(measure).forEach((threadName) => {
if (!threads[threadName]) {
threads[threadName] = [];
}
threads[threadName].push(measure[threadName]);
});
});

const statsByThread: {
[threadName: string]: {
minMaxRange: [number, number];
deviationRange: [number, number];
variationCoefficient: number;
};
} = {};

Object.keys(threads).forEach((threadName) => {
const threadValues = threads[threadName];
const threadAverage = threadValues.reduce((sum, value) => sum + value, 0) / threadValues.length;
const threadStandardDeviation = getStandardDeviation({
values: threadValues,
average: threadAverage,
});
statsByThread[threadName] = {
minMaxRange: getMinMax(threadValues),
deviationRange: threadStandardDeviation.deviationRange,
variationCoefficient: roundToDecimal(
(threadStandardDeviation.deviation / threadAverage) * 100
),
};
});
return statsByThread;
};

export const getHighCpuStats = (
iterations: TestCaseIterationResult[],
averageResultHighCpuUsage: AveragedTestCaseResult["averageHighCpuUsage"]
) => {
const averageTotalHighCpu = getAverageTotalHighCPUUsage(averageResultHighCpuUsage);

const averageTotalHighCPuUsage = iterations.map((iteration) =>
getAverageTotalHighCPUUsage(getHighCpuUsage(iteration.measures))
);

const standardDeviation = getStandardDeviation({
values: averageTotalHighCPuUsage,
average: averageTotalHighCpu,
});

return {
threads: getStatsByThread(iterations),
minMaxRange: getMinMax(averageTotalHighCPuUsage),
deviationRange: standardDeviation.deviationRange,
variationCoefficient: roundToDecimal((standardDeviation.deviation / averageTotalHighCpu) * 100),
};
};
29 changes: 29 additions & 0 deletions packages/core/reporter/src/reporting/ram.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Measure, TestCaseIterationResult } from "@perf-profiler/types";
import { getMinMax } from "../utils/getMinMax";
import { getStandardDeviation } from "../utils/getStandardDeviation";
import { roundToDecimal } from "../utils/round";
import { average } from "./averageIterations";

export const getAverageRAMUsage = (measures: Measure[]) =>
average(measures.map((measure) => measure.ram));

export const getRamStats = (iterations: TestCaseIterationResult[], averageRam?: number) => {
if (!averageRam) return undefined;

const values: number[] = [];
iterations.forEach((iteration) => {
const averageRamUsage = getAverageRAMUsage(iteration.measures);
averageRamUsage && values.push(averageRamUsage);
});

const standardDeviation = getStandardDeviation({
values,
average: averageRam,
});

return {
minMaxRange: getMinMax(values),
deviationRange: standardDeviation.deviationRange,
variationCoefficient: roundToDecimal((standardDeviation.deviation / averageRam) * 100),
};
};

0 comments on commit d718057

Please sign in to comment.