1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tools/footprint/wm.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,613 @@ 1.4 +/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * This program tracks a process's working memory usage using the 1.12 + * ``performance'' entries in the Win32 registry. It borrows from 1.13 + * the ``pviewer'' source code in the MS SDK. 1.14 + */ 1.15 + 1.16 +#include <assert.h> 1.17 +#include <windows.h> 1.18 +#include <winperf.h> 1.19 +#include <stdio.h> 1.20 +#include <stdlib.h> 1.21 + 1.22 +#define PN_PROCESS 1 1.23 +#define PN_PROCESS_CPU 2 1.24 +#define PN_PROCESS_PRIV 3 1.25 +#define PN_PROCESS_USER 4 1.26 +#define PN_PROCESS_WORKING_SET 5 1.27 +#define PN_PROCESS_PEAK_WS 6 1.28 +#define PN_PROCESS_PRIO 7 1.29 +#define PN_PROCESS_ELAPSE 8 1.30 +#define PN_PROCESS_ID 9 1.31 +#define PN_PROCESS_PRIVATE_PAGE 10 1.32 +#define PN_PROCESS_VIRTUAL_SIZE 11 1.33 +#define PN_PROCESS_PEAK_VS 12 1.34 +#define PN_PROCESS_FAULT_COUNT 13 1.35 +#define PN_THREAD 14 1.36 +#define PN_THREAD_CPU 15 1.37 +#define PN_THREAD_PRIV 16 1.38 +#define PN_THREAD_USER 17 1.39 +#define PN_THREAD_START 18 1.40 +#define PN_THREAD_SWITCHES 19 1.41 +#define PN_THREAD_PRIO 20 1.42 +#define PN_THREAD_BASE_PRIO 21 1.43 +#define PN_THREAD_ELAPSE 22 1.44 +#define PN_THREAD_DETAILS 23 1.45 +#define PN_THREAD_PC 24 1.46 +#define PN_IMAGE 25 1.47 +#define PN_IMAGE_NOACCESS 26 1.48 +#define PN_IMAGE_READONLY 27 1.49 +#define PN_IMAGE_READWRITE 28 1.50 +#define PN_IMAGE_WRITECOPY 29 1.51 +#define PN_IMAGE_EXECUTABLE 30 1.52 +#define PN_IMAGE_EXE_READONLY 31 1.53 +#define PN_IMAGE_EXE_READWRITE 32 1.54 +#define PN_IMAGE_EXE_WRITECOPY 33 1.55 +#define PN_PROCESS_ADDRESS_SPACE 34 1.56 +#define PN_PROCESS_PRIVATE_NOACCESS 35 1.57 +#define PN_PROCESS_PRIVATE_READONLY 36 1.58 +#define PN_PROCESS_PRIVATE_READWRITE 37 1.59 +#define PN_PROCESS_PRIVATE_WRITECOPY 38 1.60 +#define PN_PROCESS_PRIVATE_EXECUTABLE 39 1.61 +#define PN_PROCESS_PRIVATE_EXE_READONLY 40 1.62 +#define PN_PROCESS_PRIVATE_EXE_READWRITE 41 1.63 +#define PN_PROCESS_PRIVATE_EXE_WRITECOPY 42 1.64 +#define PN_PROCESS_MAPPED_NOACCESS 43 1.65 +#define PN_PROCESS_MAPPED_READONLY 44 1.66 +#define PN_PROCESS_MAPPED_READWRITE 45 1.67 +#define PN_PROCESS_MAPPED_WRITECOPY 46 1.68 +#define PN_PROCESS_MAPPED_EXECUTABLE 47 1.69 +#define PN_PROCESS_MAPPED_EXE_READONLY 48 1.70 +#define PN_PROCESS_MAPPED_EXE_READWRITE 49 1.71 +#define PN_PROCESS_MAPPED_EXE_WRITECOPY 50 1.72 +#define PN_PROCESS_IMAGE_NOACCESS 51 1.73 +#define PN_PROCESS_IMAGE_READONLY 52 1.74 +#define PN_PROCESS_IMAGE_READWRITE 53 1.75 +#define PN_PROCESS_IMAGE_WRITECOPY 54 1.76 +#define PN_PROCESS_IMAGE_EXECUTABLE 55 1.77 +#define PN_PROCESS_IMAGE_EXE_READONLY 56 1.78 +#define PN_PROCESS_IMAGE_EXE_READWRITE 57 1.79 +#define PN_PROCESS_IMAGE_EXE_WRITECOPY 58 1.80 + 1.81 +struct entry_t { 1.82 + int e_key; 1.83 + int e_index; 1.84 + char* e_title; 1.85 +}; 1.86 + 1.87 +entry_t entries[] = { 1.88 +{ PN_PROCESS, 0, TEXT("Process") }, 1.89 +{ PN_PROCESS_CPU, 0, TEXT("% Processor Time") }, 1.90 +{ PN_PROCESS_PRIV, 0, TEXT("% Privileged Time") }, 1.91 +{ PN_PROCESS_USER, 0, TEXT("% User Time") }, 1.92 +{ PN_PROCESS_WORKING_SET, 0, TEXT("Working Set") }, 1.93 +{ PN_PROCESS_PEAK_WS, 0, TEXT("Working Set Peak") }, 1.94 +{ PN_PROCESS_PRIO, 0, TEXT("Priority Base") }, 1.95 +{ PN_PROCESS_ELAPSE, 0, TEXT("Elapsed Time") }, 1.96 +{ PN_PROCESS_ID, 0, TEXT("ID Process") }, 1.97 +{ PN_PROCESS_PRIVATE_PAGE, 0, TEXT("Private Bytes") }, 1.98 +{ PN_PROCESS_VIRTUAL_SIZE, 0, TEXT("Virtual Bytes") }, 1.99 +{ PN_PROCESS_PEAK_VS, 0, TEXT("Virtual Bytes Peak") }, 1.100 +{ PN_PROCESS_FAULT_COUNT, 0, TEXT("Page Faults/sec") }, 1.101 +{ PN_THREAD, 0, TEXT("Thread") }, 1.102 +{ PN_THREAD_CPU, 0, TEXT("% Processor Time") }, 1.103 +{ PN_THREAD_PRIV, 0, TEXT("% Privileged Time") }, 1.104 +{ PN_THREAD_USER, 0, TEXT("% User Time") }, 1.105 +{ PN_THREAD_START, 0, TEXT("Start Address") }, 1.106 +{ PN_THREAD_SWITCHES, 0, TEXT("Con0, TEXT Switches/sec") }, 1.107 +{ PN_THREAD_PRIO, 0, TEXT("Priority Current") }, 1.108 +{ PN_THREAD_BASE_PRIO, 0, TEXT("Priority Base") }, 1.109 +{ PN_THREAD_ELAPSE, 0, TEXT("Elapsed Time") }, 1.110 +{ PN_THREAD_DETAILS, 0, TEXT("Thread Details") }, 1.111 +{ PN_THREAD_PC, 0, TEXT("User PC") }, 1.112 +{ PN_IMAGE, 0, TEXT("Image") }, 1.113 +{ PN_IMAGE_NOACCESS, 0, TEXT("No Access") }, 1.114 +{ PN_IMAGE_READONLY, 0, TEXT("Read Only") }, 1.115 +{ PN_IMAGE_READWRITE, 0, TEXT("Read/Write") }, 1.116 +{ PN_IMAGE_WRITECOPY, 0, TEXT("Write Copy") }, 1.117 +{ PN_IMAGE_EXECUTABLE, 0, TEXT("Executable") }, 1.118 +{ PN_IMAGE_EXE_READONLY, 0, TEXT("Exec Read Only") }, 1.119 +{ PN_IMAGE_EXE_READWRITE, 0, TEXT("Exec Read/Write") }, 1.120 +{ PN_IMAGE_EXE_WRITECOPY, 0, TEXT("Exec Write Copy") }, 1.121 +{ PN_PROCESS_ADDRESS_SPACE, 0, TEXT("Process Address Space") }, 1.122 +{ PN_PROCESS_PRIVATE_NOACCESS, 0, TEXT("Reserved Space No Access") }, 1.123 +{ PN_PROCESS_PRIVATE_READONLY, 0, TEXT("Reserved Space Read Only") }, 1.124 +{ PN_PROCESS_PRIVATE_READWRITE, 0, TEXT("Reserved Space Read/Write") }, 1.125 +{ PN_PROCESS_PRIVATE_WRITECOPY, 0, TEXT("Reserved Space Write Copy") }, 1.126 +{ PN_PROCESS_PRIVATE_EXECUTABLE, 0, TEXT("Reserved Space Executable") }, 1.127 +{ PN_PROCESS_PRIVATE_EXE_READONLY, 0, TEXT("Reserved Space Exec Read Only") }, 1.128 +{ PN_PROCESS_PRIVATE_EXE_READWRITE, 0, TEXT("Reserved Space Exec Read/Write") }, 1.129 +{ PN_PROCESS_PRIVATE_EXE_WRITECOPY, 0, TEXT("Reserved Space Exec Write Copy") }, 1.130 +{ PN_PROCESS_MAPPED_NOACCESS, 0, TEXT("Mapped Space No Access") }, 1.131 +{ PN_PROCESS_MAPPED_READONLY, 0, TEXT("Mapped Space Read Only") }, 1.132 +{ PN_PROCESS_MAPPED_READWRITE, 0, TEXT("Mapped Space Read/Write") }, 1.133 +{ PN_PROCESS_MAPPED_WRITECOPY, 0, TEXT("Mapped Space Write Copy") }, 1.134 +{ PN_PROCESS_MAPPED_EXECUTABLE, 0, TEXT("Mapped Space Executable") }, 1.135 +{ PN_PROCESS_MAPPED_EXE_READONLY, 0, TEXT("Mapped Space Exec Read Only") }, 1.136 +{ PN_PROCESS_MAPPED_EXE_READWRITE, 0, TEXT("Mapped Space Exec Read/Write") }, 1.137 +{ PN_PROCESS_MAPPED_EXE_WRITECOPY, 0, TEXT("Mapped Space Exec Write Copy") }, 1.138 +{ PN_PROCESS_IMAGE_NOACCESS, 0, TEXT("Image Space No Access") }, 1.139 +{ PN_PROCESS_IMAGE_READONLY, 0, TEXT("Image Space Read Only") }, 1.140 +{ PN_PROCESS_IMAGE_READWRITE, 0, TEXT("Image Space Read/Write") }, 1.141 +{ PN_PROCESS_IMAGE_WRITECOPY, 0, TEXT("Image Space Write Copy") }, 1.142 +{ PN_PROCESS_IMAGE_EXECUTABLE, 0, TEXT("Image Space Executable") }, 1.143 +{ PN_PROCESS_IMAGE_EXE_READONLY, 0, TEXT("Image Space Exec Read Only") }, 1.144 +{ PN_PROCESS_IMAGE_EXE_READWRITE, 0, TEXT("Image Space Exec Read/Write") }, 1.145 +{ PN_PROCESS_IMAGE_EXE_WRITECOPY, 0, TEXT("Image Space Exec Write Copy") }, 1.146 +{ 0, 0, 0 }, 1.147 +}; 1.148 + 1.149 +#define NENTRIES ((sizeof(entries) / sizeof(entry_t)) - 1) 1.150 + 1.151 +static int 1.152 +key_for_index(int key) 1.153 +{ 1.154 + entry_t* entry = entries + NENTRIES / 2; 1.155 + unsigned int step = 64 / 4; // XXX 1.156 + 1.157 + while (step) { 1.158 + if (key < entry->e_key) 1.159 + entry -= step; 1.160 + else if (key > entry->e_key) 1.161 + entry += step; 1.162 + 1.163 + if (key == entry->e_key) 1.164 + return entry->e_index; 1.165 + 1.166 + step >>= 1; 1.167 + } 1.168 + 1.169 + assert(false); 1.170 + return 0; 1.171 +} 1.172 + 1.173 + 1.174 +class auto_hkey { 1.175 +protected: 1.176 + HKEY hkey; 1.177 + 1.178 + HKEY* begin_assignment() { 1.179 + if (hkey) { 1.180 + ::RegCloseKey(hkey); 1.181 + hkey = 0; 1.182 + } 1.183 + return &hkey; 1.184 + } 1.185 + 1.186 +public: 1.187 + auto_hkey() : hkey(0) {} 1.188 + ~auto_hkey() { ::RegCloseKey(hkey); } 1.189 + 1.190 + HKEY get() const { return hkey; } 1.191 + operator HKEY() const { return get(); } 1.192 + 1.193 + friend HKEY* 1.194 + getter_Acquires(auto_hkey& hkey); 1.195 +}; 1.196 + 1.197 +static HKEY* 1.198 +getter_Acquires(auto_hkey& hkey) 1.199 +{ 1.200 + return hkey.begin_assignment(); 1.201 +} 1.202 + 1.203 + 1.204 +static int 1.205 +get_perf_titles(char*& buffer, char**& titles, int& last_title_index) 1.206 +{ 1.207 + DWORD result; 1.208 + 1.209 + // Open the perflib key to find out the last counter's index and 1.210 + // system version. 1.211 + auto_hkey perflib_hkey; 1.212 + result = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, 1.213 + TEXT("software\\microsoft\\windows nt\\currentversion\\perflib"), 1.214 + 0, 1.215 + KEY_READ, 1.216 + getter_Acquires(perflib_hkey)); 1.217 + 1.218 + if (result != ERROR_SUCCESS) 1.219 + return result; 1.220 + 1.221 + // Get the last counter's index so we know how much memory to 1.222 + // allocate for titles 1.223 + DWORD data_size = sizeof(DWORD); 1.224 + DWORD type; 1.225 + result = ::RegQueryValueEx(perflib_hkey, 1.226 + TEXT("Last Counter"), 1.227 + 0, 1.228 + &type, 1.229 + reinterpret_cast<BYTE*>(&last_title_index), 1.230 + &data_size); 1.231 + 1.232 + if (result != ERROR_SUCCESS) 1.233 + return result; 1.234 + 1.235 + // Find system version, for system earlier than 1.0a, there's no 1.236 + // version value. 1.237 + int version; 1.238 + result = ::RegQueryValueEx(perflib_hkey, 1.239 + TEXT("Version"), 1.240 + 0, 1.241 + &type, 1.242 + reinterpret_cast<BYTE*>(&version), 1.243 + &data_size); 1.244 + 1.245 + bool is_nt_10 = (result == ERROR_SUCCESS); 1.246 + 1.247 + // Now, get ready for the counter names and indexes. 1.248 + char* counter_value_name; 1.249 + auto_hkey counter_autohkey; 1.250 + HKEY counter_hkey; 1.251 + if (is_nt_10) { 1.252 + // NT 1.0, so make hKey2 point to ...\perflib\009 and get 1.253 + // the counters from value "Counters" 1.254 + counter_value_name = TEXT("Counters"); 1.255 + result = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, 1.256 + TEXT("software\\microsoft\\windows nt\\currentversion\\perflib\\009"), 1.257 + 0, 1.258 + KEY_READ, 1.259 + getter_Acquires(counter_autohkey)); 1.260 + 1.261 + if (result != ERROR_SUCCESS) 1.262 + return result; 1.263 + 1.264 + counter_hkey = counter_autohkey; 1.265 + } 1.266 + else { 1.267 + // NT 1.0a or later. Get the counters in key HKEY_PERFORMANCE_KEY 1.268 + // and from value "Counter 009" 1.269 + counter_value_name = TEXT("Counter 009"); 1.270 + counter_hkey = HKEY_PERFORMANCE_DATA; 1.271 + } 1.272 + 1.273 + // Find out the size of the data. 1.274 + result = ::RegQueryValueEx(counter_hkey, 1.275 + counter_value_name, 1.276 + 0, 1.277 + &type, 1.278 + 0, 1.279 + &data_size); 1.280 + 1.281 + if (result != ERROR_SUCCESS) 1.282 + return result; 1.283 + 1.284 + // Allocate memory 1.285 + buffer = new char[data_size]; 1.286 + titles = new char*[last_title_index + 1]; 1.287 + for (int i = 0; i <= last_title_index; ++i) 1.288 + titles[i] = 0; 1.289 + 1.290 + // Query the data 1.291 + result = ::RegQueryValueEx(counter_hkey, 1.292 + counter_value_name, 1.293 + 0, 1.294 + &type, 1.295 + reinterpret_cast<BYTE*>(buffer), 1.296 + &data_size); 1.297 + if (result != ERROR_SUCCESS) 1.298 + return result; 1.299 + 1.300 + // Setup the titles array of pointers to point to beginning of 1.301 + // each title string. 1.302 + char* title = buffer; 1.303 + int len; 1.304 + 1.305 + while (len = lstrlen(title)) { 1.306 + int index = atoi(title); 1.307 + title += len + 1; 1.308 + 1.309 + if (index <= last_title_index) 1.310 + titles[index] = title; 1.311 + 1.312 +#ifdef DEBUG 1.313 + printf("%d=%s\n", index, title); 1.314 +#endif 1.315 + 1.316 + title += lstrlen(title) + 1; 1.317 + } 1.318 + 1.319 + return ERROR_SUCCESS; 1.320 +} 1.321 + 1.322 +static void 1.323 +init_entries() 1.324 +{ 1.325 + char* buffer; 1.326 + char** titles; 1.327 + int last = 0; 1.328 + 1.329 + DWORD result = get_perf_titles(buffer, titles, last); 1.330 + 1.331 + assert(result == ERROR_SUCCESS); 1.332 + 1.333 + for (entry_t* entry = entries; entry->e_key != 0; ++entry) { 1.334 + for (int index = 0; index <= last; ++index) { 1.335 + if (titles[index] && 0 == lstrcmpi(titles[index], entry->e_title)) { 1.336 + entry->e_index = index; 1.337 + break; 1.338 + } 1.339 + } 1.340 + 1.341 + if (entry->e_index == 0) { 1.342 + fprintf(stderr, "warning: unable to find index for ``%s''\n", entry->e_title); 1.343 + } 1.344 + } 1.345 + 1.346 + delete[] buffer; 1.347 + delete[] titles; 1.348 +} 1.349 + 1.350 + 1.351 + 1.352 +static DWORD 1.353 +get_perf_data(HKEY perf_hkey, char* object_index, PERF_DATA_BLOCK** data, DWORD* size) 1.354 +{ 1.355 + if (! *data) 1.356 + *data = reinterpret_cast<PERF_DATA_BLOCK*>(new char[*size]); 1.357 + 1.358 + DWORD result; 1.359 + 1.360 + while (1) { 1.361 + DWORD type; 1.362 + DWORD real_size = *size; 1.363 + 1.364 + result = ::RegQueryValueEx(perf_hkey, 1.365 + object_index, 1.366 + 0, 1.367 + &type, 1.368 + reinterpret_cast<BYTE*>(*data), 1.369 + &real_size); 1.370 + 1.371 + if (result != ERROR_MORE_DATA) 1.372 + break; 1.373 + 1.374 + delete[] *data; 1.375 + *size += 1024; 1.376 + *data = reinterpret_cast<PERF_DATA_BLOCK*>(new char[*size]); 1.377 + 1.378 + if (! *data) 1.379 + return ERROR_NOT_ENOUGH_MEMORY; 1.380 + } 1.381 + 1.382 + return result; 1.383 +} 1.384 + 1.385 + 1.386 +static const PERF_OBJECT_TYPE* 1.387 +first_object(const PERF_DATA_BLOCK* data) 1.388 +{ 1.389 + return data 1.390 + ? reinterpret_cast<const PERF_OBJECT_TYPE*>(reinterpret_cast<const char*>(data) + data->HeaderLength) 1.391 + : 0; 1.392 +} 1.393 + 1.394 +static const PERF_OBJECT_TYPE* 1.395 +next_object(const PERF_OBJECT_TYPE* object) 1.396 +{ 1.397 + return object 1.398 + ? reinterpret_cast<const PERF_OBJECT_TYPE*>(reinterpret_cast<const char*>(object) + object->TotalByteLength) 1.399 + : 0; 1.400 +} 1.401 + 1.402 +const PERF_OBJECT_TYPE* 1.403 +find_object(const PERF_DATA_BLOCK* data, DWORD index) 1.404 +{ 1.405 + const PERF_OBJECT_TYPE* object = first_object(data); 1.406 + if (! object) 1.407 + return 0; 1.408 + 1.409 + for (int i = 0; i < data->NumObjectTypes; ++i) { 1.410 + if (object->ObjectNameTitleIndex == index) 1.411 + return object; 1.412 + 1.413 + object = next_object(object); 1.414 + } 1.415 + 1.416 + return 0; 1.417 +} 1.418 + 1.419 + 1.420 +static const PERF_COUNTER_DEFINITION* 1.421 +first_counter(const PERF_OBJECT_TYPE* object) 1.422 +{ 1.423 + return object 1.424 + ? reinterpret_cast<const PERF_COUNTER_DEFINITION*>(reinterpret_cast<const char*>(object) + object->HeaderLength) 1.425 + : 0; 1.426 +} 1.427 + 1.428 +static const PERF_COUNTER_DEFINITION* 1.429 +next_counter(const PERF_COUNTER_DEFINITION* counter) 1.430 +{ 1.431 + return counter ? 1.432 + reinterpret_cast<const PERF_COUNTER_DEFINITION*>(reinterpret_cast<const char*>(counter) + counter->ByteLength) 1.433 + : 0; 1.434 +} 1.435 + 1.436 + 1.437 +static const PERF_COUNTER_DEFINITION* 1.438 +find_counter(const PERF_OBJECT_TYPE* object, int index) 1.439 +{ 1.440 + const PERF_COUNTER_DEFINITION* counter = 1.441 + first_counter(object); 1.442 + 1.443 + if (! counter) 1.444 + return 0; 1.445 + 1.446 + for (int i; i < object->NumCounters; ++i) { 1.447 + if (counter->CounterNameTitleIndex == index) 1.448 + return counter; 1.449 + 1.450 + counter = next_counter(counter); 1.451 + } 1.452 + 1.453 + return 0; 1.454 +} 1.455 + 1.456 + 1.457 +static const PERF_INSTANCE_DEFINITION* 1.458 +first_instance(const PERF_OBJECT_TYPE* object) 1.459 +{ 1.460 + return object 1.461 + ? reinterpret_cast<const PERF_INSTANCE_DEFINITION*>(reinterpret_cast<const char*>(object) + object->DefinitionLength) 1.462 + : 0; 1.463 +} 1.464 + 1.465 + 1.466 +static const PERF_INSTANCE_DEFINITION* 1.467 +next_instance(const PERF_INSTANCE_DEFINITION* instance) 1.468 +{ 1.469 + if (instance) { 1.470 + const PERF_COUNTER_BLOCK* counter_block = 1.471 + reinterpret_cast<const PERF_COUNTER_BLOCK*>(reinterpret_cast<const char*>(instance) + instance->ByteLength); 1.472 + 1.473 + return reinterpret_cast<const PERF_INSTANCE_DEFINITION*>(reinterpret_cast<const char*>(counter_block) + counter_block->ByteLength); 1.474 + } 1.475 + else { 1.476 + return 0; 1.477 + } 1.478 +} 1.479 + 1.480 + 1.481 +static const wchar_t* 1.482 +instance_name(const PERF_INSTANCE_DEFINITION* instance) 1.483 +{ 1.484 + return instance 1.485 + ? reinterpret_cast<const wchar_t*>(reinterpret_cast<const char*>(instance) + instance->NameOffset) 1.486 + : 0; 1.487 +} 1.488 + 1.489 + 1.490 +static const void* 1.491 +counter_data(const PERF_INSTANCE_DEFINITION* instance, 1.492 + const PERF_COUNTER_DEFINITION* counter) 1.493 +{ 1.494 + if (counter && instance) { 1.495 + const PERF_COUNTER_BLOCK* counter_block; 1.496 + counter_block = reinterpret_cast<const PERF_COUNTER_BLOCK*>(reinterpret_cast<const char*>(instance) + instance->ByteLength); 1.497 + return reinterpret_cast<const char*>(counter_block) + counter->CounterOffset; 1.498 + } 1.499 + else { 1.500 + return 0; 1.501 + } 1.502 +} 1.503 + 1.504 + 1.505 +static bool 1.506 +list_process(PERF_DATA_BLOCK* perf_data, wchar_t* process_name) 1.507 +{ 1.508 + const PERF_OBJECT_TYPE* process = find_object(perf_data, key_for_index(PN_PROCESS)); 1.509 + const PERF_COUNTER_DEFINITION* working_set = find_counter(process, key_for_index(PN_PROCESS_WORKING_SET)); 1.510 + const PERF_COUNTER_DEFINITION* peak_working_set = find_counter(process, key_for_index(PN_PROCESS_PEAK_WS)); 1.511 + const PERF_COUNTER_DEFINITION* private_page = find_counter(process, key_for_index(PN_PROCESS_PRIVATE_PAGE)); 1.512 + const PERF_COUNTER_DEFINITION* virtual_size = find_counter(process, key_for_index(PN_PROCESS_VIRTUAL_SIZE)); 1.513 + 1.514 + const PERF_INSTANCE_DEFINITION* instance = first_instance(process); 1.515 + int index = 0; 1.516 + 1.517 + bool found = false; 1.518 + 1.519 + while (instance && index < process->NumInstances) { 1.520 + const wchar_t* name = instance_name(instance); 1.521 + if (lstrcmpW(process_name, name) == 0) { 1.522 + printf("%d %d %d %d\n", 1.523 + *(static_cast<const int*>(counter_data(instance, working_set))), 1.524 + *(static_cast<const int*>(counter_data(instance, peak_working_set))), 1.525 + *(static_cast<const int*>(counter_data(instance, private_page))), 1.526 + *(static_cast<const int*>(counter_data(instance, virtual_size)))); 1.527 + 1.528 + found = true; 1.529 + } 1.530 + 1.531 + instance = next_instance(instance); 1.532 + ++index; 1.533 + } 1.534 + 1.535 + if (found) { 1.536 +#if 0 1.537 + // Dig up address space data. 1.538 + PERF_OBJECT_TYPE* address_space = FindObject(costly_data, PX_PROCESS_ADDRESS_SPACE); 1.539 + PERF_COUNTER_DEFINITION* image_executable = FindCounter(process, PX_PROCESS_IMAGE_EXECUTABLE); 1.540 + PERF_COUNTER_DEFINITION* image_exe_readonly = FindCounter(process, PX_PROCESS_IMAGE_EXE_READONLY); 1.541 + PERF_COUNTER_DEFINITION* image_exe_readwrite = FindCounter(process, PX_PROCESS_IMAGE_EXE_READWRITE); 1.542 + PERF_COUNTER_DEFINITION* image_exe_writecopy = FindCounter(process, PX_PROCESS_IMAGE_EXE_WRITECOPY); 1.543 +#endif 1.544 + } 1.545 + 1.546 + return found; 1.547 +} 1.548 + 1.549 + 1.550 +int 1.551 +main(int argc, char* argv[]) 1.552 +{ 1.553 + wchar_t process_name[32]; 1.554 + 1.555 + int interval = 10000; // msec 1.556 + 1.557 + int i = 0; 1.558 + while (++i < argc) { 1.559 + if (argv[i][0] != '-') 1.560 + break; 1.561 + 1.562 + switch (argv[i][1]) { 1.563 + case 'i': 1.564 + interval = atoi(argv[++i]) * 1000; 1.565 + break; 1.566 + 1.567 + default: 1.568 + fprintf(stderr, "unknown option `%c'\n", argv[i][1]); 1.569 + exit(1); 1.570 + } 1.571 + } 1.572 + 1.573 + if (argv[i]) { 1.574 + char* p = argv[i]; 1.575 + wchar_t* q = process_name; 1.576 + while (*q++ = wchar_t(*p++)) 1.577 + continue; 1.578 + } 1.579 + else { 1.580 + fprintf(stderr, "no image name specified\n"); 1.581 + exit(1); 1.582 + } 1.583 + 1.584 + init_entries(); 1.585 + 1.586 + PERF_DATA_BLOCK* perf_data = 0; 1.587 + PERF_DATA_BLOCK* costly_data = 0; 1.588 + DWORD perf_data_size = 50 * 1024; 1.589 + DWORD costly_data_size = 100 * 1024; 1.590 + 1.591 + do { 1.592 + char buf[64]; 1.593 + sprintf(buf, "%ld %ld", 1.594 + key_for_index(PN_PROCESS), 1.595 + key_for_index(PN_THREAD)); 1.596 + 1.597 + get_perf_data(HKEY_PERFORMANCE_DATA, buf, &perf_data, &perf_data_size); 1.598 + 1.599 +#if 0 1.600 + sprintf(buf, "%ld %ld %ld", 1.601 + key_for_index(PN_PROCESS_ADDRESS_SPACE), 1.602 + key_for_index(PN_IMAGE), 1.603 + key_for_index(PN_THREAD_DETAILS)); 1.604 + 1.605 + get_perf_data(HKEY_PERFORMANCE_DATA, buf, &costly_data, &costly_data_size); 1.606 +#endif 1.607 + 1.608 + if (! list_process(perf_data, process_name)) 1.609 + break; 1.610 + 1.611 + _sleep(interval); 1.612 + } while (1); 1.613 + 1.614 + return 0; 1.615 +} 1.616 +