@@ -29,9 +29,8 @@ export class Sync {
2929 // There's probably a way to use Effect, but lets keep it simple for now.
3030 #update: PromiseWithResolvers < void > ;
3131
32- // Batched late-frame tracking: accumulate count and max lateness, log on recovery.
33- #lateCount = 0 ;
34- #lateMaxMs = 0 ;
32+ // Per-label late-frame tracking: accumulate count and max lateness, flush on recovery.
33+ #late = new Map < string , { count : number ; maxMs : number } > ( ) ;
3534
3635 signals = new Effect ( ) ;
3736
@@ -58,7 +57,7 @@ export class Sync {
5857 }
5958
6059 // Update the reference if this is the earliest frame we've seen, relative to its timestamp.
61- received ( timestamp : Time . Milli ) : void {
60+ received ( timestamp : Time . Milli , label = "" ) : void {
6261 const now = Time . Milli . now ( ) ;
6362 const ref = Time . Milli . sub ( now , timestamp ) ;
6463 const currentRef = this . #reference. peek ( ) ;
@@ -69,12 +68,21 @@ export class Sync {
6968 // Otherwise, chained `wait()` calls would cause a false-positive during CPU starvation.
7069 const sleep = Time . Milli . add ( Time . Milli . sub ( currentRef , ref ) , this . #latency. peek ( ) ) ;
7170 if ( sleep < 0 ) {
72- this . #lateCount++ ;
73- this . #lateMaxMs = Math . max ( this . #lateMaxMs, - sleep ) ;
74- } else if ( this . #lateCount > 0 ) {
75- console . warn ( `sync: ${ this . #lateCount} late frame(s), max ${ Math . round ( this . #lateMaxMs) } ms behind` ) ;
76- this . #lateCount = 0 ;
77- this . #lateMaxMs = 0 ;
71+ const entry = this . #late. get ( label ) ;
72+ if ( entry ) {
73+ entry . count ++ ;
74+ entry . maxMs = Math . max ( entry . maxMs , - sleep ) ;
75+ } else {
76+ this . #late. set ( label , { count : 1 , maxMs : - sleep } ) ;
77+ }
78+ } else {
79+ const entry = this . #late. get ( label ) ;
80+ if ( entry ) {
81+ const prefix = label ? `sync[${ label } ]` : "sync" ;
82+ const behind = Sync . #formatDuration( entry . maxMs ) ;
83+ console . warn ( `${ prefix } : ${ entry . count } late frame(s), max ${ behind } behind` ) ;
84+ this . #late. delete ( label ) ;
85+ }
7886 }
7987
8088 if ( ref >= currentRef ) {
@@ -114,6 +122,15 @@ export class Sync {
114122 }
115123 }
116124
125+ static #formatDuration( ms : number ) : string {
126+ ms = Math . round ( ms ) ;
127+ if ( ms < 1000 ) return `${ ms } ms` ;
128+ const s = ms / 1000 ;
129+ if ( s < 60 ) return `${ Math . round ( s * 10 ) / 10 } s` ;
130+ const m = s / 60 ;
131+ return `${ Math . round ( m * 10 ) / 10 } m` ;
132+ }
133+
117134 close ( ) {
118135 this . signals . close ( ) ;
119136 }
0 commit comments