@@ -90,28 +90,28 @@ mod time {
90
90
Ok ( Date :: now ( ) / 1000.0 )
91
91
}
92
92
93
- #[ cfg( any ( windows , target_os = "wasi" ) ) ]
93
+ #[ cfg( target_os = "wasi" ) ]
94
94
#[ pyfunction]
95
95
fn monotonic ( vm : & VirtualMachine ) -> PyResult < f64 > {
96
96
// TODO: implement proper monotonic time for other platforms.
97
97
Ok ( duration_since_system_now ( vm) ?. as_secs_f64 ( ) )
98
98
}
99
99
100
- #[ cfg( any ( windows , target_os = "wasi" ) ) ]
100
+ #[ cfg( target_os = "wasi" ) ]
101
101
#[ pyfunction]
102
102
fn monotonic_ns ( vm : & VirtualMachine ) -> PyResult < u128 > {
103
103
// TODO: implement proper monotonic time for other platforms.
104
104
Ok ( duration_since_system_now ( vm) ?. as_nanos ( ) )
105
105
}
106
106
107
- #[ cfg( any ( windows , target_os = "wasi" ) ) ]
107
+ #[ cfg( target_os = "wasi" ) ]
108
108
#[ pyfunction]
109
109
fn perf_counter ( vm : & VirtualMachine ) -> PyResult < f64 > {
110
110
// TODO: implement proper monotonic time for other platforms.
111
111
Ok ( duration_since_system_now ( vm) ?. as_secs_f64 ( ) )
112
112
}
113
113
114
- #[ cfg( any ( windows , target_os = "wasi" ) ) ]
114
+ #[ cfg( target_os = "wasi" ) ]
115
115
#[ pyfunction]
116
116
fn perf_counter_ns ( vm : & VirtualMachine ) -> PyResult < u128 > {
117
117
// TODO: implement proper monotonic time for other platforms.
@@ -244,15 +244,16 @@ mod time {
244
244
Ok ( get_thread_time ( vm) ?. as_nanos ( ) as u64 )
245
245
}
246
246
247
+ #[ cfg( any( windows, all( target_arch = "wasm32" , not( target_os = "unknown" ) ) ) ) ]
248
+ pub ( super ) fn time_muldiv ( ticks : i64 , mul : i64 , div : i64 ) -> u64 {
249
+ let intpart = ticks / div;
250
+ let ticks = ticks % div;
251
+ let remaining = ( ticks * mul) / div;
252
+ ( intpart * mul + remaining) as u64
253
+ }
254
+
247
255
#[ cfg( all( target_arch = "wasm32" , not( target_os = "unknown" ) ) ) ]
248
256
fn get_process_time ( vm : & VirtualMachine ) -> PyResult < std:: time:: Duration > {
249
- fn time_muldiv ( ticks : i64 , mul : i64 , div : i64 ) -> u64 {
250
- let intpart = ticks / div;
251
- let ticks = ticks % div;
252
- let remaining = ( ticks * mul) / div;
253
- ( intpart * mul + remaining) as u64
254
- }
255
-
256
257
let t: libc:: tms = unsafe {
257
258
let mut t = std:: mem:: MaybeUninit :: uninit ( ) ;
258
259
if libc:: times ( t. as_mut_ptr ( ) ) == -1 {
@@ -684,12 +685,19 @@ mod unix {
684
685
#[ cfg( windows) ]
685
686
#[ pymodule( name = "time" ) ]
686
687
mod windows {
687
- use crate :: { PyResult , VirtualMachine } ;
688
+ use super :: { time_muldiv, MS_TO_NS , SEC_TO_NS } ;
689
+ use crate :: {
690
+ builtins:: { PyNamespace , PyStrRef } ,
691
+ stdlib:: os:: errno_err,
692
+ PyRef , PyResult , VirtualMachine ,
693
+ } ;
688
694
use std:: time:: Duration ;
689
695
use winapi:: shared:: { minwindef:: FILETIME , ntdef:: ULARGE_INTEGER } ;
690
696
use winapi:: um:: processthreadsapi:: {
691
697
GetCurrentProcess , GetCurrentThread , GetProcessTimes , GetThreadTimes ,
692
698
} ;
699
+ use winapi:: um:: profileapi:: { QueryPerformanceCounter , QueryPerformanceFrequency } ;
700
+ use winapi:: um:: sysinfoapi:: { GetSystemTimeAdjustment , GetTickCount64 } ;
693
701
694
702
fn u64_from_filetime ( time : FILETIME ) -> u64 {
695
703
unsafe {
@@ -704,6 +712,131 @@ mod windows {
704
712
}
705
713
}
706
714
715
+ fn win_perf_counter_frequency ( vm : & VirtualMachine ) -> PyResult < i64 > {
716
+ let freq = unsafe {
717
+ let mut freq = std:: mem:: MaybeUninit :: uninit ( ) ;
718
+ if QueryPerformanceFrequency ( freq. as_mut_ptr ( ) ) == 0 {
719
+ return Err ( errno_err ( vm) ) ;
720
+ }
721
+ freq. assume_init ( )
722
+ } ;
723
+ let frequency = unsafe { freq. QuadPart ( ) } ;
724
+
725
+ if * frequency < 1 {
726
+ Err ( vm. new_runtime_error ( "invalid QueryPerformanceFrequency" . to_owned ( ) ) )
727
+ } else if * frequency > i64:: MAX / SEC_TO_NS {
728
+ Err ( vm. new_overflow_error ( "QueryPerformanceFrequency is too large" . to_owned ( ) ) )
729
+ } else {
730
+ Ok ( * frequency)
731
+ }
732
+ }
733
+
734
+ fn global_frequency ( vm : & VirtualMachine ) -> PyResult < i64 > {
735
+ rustpython_common:: static_cell! {
736
+ static FREQUENCY : PyResult <i64 >;
737
+ } ;
738
+ FREQUENCY
739
+ . get_or_init ( || win_perf_counter_frequency ( vm) )
740
+ . clone ( )
741
+ }
742
+
743
+ fn win_perf_counter ( vm : & VirtualMachine ) -> PyResult < Duration > {
744
+ let now = unsafe {
745
+ let mut performance_count = std:: mem:: MaybeUninit :: uninit ( ) ;
746
+ QueryPerformanceCounter ( performance_count. as_mut_ptr ( ) ) ;
747
+ performance_count. assume_init ( )
748
+ } ;
749
+
750
+ let ticks = unsafe { now. QuadPart ( ) } ;
751
+ Ok ( Duration :: from_nanos ( time_muldiv (
752
+ * ticks,
753
+ SEC_TO_NS ,
754
+ global_frequency ( vm) ?,
755
+ ) ) )
756
+ }
757
+
758
+ fn get_system_time_adjustment ( vm : & VirtualMachine ) -> PyResult < u32 > {
759
+ let mut _time_adjustment = std:: mem:: MaybeUninit :: uninit ( ) ;
760
+ let mut time_increment = std:: mem:: MaybeUninit :: uninit ( ) ;
761
+ let mut _is_time_adjustment_disabled = std:: mem:: MaybeUninit :: uninit ( ) ;
762
+ let time_increment = unsafe {
763
+ if GetSystemTimeAdjustment (
764
+ _time_adjustment. as_mut_ptr ( ) ,
765
+ time_increment. as_mut_ptr ( ) ,
766
+ _is_time_adjustment_disabled. as_mut_ptr ( ) ,
767
+ ) == 0
768
+ {
769
+ return Err ( errno_err ( vm) ) ;
770
+ }
771
+ time_increment. assume_init ( )
772
+ } ;
773
+ Ok ( time_increment)
774
+ }
775
+
776
+ fn get_monotonic_clock ( vm : & VirtualMachine ) -> PyResult < Duration > {
777
+ let ticks = unsafe { GetTickCount64 ( ) } ;
778
+
779
+ Ok ( Duration :: from_nanos (
780
+ ( ticks as i64 ) . checked_mul ( MS_TO_NS ) . ok_or_else ( || {
781
+ vm. new_overflow_error ( "timestamp too large to convert to i64" . to_owned ( ) )
782
+ } ) ? as u64 ,
783
+ ) )
784
+ }
785
+
786
+ #[ pyfunction]
787
+ fn get_clock_info ( name : PyStrRef , vm : & VirtualMachine ) -> PyResult < PyRef < PyNamespace > > {
788
+ let ( adj, imp, mono, res) = match name. as_ref ( ) {
789
+ "monotonic" => (
790
+ false ,
791
+ "GetTickCount64()" ,
792
+ true ,
793
+ get_system_time_adjustment ( vm) ? as f64 * 1e-7 ,
794
+ ) ,
795
+ "perf_counter" => (
796
+ false ,
797
+ "QueryPerformanceCounter()" ,
798
+ true ,
799
+ 1.0 / ( global_frequency ( vm) ? as f64 ) ,
800
+ ) ,
801
+ "process_time" => ( false , "GetProcessTimes()" , true , 1e-7 ) ,
802
+ "thread_time" => ( false , "GetThreadTimes()" , true , 1e-7 ) ,
803
+ "time" => (
804
+ true ,
805
+ "GetSystemTimeAsFileTime()" ,
806
+ false ,
807
+ get_system_time_adjustment ( vm) ? as f64 * 1e-7 ,
808
+ ) ,
809
+ _ => return Err ( vm. new_value_error ( "unknown clock" . to_owned ( ) ) ) ,
810
+ } ;
811
+
812
+ Ok ( py_namespace ! ( vm, {
813
+ "implementation" => vm. new_pyobj( imp) ,
814
+ "monotonic" => vm. ctx. new_bool( mono) ,
815
+ "adjustable" => vm. ctx. new_bool( adj) ,
816
+ "resolution" => vm. ctx. new_float( res) ,
817
+ } ) )
818
+ }
819
+
820
+ #[ pyfunction]
821
+ fn monotonic ( vm : & VirtualMachine ) -> PyResult < f64 > {
822
+ Ok ( get_monotonic_clock ( vm) ?. as_secs_f64 ( ) )
823
+ }
824
+
825
+ #[ pyfunction]
826
+ fn monotonic_ns ( vm : & VirtualMachine ) -> PyResult < u128 > {
827
+ Ok ( get_monotonic_clock ( vm) ?. as_nanos ( ) )
828
+ }
829
+
830
+ #[ pyfunction]
831
+ fn perf_counter ( vm : & VirtualMachine ) -> PyResult < f64 > {
832
+ Ok ( win_perf_counter ( vm) ?. as_secs_f64 ( ) )
833
+ }
834
+
835
+ #[ pyfunction]
836
+ fn perf_counter_ns ( vm : & VirtualMachine ) -> PyResult < u128 > {
837
+ Ok ( win_perf_counter ( vm) ?. as_nanos ( ) )
838
+ }
839
+
707
840
pub ( super ) fn get_thread_time ( vm : & VirtualMachine ) -> PyResult < Duration > {
708
841
let ( kernel_time, user_time) = unsafe {
709
842
let mut _creation_time = std:: mem:: MaybeUninit :: uninit ( ) ;
0 commit comments