1 module mecca.platform.os.darwin.time; 2 3 version (Darwin): 4 package(mecca): 5 6 import mecca.platform.os.darwin.dispatch; 7 8 struct Timer 9 { 10 @nogc: 11 nothrow: 12 13 import core.time : Duration; 14 15 alias Callback = extern (C) void function(); 16 17 private 18 { 19 Duration interval; 20 Callback callback; 21 22 dispatch_source_t timer; 23 dispatch_queue_t queue; 24 } 25 26 this(Duration interval, Callback callback) 27 in 28 { 29 assert(callback !is null); 30 } 31 do 32 { 33 this.callback = callback; 34 this.interval = interval; 35 } 36 37 void start() @trusted 38 { 39 import mecca.log : INFO; 40 41 const interval = this.interval.total!"nsecs"; 42 43 queue = dispatch_queue_create("com.github.weka-io.mecca.timer", null); 44 timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); 45 46 dispatch_source_set_event_handler_f(timer, &handler); 47 dispatch_set_context(timer, &this); 48 dispatch_source_set_cancel_handler_f(timer, &cancelHandler); 49 50 INFO!"Hang detector will wake up every %s nsecs"(interval); 51 52 const start = dispatch_time(DISPATCH_TIME_NOW, interval); 53 dispatch_source_set_timer(timer, start, interval, 0); 54 55 dispatch_activate(timer); 56 } 57 58 void cancel() @trusted 59 { 60 dispatch_source_cancel(timer); 61 } 62 63 bool isSet() const pure @safe 64 { 65 return timer !is null; 66 } 67 68 private: 69 70 void release() 71 { 72 dispatch_release(timer); 73 dispatch_release(queue); 74 } 75 76 extern (C) static void handler(void* timer) 77 { 78 (cast(Timer*) timer).callback(); 79 } 80 81 extern (C) static void cancelHandler(void* timer) 82 { 83 (cast(Timer*) timer).release(); 84 } 85 } 86 87 auto calculateCycles() 88 { 89 import core.sys.darwin.mach.kern_return : KERN_SUCCESS; 90 import core.sys.posix.time : nanosleep, timespec; 91 import core.time: mach_absolute_time, mach_timebase_info_data_t, 92 mach_timebase_info; 93 94 import std.exception: enforce, errnoEnforce; 95 import std.typecons: tuple; 96 97 import mecca.platform.x86: readTSC; 98 99 const sleepTime = timespec(0, 200_000_000); 100 101 const start = mach_absolute_time(); 102 const cyc0 = readTSC(); 103 const rcNanosleep = nanosleep(&sleepTime, null); 104 const end = mach_absolute_time(); 105 const cyc1 = readTSC(); 106 107 errnoEnforce(rcNanosleep == 0, "nanosleep"); // we hope we won't be interrupted by a signal here 108 109 const elapsed = end - start; 110 111 mach_timebase_info_data_t timebaseInfo; 112 enforce(mach_timebase_info(&timebaseInfo) == KERN_SUCCESS); 113 114 const nsecs = elapsed * timebaseInfo.numer / timebaseInfo.denom; 115 116 const cyclesPerSecond = cast(long)((cyc1 - cyc0) / (nsecs / 1E9)); 117 const cyclesPerMsec = cyclesPerSecond / 1_000; 118 const cyclesPerUsec = cyclesPerSecond / 1_000_000; 119 120 return tuple!("perSecond", "perMsec", "perUsec")( 121 cyclesPerSecond, cyclesPerMsec, cyclesPerUsec); 122 }