1

Тема: 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')]
}