Подтвердить что ты не робот

Как получить использование процессора в потоке в windows (win32)

Ищем функции API Win32, пример кода С++ или Delphi, который говорит мне о потреблении процессора (процентное и/или общее время процессора) потока (а не итога для процесса). У меня есть идентификатор потока.

Я знаю, что Sysinternals Process Explorer может отображать эту информацию, но мне нужна эта информация внутри моей программы.

4b9b3361

Ответ 1

С помощью ответа RRUZ выше я, наконец, придумал этот код для Borland Delphi:

const
  THREAD_TERMINATE                 = $0001;
  THREAD_SUSPEND_RESUME            = $0002;
  THREAD_GET_CONTEXT               = $0008;
  THREAD_SET_CONTEXT               = $0010;
  THREAD_SET_INFORMATION           = $0020;
  THREAD_QUERY_INFORMATION         = $0040;
  THREAD_SET_THREAD_TOKEN          = $0080;
  THREAD_IMPERSONATE               = $0100;
  THREAD_DIRECT_IMPERSONATION      = $0200;
  THREAD_SET_LIMITED_INFORMATION   = $0400;
  THREAD_QUERY_LIMITED_INFORMATION = $0800;
  THREAD_ALL_ACCESS                = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $03FF;

function OpenThread(dwDesiredAccess: DWord;
                    bInheritHandle: Bool;
                    dwThreadId: DWord): DWord; stdcall; external 'kernel32.dll';


procedure TForm1.Button1Click(Sender: TObject);
var iii:integer;
    handle:thandle;
    creationtime,exittime,kerneltime,usertime:filetime;
begin
  Handle:=OpenThread(THREAD_SET_INFORMATION or THREAD_QUERY_INFORMATION, False, windows.GetCurrentThreadId);
  if handle<>0 then
  begin
    getthreadtimes(Handle,creationtime,exittime,kerneltime,usertime);
    label1.caption:='Total time for Thread #'+inttostr(windows.GetCurrentThreadId)+': '+inttostr( (int64(kerneltime)+int64(usertime)) div 1000 )+' msec';
    CloseHandle(Handle);
  end;
end;

Ответ 2

Вы должны использовать эти функции для получения использования процессора в потоке и процессе.

GetThreadTimes (извлекает информацию о времени для указанного потока.)

GetProcessTimes (Получает информацию о времени для указанного процесса.)

GetSystemTime (извлекает текущую системную дату и время. Системное время выражается в скоординированном универсальном времени UTC)

Здесь отличная статья от Dr. Dobb Параметры производительности Win32

Bye.

Ответ 3

Данные, на которые вы ссылаетесь, доступны с помощью специальных вызовов WMI. Вы можете запросить Win32_Process, чтобы получить все виды информации о конкретном процессе, и запросить Win32_PerfFormattedData_PerfProc_Process, чтобы получить количество потоков, и получить дескриптор потока (что я считаю вашим поиском) вы можете запросить Win32_PerfRawData_PerfProc_Thread, чтобы получить процент используемого времени процессора.

Существует библиотека доступная для Delphi, которая предоставляет обертки для большинства запросов WMI, однако для получения точного запроса потребуется некоторое экспериментирование ваш поиск. Синтаксис запроса очень широк, например, например, в моей системе, чтобы вернуть процент процессорного времени для потока 8, для идентификатора процесса 4:

SELECT PercentProcessorTime FROM Win32_PerfRawData_PerfProc_Thread 
  WHERE IdProcess=4 and IdThread=8

Большинство программ, которые представляют статистическую информацию о запущенных процессах, теперь используют WMI для запроса этой информации.

Ответ 4

Важно знать, что в определенных ситуациях время выполнения потока может оказаться бесполезным. Время выполнения каждого потока обновляется каждые 15 миллисекунд, как правило, для многоядерных систем, поэтому, если поток завершает свою задачу до этого времени, время выполнения будет reset. Более подробную информацию можно получить по ссылке: функция GetThreadTimes, и я был удивлены результатом! и Почему GetThreadTimes ошибочен

Ответ 5

Использование "GetThreadTimes"? Если вы измеряете время между вызовами на "GetThreadTimes" и сохраняете предыдущее время пользователя и/или ядра, тогда вы знаете, сколько времени было у потока с момента последнего обновления. Вы также знаете, сколько времени прошло в среднем, и, таким образом, вы можете определить, сколько процессорного времени было использовано. Было бы лучше (по причинам разрешения таймера) сделать эту проверку каждую секунду или около того и выработать ее среднее использование ЦП за эту секунду.

Ответ 6

Здесь - простая оболочка запроса WMI. С его помощью вы можете вызвать это, чтобы получить данные:

getWmiQueryResult(L"SELECT PercentProcessorTime FROM Win32_PerfRawData_PerfProc_Thread WHERE IdProcess=4 and IdThread=8", L"PercentProcessorTime ");

Также вы можете посмотреть документацию Win32_PerfRawData_PerfProc_Thread, чтобы узнать, какие другие свойства вы можете получить.

Ответ 7

В этом примере используется GetProcessTimes() но его можно легко изменить, чтобы использовать GetThreadTimes().

clock() ISO C clock() ПРЕДОСТАВЛЯЮТСЯ, чтобы дать вам истекшие процессорные секунды при делении на CLOCKS_PER_SEC. Однако на веб-странице Visual Studio 2019 говорится:

Функция часов сообщает, сколько времени настенных часов прошло с момента инициализации CRT во время запуска процесса. Обратите внимание, что эта функция не строго соответствует ISO C, в котором в качестве возвращаемого значения указывается чистое время ЦП.

Итак, вот замена, которую я сделал. В Windows 7/Visual Studio 2017 CLOCKS_PER_SEC имеет значение 1000, а GetProcessTimes() имеет точность только в миллисекундах, поэтому точность не теряется, возвращая clock_t вместо double, скажем.

clock_t AKClock() {
#ifdef WIN32
  FILETIME  ftimeCreate, ftimeExit, ftimeKernel, ftimeUser;
  SYSTEMTIME stimeKernel, stimeUser;

  if ( ! GetProcessTimes( GetCurrentProcess(), &ftimeCreate, &ftimeExit,
                          &ftimeKernel, &ftimeUser )        ||
       ! FileTimeToSystemTime( &ftimeKernel, &stimeKernel ) ||
       ! FileTimeToSystemTime( &ftimeUser,   &stimeUser   )     ) {
      char szError[ 1024 ];
      MyLoggingFunction( "AKClock() failed; returning -1: %s",
                         AKGetLastError( szError, sizeof( szError ) ) );
      return (clock_t) -1.0;
  }

  return (clock_t)
         ( ( stimeKernel.wHour         * 3600.0 +
             stimeKernel.wMinute       *   60.0 +
             stimeKernel.wSecond                +
             stimeKernel.wMilliseconds / 1000.0 +
             stimeUser.wHour           * 3600.0 +
             stimeUser.wMinute         *   60.0 +
             stimeUser.wSecond                  +
             stimeUser.wMilliseconds   / 1000.0   ) * CLOCKS_PER_SEC );
#else
    return clock();
#endif
}

А для полноты вот AKGetLastError():

void AKstrncpy( char *pszDest, const char *pszSrc, const size_t sDest ) {

  strncpy( pszDest, pszSrc, sDest );
  pszDest[ sDest - 1 ] = '\0';
}

char* AKGetLastError( char* szBuf, int iBufSize ) {

  DWORD  errorMessageID = GetLastError();
  char*  pszError = NULL;
  size_t sizeBuf;

  if( errorMessageID == 0 ) {
      AKstrncpy( szBuf, "(no error)", iBufSize );
      return szBuf;
  }

  sizeBuf = FormatMessageA(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL, errorMessageID, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
            (LPSTR) &pszError, 0, NULL );

  AKstrncpy( szBuf, pszError, iBufSize );

  LocalFree( pszError );

  int iLen = strlen( szBuf );
  if ( strcmp( szBuf + iLen - 2, "\r\n" ) == 0 )
      szBuf[ iLen - 2 ] = '\0';

  return szBuf;
}