# ------------------------------------------------------------ # Copyright (c) 2014-2019 # Q.W.Page Associates Inc. # www.qwpage.com # All rights reserved. # ------------------------------------------------------------ ::namespace eval ::qw::clockutil {} ::proc ::qw::clockutil::runtime_format_hms {sargs} { /* { 2.34.0 Changed .clock_start to .seconds_start. Added .microseconds_start/.milliseconds_start. ::qw::clockutil::runtime_format_hms .seconds $seconds; ::qw::clockutil::runtime_format_hms .milliseconds $milliseconds; ::qw::clockutil::runtime_format_hms .microseconds $Microseconds; Calculates the number of seconds in the interval defined by .clock_start/.clock_end and formats it as HHH:MM:SS. The hours are not fixed width and use as many digits as necessary. The minutes and seconds are always two digits. .clock_end is optional and if not specified (or empty) will default to the current clock seconds (::clock seconds;). Specify .milliseconds and the format will be HHH::HH::MM.mmm Specify .microseconds and the format will be HHH::HH::MM.mmmmmm */ } ::set Seconds [::sargs::get $sargs .seconds]; ::if {$Seconds eq ""} { ::set ClockStart [::sargs::get $sargs .seconds_start]; ::if {$ClockStart ne ""} { ::set ClockEnd [::sargs::get $sargs .seconds_end]; ::if {$ClockEnd eq ""} { ::set ClockEnd [::clock seconds]; } ::set Seconds [::expr {$ClockEnd-$ClockStart}]; } } ::if {$Seconds ne ""} { /* { Format as 0:00:00 */ } ::set Hours [::expr $Seconds/3600]; ::set Seconds [::expr {$Seconds%3600}] ::set Minutes [::expr $Seconds/60]; ::set Seconds [::expr {$Seconds%60}] /* { When we format the numbers to fixed width, spaces are used for padding. We use strmap to replace those spaces with zeros. */ } ::set Result [::string map [::list " " 0] [::format "%i:%2i:%2i" $Hours $Minutes $Seconds]]; ::return $Result; } ::set MilliSeconds [::sargs::get $sargs .milliseconds]; ::if {$MilliSeconds eq ""} { ::set ClockStart [::sargs::get $sargs .milliseconds_start]; ::if {$ClockStart ne ""} { ::set ClockEnd [::sargs::get $sargs .milliseconds]; ::if {$ClockEnd eq ""} { ::set ClockEnd [::clock clicks -milliseconds]; } ::set MilliSeconds [::expr {$ClockEnd-$ClockStart}]; } } ::if {$MilliSeconds ne ""} { /* { Format as 0:00:00.xxx */ } ::set Hours [::expr $MilliSeconds/3600000]; ::set MilliSeconds [::expr {$MilliSeconds%3600000}]; ::set Minutes [::expr $MilliSeconds/60000]; ::set MilliSeconds [::expr {$MilliSeconds%60000}]; ::set Seconds [::expr $MilliSeconds/1000]; ::set MilliSeconds [::expr {$MilliSeconds%1000}] /* { When we format the numbers to fixed width, spaces are used for padding. We use strmap to replace those spaces with zeros. */ } ::return [::string map [::list " " 0] [::format "%i:%2i:%2i.%3i" $Hours $Minutes $Seconds $MilliSeconds]]; } ::set MicroSeconds [::sargs::get $sargs .microseconds]; ::if {$MicroSeconds eq ""} { ::set ClockStart [::sargs::get $sargs .microseconds_start]; ::if {$ClockStart ne ""} { ::set ClockEnd [::sargs::get $sargs .microseconds]; ::if {$ClockEnd eq ""} { ::set ClockEnd [::clock clicks -microseconds]; } ::set MicroSeconds [::expr {$ClockEnd-$ClockStart}]; } } ::if {$MicroSeconds ne ""} { /* { Format as 0:00:00.xxxxxx */ } ::set Hours [::expr $MicroSeconds/3600000000]; ::set MicroSeconds [::expr {$MicroSeconds%3600000000}]; ::set Minutes [::expr $MicroSeconds/60000000]; ::set MicroSeconds [::expr {$MicroSeconds%60000000}]; ::set Seconds [::expr $MicroSeconds/1000000]; ::set MicroSeconds [::expr {$MicroSeconds%1000000}] /* { When we format the numbers to fixed width, spaces are used for padding. We use strmap to replace those spaces with zeros. */ } ::return [::string map [::list " " 0] [::format "%i:%2i:%2i.%6i" $Hours $Minutes $Seconds $MicroSeconds]]; } ::qw::throw "[::qw::procname] - invalid arguments \"$sargs\"."; } # ------------------------------------------------------------ # ::qw::sleep # ------------------------------------------------------------ /* { 2.34.11 - replace usleep with nanosleep (usleep depecated and compiler producing warnings). 2.34.9 - use gnu sleep()/usleep in [::qw::system] cpp_sleep .seconds/.milliseconds/.microseconds 2.34.0 Code stolen from https://wiki.tcl-lang.org/page/sleep near bottom. Rational: Tcl_Sleep doesn't work. Gives us 15 when we want 1 ms, for example. This code calibrates the number of clicks per second and then uses clicks instead of milliseconds in the wait loop. ::qw::sleep uses the processor at max so it's an in your face delay. It is only used to simulate delays such as when simulating latency values, and really should not be used in a release version of nv2. */ } ::if {$::qw::control(use_gnu_sleep_function)} { ::proc ::qw::sleep {Milliseconds} { [::qw::system] cpp_sleep .milliseconds $Milliseconds; } } else { ::set ::qw::sleep_clicks_per_millisecond 0; ::proc ::qw::sleep_calibrate {} { ::set Start [::clock clicks]; ::after 1000; ::set End [::clock clicks]; ::set ::qw::sleep_clicks_per_millisecond [::expr {($End-$Start)/1000.0}] } ::proc ::qw::sleep {Milliseconds} { /* { Usage: ::qw::sleep $Milliseconds; 2.34.0 The Tclx ::sleep proc was not accurate enough for latency purposes so we implemented our own sleep proc. */ } ::if {$::qw::sleep_clicks_per_millisecond==0} { ::qw::sleep_calibrate; } ::set Chunk [::expr {$::qw::sleep_clicks_per_millisecond*$Milliseconds}]; ::set s0 [::clock clicks]; ::while {1} { ::set s1 [::clock clicks]; ::if {$s1<$s0} { /* { We have possibly wrapped. Let's just get out of here. */ } ::break; } ::set Diff [::expr {$s1-$s0}]; ::if {$Diff>$Chunk} { ::break; } } } ::if {$::qw::control(latency_socket_upload) \ ||$::qw::control(latency_socket_download) \ ||$::qw::control(latency_plug_upload) \ ||$::qw::control(latency_plug_download)} { ::qw::sleep_calibrate; } }