/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with this * work for additional information regarding copyright ownership. The ASF * licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ #include "winutils.h" #include #include #include #include #ifdef PSAPI_VERSION #undef PSAPI_VERSION #endif #define PSAPI_VERSION 1 #pragma comment(lib, "psapi.lib") #pragma comment(lib, "Powrprof.lib") #pragma comment(lib, "pdh.lib") CONST PWSTR COUNTER_PATH_NET_READ_ALL = L"\\Network Interface(*)\\Bytes Received/Sec"; CONST PWSTR COUNTER_PATH_NET_WRITE_ALL = L"\\Network Interface(*)\\Bytes Sent/Sec"; CONST PWSTR COUNTER_PATH_DISK_READ_ALL = L"\\LogicalDisk(*)\\Disk Read Bytes/sec"; CONST PWSTR COUNTER_PATH_DISK_WRITE_ALL = L"\\LogicalDisk(*)\\Disk Write Bytes/sec"; typedef struct _PROCESSOR_POWER_INFORMATION { ULONG Number; ULONG MaxMhz; ULONG CurrentMhz; ULONG MhzLimit; ULONG MaxIdleState; ULONG CurrentIdleState; } PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION; //---------------------------------------------------------------------------- // Function: SystemInfo // // Description: // Returns the resource information about the machine // // Returns: // EXIT_SUCCESS: On success // EXIT_FAILURE: otherwise int SystemInfo() { size_t vmemSize, vmemFree, memSize, memFree; PERFORMANCE_INFORMATION memInfo; SYSTEM_INFO sysInfo; FILETIME idleTimeFt, kernelTimeFt, userTimeFt; ULARGE_INTEGER idleTime, kernelTime, userTime; ULONGLONG cpuTimeMs; size_t size; LPBYTE pBuffer; PROCESSOR_POWER_INFORMATION const *ppi; ULONGLONG cpuFrequencyKhz; NTSTATUS status; LONGLONG diskRead, diskWrite, netRead, netWrite; ZeroMemory(&memInfo, sizeof(PERFORMANCE_INFORMATION)); memInfo.cb = sizeof(PERFORMANCE_INFORMATION); if(!GetPerformanceInfo(&memInfo, sizeof(PERFORMANCE_INFORMATION))) { ReportErrorCode(L"GetPerformanceInfo", GetLastError()); return EXIT_FAILURE; } vmemSize = memInfo.CommitLimit*memInfo.PageSize; vmemFree = vmemSize - memInfo.CommitTotal*memInfo.PageSize; memSize = memInfo.PhysicalTotal*memInfo.PageSize; memFree = memInfo.PhysicalAvailable*memInfo.PageSize; GetSystemInfo(&sysInfo); if(!GetSystemTimes(&idleTimeFt, &kernelTimeFt, &userTimeFt)) { ReportErrorCode(L"GetSystemTimes", GetLastError()); return EXIT_FAILURE; } idleTime.HighPart = idleTimeFt.dwHighDateTime; idleTime.LowPart = idleTimeFt.dwLowDateTime; kernelTime.HighPart = kernelTimeFt.dwHighDateTime; kernelTime.LowPart = kernelTimeFt.dwLowDateTime; userTime.HighPart = userTimeFt.dwHighDateTime; userTime.LowPart = userTimeFt.dwLowDateTime; cpuTimeMs = (kernelTime.QuadPart - idleTime.QuadPart + userTime.QuadPart)/10000; // allocate buffer to get info for each processor size = sysInfo.dwNumberOfProcessors * sizeof(PROCESSOR_POWER_INFORMATION); pBuffer = (BYTE*) LocalAlloc(LPTR, size); if(!pBuffer) { ReportErrorCode(L"LocalAlloc", GetLastError()); return EXIT_FAILURE; } status = CallNtPowerInformation(ProcessorInformation, NULL, 0, pBuffer, (long)size); if(0 != status) { fwprintf_s(stderr, L"Error in CallNtPowerInformation. Err:%d\n", status); LocalFree(pBuffer); return EXIT_FAILURE; } ppi = (PROCESSOR_POWER_INFORMATION const *)pBuffer; cpuFrequencyKhz = ppi->MaxMhz*1000; LocalFree(pBuffer); status = GetDiskAndNetwork(&diskRead, &diskWrite, &netRead, &netWrite); if(0 != status) { fwprintf_s(stderr, L"Error in GetDiskAndNetwork. Err:%d\n", status); return EXIT_FAILURE; } fwprintf_s(stdout, L"%Iu,%Iu,%Iu,%Iu,%u,%I64u,%I64u,%I64d,%I64d,%I64d,%I64d\n", vmemSize, memSize, vmemFree, memFree, sysInfo.dwNumberOfProcessors, cpuFrequencyKhz, cpuTimeMs, diskRead, diskWrite, netRead, netWrite); return EXIT_SUCCESS; } void SystemInfoUsage() { fwprintf(stdout, L"\ Usage: systeminfo\n\ Prints machine information on stdout\n\ Comma separated list of the following values.\n\ VirtualMemorySize(bytes),PhysicalMemorySize(bytes),\n\ FreeVirtualMemory(bytes),FreePhysicalMemory(bytes),\n\ NumberOfProcessors,CpuFrequency(Khz),\n\ CpuTime(MilliSec,Kernel+User),\n\ DiskRead(bytes),DiskWrite(bytes),\n\ NetworkRead(bytes),NetworkWrite(bytes)\n"); } int GetDiskAndNetwork(LONGLONG* diskRead, LONGLONG* diskWrite, LONGLONG* netRead, LONGLONG* netWrite) { int ret = EXIT_SUCCESS; PDH_STATUS status = ERROR_SUCCESS; PDH_HQUERY hQuery = NULL; PDH_HCOUNTER hCounterNetRead = NULL; PDH_HCOUNTER hCounterNetWrite = NULL; PDH_HCOUNTER hCounterDiskRead = NULL; PDH_HCOUNTER hCounterDiskWrite = NULL; DWORD i; if(status = PdhOpenQuery(NULL, 0, &hQuery)) { fwprintf_s(stderr, L"PdhOpenQuery failed with 0x%x.\n", status); ret = EXIT_FAILURE; goto cleanup; } // Add each one of the counters with wild cards if(status = PdhAddCounter(hQuery, COUNTER_PATH_NET_READ_ALL, 0, &hCounterNetRead)) { fwprintf_s(stderr, L"PdhAddCounter %s failed with 0x%x.\n", COUNTER_PATH_NET_READ_ALL, status); ret = EXIT_FAILURE; goto cleanup; } if(status = PdhAddCounter(hQuery, COUNTER_PATH_NET_WRITE_ALL, 0, &hCounterNetWrite)) { fwprintf_s(stderr, L"PdhAddCounter %s failed with 0x%x.\n", COUNTER_PATH_NET_WRITE_ALL, status); ret = EXIT_FAILURE; goto cleanup; } if(status = PdhAddCounter(hQuery, COUNTER_PATH_DISK_READ_ALL, 0, &hCounterDiskRead)) { fwprintf_s(stderr, L"PdhAddCounter %s failed with 0x%x.\n", COUNTER_PATH_DISK_READ_ALL, status); ret = EXIT_FAILURE; goto cleanup; } if(status = PdhAddCounter(hQuery, COUNTER_PATH_DISK_WRITE_ALL, 0, &hCounterDiskWrite)) { fwprintf_s(stderr, L"PdhAddCounter %s failed with 0x%x.\n", COUNTER_PATH_DISK_WRITE_ALL, status); ret = EXIT_FAILURE; goto cleanup; } if(status = PdhCollectQueryData(hQuery)) { fwprintf_s(stderr, L"PdhCollectQueryData() failed with 0x%x.\n", status); ret = EXIT_FAILURE; goto cleanup; } // Read and aggregate counters status = ReadTotalCounter(hCounterNetRead, netRead); if(ERROR_SUCCESS != status) { fwprintf_s(stderr, L"ReadTotalCounter(Network Read): Error 0x%x.\n", status); ret = EXIT_FAILURE; } status = ReadTotalCounter(hCounterNetWrite, netWrite); if(ERROR_SUCCESS != status) { fwprintf_s(stderr, L"ReadTotalCounter(Network Write): Error 0x%x.\n", status); ret = EXIT_FAILURE; } status = ReadTotalCounter(hCounterDiskRead, diskRead); if(ERROR_SUCCESS != status) { fwprintf_s(stderr, L"ReadTotalCounter(Disk Read): Error 0x%x.\n", status); ret = EXIT_FAILURE; } status = ReadTotalCounter(hCounterDiskWrite, diskWrite); if(ERROR_SUCCESS != status) { fwprintf_s(stderr, L"ReadTotalCounter(Disk Write): Error 0x%x.\n", status); ret = EXIT_FAILURE; } cleanup: if (hQuery) { status = PdhCloseQuery(hQuery); } return ret; } PDH_STATUS ReadTotalCounter(PDH_HCOUNTER hCounter, LONGLONG* ret) { PDH_STATUS status = ERROR_SUCCESS; DWORD i = 0; DWORD dwBufferSize = 0; DWORD dwItemCount = 0; PDH_RAW_COUNTER_ITEM *pItems = NULL; // Initialize output *ret = 0; // Get the required size of the pItems buffer status = PdhGetRawCounterArray(hCounter, &dwBufferSize, &dwItemCount, NULL); if (PDH_MORE_DATA == status) { pItems = (PDH_RAW_COUNTER_ITEM *) malloc(dwBufferSize); if (pItems) { // Actually query the counter status = PdhGetRawCounterArray(hCounter, &dwBufferSize, &dwItemCount, pItems); if (ERROR_SUCCESS == status) { for (i = 0; i < dwItemCount; i++) { if (wcscmp(L"_Total", pItems[i].szName) == 0) { *ret = pItems[i].RawValue.FirstValue; break; } else { *ret += pItems[i].RawValue.FirstValue; } } } else { *ret = -1; goto cleanup; } // Reset structures free(pItems); pItems = NULL; dwBufferSize = dwItemCount = 0; } else { *ret = -1; status = PDH_NO_DATA; goto cleanup; } } else { *ret = -1; goto cleanup; } cleanup: if (pItems) { free(pItems); } return status; }