Тема: Python: разрешение системного таймера
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from platform import system
from sys import exit
if __name__ == '__main__':
os = system()
if 'Linux' == os:
from ctypes import CDLL
from struct import pack, unpack
libc = CDLL('libc.so.6')
timespec = pack('ql', 1, 2)
if 0 != (err := libc.clock_getres(5, timespec)):
libc.perror('clock_getres')
exit(err)
print('Текущее разрешение: %.3f ms' % (unpack('ql', timespec)[1] / 1e6))
elif 'Windows' == os:
from ctypes import byref, create_unicode_buffer, c_bool, c_ulong, windll
tm, inc, dis = c_ulong(), c_ulong(), c_bool()
if not windll.kernel32.GetSystemTimeAdjustment(byref(tm), byref(inc), byref(dis)):
err, msg = windll.kernel32.GetLastError(), create_unicode_buffer(0x100)
print('Какая-то неведомая ошибка.'
if not windll.kernel32.FormatMessageW(
0x12FF, None, err, 0x400, msg, len(msg), None
) else msg.value
)
exit(err)
print('Текущее разрешение: %.3f ms' % (tm.value / 1e4))
else:
print('Увы, нужны Windows или Linux.')
Небольшое отсnупление касательно Windows.
; иерархия вызовов
kernel32!GetSystemTimeAdjustment
kernelbase!GetSystemTimeAdjustment
ntdll!NtQuerySystemInformation (SYSTEM_BASIC_INFORMATION->TimerResolution)
То есть в коде выше задействовано самое высокоуровневое API. Также есть ntdll!NtQueryTimerResolution, возвращающая помимо прочего ещё значения максимально и минимально допустимых, которые в свою очередь забираются из ядерных KeM(ax|in)imumIncrement, в чём можно убедиться ковырнув упомянутую функцию WinDbg'ом и скормив ему следующий сценарий:
'use strict';
const log = x => host.diagnostics.debugLog(`${x}\n`);
const is_kd = () => host.currentSession.Attributes.Target.IsKernelTarget;
/*
* .scriptload clockres.js
* !clockres
*/
function *GetClockRes() {
if (!is_kd()) {
log('Incorrect debugger environment.');
return;
}
['Maximum', 'Minimum', 'Current'].forEach(
i => {
let value = host.createPointerObject(
host.getModuleSymbolAddress('nt', `Ke${"Current" == i ? "Time" : i}Increment`),
'nt', 'unsigned long *'
)[0];
log(`${i} timer interval: ${parseFloat(value / 10000)} ms`);
}
);
}
function initializeScript() {
return [new host.functionAlias(GetClockRes, 'clockres')]
}