1- import { useState , useEffect } from "react" ;
1+ import { useState , useEffect , useRef } from "react" ;
22import DataCard from "../components/DataCard" ;
33import { createCanProcessor } from "../utils/canProcessor" ;
44
@@ -10,6 +10,18 @@ function Dashboard() {
1010 rawData : string ;
1111 } } > ( { } ) ;
1212 const [ processor , setProcessor ] = useState < any > ( null ) ;
13+ const [ performanceStats , setPerformanceStats ] = useState ( {
14+ messagesPerSecond : 0 ,
15+ avgProcessingTime : 0 ,
16+ memoryUsage : 'N/A' as string | number ,
17+ fps : 0
18+ } ) ;
19+
20+ const messageCountRef = useRef ( 0 ) ;
21+ const processingTimesRef = useRef < number [ ] > ( [ ] ) ;
22+ const lastSecondRef = useRef ( Date . now ( ) ) ;
23+ const frameCountRef = useRef ( 0 ) ;
24+ const lastFpsUpdateRef = useRef ( Date . now ( ) ) ;
1325
1426 useEffect ( ( ) => {
1527 // Initialize CAN processor
@@ -36,6 +48,52 @@ function Dashboard() {
3648 } ) ;
3749 } , [ ] ) ;
3850
51+ // Performance monitoring
52+ useEffect ( ( ) => {
53+ // FPS monitoring
54+ const updateFPS = ( ) => {
55+ frameCountRef . current ++ ;
56+ const now = Date . now ( ) ;
57+ if ( now - lastFpsUpdateRef . current >= 1000 ) {
58+ const fps = Math . round ( ( frameCountRef . current * 1000 ) / ( now - lastFpsUpdateRef . current ) ) ;
59+ setPerformanceStats ( prev => ( { ...prev , fps } ) ) ;
60+
61+ if ( fps < 30 ) {
62+ console . warn ( `Low FPS: ${ fps } ` ) ;
63+ }
64+
65+ frameCountRef . current = 0 ;
66+ lastFpsUpdateRef . current = now ;
67+ }
68+ requestAnimationFrame ( updateFPS ) ;
69+ } ;
70+ requestAnimationFrame ( updateFPS ) ;
71+
72+ // Memory monitoring
73+ const updateMemory = ( ) => {
74+ if ( 'memory' in performance ) {
75+ const memInfo = ( performance as any ) . memory ;
76+ const memoryMB = Math . round ( memInfo . usedJSHeapSize / 1024 / 1024 ) ;
77+ console . log ( 'Memory info:' , memInfo , 'Memory MB:' , memoryMB ) ;
78+ setPerformanceStats ( prev => ( {
79+ ...prev ,
80+ memoryUsage : memoryMB
81+ } ) ) ;
82+
83+ if ( memoryMB > 100 ) {
84+ console . warn ( `High memory usage: ${ memoryMB } MB` ) ;
85+ }
86+ } else {
87+ console . log ( 'Performance.memory API not available' ) ;
88+ }
89+ } ;
90+ const memoryInterval = setInterval ( updateMemory , 2000 ) ;
91+
92+ return ( ) => {
93+ clearInterval ( memoryInterval ) ;
94+ } ;
95+ } , [ ] ) ;
96+
3997 // WebSocket connection for real-time CAN data
4098 useEffect ( ( ) => {
4199 if ( ! processor ) return ;
@@ -47,6 +105,8 @@ function Dashboard() {
47105 } ;
48106
49107 ws . onmessage = ( event ) => {
108+ const startTime = performance . now ( ) ;
109+
50110 try {
51111 console . log ( 'Received WebSocket message:' , event . data ) ;
52112
@@ -91,6 +151,46 @@ function Dashboard() {
91151 ...updates
92152 } ) ) ;
93153 }
154+
155+ // Performance tracking
156+ const processingTime = performance . now ( ) - startTime ;
157+ processingTimesRef . current . push ( processingTime ) ;
158+
159+ // Keep only last 100 processing times
160+ if ( processingTimesRef . current . length > 100 ) {
161+ processingTimesRef . current = processingTimesRef . current . slice ( - 100 ) ;
162+ }
163+
164+ // Count actual CAN messages decoded
165+ const canMessageCount = messagesToProcess . filter ( msg => msg && msg . signals ) . length ;
166+ messageCountRef . current += canMessageCount ;
167+
168+ // Update stats every second
169+ const now = Date . now ( ) ;
170+ if ( now - lastSecondRef . current >= 1000 ) {
171+ const messagesPerSecond = messageCountRef . current ;
172+ const avgProcessingTime = processingTimesRef . current . length > 0
173+ ? processingTimesRef . current . reduce ( ( a , b ) => a + b , 0 ) / processingTimesRef . current . length
174+ : 0 ;
175+
176+ setPerformanceStats ( prev => ( {
177+ ...prev ,
178+ messagesPerSecond,
179+ avgProcessingTime : Math . round ( avgProcessingTime * 100 ) / 100
180+ } ) ) ;
181+
182+ // Performance warnings
183+ if ( messagesPerSecond > 100 ) {
184+ console . warn ( `High CAN message rate: ${ messagesPerSecond } messages/sec` ) ;
185+ }
186+ if ( avgProcessingTime > 10 ) {
187+ console . warn ( `Slow processing: ${ avgProcessingTime } ms average` ) ;
188+ }
189+
190+ messageCountRef . current = 0 ;
191+ lastSecondRef . current = now ;
192+ }
193+
94194 } catch ( error ) {
95195 console . error ( 'Error processing WebSocket message:' , error ) ;
96196 }
@@ -110,32 +210,44 @@ function Dashboard() {
110210 } , [ processor ] ) ;
111211
112212 return (
113- < div className = "flex flex-wrap" >
114- { Object . entries ( canMessages ) . map ( ( [ canId , message ] ) => {
115- const data = Object . entries ( message . signals ) . map ( ( [ key , value ] ) => ( {
116- [ key ] : `${ value . sensorReading } ${ value . unit } `
117- } ) ) ;
213+ < div className = "flex flex-col min-h-screen" >
214+ < div className = "flex flex-wrap flex-1" >
215+ { Object . entries ( canMessages ) . map ( ( [ canId , message ] ) => {
216+ const data = Object . entries ( message . signals ) . map ( ( [ key , value ] ) => ( {
217+ [ key ] : `${ value . sensorReading } ${ value . unit } `
218+ } ) ) ;
219+
220+ return (
221+ < DataCard
222+ key = { canId }
223+ msgID = { canId }
224+ messageName = { message . messageName }
225+ data = { data . length > 0 ? data : [ { "No Data" : "Waiting for messages..." } ] }
226+ lastUpdated = { message . lastUpdated }
227+ rawData = { message . rawData }
228+ />
229+ ) ;
230+ } ) }
231+
232+ { /* Static card for comparison */ }
233+ < DataCard
234+ msgID = "1006"
235+ messageName = "TORCH_M1_V1"
236+ category = "BMS/TORCH"
237+ lastUpdated = { Date . now ( ) }
238+ rawData = "00 01 02 03 04 05 06 07"
239+ />
240+ </ div >
118241
119- return (
120- < DataCard
121- key = { canId }
122- msgID = { canId }
123- messageName = { message . messageName }
124- data = { data . length > 0 ? data : [ { "No Data" : "Waiting for messages..." } ] }
125- lastUpdated = { message . lastUpdated }
126- rawData = { message . rawData }
127- />
128- ) ;
129- } ) }
130-
131- { /* Static card for comparison */ }
132- < DataCard
133- msgID = "1006"
134- messageName = "TORCH_M1_V1"
135- category = "BMS/TORCH"
136- lastUpdated = { Date . now ( ) }
137- rawData = "00 01 02 03 04 05 06 07"
138- />
242+ { /* Performance Stats - low key at bottom */ }
243+ < div className = "w-full py-2 px-4 bg-gray-700 text-gray-300 text-xs border-t border-gray-600" >
244+ < div className = "flex justify-between items-center max-w-6xl mx-auto" >
245+ < span > FPS: { performanceStats . fps } </ span >
246+ < span > CAN frames/sec: { performanceStats . messagesPerSecond } </ span >
247+ < span > Avg: { performanceStats . avgProcessingTime } ms</ span >
248+ < span > Mem: { performanceStats . memoryUsage } { typeof performanceStats . memoryUsage === 'number' ? 'MB' : '' } </ span >
249+ </ div >
250+ </ div >
139251 </ div >
140252 ) ;
141253}
0 commit comments