-
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Start work for issue #1077 * perf: improve perf of fps calcs and its accuracy
- Loading branch information
1 parent
df8e25a
commit 7da7bdf
Showing
6 changed files
with
82 additions
and
160 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,87 +1,87 @@ | ||
// <copyright file="TimerService.cs" company="KinsonDigital"> | ||
// <copyright file="TimerService.cs" company="KinsonDigital"> | ||
// Copyright (c) KinsonDigital. All rights reserved. | ||
// </copyright> | ||
|
||
namespace Velaptor.Services; | ||
|
||
using System; | ||
using System.Runtime.CompilerServices; | ||
|
||
/// <inheritdoc/> | ||
internal sealed class TimerService : ITimerService | ||
{ | ||
private readonly IStopWatchWrapper timer; | ||
private readonly double[] timeSamples = new double[1000]; | ||
private const int SAMPLE_SIZE = 1000; | ||
private readonly IStopWatchWrapper stopWatch; | ||
private readonly double[] timeSamples = new double[SAMPLE_SIZE]; | ||
private readonly double tickFreqMs; | ||
private double runningSum; | ||
private long startTicks; | ||
private long stopTicks; | ||
private int index; | ||
private bool isArrayFull; | ||
private int divisor; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="TimerService"/> class. | ||
/// </summary> | ||
/// <param name="stopWatch">Tracks and measures time passed.</param> | ||
public TimerService(IStopWatchWrapper stopWatch) => this.timer = stopWatch; | ||
public TimerService(IStopWatchWrapper stopWatch) | ||
{ | ||
this.stopWatch = stopWatch; | ||
this.tickFreqMs = 1000.0 / this.stopWatch.Frequency; | ||
} | ||
|
||
/// <inheritdoc/> | ||
/// <remarks>This is averaged over 1000 samples.</remarks> | ||
public float MillisecondsPassed { get; private set; } | ||
|
||
/// <inheritdoc/> | ||
public void Start() => this.timer.Start(); | ||
public void Start() => this.startTicks = this.stopWatch.GetTimestamp(); | ||
|
||
/// <inheritdoc/> | ||
public void Stop() | ||
{ | ||
if (!this.timer.IsRunning) | ||
{ | ||
return; | ||
} | ||
this.stopTicks = this.stopWatch.GetTimestamp(); | ||
var sample = (this.stopTicks - this.startTicks) * this.tickFreqMs; | ||
AddSample(sample); | ||
|
||
this.timer.Stop(); | ||
// Set the divisor to avoid division by zero and to divide by the correct number of samples | ||
// which is important for calculating the average | ||
this.divisor = this.index == 1 ? 1 : this.index; | ||
|
||
AddSample(this.timer.Elapsed.TotalMilliseconds); | ||
|
||
// Get the average of the samples and save it | ||
MillisecondsPassed = Average(); | ||
// Calculate average using running sum | ||
MillisecondsPassed = (float)(this.runningSum / (this.isArrayFull ? SAMPLE_SIZE : this.divisor)); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public void Reset() => this.timer.Reset(); | ||
public void Reset() | ||
{ | ||
this.index = 0; | ||
this.runningSum = 0; | ||
this.isArrayFull = false; | ||
Array.Clear(this.timeSamples, 0, SAMPLE_SIZE); | ||
MillisecondsPassed = 0; | ||
} | ||
|
||
/// <summary> | ||
/// Adds the given <paramref name="sample"/> to the list of samples. | ||
/// </summary> | ||
/// <param name="sample">The sample to add.</param> | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
private void AddSample(double sample) | ||
{ | ||
// Subtract the old value from running sum before replacing it | ||
this.runningSum -= this.timeSamples[this.index]; | ||
this.runningSum += sample; | ||
this.timeSamples[this.index] = sample; | ||
|
||
if (this.index >= this.timeSamples.Length - 1) | ||
{ | ||
this.index = 0; | ||
} | ||
else | ||
if (this.index == SAMPLE_SIZE - 1) | ||
{ | ||
this.index += 1; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Calculates the average of all the samples. | ||
/// </summary> | ||
/// <returns>The sample average.</returns> | ||
/// <remarks>If any of the samples are 0, it is not counted towards the average.</remarks> | ||
private float Average() | ||
{ | ||
var sum = 0.0; | ||
var count = 0; | ||
|
||
foreach (var t in this.timeSamples) | ||
{ | ||
if (t == 0) | ||
{ | ||
continue; | ||
} | ||
|
||
sum += t; | ||
count += 1; | ||
this.isArrayFull = true; | ||
} | ||
|
||
return count == 0 ? 0 : (float)sum / count; | ||
this.index = this.index >= this.timeSamples.Length - 1 | ||
? 0 | ||
: this.index + 1; | ||
} | ||
} |