text: /* **********************************************************
   * Copyright (c) 2003 VMware, Inc.  All rights reserved.
   * **********************************************************/
  
  /*
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   * 
   * * Redistributions of source code must retain the above copyright notice,
   *   this list of conditions and the following disclaimer.
   * 
   * * Redistributions in binary form must reproduce the above copyright notice,
   *   this list of conditions and the following disclaimer in the documentation
   *   and/or other materials provided with the distribution.
   * 
   * * Neither the name of VMware, Inc. nor the names of its contributors may be
   *   used to endorse or promote products derived from this software without
   *   specific prior written permission.
   * 
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
   * DAMAGE.
   */
  
  #define _WIN32_WINNT 0x0400
  
  #include <Windows.h>
  #include <stdio.h>
  #include <Tlhelp32.h>
  #include <tchar.h>
  #include <pdh.h>
  
  // a.s.
  #include <stdlib.h>
  
  #define MAXPATH 80
  #define NCOUNTERS 27
  #define MCOUNTERS 3
  
  TCHAR *counters[NCOUNTERS] = {
      _T("Thread Count"),
      _T("Working Set"),
      _T("Page Faults/sec"),
      _T("Page File Bytes"),
      _T("% User Time"),
      _T("% Privileged Time"),
      _T("% Processor Time"),
      _T("Creating Process ID"),
      _T("Elapsed Time"),
      _T("Handle Count"),
      _T("ID Process"),
      _T("IO Data Bytes/sec"),
      _T("IO Data Operations/sec"),
      _T("IO Other Bytes/sec"),
      _T("IO Other Operations/sec"),
      _T("IO Read Bytes/sec"),
      _T("IO Read Operations/sec"),
      _T("IO Write Bytes/sec"),
      _T("IO Write Operations/sec"),
      _T("Page File Bytes Peak"),
      _T("Pool Nonpaged Bytes"),
      _T("Pool Paged Bytes"),
      _T("Priority Base"),
      _T("Private Bytes"),
      _T("Virtual Bytes"),
      _T("Virtual Bytes Peak"),
      _T("Working Set Peak"),
  };
  
  TCHAR *shortnames[NCOUNTERS] = {
      _T("tc"),
      _T("wss"),
      _T("pgflts"),
      _T("pgfileK"),
      _T("utimes"),
      _T("ktimes"),
      _T("ttimes"),
      _T("ppid"),
      _T("realtim"),
      _T("handles"),
      _T("pid"),
      _T("IOdataK"),
      _T("IOdataO"),
      _T("IOothrK"),
      _T("IOothrO"),
      _T("IOreadK"),
      _T("IOreadO"),
      _T("IOwritK"),
      _T("IOwritO"),
      _T("pgfpeak"),
      _T("poolnpK"),
      _T("poolpK"),
      _T("priorty"),
      _T("privK"),
      _T("vmK"),
      _T("vmpeak"),
      _T("wsspeak"),
  };
  
  TCHAR *formatstrings[NCOUNTERS] = {
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.2f\t"),
      _T("%.2f\t"),
      _T("%.2f\t"),
      _T("%.0f\t"),
      _T("%.2f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
      _T("%.0f\t"),
  };
  
  BOOL use_kb[NCOUNTERS] = {
      0,
      1,
      0,
      1,
      0,
      0,
      0,
      0,
      0,
      0,
      0,
      1,
      0,
      1,
      0,
      1,
      0,
      1,
      0,
      1,
      1,
      1,
      0,
      1,
      1,
      1,
      1,
  };
  
  int waitforprocess(TCHAR *name) {
      HANDLE processes;
      PROCESSENTRY32 pe = { sizeof(pe) };
      BOOL fOK;
      while(1) {
          processes = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
          fOK = Process32First(processes, &pe);
          for (; fOK; fOK = Process32Next(processes, &pe)) {
              if(!_tcsicmp(pe.szExeFile,name))
                  return pe.th32ProcessID;
          }
          CloseHandle(processes);
          Sleep(181);
      }
  }
  
  // a.s.
  void GetProcNameFromId( int pid, TCHAR* pName )
  {
      HANDLE processes;
      PROCESSENTRY32 pe = { sizeof(pe) };
      BOOL fOK;
      while(1) {
          processes = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
          fOK = Process32First(processes, &pe);
          for (; fOK; fOK = Process32Next(processes, &pe)) {
              if( (int)pe.th32ProcessID == pid)
                          {
                                  _tcscpy( pName, pe.szExeFile );
                                  return;
                          }
          }
          CloseHandle(processes);
          Sleep(181);
      }
  
  }
  // eof a.s.
  
  int __cdecl _tmain (int argc, TCHAR **argv)
  {
     HQUERY hQuery;
     HCOUNTER *pCounterHandle;
     PDH_STATUS pdhStatus;
     PDH_FMT_COUNTERVALUE fmtValue;
     DWORD ctrType;
     TCHAR szPathBuffer[MAXPATH];
     int i, samples=0;
     int NUM_SAMPLES=1000, INTERVAL_MS=1000;
     int pid;
     FILE *fp = stdout;
     char fn[MAXPATH];
     TCHAR basename[MAXPATH];
     HANDLE htimer;
     LARGE_INTEGER duetime;
  
     if(argc<2) {
         _ftprintf(stderr,_T("Usage: %s [<exeName> | <pid> | all] [num_samples] [interval] [outputfile]\n"), argv[0]);        
         return -1;
     }
  
     if(_tcscmp(argv[1],_T("all"))) {
         if( isalpha( *argv[1] ) ) {
             printf("waiting...\n");
             pid = waitforprocess(argv[1]);
             //remove .exe
             _tcscpy(basename, argv[1]);
             basename[_tcslen(argv[1]) - 4] = _T('\0');
         }
         else {
             pid = _ttoi( argv[1] );
             GetProcNameFromId( pid, basename );
             basename[_tcslen(basename) - 4] = _T('\0');
         }
         // eof a.s.
     }
     else {
         pid = 0;
         _tcscpy(basename, _T("_Total"));
     }
     
     if(argc>2) {
         NUM_SAMPLES=_ttoi(argv[2]);
         if(argc>3)
             INTERVAL_MS=_ttoi(argv[3]);
         if(argc>4) {
             sprintf(fn, "%S", argv[4]);
             fp = fopen(fn,"w");
             if(fp==NULL) {
                 _ftprintf(stderr, _T("error opening output file %s\n"),
                           argv[4]);
                 return -1;
             }
         }           
     }
  
     _ftprintf(stderr,
               _T("Monitoring %s, pid=%d. Using %d samples at %dms interval\n"),
               basename, pid, NUM_SAMPLES, INTERVAL_MS);
     
     pdhStatus = PdhOpenQuery (0, 0, &hQuery);
     pCounterHandle = (HCOUNTER *)malloc(NCOUNTERS*sizeof(HCOUNTER));
  
     for(i=0; i<NCOUNTERS; ++i) {
         _stprintf(szPathBuffer,_T("\\Process(%s)\\%s"), basename, counters[i]);
         pdhStatus = PdhAddCounter (hQuery,
                                    szPathBuffer,
                                    0, 
                                    &pCounterHandle[i]);
     }
  
     // "Prime" counters that need two values to display a formatted value.
     pdhStatus = PdhCollectQueryData (hQuery);
  
     //disp titles
     for(i=0; i<NCOUNTERS; ++i)
         _ftprintf(fp, _T("%s\t"), shortnames[i]);
     _ftprintf(fp, _T("\n"));
  
     htimer = CreateWaitableTimer(NULL, FALSE, NULL);
     duetime.LowPart = 0;
     duetime.HighPart = 0;
     SetWaitableTimer(htimer, &duetime, INTERVAL_MS, NULL, NULL, FALSE);
  
     while (samples++ < NUM_SAMPLES) {
  
         //first wait is instantaneous
         WaitForSingleObject(htimer, INTERVAL_MS * 2);
         
         pdhStatus = PdhCollectQueryData (hQuery);
         
         for(i=0; i<NCOUNTERS; ++i) {
             // Get the current value of this counter.
             pdhStatus = PdhGetFormattedCounterValue (pCounterHandle[i],
                                                      PDH_FMT_DOUBLE,
                                                      &ctrType,
                                                      &fmtValue);
             
             if (pdhStatus == ERROR_SUCCESS) {
                 _ftprintf (fp, formatstrings[i], use_kb[i] ? 
                            fmtValue.doubleValue / 1024 : fmtValue.doubleValue);
             } else {
                 goto processgone;
             }
         }
         _ftprintf(fp, _T("\n"));       
     }
     
   processgone:
  
     pdhStatus = PdhCloseQuery (hQuery);
  
     if(fp != stdout)
         fclose(fp);
  
     free(pCounterHandle);
  
     return 0;
  }
  
  