wake-up-neo.com

FPS in JS prüfen?

Wie überprüfe ich die fps meines Javascript? Ich verwende diese Schleife:

gameloopId = setInterval(gameLoop, 10);
33
CyanPrime

Betrachten Sie in gameLoop den Unterschied zwischen new Date und new Date von der letzten Schleife (speichern Sie ihn in einer Variablen).
Mit anderen Worten:

var lastLoop = new Date();
function gameLoop() { 
    var thisLoop = new Date();
    var fps = 1000 / (thisLoop - lastLoop);
    lastLoop = thisLoop;
    ...
}

thisLoop - lastLoop ist die Anzahl der Millisekunden, die zwischen den beiden Schleifen vergangen sind.

25
SLaks

Der Code von @Slaks gibt Ihnen nur die momentane FPS des letzten Frames, die bei Schluckaufzeiten variieren oder irreführen kann. Ich bevorzuge die Verwendung eines einfach zu schreibenden und zu berechnenden Tiefpassfilters, um schnelle Transienten zu entfernen und einen angemessenen Pseudo-Durchschnitt der neuesten Ergebnisse anzuzeigen:

// The higher this value, the less the fps will reflect temporary variations
// A value of 1 will only keep the last value
var filterStrength = 20;
var frameTime = 0, lastLoop = new Date, thisLoop;

function gameLoop(){
  // ...
  var thisFrameTime = (thisLoop=new Date) - lastLoop;
  frameTime+= (thisFrameTime - frameTime) / filterStrength;
  lastLoop = thisLoop;
}

// Report the fps only every second, to only lightly affect measurements
var fpsOut = document.getElementById('fps');
setInterval(function(){
  fpsOut.innerHTML = (1000/frameTime).toFixed(1) + " fps";
},1000);

Die Halbwertzeit dieses Filters - die Anzahl der Frames, die erforderlich ist, um sich vom alten Wert auf einen neuen, stabilen Wert zu bewegen - ist filterStrength*Math.log(2) (ungefähr 70% der Stärke). 

Eine Stärke von 20 bewegt sich beispielsweise zur Hälfte in 14 Frames, in 3/4 des Weges in 28 Frames, 90% in 46 Frames und 99% in 92 Frames. Bei einem System, das mit etwa 30 Bildern pro Sekunde läuft, ist eine plötzliche, drastische Leistungsverschiebung in einer halben Sekunde offensichtlich, aber es werden immer noch Anomalien im Single-Frame-Modus "weggeworfen", da sich der Wert nur um 5% der Differenz verschiebt.

Hier ist ein visueller Vergleich verschiedener Filterstärken für ein ~ 30fps-Spiel, das einen kurzzeitigen Einbruch auf 10fps hat und später bis zu 50fps beschleunigt. Wie Sie sehen, spiegeln niedrigere Filterwerte schneller "gute" Änderungen wider, sind aber auch anfälliger für vorübergehende Probleme:
enter image description here

Schließlich ist hier ein Beispiel , wie der obige Code verwendet wird, um eine 'Spiel'-Schleife zu testen.

91
Phrogz

Was ist mit requestAnimationFrame ?

var before,now,fps;
before=Date.now();
fps=0;
requestAnimationFrame(
    function loop(){
        now=Date.now();
        fps=Math.round(1000/(now-before));
        before=now;
        requestAnimationFrame(loop);
        console.log("fps",fps)
    }
 );
2
davidmars

Ich verwende das, um fps zu berechnen

  var GameCanvas = document.getElementById("gameCanvas");
  var GameContext = doContext(GameCanvas,"GameCanvas");
  var FPS = 0;
  var TimeNow;
  var TimeTaken;
  var ASecond = 1000;
  var FPSLimit = 25;
  var StartTime = Date.now();
  var TimeBefore = StartTime;
  var FrameTime = ASecond/FPSLimit;
  var State = { Title:0, Started:1, Paused:2, Over:3 };
  var GameState = State.Title;

  function gameLoop() {
    requestAnimationFrame(gameLoop);
    TimeNow = Date.now();
    TimeTaken = TimeNow - TimeBefore;

    if (TimeTaken >= FrameTime) {
      FPS++
      if((TimeNow - StartTime) >= ASecond){
        StartTime += ASecond;
        doFPS();
        FPS = 0;
      }

      switch(GameState){
        case State.Title :
          break;
        case State.Started :
          break;
        case State.Paused :
          break;
        case State.Over :
          break;
      }
      TimeBefore = TimeNow - (TimeTaken % FrameTime);
    }
  }

  Sprites.onload = function(){
    requestAnimationFrame(gameLoop);
  }

  function drawText(Context,_Color, _X, _Y, _Text, _Size){
    Context.font =  "italic "+ _Size +" bold";
    Context.fillStyle = _Color;
    Context.fillText(_Text, _X, _Y);
  }

  function doFPS()(
    drawText(GameContext,"black",10,24,"FPS : " + FPS,"24px");
  }

  function doContext(Canvas,Name){
    if (Canvas.getContext) {
      var Context = Canvas.getContext('2d');
      return Context;
    }else{
      alert( Name + ' not supported your Browser needs updating');
    }
  }
2
sha1962

Meine 2 Cent:

Nützlich für mich, um Optimierungen zu vergleichen. Brennen Sie natürlich nur für Tests ein wenig Ressourcen.

Idealerweise sollte die Framerate Ihrer App bei Verwendung von Ereignissen, Schleifen usw. bei voller Auslastung über 50 Frames pro Sekunde liegen. 

Bildschirme werden zumindest für jetzt ohnehin nicht über 60 Hz aktualisiert.

Menschen fühlen sich unter 24 FPS verzögert, dies ist 1000/24 ​​= 41ms

41ms für ein Bild ist also der letzte kritische Tiefpunkt, bevor die Gefühle eingefroren werden.

let be = Date.now(),fps=0;
requestAnimationFrame(
    function loop(){
        let now = Date.now()
        fps = Math.round(1000 / (now - be))
        be = now
        requestAnimationFrame(loop)
        if (fps < 35){
          kFps.style.color = "red"
          kFps.textContent = fps 
        } if (fps >= 35 && fps <= 41) {
            kFps.style.color = "deepskyblue"
            kFps.textContent = fps + " FPS"
          } else {
            kFps.style.color = "black"
            kFps.textContent = fps + " FPS"
        }
        kpFps.value = fps
    }
 )
<span id="kFps"></span>
<progress id="kpFps" value="0" min="0" max="100" style="vertical-align:middle"></progress>

Nur eine Schleife, um die Idee zu erhalten, im 50-ms-Intervall, sollte es ruhig weitergehen. Sehen Sie die Fortschrittsleiste springen? Dies ist ein Frame-Verlust, und Browser, die versuchen, durch Opfer zu bleiben, indem sie zum nächsten Frame springen, müssen wir das vermeiden! 

let t
for (let i=0;i<99999;i++){
  t = setTimeout(function(){
   console.log("I am burning your CPU! " + i)
   clearTimeout(t)
  },50)
  
}

0
Cryptopat