- - mqt_js -
+ - RN JS Thread -
@@ -19875,7 +19951,7 @@ exports[`
renders the comparison view with videos 2`] = `
- - mqt_js for 1.5s
+ - RN JS Thread for 1.5s
renders the comparison view with videos 2`] = `
- - mqt_js -
+ - RN JS Thread -
@@ -20207,7 +20283,45 @@ exports[`
renders the comparison view with videos 2`] = `
- CPU Usage per thread (%)
+
+
+
+
+
+
+
+
+
+
+
+ RN JS Thread CPU Usage (%)
+
renders the comparison view with videos 2`] = `
- Threads
+ Other threads
(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/packages/core/web-reporter-ui/src/components/icons/ReactNativeLogo.tsx b/packages/core/web-reporter-ui/src/components/icons/ReactNativeLogo.tsx
new file mode 100644
index 00000000..dd48289a
--- /dev/null
+++ b/packages/core/web-reporter-ui/src/components/icons/ReactNativeLogo.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+
+export const RNLogo = ({ size }: { size: number }) => (
+
+
+
+
+
+
+
+
+);
diff --git a/packages/core/web-reporter-ui/src/sections/CPUReport.tsx b/packages/core/web-reporter-ui/src/sections/CPUReport.tsx
index 5152ad28..11c5bc51 100644
--- a/packages/core/web-reporter-ui/src/sections/CPUReport.tsx
+++ b/packages/core/web-reporter-ui/src/sections/CPUReport.tsx
@@ -1,15 +1,11 @@
import React from "react";
-import {
- AveragedTestCaseResult,
- Measure,
- POLLING_INTERVAL,
- ThreadNames,
-} from "@perf-profiler/types";
+import { AveragedTestCaseResult, Measure, POLLING_INTERVAL } from "@perf-profiler/types";
import { ComparativeThreadTable, ThreadTable } from "../components/ThreadTable";
import { Collapsible } from "../components/Collapsible";
import { getColorPalette } from "../theme/colors";
import { getAverageCpuUsage, roundToDecimal } from "@perf-profiler/reporter";
import { ReportChart } from "../components/Charts/ReportChart";
+import { THREAD_ICON_MAPPING, getAutoSelectedThreads } from "./threads";
const buildSeriesData = (measures: Measure[], calculate: (measure: Measure) => number) =>
measures
@@ -29,32 +25,6 @@ const totalCpuAnnotationInterval = [{ y: 300, y2: 1000, color: "#E62E2E", label:
const perThreadCpuAnnotationInterval = [{ y: 90, y2: 100, color: "#E62E2E", label: "Danger Zone" }];
-const autoSelectedThreads = [
- ThreadNames.RN.JS_IOS,
- ThreadNames.RN.JS_ANDROID,
- ThreadNames.RN.JS_BRIDGELESS_ANDROID,
- ThreadNames.FLUTTER.UI,
- ThreadNames.ANDROID.UI,
- ThreadNames.IOS.UI,
-];
-
-const getAutoSelectedThreads = (results: AveragedTestCaseResult[]) => {
- const autoSelectedThread = autoSelectedThreads.find((threadName) =>
- results
- .filter((result) => result.average.measures.length > 0)
- .every((result) => {
- const lastMeasure = result.average.measures[result.average.measures.length - 1];
- return (
- lastMeasure.cpu.perName[threadName] !== undefined ||
- // Support legacy json files with thread names in parenthesis
- lastMeasure.cpu.perName[`(${threadName})`] !== undefined
- );
- })
- );
-
- return autoSelectedThread ? [autoSelectedThread] : [];
-};
-
export const getNumberOfThreads = (results: AveragedTestCaseResult[]) => {
if (results.length === 0 || results[0].average.measures.length === 0) {
return 0;
@@ -82,6 +52,22 @@ export const CPUReport = ({ results }: { results: AveragedTestCaseResult[] }) =>
data: buildAverageCpuSeriesData(result.average.measures),
}));
+ const TitleIcon = THREAD_ICON_MAPPING[selectedThreads[0]];
+
+ const chartTitle =
+ selectedThreads.length === 1 ? (
+
+ {TitleIcon ? (
+
+
+
+ ) : null}
+ {`${selectedThreads[0]} CPU Usage (%)`}
+
+ ) : (
+ "CPU Usage per thread (%)"
+ );
+
return (
<>
{getNumberOfThreads(results) > 1 && (
<>
1 ? getColorPalette().slice(0, results.length) : undefined}
@@ -103,7 +89,7 @@ export const CPUReport = ({ results }: { results: AveragedTestCaseResult[] }) =>
/>
{"Threads"} }
+ header={
{"Other threads"}
}
className="border rounded-lg border-gray-800 py-4 px-4"
>
{results.length > 1 ? (
diff --git a/packages/core/web-reporter-ui/src/sections/threads.tsx b/packages/core/web-reporter-ui/src/sections/threads.tsx
new file mode 100644
index 00000000..f7cc7947
--- /dev/null
+++ b/packages/core/web-reporter-ui/src/sections/threads.tsx
@@ -0,0 +1,77 @@
+import React from "react";
+import { AveragedTestCaseResult, TestCaseResult, ThreadNames } from "@perf-profiler/types";
+import { RNLogo } from "../components/icons/ReactNativeLogo";
+import { FlutterLogo } from "../components/icons/FlutterLogo";
+
+export const getAutoSelectedThreads = (results: AveragedTestCaseResult[]) => {
+ const autoSelectedThread = autoSelectedThreads.find((threadName) =>
+ results
+ .filter((result) => result.average.measures.length > 0)
+ .every((result) => {
+ const lastMeasure = result.average.measures[result.average.measures.length - 1];
+ return (
+ lastMeasure.cpu.perName[threadName] !== undefined ||
+ // Support legacy json files with thread names in parenthesis
+ lastMeasure.cpu.perName[`(${threadName})`] !== undefined
+ );
+ })
+ );
+
+ return autoSelectedThread ? [autoSelectedThread] : [];
+};
+
+const THREAD_NAME_MAPPING: {
+ [key: string]: string;
+} = {
+ [ThreadNames.FLUTTER.UI]: "Flutter UI Thread",
+ [ThreadNames.FLUTTER.RASTER]: "Flutter Raster Thread",
+ [ThreadNames.FLUTTER.IO]: "Flutter IO Thread",
+ [ThreadNames.RN.JS_ANDROID]: "RN JS Thread",
+ [ThreadNames.RN.JS_BRIDGELESS_ANDROID]: "RN JS Thread",
+ [ThreadNames.RN.JS_IOS]: "RN JS Thread",
+ [ThreadNames.RN.OLD_BRIDGE]: "RN Bridge Thread",
+};
+
+export const THREAD_ICON_MAPPING = {
+ [THREAD_NAME_MAPPING[ThreadNames.FLUTTER.UI]]: FlutterLogo,
+ [THREAD_NAME_MAPPING[ThreadNames.FLUTTER.RASTER]]: FlutterLogo,
+ [THREAD_NAME_MAPPING[ThreadNames.FLUTTER.IO]]: FlutterLogo,
+ [THREAD_NAME_MAPPING[ThreadNames.RN.JS_ANDROID]]: RNLogo,
+ [THREAD_NAME_MAPPING[ThreadNames.RN.JS_BRIDGELESS_ANDROID]]: RNLogo,
+ [THREAD_NAME_MAPPING[ThreadNames.RN.JS_IOS]]: RNLogo,
+ [THREAD_NAME_MAPPING[ThreadNames.RN.OLD_BRIDGE]]: RNLogo,
+};
+
+const autoSelectedThreads = [
+ ThreadNames.RN.JS_IOS,
+ ThreadNames.RN.JS_ANDROID,
+ ThreadNames.RN.JS_BRIDGELESS_ANDROID,
+ ThreadNames.FLUTTER.UI,
+ ThreadNames.ANDROID.UI,
+ ThreadNames.IOS.UI,
+].map((threadName) => THREAD_NAME_MAPPING[threadName] || threadName);
+
+export const getNumberOfThreads = (results: AveragedTestCaseResult[]) => {
+ if (results.length === 0 || results[0].average.measures.length === 0) {
+ return 0;
+ }
+ const lastMeasure = results[0].average.measures[results[0].average.measures.length - 1];
+ return Object.keys(lastMeasure.cpu.perName).length;
+};
+
+export const mapThreadNames = (results: TestCaseResult[]): TestCaseResult[] =>
+ results.map((result) => ({
+ ...result,
+ iterations: result.iterations.map((iteration) => ({
+ ...iteration,
+ measures: iteration.measures.map((measure) => ({
+ ...measure,
+ cpu: {
+ ...measure.cpu,
+ perName: Object.keys(measure.cpu.perName).reduce((acc, key) => {
+ return { ...acc, [THREAD_NAME_MAPPING[key] || key]: measure.cpu.perName[key] };
+ }, {}),
+ },
+ })),
+ })),
+ }));