For this week’s blog post we are going to discuss tracking elapsed time in Legato. Like many things in Legato, there are a number of different ways to accomplish this task, each with their pros and cons. Many of these functions have appeared in other scripts we’ve previously posted but this article will be a more in-depth look at these functions.
Many of these functions use the GetTickCount64 Windows SDK function behind the scenes. This function gives the number of milliseconds elapsed since the computer was started. Depending on the hardware in the system the resolution of the function is 10ms to 16ms. This means that Legato functions may not have the resolution for extremely fast timing like those used in video rendering or graphics. Most Legato scripts do not require this level of precision so these functions are sufficient.
Since we are talking about the GetTickCount64 Windows SDK function, we can go straight to the Legato equivalent:
qword = GetTickCount ( );
This function simply returns the value of the GetTickCount64 Windows SDK function. While this information isn’t necessarily useful on its own, multiple calls to the function can be used to compare elapsed times. This has been shown in a number of scripts. Here’s a quick example:
qword i1;
i1 = GetTickCount();
Sleep(20);
AddMessage("%d ms", GetTickCount() - i1);
This simple script gets the current tick, sleeps for 20ms, and then prints out the difference between the current tick and the last one. This gives us the elapsed run time, in milliseconds, between the GetTickCount calls. If you run the script on your computer you may get “16 ms” or maybe even “32 ms”. This is because we only slept for 20ms and the resolution of the function can be as low as 16ms. You also may have gotten values like “17 ms”. This is because the Sleep function sometimes sleeps a little longer than the given amount due to the added time needed to switch thread contexts.
For an example as simple as this, we could have also used the GetElapsedTime function. This function works exactly like GetTickCount except it returns the number of milliseconds since the script was started. Behind the scenes, it simply does a comparison between to calls to GetTickCount but saves us the hassle of remembering the first call. Let’s look at the adjusted script:
qword i1;
i1 = GetTickCount();
Sleep(20);
AddMessage("%d ms GetTickCount()", GetTickCount() - i1);
AddMessage("%d ms GetElapsedTime()", GetElapsedTime());
All we have done is add a call to GetElapsedTime at the end of the script. Most of the time we will get the same values for both calls but due to rounding and the precision of the GetTickCount64 we may end up with different values like this:
16 ms GetTickCount()
31 ms GetElapsedTime()
It is important to note that you can reset the starting time for the GetElapsedTime function by calling the ResetElapsedTime function. This can be useful as user input from a dialog or message box may skew the script’s elapsed time dramatically.
So far we’ve seen functions that allow us to measure the time a script has been running or the time it took to run between two lines of code. But what about time spent in the application? For that Legato offers the GetLastActivityTick function.
qword = GetLastActivityTick ( [int mode] );
This function returns the tick count since the last user action, as determined by the mode parameter. What this means is we can see how long it has been since the user has pressed a key on the keyboard or clicked a mouse button (while the application is active). Here are the acceptable values for mode:
| SDK Name | | Description | |
| GLAT_ANY_ACTION | | Latest of any action. | |
| GLAT_MOUSE_CLICK | | Last mouse down click (within the application) of either left or right buttons. Drag does not count except for the initial mouse button down, if initiated in the application. | |
| GLAT_KEYBOARD | | Any non system key down or character action. | |
| GLAT_EDIT_ACTION | | Any action that results in an actual edit change to a file (view). | |
| GLAT_DIALOG_ACTION | | Any control commands or notifications including receiving or losing focus such as from tabbing through controls. | |
If the user has not engaged in a class of activity since the time the application started, the return value is zero.
Consider the following script:
qword aa, mc, kb, ea, da;
aa = GetTickCount() - GetLastActivityTick();
mc = GetTickCount() - GetLastActivityTick(GLAT_MOUSE_CLICK);
kb = GetTickCount() - GetLastActivityTick(GLAT_KEYBOARD);
ea = GetTickCount() - GetLastActivityTick(GLAT_EDIT_ACTION);
da = GetTickCount() - GetLastActivityTick(GLAT_DIALOG_ACTION);
AddMessage(FormatString("All %d, Mouse %d, Keyboard %d, Edit %d, Dialog %d", aa, mc, kb, ea, da));
This script gets the difference between the current tick and the last activity tick for each mode. This gives us the time in milliseconds since the last time the user made one of these actions. The output could look something like this:
All 16, Mouse 250, Keyboard 16, Edit 13625, Dialog 74755938
As you see the dialog value is extremely large (~20 hours) because I left my GoFiler running overnight. Since the value of this function may be 0 for no activity, we should put some error checking into a real script. Technically, 0 is a valid value for the GetTickCount64 function but because it is the number of milliseconds since the computer was started and the value is a 64-bit, we can do some quick math to see that it will take ~213,503,982,334 days for the counter to wrap around to 0 (not likely to happen).
Now that we’ve discussed all the GetTickCount64 based functions there are a few others we can look at.
string = GetLocalTime ( int format );
qword = GetLocalTime ( );
string = GetUTCTime ( int format );
qword = GetUTCTime ( );
These functions return the local time or UTC time in either a string or qword format. If the qword format is used the resulting value is a Microsoft file time. File times are a 64-bit number that represents the number of 100-nanosecond intervals since January 1, 1601. This gives us an actual time not relative to the start of the computer or script which can be useful. Because they are higher precision we can use them instead of the GetTickCount functions. However, they can be more expensive to call because calculating the system time may result in additional calculations and system calls. Here is an example script using the GetLocalTime function instead of GetTickCount:
qword i1;
i1 = GetLocalTime();
Sleep(20);
AddMessage("%d ms GetTickCount()", (GetLocalTime() - i1) / 10000);
Running this script does result in a more precise answer (usually 20ms or 21ms) but as you can see it required more operations in the Legato script (the / operation to convert to milliseconds) and even more operations behind the scenes. Depending on your script this additional overhead may not be important but it is something to consider.
This concludes our quick summary of how to track time in Legato. You can use these functions to optimize scripts, track slow points in a job workflow, or perform other tasks in a timely manner.
David Theis has been developing software for Windows operating systems for over fifteen years. He has a Bachelor of Sciences in Computer Science from the Rochester Institute of Technology and co-founded Novaworks in 2006. He is the Vice President of Development and is one of the primary developers of GoFiler, a financial reporting software package designed to create and file EDGAR XML, HTML, and XBRL documents to the U.S. Securities and Exchange Commission. |
Additional Resources
Novaworks’ Legato Resources
Legato Script Developers LinkedIn Group
Primer: An Introduction to Legato