ff731849b0
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Eric Bailey <git@esb.lol>
391 lines
11 KiB
Diff
391 lines
11 KiB
Diff
diff --git a/lib/module/component/PerformanceMonitor.js b/lib/module/component/PerformanceMonitor.js
|
|
index 9c98d6cc395419f50969753a4e4c7962b7be588f..3686a97280ac540efa0814ac4dea40358860a76f 100644
|
|
--- a/lib/module/component/PerformanceMonitor.js
|
|
+++ b/lib/module/component/PerformanceMonitor.js
|
|
@@ -1,125 +1,5 @@
|
|
'use strict';
|
|
|
|
-import React, { useEffect, useRef } from 'react';
|
|
-import { StyleSheet, TextInput, View } from 'react-native';
|
|
-import { addWhitelistedNativeProps } from "../ConfigHelper.js";
|
|
-import { createAnimatedComponent } from "../createAnimatedComponent/index.js";
|
|
-import { useAnimatedProps, useFrameCallback, useSharedValue } from "../hook/index.js";
|
|
-function createCircularDoublesBuffer(size) {
|
|
- 'worklet';
|
|
-
|
|
- return {
|
|
- next: 0,
|
|
- buffer: new Float32Array(size),
|
|
- size,
|
|
- count: 0,
|
|
- push(value) {
|
|
- const oldValue = this.buffer[this.next];
|
|
- const oldCount = this.count;
|
|
- this.buffer[this.next] = value;
|
|
- this.next = (this.next + 1) % this.size;
|
|
- this.count = Math.min(this.size, this.count + 1);
|
|
- return oldCount === this.size ? oldValue : null;
|
|
- },
|
|
- front() {
|
|
- const notEmpty = this.count > 0;
|
|
- if (notEmpty) {
|
|
- const current = this.next - 1;
|
|
- const index = current < 0 ? this.size - 1 : current;
|
|
- return this.buffer[index];
|
|
- }
|
|
- return null;
|
|
- },
|
|
- back() {
|
|
- const notEmpty = this.count > 0;
|
|
- return notEmpty ? this.buffer[this.next] : null;
|
|
- }
|
|
- };
|
|
-}
|
|
-const DEFAULT_BUFFER_SIZE = 20;
|
|
-addWhitelistedNativeProps({
|
|
- text: true
|
|
-});
|
|
-const AnimatedTextInput = createAnimatedComponent(TextInput);
|
|
-function loopAnimationFrame(fn) {
|
|
- let lastTime = 0;
|
|
- function loop() {
|
|
- requestAnimationFrame(time => {
|
|
- if (lastTime > 0) {
|
|
- fn(lastTime, time);
|
|
- }
|
|
- lastTime = time;
|
|
- requestAnimationFrame(loop);
|
|
- });
|
|
- }
|
|
- loop();
|
|
-}
|
|
-function getFps(renderTimeInMs) {
|
|
- 'worklet';
|
|
-
|
|
- return 1000 / renderTimeInMs;
|
|
-}
|
|
-function completeBufferRoutine(buffer, timestamp) {
|
|
- 'worklet';
|
|
-
|
|
- timestamp = Math.round(timestamp);
|
|
- const droppedTimestamp = buffer.push(timestamp) ?? timestamp;
|
|
- const measuredRangeDuration = timestamp - droppedTimestamp;
|
|
- return getFps(measuredRangeDuration / buffer.count);
|
|
-}
|
|
-function JsPerformance({
|
|
- smoothingFrames
|
|
-}) {
|
|
- const jsFps = useSharedValue(null);
|
|
- const totalRenderTime = useSharedValue(0);
|
|
- const circularBuffer = useRef(createCircularDoublesBuffer(smoothingFrames));
|
|
- useEffect(() => {
|
|
- loopAnimationFrame((_, timestamp) => {
|
|
- timestamp = Math.round(timestamp);
|
|
- const currentFps = completeBufferRoutine(circularBuffer.current, timestamp);
|
|
-
|
|
- // JS fps have to be measured every 2nd frame,
|
|
- // thus 2x multiplication has to occur here
|
|
- jsFps.value = (currentFps * 2).toFixed(0);
|
|
- });
|
|
- }, [jsFps, totalRenderTime]);
|
|
- const animatedProps = useAnimatedProps(() => {
|
|
- const text = 'JS: ' + (jsFps.value ?? 'N/A') + ' ';
|
|
- return {
|
|
- text,
|
|
- defaultValue: text
|
|
- };
|
|
- });
|
|
- return <View style={styles.container}>
|
|
- <AnimatedTextInput style={styles.text} animatedProps={animatedProps} editable={false} />
|
|
- </View>;
|
|
-}
|
|
-function UiPerformance({
|
|
- smoothingFrames
|
|
-}) {
|
|
- const uiFps = useSharedValue(null);
|
|
- const circularBuffer = useSharedValue(null);
|
|
- useFrameCallback(({
|
|
- timestamp
|
|
- }) => {
|
|
- if (circularBuffer.value === null) {
|
|
- circularBuffer.value = createCircularDoublesBuffer(smoothingFrames);
|
|
- }
|
|
- timestamp = Math.round(timestamp);
|
|
- const currentFps = completeBufferRoutine(circularBuffer.value, timestamp);
|
|
- uiFps.value = currentFps.toFixed(0);
|
|
- });
|
|
- const animatedProps = useAnimatedProps(() => {
|
|
- const text = 'UI: ' + (uiFps.value ?? 'N/A') + ' ';
|
|
- return {
|
|
- text,
|
|
- defaultValue: text
|
|
- };
|
|
- });
|
|
- return <View style={styles.container}>
|
|
- <AnimatedTextInput style={styles.text} animatedProps={animatedProps} editable={false} />
|
|
- </View>;
|
|
-}
|
|
/**
|
|
* A component that lets you measure fps values on JS and UI threads on both the
|
|
* Paper and Fabric architectures.
|
|
@@ -127,38 +7,7 @@ function UiPerformance({
|
|
* @param smoothingFrames - Determines amount of saved frames which will be used
|
|
* for fps value smoothing.
|
|
*/
|
|
-export function PerformanceMonitor({
|
|
- smoothingFrames = DEFAULT_BUFFER_SIZE
|
|
-}) {
|
|
- return <View style={styles.monitor}>
|
|
- <JsPerformance smoothingFrames={smoothingFrames} />
|
|
- <UiPerformance smoothingFrames={smoothingFrames} />
|
|
- </View>;
|
|
+export function PerformanceMonitor() {
|
|
+ return null;
|
|
}
|
|
-const styles = StyleSheet.create({
|
|
- monitor: {
|
|
- flexDirection: 'row',
|
|
- position: 'absolute',
|
|
- backgroundColor: '#0006',
|
|
- zIndex: 1000
|
|
- },
|
|
- header: {
|
|
- fontSize: 14,
|
|
- color: '#ffff',
|
|
- paddingHorizontal: 5
|
|
- },
|
|
- text: {
|
|
- fontSize: 13,
|
|
- fontVariant: ['tabular-nums'],
|
|
- color: '#ffff',
|
|
- fontFamily: 'monospace',
|
|
- paddingHorizontal: 3
|
|
- },
|
|
- container: {
|
|
- alignItems: 'center',
|
|
- justifyContent: 'center',
|
|
- flexDirection: 'row',
|
|
- flexWrap: 'wrap'
|
|
- }
|
|
-});
|
|
//# sourceMappingURL=PerformanceMonitor.js.map
|
|
\ No newline at end of file
|
|
diff --git a/src/component/PerformanceMonitor.tsx b/src/component/PerformanceMonitor.tsx
|
|
index ff8fc8a947a0aeb959e21ec061882c3d190a2ce0..34dde79727765623df80dbcdab5016de6fd5d82c 100644
|
|
--- a/src/component/PerformanceMonitor.tsx
|
|
+++ b/src/component/PerformanceMonitor.tsx
|
|
@@ -1,170 +1,5 @@
|
|
'use strict';
|
|
|
|
-import React, { useEffect, useRef } from 'react';
|
|
-import { StyleSheet, TextInput, View } from 'react-native';
|
|
-
|
|
-import { addWhitelistedNativeProps } from '../ConfigHelper';
|
|
-import { createAnimatedComponent } from '../createAnimatedComponent';
|
|
-import type { FrameInfo } from '../frameCallback';
|
|
-import { useAnimatedProps, useFrameCallback, useSharedValue } from '../hook';
|
|
-
|
|
-type CircularBuffer = ReturnType<typeof createCircularDoublesBuffer>;
|
|
-function createCircularDoublesBuffer(size: number) {
|
|
- 'worklet';
|
|
-
|
|
- return {
|
|
- next: 0 as number,
|
|
- buffer: new Float32Array(size),
|
|
- size,
|
|
- count: 0 as number,
|
|
-
|
|
- push(value: number): number | null {
|
|
- const oldValue = this.buffer[this.next];
|
|
- const oldCount = this.count;
|
|
- this.buffer[this.next] = value;
|
|
-
|
|
- this.next = (this.next + 1) % this.size;
|
|
- this.count = Math.min(this.size, this.count + 1);
|
|
- return oldCount === this.size ? oldValue : null;
|
|
- },
|
|
-
|
|
- front(): number | null {
|
|
- const notEmpty = this.count > 0;
|
|
- if (notEmpty) {
|
|
- const current = this.next - 1;
|
|
- const index = current < 0 ? this.size - 1 : current;
|
|
- return this.buffer[index];
|
|
- }
|
|
- return null;
|
|
- },
|
|
-
|
|
- back(): number | null {
|
|
- const notEmpty = this.count > 0;
|
|
- return notEmpty ? this.buffer[this.next] : null;
|
|
- },
|
|
- };
|
|
-}
|
|
-
|
|
-const DEFAULT_BUFFER_SIZE = 20;
|
|
-addWhitelistedNativeProps({ text: true });
|
|
-const AnimatedTextInput = createAnimatedComponent(TextInput);
|
|
-
|
|
-function loopAnimationFrame(fn: (lastTime: number, time: number) => void) {
|
|
- let lastTime = 0;
|
|
-
|
|
- function loop() {
|
|
- requestAnimationFrame((time) => {
|
|
- if (lastTime > 0) {
|
|
- fn(lastTime, time);
|
|
- }
|
|
- lastTime = time;
|
|
- requestAnimationFrame(loop);
|
|
- });
|
|
- }
|
|
-
|
|
- loop();
|
|
-}
|
|
-
|
|
-function getFps(renderTimeInMs: number): number {
|
|
- 'worklet';
|
|
- return 1000 / renderTimeInMs;
|
|
-}
|
|
-
|
|
-function completeBufferRoutine(
|
|
- buffer: CircularBuffer,
|
|
- timestamp: number
|
|
-): number {
|
|
- 'worklet';
|
|
- timestamp = Math.round(timestamp);
|
|
-
|
|
- const droppedTimestamp = buffer.push(timestamp) ?? timestamp;
|
|
-
|
|
- const measuredRangeDuration = timestamp - droppedTimestamp;
|
|
-
|
|
- return getFps(measuredRangeDuration / buffer.count);
|
|
-}
|
|
-
|
|
-function JsPerformance({ smoothingFrames }: { smoothingFrames: number }) {
|
|
- const jsFps = useSharedValue<string | null>(null);
|
|
- const totalRenderTime = useSharedValue(0);
|
|
- const circularBuffer = useRef<CircularBuffer>(
|
|
- createCircularDoublesBuffer(smoothingFrames)
|
|
- );
|
|
-
|
|
- useEffect(() => {
|
|
- loopAnimationFrame((_, timestamp) => {
|
|
- timestamp = Math.round(timestamp);
|
|
-
|
|
- const currentFps = completeBufferRoutine(
|
|
- circularBuffer.current,
|
|
- timestamp
|
|
- );
|
|
-
|
|
- // JS fps have to be measured every 2nd frame,
|
|
- // thus 2x multiplication has to occur here
|
|
- jsFps.value = (currentFps * 2).toFixed(0);
|
|
- });
|
|
- }, [jsFps, totalRenderTime]);
|
|
-
|
|
- const animatedProps = useAnimatedProps(() => {
|
|
- const text = 'JS: ' + (jsFps.value ?? 'N/A') + ' ';
|
|
- return { text, defaultValue: text };
|
|
- });
|
|
-
|
|
- return (
|
|
- <View style={styles.container}>
|
|
- <AnimatedTextInput
|
|
- style={styles.text}
|
|
- animatedProps={animatedProps}
|
|
- editable={false}
|
|
- />
|
|
- </View>
|
|
- );
|
|
-}
|
|
-
|
|
-function UiPerformance({ smoothingFrames }: { smoothingFrames: number }) {
|
|
- const uiFps = useSharedValue<string | null>(null);
|
|
- const circularBuffer = useSharedValue<CircularBuffer | null>(null);
|
|
-
|
|
- useFrameCallback(({ timestamp }: FrameInfo) => {
|
|
- if (circularBuffer.value === null) {
|
|
- circularBuffer.value = createCircularDoublesBuffer(smoothingFrames);
|
|
- }
|
|
-
|
|
- timestamp = Math.round(timestamp);
|
|
-
|
|
- const currentFps = completeBufferRoutine(circularBuffer.value, timestamp);
|
|
-
|
|
- uiFps.value = currentFps.toFixed(0);
|
|
- });
|
|
-
|
|
- const animatedProps = useAnimatedProps(() => {
|
|
- const text = 'UI: ' + (uiFps.value ?? 'N/A') + ' ';
|
|
- return { text, defaultValue: text };
|
|
- });
|
|
-
|
|
- return (
|
|
- <View style={styles.container}>
|
|
- <AnimatedTextInput
|
|
- style={styles.text}
|
|
- animatedProps={animatedProps}
|
|
- editable={false}
|
|
- />
|
|
- </View>
|
|
- );
|
|
-}
|
|
-
|
|
-export type PerformanceMonitorProps = {
|
|
- /**
|
|
- * Sets amount of previous frames used for smoothing at highest expectedFps.
|
|
- *
|
|
- * Automatically scales down at lower frame rates.
|
|
- *
|
|
- * Affects jumpiness of the FPS measurements value.
|
|
- */
|
|
- smoothingFrames?: number;
|
|
-};
|
|
-
|
|
/**
|
|
* A component that lets you measure fps values on JS and UI threads on both the
|
|
* Paper and Fabric architectures.
|
|
@@ -172,40 +7,6 @@ export type PerformanceMonitorProps = {
|
|
* @param smoothingFrames - Determines amount of saved frames which will be used
|
|
* for fps value smoothing.
|
|
*/
|
|
-export function PerformanceMonitor({
|
|
- smoothingFrames = DEFAULT_BUFFER_SIZE,
|
|
-}: PerformanceMonitorProps) {
|
|
- return (
|
|
- <View style={styles.monitor}>
|
|
- <JsPerformance smoothingFrames={smoothingFrames} />
|
|
- <UiPerformance smoothingFrames={smoothingFrames} />
|
|
- </View>
|
|
- );
|
|
+export function PerformanceMonitor() {
|
|
+ return null;
|
|
}
|
|
-
|
|
-const styles = StyleSheet.create({
|
|
- monitor: {
|
|
- flexDirection: 'row',
|
|
- position: 'absolute',
|
|
- backgroundColor: '#0006',
|
|
- zIndex: 1000,
|
|
- },
|
|
- header: {
|
|
- fontSize: 14,
|
|
- color: '#ffff',
|
|
- paddingHorizontal: 5,
|
|
- },
|
|
- text: {
|
|
- fontSize: 13,
|
|
- fontVariant: ['tabular-nums'],
|
|
- color: '#ffff',
|
|
- fontFamily: 'monospace',
|
|
- paddingHorizontal: 3,
|
|
- },
|
|
- container: {
|
|
- alignItems: 'center',
|
|
- justifyContent: 'center',
|
|
- flexDirection: 'row',
|
|
- flexWrap: 'wrap',
|
|
- },
|
|
-});
|