Created
April 17, 2017 15:42
-
-
Save nico/f3a1b13d5460194c8dcbee27756079f3 to your computer and use it in GitHub Desktop.
tim.exe memory tracking
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/tim.cc b/tim.cc | |
index 4d8200e..f6cfc19 100644 | |
--- a/tim.cc | |
+++ b/tim.cc | |
@@ -16,7 +16,11 @@ | |
#include <stdlib.h> | |
#include <windows.h> | |
+#include <psapi.h> // Must be after windows.h | |
+ | |
#include <algorithm> | |
+#include <string> | |
+using namespace std; | |
LPWSTR FindStartOfSubCommand(LPWSTR orig_command, bool* want_avg) { | |
int num_args; | |
@@ -42,6 +46,25 @@ struct Result { | |
DWORD exit_code; | |
}; | |
+wstring GetLastErrorString() { | |
+ DWORD err = GetLastError(); | |
+ | |
+ wchar_t* msg_buf; | |
+ FormatMessageW( | |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
+ FORMAT_MESSAGE_FROM_SYSTEM | | |
+ FORMAT_MESSAGE_IGNORE_INSERTS, | |
+ NULL, | |
+ err, | |
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
+ (wchar_t*)&msg_buf, | |
+ 0, | |
+ NULL); | |
+ wstring msg = msg_buf; | |
+ LocalFree(msg_buf); | |
+ return msg; | |
+} | |
+ | |
Result Run(LPWSTR command) { | |
STARTUPINFO startup_info = { sizeof(STARTUPINFO) }; | |
PROCESS_INFORMATION process_info; | |
@@ -55,17 +78,51 @@ Result Run(LPWSTR command) { | |
QueryPerformanceFrequency(&qpc_frequency); | |
QueryPerformanceCounter(&qpc_start_time); | |
- if (!CreateProcess(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL, | |
- &startup_info, &process_info)) { | |
+ if (!CreateProcess(NULL, command, NULL, NULL, TRUE, | |
+ CREATE_SUSPENDED, | |
+ NULL, NULL, &startup_info, &process_info)) { | |
wprintf(L"tim: Could not spawn subprocess, command line:\n" | |
L"%ws\n" | |
L"You may need to prefix the command with \"cmd /c \".\n", | |
command); | |
exit(1); | |
} | |
+ HANDLE job = CreateJobObject(NULL, NULL); | |
+ if (!AssignProcessToJobObject(job, process_info.hProcess)) { | |
+ wprintf(L"failed to AssignProcessToJobObject %s\n", | |
+ GetLastErrorString().c_str()); | |
+ } | |
+ ResumeThread(process_info.hThread); | |
+ | |
CloseHandle(process_info.hThread); | |
WaitForSingleObject(process_info.hProcess, INFINITE); | |
+ | |
+ // Collect additional stuff. This is cool, but doesn't get subprocess data. | |
+ PROCESS_MEMORY_COUNTERS_EX pmc; | |
+ IO_COUNTERS ioc; | |
+ GetProcessMemoryInfo(process_info.hProcess, | |
+ (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)); | |
+ GetProcessIoCounters(process_info.hProcess, &ioc); | |
+ | |
GetExitCodeProcess(process_info.hProcess, &result.exit_code); | |
+ | |
+ //JOBOBJECT_BASIC_PROCESS_ID_LIST* list; // needs dynamic alloc | |
+ JOBOBJECT_BASIC_ACCOUNTING_INFORMATION acct; | |
+ if (!QueryInformationJobObject(job, JobObjectBasicAccountingInformation, | |
+ &acct, sizeof(acct), NULL)) { | |
+ wprintf(L"failed to QueryInformationJobObject\n"); | |
+ } | |
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit; | |
+ if (!QueryInformationJobObject(job, JobObjectExtendedLimitInformation, | |
+ &limit, sizeof(limit), NULL)) { | |
+ wprintf(L"failed to QueryInformationJobObject\n"); | |
+ } | |
+ | |
+ wprintf(L"%ld processes", acct.TotalProcesses); | |
+ | |
+ CloseHandle(job); | |
+ | |
+ | |
CloseHandle(process_info.hProcess); | |
QueryPerformanceCounter(&qpc_end_time); | |
@@ -74,6 +131,8 @@ Result Run(LPWSTR command) { | |
result.qpc_elapsed_microseconds.QuadPart *= 1000000; | |
result.qpc_elapsed_microseconds.QuadPart /= qpc_frequency.QuadPart; | |
+ | |
+ | |
ULONGLONG end_time = GetTickCount64(); | |
result.elapsed = end_time - start_time; | |
@@ -81,6 +140,10 @@ Result Run(LPWSTR command) { | |
result.elapsed / (60 * 1000), | |
(result.elapsed % (60 * 1000)) / 1000.0, | |
result.qpc_elapsed_microseconds.QuadPart); | |
+ | |
+ wprintf(L"\npeak working set: %lld\npeak pagefile: %lld\n", | |
+ pmc.PeakWorkingSetSize, pmc.PeakPagefileUsage); | |
+ wprintf(L"\ntotal peak working set: %lld\n", limit.PeakProcessMemoryUsed); | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment