Page 2 of 3

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 04 Apr 2017, 08:44
by Helgef
evilC wrote:Hmm, it seems the old QueueTimer code us WAY less CPU intensive. I see 0% CPU usage for that with a 10s sleep
I tested it again, it works very good w.r.t accuracy and cpu usage, but sometimes the script just dies, and silently exits.

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 04 Apr 2017, 08:52
by jNizM
Both function (QPC and GetSystemTimePreciseAsFileTime) used 12.5 % CPU (not compiled) for a 10 seconds test
- If I add sleep -1 to the while loop the CPU is still using 12.5 %
- As soon as I add sleep 1 to the while-loop the CPU goes down to under 1 % but its not precise like without sleep
msdn wrote:However, the accuracy depends on the priority of your thread, the priority of other threads, and whether interrupt service routines (ISRs) are running.
+ AutoHotkey itself (as long lexikos tell me that Im wrong :P )

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 06 Apr 2017, 05:02
by jNizM
Found some more interesting stuff about Timers:

Timers, Timer Resolution, and Development of Efficient Code
Timer-Resolution.docx (msdn - .docx)

with reference to SetWaitableTimerEx function (msdn)

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 06 Apr 2017, 09:24
by evilC
Here is a C# implementation that uses WaitableTimers:
Code shamelessly stolen from here

AHK

Code: Select all

#SingleInstance force
#Persistent

#include CLR.ahk

asm := CLR_LoadLibrary("bin\debug\WaitableTimer.dll")

wt := asm.CreateInstance("WaitableTimer")
MyTimer := wt.Create(Func("Test"), 1)
MyTimer.Start()
Sleep, 10000
MyTimer.Stop()

return

Test(){
	ToolTip % A_TickCount
}

^Esc::
	ExitApp
C#

Code: Select all

using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

public class WaitableTimer
{
    public TimerInstance Create(dynamic _callback, int _period)
    {
        return new TimerInstance(_callback, _period);
    }

    public class TimerInstance
    {
        dynamic callback;
        int period;
        Thread timerThread;
        _WaitableTimer waitableTimer = new _WaitableTimer(false, "");

        public TimerInstance(dynamic _callback, int _period)
        {
            callback = _callback;
            period = _period;
        }

        public void Start()
        {
            timerThread = new Thread(new ThreadStart(TimerLoop));

            timerThread.Start();
        }

        public void Stop()
        {
            timerThread.Abort();
        }

        public void TimerLoop()
        {
            waitableTimer.Set(-0L, period);
            while (true)
            {
                waitableTimer.WaitOne();
                callback();
            }
        }
    }

    public class _WaitableTimer : WaitHandle
    {
        [DllImport("kernel32.dll")]
        static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);

        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool SetWaitableTimer(SafeWaitHandle hTimer, [In] ref long pDueTime, int lPeriod, IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, [MarshalAs(UnmanagedType.Bool)] bool fResume);

        public _WaitableTimer(bool manualReset = true, string timerName = null)
        {
            this.SafeWaitHandle = CreateWaitableTimer(IntPtr.Zero, manualReset, timerName);
        }

        public void Set(long dueTime, int period)
        {
            if (!SetWaitableTimer(this.SafeWaitHandle, ref dueTime, period, IntPtr.Zero, IntPtr.Zero, false))
            {
                throw new Win32Exception();
            }
        }
    }
}
DLL is attached.

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 06 Apr 2017, 10:13
by Helgef
It seems to work well evilC. Low cpu (not noticable) and accurate.
I measured ~10 ms off on 10000 1 ms periods.

Code: Select all

#SingleInstance force
#Persistent
SetBatchLines,-1
asm := CLR_LoadLibrary(A_ScriptDir "\WaitableTimer.dll")
global period:=1
wt := asm.CreateInstance("WaitableTimer")
MyTimer := wt.Create(Func("Test"), period)
MyTimer.Start()
Sleep, 100000
MyTimer.Stop()

return

Test(){
	static ctr:=0, tic1:=0, periods:=10000
	if !ctr
		DllCall("QueryPerformanceCounter", "Int64P", tic1)
	ctr++
	if (ctr=periods){
		DllCall("QueryPerformanceCounter", "Int64P", tic2)
		DllCall("QueryPerformanceFrequency", "Int64P", f)
		MsgBox, % "Elapsed time:`t" round((tic2-tic1)*1000/f) " ms.`nExpected:`t`t" period*periods " ms."
		Exitapp
	}
	return
}

^Esc::
	ExitApp

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 06 Apr 2017, 10:54
by Helgef
@jNizM did you try SetWaitableTimerEx function with AHK-dllcall? I fail, I get A_LastError=5 (Access denied), this is what I tried, with doing as little reading in the relevant documentation as possible :lol: ,

Code: Select all

#Persistent
lpTimerAttributes:=0
lpTimerName:=0
dwFlags:=0
dwDesiredAccess:=0																; can be "str" to it seems. i.e., "str", "lpTimerName"
hTimer:=DllCall("Kernel32.dll\CreateWaitableTimerEx", "Uptr", lpTimerAttributes, "UPtr", lpTimerName, "Uint", dwFlags, "Uint", dwDesiredAccess)
MsgBox, % hTimer  "`n" ErrorLevel  "`n" A_LastError

ms:=35							; milliseconds
VarSetCapacity(lpDueTime,8,0)
NumPut(- 100 * 10000 * ms,lpDueTime,4,"Int")

lPeriod:= 0 					; 0 run once ?
pfnCompletionRoutine:= RegisterCallback("f")
lpArgToCompletionRoutine:=0		; Args to f() ?
WakeContext:=0					; Can be set to make the timer wake the computer from sleep it seems.
TolerableDelay:=0

r:=DllCall("Kernel32.dll\SetWaitableTimerEx", "Uptr", hTimer, "UPtr", &lpDueTime, "Int", lPeriod, "Ptr", pfnCompletionRoutine, "Ptr", lpArgToCompletionRoutine, "Ptr", WakeContext, "Uint", TolerableDelay)
MsgBox, % r  "`n" ErrorLevel  "`n" A_LastError

f(){
	MsgBox, % "hi from setwaitabletimer."
	exitapp
}

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 07 Apr 2017, 01:58
by jNizM

Code: Select all

TIMER_ALL_ACCESS   := 0x1F0003
TIMER_MODIFY_STATE := 0x0002
TIMER_QUERY_STATE  := 0x0001

if !(hTimer := DllCall("CreateWaitableTimerEx", "ptr", 0, "ptr", 0, "uint", 0, "uint", TIMER_ALL_ACCESS, "ptr"))
    MsgBox % "CreateWaitableTimerEx failed with Error: " A_LastError
MsgBox % "Handle to timer object: " hTimer

/*
; stuff here...

if !(DllCall("SetWaitableTimerEx", "ptr", hTimer, "int64*", DueTime, "int", Period, "ptr", CompletionRoutine, "ptr", ArgToCompletionRoutine, "ptr", WakeContext, "uint", TolerableDelay))
    MsgBox % "SetWaitableTimerEx failed with Error: " A_LastError

; more stuff here...
*/

DllCall("CloseHandle", "ptr", hTimer)
But I dont know how to use SetWaitableTimerEx to get the timer working when needed

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 08 Apr 2017, 00:00
by Soft
nice to have true sub ms timer, but MicroTimer uses too much cpu than native ahk's settimer.
can't handle the timer with games.. :(

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 08 Apr 2017, 00:16
by Helgef
jNizM wrote:

Code: Select all

TIMER_ALL_ACCESS := 0x1F0003
TIMER_MODIFY_STATE := 0x0002
TIMER_QUERY_STATE := 0x0001

if !(hTimer := DllCall("CreateWaitableTimerEx", "ptr", 0, "ptr", 0, "uint", 0, "uint", TIMER_ALL_ACCESS, "ptr"))
 MsgBox % "CreateWaitableTimerEx failed with Error: " A_LastError
MsgBox % "Handle to timer object: " hTimer

/*
; stuff here...

if !(DllCall("SetWaitableTimerEx", "ptr", hTimer, "int64*", DueTime, "int", Period, "ptr", CompletionRoutine, "ptr", ArgToCompletionRoutine, "ptr", WakeContext, "uint", TolerableDelay))
 MsgBox % "SetWaitableTimerEx failed with Error: " A_LastError

; more stuff here...
*/

DllCall("CloseHandle", "ptr", hTimer)
But I dont know how to use SetWaitableTimerEx to get the timer working when needed
With your handle, I do not get any errors, but I get no callback. :think:
Soft wrote:nice to have true sub ms timer, but MicroTimer uses too much cpu than native ahk's settimer.
can't handle the timer with games.. :(
Try this, not sub-Ms, but still far more accurate than settimer and low CPU.
Cheers.

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 08 Apr 2017, 01:27
by Soft
Try this, not sub-Ms, but still far more accurate than settimer and low CPU.
Cheers.
Thanks, I tried, but WaitableTimer is not working well with my codes unlike MicroTimer or SetTimer.
Code gets stuck when new menu subroutine interrupts? I need to figure out what's wrong now.. :eh:

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 08 Apr 2017, 07:40
by evilC
@Soft: So what, you want CreateMicro from MicroTimer, but you need less CPU usage?
I did see a post on the thread of the code that I used saying you could reduce CPU usage with a slight change, want me to build you a version with that change in?
Edit: DLL Attached.

The original author thinks this will sacrifice accuracy for lower CPU usage. As I asked in the thread though, surely if you delay a timer by the same amount of time every tick, it is still accurate (Apart, maybe, from the 1st tick?).
Please test and let me know how it compares.

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 08 Apr 2017, 19:00
by Soft
The original author thinks this will sacrifice accuracy for lower CPU usage. As I asked in the thread though, surely if you delay a timer by the same amount of time every tick, it is still accurate (Apart, maybe, from the 1st tick?).
Please test and let me know how it compares.
yeah I wanted to use MicroTimer, thanks for the updated dll
cpu usuage is significantly lower than the one without a change, (was getting almost 20% sometimes, but now getting 0.7% cpu usage, same code)
and still more accurate compared to ahk's native settimer!

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 09 Apr 2017, 12:12
by evilC
OK, well this change is minimal - I could add it as an optional mode or something?

Would this tweak only really be needed for the microsecond timers?

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 09 Apr 2017, 21:12
by Soft
evilC wrote:OK, well this change is minimal - I could add it as an optional mode or something?

Would this tweak only really be needed for the microsecond timers?
tweaking only microtimer would be enough. Besides, I don't understand the need for WaitableTimer.

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 13 Apr 2017, 19:35
by rommmcek
I was impressed by the smoothness of the mouse movement using MicroTimer, but the cursor got often stuck when quickly switching directions.
For me this is the best ratio smoothness vs CPU-usage:

Code: Select all

; NOTE: While a script like this is running, the entire operating system and all applications are
; affected by timeBeginPeriod below.

SetBatchLines -1  ; Ensures maximum effectiveness of this method.
ntchs:=2
SleepDuration = 1  ; This can sometimes be finely adjusted (e.g. 2 is different than 3) depending on the value below.
TimePeriod = 3 ; Try 7 or 3.  See comment below.
; On a PC whose sleep duration normally rounds up to 15.6 ms, try TimePeriod=7 to allow
; somewhat shorter sleeps, and try TimePeriod=3 or less to allow the shortest possible sleeps.

;~ DllCall("Winmm\timeBeginPeriod", uint, TimePeriod)  ; Affects all applications, not just this script's DllCall("Sleep"...), but does not affect SetTimer.

~Right::
loop
{
	DllCall("user32.dll\mouse_event", "UInt", 0x0001, "UInt", 1*ntchs, "UInt", 0, "UInt", 0, "UPtr", 0)
    DllCall("Sleep", UInt, SleepDuration)  ; Must use DllCall instead of the Sleep command.
	if !GetKeyState("Right", "P")
	break
}
DllCall("Winmm\timeEndPeriod", UInt, TimePeriod)  ; Should be called to restore system to normal.
return
~Left::
loop
{
	DllCall("user32.dll\mouse_event", "UInt", 0x0001, "UInt", -1*ntchs, "UInt", 0, "UInt", 0, "UPtr", 0)
    DllCall("Sleep", UInt, SleepDuration)  ; Must use DllCall instead of the Sleep command.
	if !GetKeyState("Left", "P")
	break
}
DllCall("Winmm\timeEndPeriod", UInt, TimePeriod)  ; Should be called to restore system to normal.
return
~Down::
loop
{
	DllCall("user32.dll\mouse_event", "UInt", 0x0001, "UInt", 0, "UInt", 1*ntchs, "UInt", 0, "UPtr", 0)
    DllCall("Sleep", UInt, SleepDuration)  ; Must use DllCall instead of the Sleep command.
	if !GetKeyState("Down", "P")
	break
}
DllCall("Winmm\timeEndPeriod", UInt, TimePeriod)  ; Should be called to restore system to normal.
return
~Up::
loop
{
	DllCall("user32.dll\mouse_event", "UInt", 0x0001, "UInt", 0, "UInt", -1*ntchs, "UInt", 0, "UPtr", 0)
    DllCall("Sleep", UInt, SleepDuration)  ; Must use DllCall instead of the Sleep command.
	if !GetKeyState("Up", "P")
	break
}
DllCall("Winmm\timeEndPeriod", UInt, TimePeriod)  ; Should be called to restore system to normal.
return


^Esc::
DllCall("Winmm\timeEndPeriod", UInt, TimePeriod)  ; Should be called to restore system to normal.
ExitApp
return


Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 18 Apr 2017, 01:49
by arcticir
It is too complicated to call, and can have a more simple way to use it?
E.g: DllCall("MicroTimer.dll\Sleep", "UInt",1)
thanks.

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 21 May 2017, 11:01
by Trigun
i don't understand ... with this code i can run a sleep that trigger when i want and not on tick timer?

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 23 May 2017, 16:26
by evilC
arcticir wrote:It is too complicated to call, and can have a more simple way to use it?
E.g: DllCall("MicroTimer.dll\Sleep", "UInt",1)
thanks.
DllCall("MicroTimer.dll\Sleep", "UInt",1) is C syntax, this code is C#
I guess it would be possible, but I don't do C at the moment.

It may be possible to implement it as an equivalent to Sleep, rather than as an equivalent to SetTimer (Which would simplify the syntax considerably) - if/when I get time, I will look into it.

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 23 May 2017, 16:28
by evilC
Trigun wrote:i don't understand ... with this code i can run a sleep that trigger when i want and not on tick timer?
AHK's SetTimer and Sleep commands do not work properly with values less than ~10-15 (Not AHK's fault, just a limitation of the Windows APIs it uses)

This library provides a replacement for SetTimer that is (reasonably) accurate to values <15
It even goes <1 (Into the nanosecond range)

Working around these techniques in pure AHK is possible, but it is not as CPU efficient as doing it in compiled C# code (And seeing as we could be talking about code running REALLY often, this can become a huge issue), hence this library.

Re: MicroTimer - Sub-10ms timers for AHK (C# DLL)

Posted: 23 Jun 2017, 02:56
by Trigun
i don't understand the code... (the demo don't do anything)
if i want replace my sleep commands with this library how i can do it?
something like

Code: Select all

 sleep (t) {
DllCall("MicroTimer.dll\Sleep", "UInt",t)
}