tools/footprint/wm.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 /*
     8  * This program tracks a process's working memory usage using the
     9  * ``performance'' entries in the Win32 registry. It borrows from
    10  * the ``pviewer'' source code in the MS SDK.
    11  */
    13 #include <assert.h>
    14 #include <windows.h>
    15 #include <winperf.h>
    16 #include <stdio.h>
    17 #include <stdlib.h>
    19 #define PN_PROCESS                          1
    20 #define PN_PROCESS_CPU                      2
    21 #define PN_PROCESS_PRIV                     3
    22 #define PN_PROCESS_USER                     4
    23 #define PN_PROCESS_WORKING_SET              5
    24 #define PN_PROCESS_PEAK_WS                  6
    25 #define PN_PROCESS_PRIO                     7
    26 #define PN_PROCESS_ELAPSE                   8
    27 #define PN_PROCESS_ID                       9
    28 #define PN_PROCESS_PRIVATE_PAGE            10
    29 #define PN_PROCESS_VIRTUAL_SIZE            11
    30 #define PN_PROCESS_PEAK_VS                 12
    31 #define PN_PROCESS_FAULT_COUNT             13
    32 #define PN_THREAD                          14
    33 #define PN_THREAD_CPU                      15
    34 #define PN_THREAD_PRIV                     16
    35 #define PN_THREAD_USER                     17
    36 #define PN_THREAD_START                    18
    37 #define PN_THREAD_SWITCHES                 19
    38 #define PN_THREAD_PRIO                     20
    39 #define PN_THREAD_BASE_PRIO                21
    40 #define PN_THREAD_ELAPSE                   22
    41 #define PN_THREAD_DETAILS                  23
    42 #define PN_THREAD_PC                       24
    43 #define PN_IMAGE                           25
    44 #define PN_IMAGE_NOACCESS                  26
    45 #define PN_IMAGE_READONLY                  27
    46 #define PN_IMAGE_READWRITE                 28
    47 #define PN_IMAGE_WRITECOPY                 29
    48 #define PN_IMAGE_EXECUTABLE                30
    49 #define PN_IMAGE_EXE_READONLY              31
    50 #define PN_IMAGE_EXE_READWRITE             32
    51 #define PN_IMAGE_EXE_WRITECOPY             33
    52 #define PN_PROCESS_ADDRESS_SPACE           34
    53 #define PN_PROCESS_PRIVATE_NOACCESS        35
    54 #define PN_PROCESS_PRIVATE_READONLY        36
    55 #define PN_PROCESS_PRIVATE_READWRITE       37
    56 #define PN_PROCESS_PRIVATE_WRITECOPY       38
    57 #define PN_PROCESS_PRIVATE_EXECUTABLE      39
    58 #define PN_PROCESS_PRIVATE_EXE_READONLY    40
    59 #define PN_PROCESS_PRIVATE_EXE_READWRITE   41
    60 #define PN_PROCESS_PRIVATE_EXE_WRITECOPY   42
    61 #define PN_PROCESS_MAPPED_NOACCESS         43
    62 #define PN_PROCESS_MAPPED_READONLY         44
    63 #define PN_PROCESS_MAPPED_READWRITE        45
    64 #define PN_PROCESS_MAPPED_WRITECOPY        46
    65 #define PN_PROCESS_MAPPED_EXECUTABLE       47
    66 #define PN_PROCESS_MAPPED_EXE_READONLY     48
    67 #define PN_PROCESS_MAPPED_EXE_READWRITE    49
    68 #define PN_PROCESS_MAPPED_EXE_WRITECOPY    50
    69 #define PN_PROCESS_IMAGE_NOACCESS          51
    70 #define PN_PROCESS_IMAGE_READONLY          52
    71 #define PN_PROCESS_IMAGE_READWRITE         53
    72 #define PN_PROCESS_IMAGE_WRITECOPY         54
    73 #define PN_PROCESS_IMAGE_EXECUTABLE        55
    74 #define PN_PROCESS_IMAGE_EXE_READONLY      56
    75 #define PN_PROCESS_IMAGE_EXE_READWRITE     57
    76 #define PN_PROCESS_IMAGE_EXE_WRITECOPY     58
    78 struct entry_t {
    79     int   e_key;
    80     int   e_index;
    81     char* e_title;
    82 };
    84 entry_t entries[] = {
    85 { PN_PROCESS,                          0, TEXT("Process") },
    86 { PN_PROCESS_CPU,                      0, TEXT("% Processor Time") },
    87 { PN_PROCESS_PRIV,                     0, TEXT("% Privileged Time") },
    88 { PN_PROCESS_USER,                     0, TEXT("% User Time") },
    89 { PN_PROCESS_WORKING_SET,              0, TEXT("Working Set") },
    90 { PN_PROCESS_PEAK_WS,                  0, TEXT("Working Set Peak") },
    91 { PN_PROCESS_PRIO,                     0, TEXT("Priority Base") },
    92 { PN_PROCESS_ELAPSE,                   0, TEXT("Elapsed Time") },
    93 { PN_PROCESS_ID,                       0, TEXT("ID Process") },
    94 { PN_PROCESS_PRIVATE_PAGE,             0, TEXT("Private Bytes") },
    95 { PN_PROCESS_VIRTUAL_SIZE,             0, TEXT("Virtual Bytes") },
    96 { PN_PROCESS_PEAK_VS,                  0, TEXT("Virtual Bytes Peak") },
    97 { PN_PROCESS_FAULT_COUNT,              0, TEXT("Page Faults/sec") },
    98 { PN_THREAD,                           0, TEXT("Thread") },
    99 { PN_THREAD_CPU,                       0, TEXT("% Processor Time") },
   100 { PN_THREAD_PRIV,                      0, TEXT("% Privileged Time") },
   101 { PN_THREAD_USER,                      0, TEXT("% User Time") },
   102 { PN_THREAD_START,                     0, TEXT("Start Address") },
   103 { PN_THREAD_SWITCHES,                  0, TEXT("Con0, TEXT Switches/sec") },
   104 { PN_THREAD_PRIO,                      0, TEXT("Priority Current") },
   105 { PN_THREAD_BASE_PRIO,                 0, TEXT("Priority Base") },
   106 { PN_THREAD_ELAPSE,                    0, TEXT("Elapsed Time") },
   107 { PN_THREAD_DETAILS,                   0, TEXT("Thread Details") },
   108 { PN_THREAD_PC,                        0, TEXT("User PC") },
   109 { PN_IMAGE,                            0, TEXT("Image") },
   110 { PN_IMAGE_NOACCESS,                   0, TEXT("No Access") },
   111 { PN_IMAGE_READONLY,                   0, TEXT("Read Only") },
   112 { PN_IMAGE_READWRITE,                  0, TEXT("Read/Write") },
   113 { PN_IMAGE_WRITECOPY,                  0, TEXT("Write Copy") },
   114 { PN_IMAGE_EXECUTABLE,                 0, TEXT("Executable") },
   115 { PN_IMAGE_EXE_READONLY,               0, TEXT("Exec Read Only") },
   116 { PN_IMAGE_EXE_READWRITE,              0, TEXT("Exec Read/Write") },
   117 { PN_IMAGE_EXE_WRITECOPY,              0, TEXT("Exec Write Copy") },
   118 { PN_PROCESS_ADDRESS_SPACE,            0, TEXT("Process Address Space") },
   119 { PN_PROCESS_PRIVATE_NOACCESS,         0, TEXT("Reserved Space No Access") },
   120 { PN_PROCESS_PRIVATE_READONLY,         0, TEXT("Reserved Space Read Only") },
   121 { PN_PROCESS_PRIVATE_READWRITE,        0, TEXT("Reserved Space Read/Write") },
   122 { PN_PROCESS_PRIVATE_WRITECOPY,        0, TEXT("Reserved Space Write Copy") },
   123 { PN_PROCESS_PRIVATE_EXECUTABLE,       0, TEXT("Reserved Space Executable") },
   124 { PN_PROCESS_PRIVATE_EXE_READONLY,     0, TEXT("Reserved Space Exec Read Only") },
   125 { PN_PROCESS_PRIVATE_EXE_READWRITE,    0, TEXT("Reserved Space Exec Read/Write") },
   126 { PN_PROCESS_PRIVATE_EXE_WRITECOPY,    0, TEXT("Reserved Space Exec Write Copy") },
   127 { PN_PROCESS_MAPPED_NOACCESS,          0, TEXT("Mapped Space No Access") },
   128 { PN_PROCESS_MAPPED_READONLY,          0, TEXT("Mapped Space Read Only") },
   129 { PN_PROCESS_MAPPED_READWRITE,         0, TEXT("Mapped Space Read/Write") },
   130 { PN_PROCESS_MAPPED_WRITECOPY,         0, TEXT("Mapped Space Write Copy") },
   131 { PN_PROCESS_MAPPED_EXECUTABLE,        0, TEXT("Mapped Space Executable") },
   132 { PN_PROCESS_MAPPED_EXE_READONLY,      0, TEXT("Mapped Space Exec Read Only") },
   133 { PN_PROCESS_MAPPED_EXE_READWRITE,     0, TEXT("Mapped Space Exec Read/Write") },
   134 { PN_PROCESS_MAPPED_EXE_WRITECOPY,     0, TEXT("Mapped Space Exec Write Copy") },
   135 { PN_PROCESS_IMAGE_NOACCESS,           0, TEXT("Image Space No Access") },
   136 { PN_PROCESS_IMAGE_READONLY,           0, TEXT("Image Space Read Only") },
   137 { PN_PROCESS_IMAGE_READWRITE,          0, TEXT("Image Space Read/Write") },
   138 { PN_PROCESS_IMAGE_WRITECOPY,          0, TEXT("Image Space Write Copy") },
   139 { PN_PROCESS_IMAGE_EXECUTABLE,         0, TEXT("Image Space Executable") },
   140 { PN_PROCESS_IMAGE_EXE_READONLY,       0, TEXT("Image Space Exec Read Only") },
   141 { PN_PROCESS_IMAGE_EXE_READWRITE,      0, TEXT("Image Space Exec Read/Write") },
   142 { PN_PROCESS_IMAGE_EXE_WRITECOPY,      0, TEXT("Image Space Exec Write Copy") },
   143 { 0,                                   0, 0 },
   144 };
   146 #define NENTRIES ((sizeof(entries) / sizeof(entry_t)) - 1)
   148 static int
   149 key_for_index(int key)
   150 {
   151     entry_t* entry = entries + NENTRIES / 2;
   152     unsigned int step = 64 / 4; // XXX
   154     while (step) {
   155         if (key < entry->e_key)
   156             entry -= step;
   157         else if (key > entry->e_key)
   158             entry += step;
   160         if (key == entry->e_key)
   161             return entry->e_index;
   163         step >>= 1;
   164     }
   166     assert(false);
   167     return 0;
   168 }
   171 class auto_hkey {
   172 protected:
   173     HKEY hkey;
   175     HKEY* begin_assignment() {
   176         if (hkey) {
   177             ::RegCloseKey(hkey);
   178             hkey = 0;
   179         }
   180         return &hkey;
   181     }
   183 public:
   184     auto_hkey() : hkey(0) {}
   185     ~auto_hkey() { ::RegCloseKey(hkey); }
   187     HKEY get() const { return hkey; }
   188     operator HKEY() const { return get(); }
   190     friend HKEY*
   191     getter_Acquires(auto_hkey& hkey);
   192 };
   194 static HKEY*
   195 getter_Acquires(auto_hkey& hkey)
   196 {
   197     return hkey.begin_assignment();
   198 }
   201 static int
   202 get_perf_titles(char*& buffer, char**& titles, int& last_title_index)
   203 {
   204     DWORD result;
   206     // Open the perflib key to find out the last counter's index and
   207     // system version.
   208     auto_hkey perflib_hkey;
   209     result = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
   210                             TEXT("software\\microsoft\\windows nt\\currentversion\\perflib"),
   211                             0,
   212                             KEY_READ,
   213                             getter_Acquires(perflib_hkey));
   215     if (result != ERROR_SUCCESS)
   216         return result;
   218     // Get the last counter's index so we know how much memory to
   219     // allocate for titles
   220     DWORD data_size = sizeof(DWORD);
   221     DWORD type;
   222     result = ::RegQueryValueEx(perflib_hkey,
   223                                TEXT("Last Counter"),
   224                                0,
   225                                &type,
   226                                reinterpret_cast<BYTE*>(&last_title_index),
   227                                &data_size);
   229     if (result != ERROR_SUCCESS)
   230         return result;
   232     // Find system version, for system earlier than 1.0a, there's no
   233     // version value.
   234     int version;
   235     result = ::RegQueryValueEx(perflib_hkey,
   236                                TEXT("Version"),
   237                                0,
   238                                &type,
   239                                reinterpret_cast<BYTE*>(&version),
   240                                &data_size);
   242     bool is_nt_10 = (result == ERROR_SUCCESS);
   244     // Now, get ready for the counter names and indexes.
   245     char* counter_value_name;
   246     auto_hkey counter_autohkey;
   247     HKEY counter_hkey;
   248     if (is_nt_10) {
   249         // NT 1.0, so make hKey2 point to ...\perflib\009 and get
   250         //  the counters from value "Counters"
   251         counter_value_name = TEXT("Counters");
   252         result = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
   253                                 TEXT("software\\microsoft\\windows nt\\currentversion\\perflib\\009"),
   254                                 0,
   255                                 KEY_READ,
   256                                 getter_Acquires(counter_autohkey));
   258         if (result != ERROR_SUCCESS)
   259             return result;
   261         counter_hkey = counter_autohkey;
   262     }
   263     else {
   264         // NT 1.0a or later.  Get the counters in key HKEY_PERFORMANCE_KEY
   265         //  and from value "Counter 009"
   266         counter_value_name = TEXT("Counter 009");
   267         counter_hkey = HKEY_PERFORMANCE_DATA;
   268     }
   270     // Find out the size of the data.
   271     result = ::RegQueryValueEx(counter_hkey,
   272                                counter_value_name,
   273                                0,
   274                                &type,
   275                                0,
   276                                &data_size);
   278     if (result != ERROR_SUCCESS)
   279         return result;
   281     // Allocate memory
   282     buffer = new char[data_size];
   283     titles = new char*[last_title_index + 1];
   284     for (int i = 0; i <= last_title_index; ++i)
   285         titles[i] = 0;
   287     // Query the data
   288     result = ::RegQueryValueEx(counter_hkey,
   289                                counter_value_name,
   290                                0,
   291                                &type,
   292                                reinterpret_cast<BYTE*>(buffer),
   293                                &data_size);
   294     if (result != ERROR_SUCCESS)
   295         return result;
   297     // Setup the titles array of pointers to point to beginning of
   298     // each title string.
   299     char* title = buffer;
   300     int len;
   302     while (len = lstrlen(title)) {
   303         int index = atoi(title);
   304         title += len + 1;
   306         if (index <= last_title_index)
   307             titles[index] = title;
   309 #ifdef DEBUG
   310         printf("%d=%s\n", index, title);
   311 #endif
   313         title += lstrlen(title) + 1;
   314     }
   316     return ERROR_SUCCESS;
   317 }
   319 static void
   320 init_entries()
   321 {
   322     char* buffer;
   323     char** titles;
   324     int last = 0;
   326     DWORD result = get_perf_titles(buffer, titles, last);
   328     assert(result == ERROR_SUCCESS);
   330     for (entry_t* entry = entries; entry->e_key != 0; ++entry) {
   331         for (int index = 0; index <= last; ++index) {
   332             if (titles[index] && 0 == lstrcmpi(titles[index], entry->e_title)) {
   333                 entry->e_index = index;
   334                 break;
   335             }
   336         }
   338         if (entry->e_index == 0) {
   339             fprintf(stderr, "warning: unable to find index for ``%s''\n", entry->e_title);
   340         }
   341     }
   343     delete[] buffer;
   344     delete[] titles;
   345 }
   349 static DWORD
   350 get_perf_data(HKEY perf_hkey, char* object_index, PERF_DATA_BLOCK** data, DWORD* size)
   351 {
   352     if (! *data)
   353         *data = reinterpret_cast<PERF_DATA_BLOCK*>(new char[*size]);
   355     DWORD result;
   357     while (1) {
   358         DWORD type;
   359         DWORD real_size = *size;
   361         result = ::RegQueryValueEx(perf_hkey,
   362                                    object_index,
   363                                    0,
   364                                    &type,
   365                                    reinterpret_cast<BYTE*>(*data),
   366                                    &real_size);
   368         if (result != ERROR_MORE_DATA)
   369             break;
   371         delete[] *data;
   372         *size += 1024;
   373         *data = reinterpret_cast<PERF_DATA_BLOCK*>(new char[*size]);
   375         if (! *data)
   376             return ERROR_NOT_ENOUGH_MEMORY;
   377     }
   379     return result;
   380 }
   383 static const PERF_OBJECT_TYPE*
   384 first_object(const PERF_DATA_BLOCK* data)
   385 {
   386     return data
   387         ? reinterpret_cast<const PERF_OBJECT_TYPE*>(reinterpret_cast<const char*>(data) + data->HeaderLength)
   388         : 0;
   389 }
   391 static const PERF_OBJECT_TYPE*
   392 next_object(const PERF_OBJECT_TYPE* object)
   393 {
   394     return object
   395         ? reinterpret_cast<const PERF_OBJECT_TYPE*>(reinterpret_cast<const char*>(object) + object->TotalByteLength)
   396         : 0;
   397 }
   399 const PERF_OBJECT_TYPE*
   400 find_object(const PERF_DATA_BLOCK* data, DWORD index)
   401 {
   402     const PERF_OBJECT_TYPE* object = first_object(data);
   403     if (! object)
   404         return 0;
   406     for (int i = 0; i < data->NumObjectTypes; ++i) {
   407         if (object->ObjectNameTitleIndex == index)
   408             return object;
   410         object = next_object(object);
   411     }
   413     return 0;
   414 }
   417 static const PERF_COUNTER_DEFINITION*
   418 first_counter(const PERF_OBJECT_TYPE* object)
   419 {
   420     return object
   421         ? reinterpret_cast<const PERF_COUNTER_DEFINITION*>(reinterpret_cast<const char*>(object) + object->HeaderLength)
   422         : 0;
   423 }
   425 static const PERF_COUNTER_DEFINITION*
   426 next_counter(const PERF_COUNTER_DEFINITION* counter)
   427 {
   428     return counter ?
   429         reinterpret_cast<const PERF_COUNTER_DEFINITION*>(reinterpret_cast<const char*>(counter) + counter->ByteLength)
   430         : 0;
   431 }
   434 static const PERF_COUNTER_DEFINITION*
   435 find_counter(const PERF_OBJECT_TYPE* object, int index)
   436 {
   437     const PERF_COUNTER_DEFINITION* counter =
   438         first_counter(object);
   440     if (! counter)
   441         return 0;
   443     for (int i; i < object->NumCounters; ++i) {
   444         if (counter->CounterNameTitleIndex == index)
   445             return counter;
   447         counter = next_counter(counter);
   448     }
   450     return 0;
   451 }
   454 static const PERF_INSTANCE_DEFINITION*
   455 first_instance(const PERF_OBJECT_TYPE* object)
   456 {
   457     return object
   458         ? reinterpret_cast<const PERF_INSTANCE_DEFINITION*>(reinterpret_cast<const char*>(object) + object->DefinitionLength)
   459         : 0;
   460 }
   463 static const PERF_INSTANCE_DEFINITION*
   464 next_instance(const PERF_INSTANCE_DEFINITION* instance)
   465 {
   466     if (instance) {
   467         const PERF_COUNTER_BLOCK* counter_block =
   468             reinterpret_cast<const PERF_COUNTER_BLOCK*>(reinterpret_cast<const char*>(instance) + instance->ByteLength);
   470         return reinterpret_cast<const PERF_INSTANCE_DEFINITION*>(reinterpret_cast<const char*>(counter_block) + counter_block->ByteLength);
   471     }
   472     else {
   473         return 0;
   474     }
   475 }
   478 static const wchar_t*
   479 instance_name(const PERF_INSTANCE_DEFINITION* instance)
   480 {
   481     return instance
   482         ? reinterpret_cast<const wchar_t*>(reinterpret_cast<const char*>(instance) + instance->NameOffset)
   483         : 0;
   484 }
   487 static const void*
   488 counter_data(const PERF_INSTANCE_DEFINITION* instance,
   489              const PERF_COUNTER_DEFINITION* counter)
   490 {
   491     if (counter && instance) {
   492         const PERF_COUNTER_BLOCK* counter_block; 
   493         counter_block = reinterpret_cast<const PERF_COUNTER_BLOCK*>(reinterpret_cast<const char*>(instance) + instance->ByteLength);
   494         return reinterpret_cast<const char*>(counter_block) + counter->CounterOffset;
   495     }
   496     else {
   497         return 0;
   498     }
   499 }
   502 static bool
   503 list_process(PERF_DATA_BLOCK* perf_data, wchar_t* process_name)
   504 {
   505     const PERF_OBJECT_TYPE* process = find_object(perf_data, key_for_index(PN_PROCESS));
   506     const PERF_COUNTER_DEFINITION* working_set      = find_counter(process, key_for_index(PN_PROCESS_WORKING_SET));
   507     const PERF_COUNTER_DEFINITION* peak_working_set = find_counter(process, key_for_index(PN_PROCESS_PEAK_WS));
   508     const PERF_COUNTER_DEFINITION* private_page     = find_counter(process, key_for_index(PN_PROCESS_PRIVATE_PAGE));
   509     const PERF_COUNTER_DEFINITION* virtual_size     = find_counter(process, key_for_index(PN_PROCESS_VIRTUAL_SIZE));
   511     const PERF_INSTANCE_DEFINITION* instance = first_instance(process);
   512     int index = 0;
   514     bool found = false;
   516     while (instance && index < process->NumInstances) {
   517         const wchar_t* name = instance_name(instance);
   518         if (lstrcmpW(process_name, name) == 0) {
   519             printf("%d %d %d %d\n",
   520                    *(static_cast<const int*>(counter_data(instance, working_set))),
   521                    *(static_cast<const int*>(counter_data(instance, peak_working_set))),
   522                    *(static_cast<const int*>(counter_data(instance, private_page))),
   523                    *(static_cast<const int*>(counter_data(instance, virtual_size))));
   525             found = true;
   526         }
   528         instance = next_instance(instance);
   529         ++index;
   530     }
   532     if (found) {
   533 #if 0
   534         // Dig up address space data.
   535         PERF_OBJECT_TYPE* address_space = FindObject(costly_data, PX_PROCESS_ADDRESS_SPACE);
   536         PERF_COUNTER_DEFINITION* image_executable = FindCounter(process, PX_PROCESS_IMAGE_EXECUTABLE);
   537         PERF_COUNTER_DEFINITION* image_exe_readonly = FindCounter(process, PX_PROCESS_IMAGE_EXE_READONLY);
   538         PERF_COUNTER_DEFINITION* image_exe_readwrite = FindCounter(process, PX_PROCESS_IMAGE_EXE_READWRITE);
   539         PERF_COUNTER_DEFINITION* image_exe_writecopy = FindCounter(process, PX_PROCESS_IMAGE_EXE_WRITECOPY);
   540 #endif
   541     }
   543     return found;
   544 }
   547 int
   548 main(int argc, char* argv[])
   549 {
   550     wchar_t process_name[32];
   552     int interval = 10000; // msec
   554     int i = 0;
   555     while (++i < argc) {
   556         if (argv[i][0] != '-')
   557             break;
   559         switch (argv[i][1]) {
   560         case 'i':
   561             interval = atoi(argv[++i]) * 1000;
   562             break;
   564         default:
   565             fprintf(stderr, "unknown option `%c'\n", argv[i][1]);
   566             exit(1);
   567         }
   568     }
   570     if (argv[i]) {
   571         char* p = argv[i];
   572         wchar_t* q = process_name;
   573         while (*q++ = wchar_t(*p++))
   574             continue;
   575     }
   576     else {
   577         fprintf(stderr, "no image name specified\n");
   578         exit(1);
   579     }
   581     init_entries();
   583     PERF_DATA_BLOCK* perf_data = 0;
   584     PERF_DATA_BLOCK* costly_data = 0;
   585     DWORD perf_data_size = 50 * 1024;
   586     DWORD costly_data_size = 100 * 1024;
   588     do {
   589         char buf[64];
   590         sprintf(buf, "%ld %ld",
   591                 key_for_index(PN_PROCESS),
   592                 key_for_index(PN_THREAD));
   594         get_perf_data(HKEY_PERFORMANCE_DATA, buf, &perf_data, &perf_data_size);
   596 #if 0
   597         sprintf(buf, "%ld %ld %ld",
   598                 key_for_index(PN_PROCESS_ADDRESS_SPACE),
   599                 key_for_index(PN_IMAGE),
   600                 key_for_index(PN_THREAD_DETAILS));
   602         get_perf_data(HKEY_PERFORMANCE_DATA, buf, &costly_data, &costly_data_size);
   603 #endif
   605         if (! list_process(perf_data, process_name))
   606             break;
   608         _sleep(interval);
   609     } while (1);
   611     return 0;
   612 }

mercurial