High-Res time and related functions
- Posted by jmduro Aug 07, 2021
- 1060 views
Here is another high-resolution time library which differs from previous ones by following points:
- usable in windows and linux
- improved set_rand (called randomize(): does not give the same behaviour if called twice in less than a second)
- cant generate UUIDs
include std/dll.e include std/machine.e include std/os.e include std/rand.e ifdef WINDOWS then include std/win32/msgbox.e end ifdef --*------------------------------------------------------* -- reference high resolution timer libraries --*------------------------------------------------------* ifdef WINDOWS then atom k32 = open_dll("kernel32") if k32 = -1 then error_message("kernel32.dll can\'t be opened.", 1) end if atom perf_frq_ = define_c_func(k32, "QueryPerformanceFrequency", {C_UINT}, C_UINT) atom perf_cnt_ = define_c_proc(k32, "QueryPerformanceCounter", {C_UINT}) if (perf_cnt_=-1) or (perf_frq_=-1) then error_message("The current Windows version does not support hi-res timers.", 1) end if -------------------------------------------------------------------------------- procedure error_message(sequence msg, atom quit) ifdef WINDOWS then object void = message_box(msg, "Error", MB_ICONERROR+MB_OK+MB_APPLMODAL+MB_SETFOREGROUND) elsifdef LINUX then puts(2, "Error: " & msg & "\n") end ifdef if quit then abort(1) end if end procedure -------------------------------------------------------------------------------- -- retrieves the frequency of the performance counter, in ticks per second public function QueryPerformanceFrequency() atom lpFrequency = allocate(8) if not c_func(perf_frq_, {lpFrequency}) then error_message("Your hardware does not support hi-res timers.", 1) end if atom ticks_per_sec = peek8u(lpFrequency) free(lpFrequency) return ticks_per_sec end function -------------------------------------------------------------------------------- -- retrieves the current value of the performance counter, in ticks, which is -- a high resolution (<1us) time stamp public function QueryPerformanceCounter() atom lpTicks = allocate(8) c_proc(perf_cnt_, {lpTicks}) atom ticks = peek8u(lpTicks) free(lpTicks) return ticks end function -------------------------------------------------------------------------------- -- returns an atom: number of seconds since PC has started, accurate up to 1us -- hires_time()*1000 = number of milliseconds since PC has started public function hires_time() atom ticks_per_sec = QueryPerformanceFrequency() atom ticks = QueryPerformanceCounter() return ticks/ticks_per_sec end function elsifdef LINUX then constant CLOCK_REALTIME = 0, CLOCK_MONOTONIC = 1 atom clock_gettime_ = define_c_func(open_dll(""), "clock_gettime", {C_POINTER, C_POINTER}, C_INT) public function get_time() atom timep = allocate( sizeof( C_POINTER ) ) sequence time = {0, 0} if c_func(clock_gettime_, {CLOCK_MONOTONIC, timep}) then error_message("Your hardware does not support hi-res timers.", 1) end if time = peek_longu({timep, 2}) free(timep) return time end function -- returns an atom: number of seconds since PC has started, accurate up to 1ns -- hires_time()*1000 = number of milliseconds since PC has started public function hires_time() atom secs, nsecs {secs, nsecs} = get_time() return secs + nsecs/1e9 end function end ifdef -------------------------------------------------------------------------------- -- better randomization than set_rand(time()) because it gives different results -- even if called twice in less than a second public procedure randomize() set_rand(hires_time()*1000) end procedure -------------------------------------------------------------------------------- public function gen_uuid() -- following line converted from PHP: https://www.ts-services.com/generation-uuid-php/ return sprintf( "%04x%04x-%04x-%04x-%04x-%04x%04x%04x", { rand_range(0, #FFFF), rand_range(0, #FFFF), rand_range(0, #FFFF), or_bits(rand_range(0, #0FFF), #4000), or_bits(rand_range(0, #3FFF), #8000), rand_range(0, #FFFF), rand_range(0, #FFFF), rand_range(0, #FFFF) } ) end function
Jean-Marc