The ideas presented here supersede what was shared in the
Performance Stopwatch (v1) post.
Gary shared what appears to be the purest way to track elapsed time within VoiceAttack:
// Capture start time
Set date [~~StartTime] value to the current date/time
// ** Perform your actions here **
// Capture stop time
Set date [~~StopTime] value to the current date/time
// Calculate elapsed time via DATETICKS
Set decimal [~~ElapsedTime] value to the converted value of {EXP:({DATETICKS:~~StopTime}-{DATETICKS:~~StartTime})/10000000} (round to 3 decimal places)
// Output info to event log
Write [Blue] 'Elapsed Time = {DEC:~~ElapsedTime} s' to log
The above methodology minimizes delays between capturing the start and stop times, which should produce the most accurate elapsed time measurement (with some variance between measurements due to processor activity and other factors). Also note that in the same Discord post (see above link) Gary confirmed that adding comments within the VA actions list does increase the processing time, though the majority of users will be hard-pressed to notice any difference.
In order to condense the above code into as few VA actions as possible, it is important to minimize the time between when a start/stop time SHOULD be captured and when it actually IS captured. That means the measurements need to be performed 100% inline with the VA actions (as opposed to housing the measurement functionality in a separate command (like Performance Stopwatch v1), and the start/stop times need to be set in a strategic manner. With that in mind I've reworked the Performance Stopwatch into a single inline function as follows:
Referenced Assemblies: System.dll
using System;
public class VAInline
{
public void main()
{
DateTime CurrentTime = DateTime.Now; // Capture current time
if (VA.GetBoolean("~~StopwatchRunning") == true) // Check if stopwatch is running
{
DateTime StopTime = CurrentTime; // Set StopTime to captured CurrentTime
DateTime StartTime = (DateTime)VA.GetDate("~~StartTime"); // Retrieve StartTime from VoiceAttack Date/Time variable
double ElapsedTime = Math.Round((StopTime.Ticks - StartTime.Ticks)/10000000.0, 3); // Calculate the ElapsedTime (in seconds) using DateTime Ticks
VA.WriteToLog("Elapsed Time = " + ElapsedTime.ToString("F3") + " s", "blue"); // Output ElapsedTime to event log (3 decimal places)
VA.SetBoolean("~~StopwatchRunning", null); // Reset VoiceAttack boolean variable
VA.SetDate("~~StartTime", null); // Reset VoiceAttack Date/Time variable
}
else
{
VA.SetBoolean("~~StopwatchRunning", true); // Set boolean flag indicating that stopwatch is running
VA.SetDate("~~StartTime", DateTime.Now); // Set VoiceAttack Date/Time variable to current time
}
}
}
// References
// https://docs.microsoft.com/en-us/dotnet/api/system.datetime.ticks?view=netframework-4.7.2
...and the inline function is implemented in the VA action list as follows:
Call first instance of Performance Stopwatch (capture start time)
Inline C# Function: Performance Stopwatch, wait until execution finishes
// ** Perform your actions here **
Call second instance of Performance Stopwatch (capture stop time and output elapsed time)
Inline C# Function: Performance Stopwatch, wait until execution finishes
Some notes:
- The performance stopwatch must always be implemented in pairs: the first instance collects the start time, and the second instance collects the stop time and outputs the elapsed time
- Putting aside variance in VA execution performance, the Performance Stopwatch generally adds an average of ~10-15 ms of processing delay compared to the "pure" method illustrated above. I guess that's the price of condensing the elapsed time measurement into as few actions as possible.
- The inline function uses command-shared (~~) variables, so you can spread out your inline function pairs among commands and subcommands (in the same execution chain)
- A benefit of using command-shared variables and taking discrete start/stop time measurements is that there's no harm in "interrupting" the measurement through events like 'Stop All Commands' or a profile switch. In other words, there's nothing left running in the background and all the VA variables naturally get reset whenever the measurement is interrupted.