import {Timed} from "Player"; import {PerformanceChartPoint} from "Player/mobile/managers/IOSPerformanceTrackManager"; import React from 'react'; import {MobilePlayerContext, PlayerContext} from 'App/components/Session/playerContext'; import { observer } from 'mobx-react-lite'; import { AreaChart, Area, ComposedChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer, ReferenceLine, Label, } from 'recharts'; import { durationFromMsFormatted } from 'App/date'; import { formatBytes } from 'App/utils'; import {Tooltip as TooltipANT} from 'antd'; import stl from './performance.module.css'; import BottomBlock from '../BottomBlock'; import InfoLine from '../BottomBlock/InfoLine'; import { useStore } from 'App/mstore' import { Segmented } from 'antd' const CPU_VISUAL_OFFSET = 10; const FPS_COLOR = '#C5E5E7'; const FPS_STROKE_COLOR = '#92C7CA'; const FPS_LOW_COLOR = 'pink'; const FPS_VERY_LOW_COLOR = 'red'; const CPU_COLOR = '#A8D1DE'; const CPU_STROKE_COLOR = '#69A5B8'; const USED_HEAP_COLOR = '#A9ABDC'; const USED_HEAP_STROKE_COLOR = '#8588CF'; const TOTAL_HEAP_STROKE_COLOR = '#4A4EB7'; const NODES_COUNT_COLOR = '#C6A9DC'; const NODES_COUNT_STROKE_COLOR = '#7360AC'; const HIDDEN_SCREEN_COLOR = '#CCC'; const CURSOR_COLOR = '#394EFF'; const Gradient = ({ color, id }) => ( ); const TOTAL_HEAP = 'Allocated Heap'; const USED_HEAP = 'JS Heap'; const FPS = 'Framerate'; const CPU = 'CPU Load'; const NODES_COUNT = 'Nodes Сount'; const FPSTooltip = ({ active, payload }) => { if (!payload) return null; if (!active || !payload || payload.length < 3) { return null; } if (payload[0].value === null) { return (
{'Page is not active. User switched the tab or hid the window.'}
); } let style; if (payload[1].value != null && payload[1].value > 0) { style = { color: FPS_LOW_COLOR }; } if (payload[2].value != null && payload[2].value > 0) { style = { color: FPS_VERY_LOW_COLOR }; } return (
{`${FPS}: `} {Math.trunc(payload[0].value)}
); }; const CPUTooltip = ({ active, payload }) => { if (!payload) return null; if (!active || payload.length < 1 || payload[0].value === null) { return null; } return (
{`${CPU}: `} {payload[0].value - CPU_VISUAL_OFFSET} {'%'}
); }; const MobileCpuTooltip = ({ active, payload }) => { if (!payload) return null; if (!active || payload.length < 1) { return null; } if (payload[0].value === null) { return (
{'App is in the background.'}
); } return (
{`${CPU}: `} {payload[0].value} {'%'}
); } const HeapTooltip = ({ active, payload }) => { if (!payload) return null; if (!active || payload.length < 2) return null; return (

{`${TOTAL_HEAP}: `} {formatBytes(payload[0].value)}

{`${USED_HEAP}: `} {formatBytes(payload[1].value)}

); }; const MobileMemoryTooltip = ({ active, payload }) => { if (!payload) return null; if (!active || payload.length < 1 || payload[1].value === null) return null; return (

Used Memory: {formatBytes(payload[1].value)}

); } const NodesCountTooltip = ({ active, payload }) => { if (!payload) return null; if (!active || !payload || payload.length === 0) return null; return (

{`${NODES_COUNT}: `} {payload[0].value}

); }; const TICKS_COUNT = 10; function generateTicks(data: Array): Array { if (data.length === 0) return []; const minTime = data[0].time; const maxTime = data[data.length - 1].time; const ticks = []; const tickGap = (maxTime - minTime) / (TICKS_COUNT + 1); for (let i = 0; i < TICKS_COUNT; i++) { const tick = tickGap * (i + 1) + minTime; ticks.push(tick); } return ticks; } const LOW_FPS = 30; const VERY_LOW_FPS = 20; const LOW_FPS_MARKER_VALUE = 5; const HIDDEN_SCREEN_MARKER_VALUE = 20; function addFpsMetadata(data) { return [...data].map((point, i) => { let fpsVeryLowMarker = null; let fpsLowMarker = null; let hiddenScreenMarker = 0; if (point.fps != null) { fpsVeryLowMarker = 0; fpsLowMarker = 0; if (point.fps < VERY_LOW_FPS) { fpsVeryLowMarker = LOW_FPS_MARKER_VALUE; } else if (point.fps < LOW_FPS) { fpsLowMarker = LOW_FPS_MARKER_VALUE; } } if ( point.fps == null || (i > 0 && data[i - 1].fps == null) //|| //(i < data.length-1 && data[i + 1].fps == null) ) { hiddenScreenMarker = HIDDEN_SCREEN_MARKER_VALUE; } if (point.cpu != null) { point.cpu += CPU_VISUAL_OFFSET; } return { ...point, fpsLowMarker, fpsVeryLowMarker, hiddenScreenMarker, }; }); } function generateMobileChart(data: PerformanceChartPoint[], biggestMemSpike: number) { return data.map(p => ({ ...p, isBackground: p.isBackground ? 50 : 0, isMemBackground: p.isBackground ? biggestMemSpike : 0 })) } export const MobilePerformance = observer(() => { const { player, store } = React.useContext(MobilePlayerContext); const [_timeTicks, setTicks] = React.useState([]) const [_data, setData] = React.useState([]) const { sessionStore } = useStore(); const { performanceChartTime = 0, performanceChartData = [], } = store.get(); React.useEffect(() => { // setTicks(generateTicks(performanceChartData)); setTicks(performanceChartData.map(p => p.time)); const biggestMemSpike = performanceChartData.reduce((acc, p) => { if (p.memory && p.memory > acc) return p.memory; return acc; }, 0); setData(generateMobileChart(performanceChartData, biggestMemSpike)); }, []) const onDotClick = ({ index: pointer }: { index: number }) => { const point = _data[pointer]; if (!!point) { player.jump(point.time); } }; const onChartClick = (e: any) => { if (e === null) return; const { activeTooltipIndex } = e; const point = _data[activeTooltipIndex]; if (!!point) { player.jump(point.time); } }; const availableCount = 2 const height = `${100 / availableCount}%`; return (
Performance
{/* */} ''} domain={[0, 'dataMax']} ticks={_timeTicks} > ''} // tick={false} + _timeTicks to cartesian array domain={[0, 'dataMax']} ticks={_timeTicks} > max * 1.2]} /> {/**/}
); }); function Performance() { const { sessionStore } = useStore(); const userDeviceHeapSize = sessionStore.current.userDeviceHeapSize || 0; const { player, store } = React.useContext(PlayerContext); const [_timeTicks, setTicks] = React.useState([]) const [_data, setData] = React.useState([]) const { // connType, // connBandwidth, tabStates, currentTab, } = store.get(); const { performanceChartTime = [], performanceChartData = [], performanceAvailability: availability = {} } = tabStates[currentTab]; React.useEffect(() => { setTicks(generateTicks(performanceChartData)); setData(addFpsMetadata(performanceChartData)); }, [currentTab]) const onDotClick = ({ index: pointer }: { index: number }) => { const point = _data[pointer]; if (!!point) { player.jump(point.time); } }; const onChartClick = (e: any) => { if (e === null) return; const { activeTooltipIndex } = e; const point = _data[activeTooltipIndex]; if (!!point) { player.jump(point.time); } }; const { fps, cpu, heap, nodes } = availability; const availableCount = [fps, cpu, heap, nodes].reduce((c, av) => (av ? c + 1 : c), 0); const height = availableCount === 0 ? '0' : `${100 / availableCount}%`; return (
Performance
All Tabs ), value: 'all', disabled: true, }, { label: 'Current Tab', value: 'current' }, ]} defaultValue="current" size="small" className="rounded-full font-medium" />
{fps && ( )} {cpu && ( {/* */} ''} domain={[0, 'dataMax']} ticks={_timeTicks} > )} {heap && ( ''} // tick={false} + _timeTicks to cartesian array domain={[0, 'dataMax']} ticks={_timeTicks} > max * 1.2]} /> )} {nodes && ( ''} domain={[0, 'dataMax']} ticks={_timeTicks} > max * 1.2]} /> )}
); } export const ConnectedPerformance = observer(Performance);