modelDiagnostics.js 2.0 KB

1234567891011121314151617181920
  1. // Development-only, read-only browser evidence. No forced render or streaming changes.
  2. export function attachModelDiagnostics(scene, host, readState, {now=()=>performance.now(),isMoving=()=>false}={}) {
  3. const node=host.ownerDocument.createElement('details'),summary=host.ownerDocument.createElement('summary'),output=host.ownerDocument.createElement('output')
  4. node.setAttribute('data-model-diagnostics','');summary.textContent='模型加载诊断(开发)'
  5. node.style.cssText='position:absolute;bottom:4px;left:4px;z-index:8;max-width:420px;font:11px monospace;background:#061827dd;color:#bad4e0;padding:4px;pointer-events:auto'
  6. output.style.cssText='display:block;white-space:pre-wrap;max-height:180px;overflow:auto'
  7. output.setAttribute('aria-label','模型加载诊断读数');node.append(summary,output);host.appendChild(node)
  8. let start=null,lastFrame=null,lastPaint=-Infinity,total=0
  9. const durations=[],intervals=[]
  10. const add=(list,n)=>{list.push(n);if(list.length>120)list.shift()}
  11. const stats=list=>{const sorted=[...list].sort((a,b)=>a-b);return{samples:list.length,p50Ms:sorted.length?+sorted[Math.floor(sorted.length*.5)].toFixed(2):null,p95Ms:sorted.length?+sorted[Math.min(sorted.length-1,Math.floor(sorted.length*.95))].toFixed(2):null}}
  12. const pre=scene.preRender.addEventListener(()=>{start=now()})
  13. function paint(){const state=readState();output.textContent=JSON.stringify({...state,renderEvents:total,renderSubmissionDuration:stats(durations),movingFrameIntervals:stats(intervals),gpuTimeMeasured:false,fpsDuringIdleMeaningful:false},null,2)}
  14. const post=scene.postRender.addEventListener(()=>{const t=now();total++
  15. if(!host.ownerDocument.hidden){if(start!==null)add(durations,t-start);if(lastFrame!==null&&isMoving()&&t-lastFrame<1000)add(intervals,t-lastFrame)}
  16. start=null;lastFrame=t;if(t-lastPaint>=500){lastPaint=t;paint()}
  17. })
  18. summary.addEventListener('click',paint);paint()
  19. return()=>{pre();post();node.remove()}
  20. }