2010-12-22 Lucas Forschler <lforschler@apple.com>
authorlforschler@apple.com <lforschler@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Dec 2010 21:05:15 +0000 (21:05 +0000)
committerlforschler@apple.com <lforschler@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Dec 2010 21:05:15 +0000 (21:05 +0000)
        Reviewed by Alice Liu.

        <rdar://problem/8633222> record-memory-win needs to record memory used by the webprocess.
        Verified on Chrome, Safari, and IE.
        With this change, we will record memory from a parent browser window and all child processes.

        * record-memory-win/main.cpp:
        (ProcessArgs):
        (PrintUsage):
        (getMemoryInfo):
        (printProcessInfo):
        (evalProcesses):
        (UseImage):
        (QueryContinuously):
        (ElapsedTime):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@74498 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Tools/ChangeLog
Tools/record-memory-win/main.cpp

index bdc0b028c3451c3f594785d08ecfb8dc9d2eb529..baa6e93f6237c941e2b909e9156502a9a1a02ef1 100644 (file)
@@ -1,3 +1,21 @@
+2010-12-22  Lucas Forschler  <lforschler@apple.com>
+
+        Reviewed by Alice Liu.
+
+        <rdar://problem/8633222> record-memory-win needs to record memory used by the webprocess.
+        Verified on Chrome, Safari, and IE.
+        With this change, we will record memory from a parent browser window and all child processes.
+
+        * record-memory-win/main.cpp:
+        (ProcessArgs):
+        (PrintUsage):
+        (getMemoryInfo):
+        (printProcessInfo):
+        (evalProcesses):
+        (UseImage):
+        (QueryContinuously):
+        (ElapsedTime):
+
 2010-12-22  Lucas Forschler  <lforschler@apple.com>
 
         Unreviewed rollout r74489, because it was missing changelog.
index e660afeb2dec147f02b43842d7a6ca6fa7b8366e..934f10102e57b5d07b8f8822b4427950bd482b95 100644 (file)
@@ -4,12 +4,12 @@
 #include <stdio.h>\r
 #include <tchar.h>\r
 #include <time.h>\r
+#include <tlhelp32.h>\r
 #include "Shlwapi.h"\r
 \r
 #pragma comment(lib, "psapi.lib")\r
 #pragma comment(lib, "shlwapi.lib")\r
 \r
-bool gSingleProcess = true;\r
 int gQueryInterval = 5; // seconds\r
 time_t gDuration = 0;   // seconds\r
 LPTSTR gCommandLine;\r
@@ -18,9 +18,8 @@ HRESULT ProcessArgs(int argc, TCHAR *argv[]);
 HRESULT PrintUsage();\r
 void UseImage(void (functionForQueryType(HANDLE)));\r
 void QueryContinuously(HANDLE hProcess);\r
+int EvalProcesses(HANDLE hProcess);\r
 time_t ElapsedTime(time_t startTime);\r
-unsigned int OneQuery(HANDLE hProcess);\r
-unsigned int OneQueryMP(HANDLE hProcess);\r
 \r
 int __cdecl _tmain (int argc, TCHAR *argv[])\r
 {\r
@@ -37,14 +36,11 @@ HRESULT ProcessArgs(int argc, TCHAR *argv[])
     LPTSTR argument;\r
     for( int count = 1; count < argc; count++ ) {\r
         argument = argv[count] ;\r
-        if (wcsstr(argument, _T("-h")) ||\r
-            wcsstr(argument, _T("--help")))\r
+        if (wcsstr(argument, _T("-h")) || wcsstr(argument, _T("--help")))\r
             return PrintUsage();\r
         else if (wcsstr(argument, _T("--exe"))) {\r
             gCommandLine = argv[++count];\r
-            if (wcsstr(gCommandLine, _T("chrome.exe")))\r
-                gSingleProcess = false;\r
-        } else if (wcsstr(argument, _T("-i")) ||\r
+        } else if (wcsstr(argument, _T("-i")) || \r
             wcsstr(argument, _T("--interval"))) {\r
             gQueryInterval = _wtoi(argv[++count]);\r
             if (gQueryInterval < 1) {\r
@@ -81,11 +77,93 @@ HRESULT PrintUsage()
     printf("-i [--interval] arg : Print memory usage every arg seconds.  Default: 5 seconds\n");\r
     printf("-d [--duration] arg : Run for up to arg seconds.  Default: no limit\n\n");\r
     printf("Examples:\n");\r
-    printf("    record-memory-win --exe \"C:\\Program Files\\Safari\\Safari.exe\"\n");\r
-    printf("    record-memory-win --exe Safari.exe -i 10 -d 7200\n");\r
+    printf("    record-memory-win --exe \"C:\\Program Files\\Safari\\Safari.exe /newprocess\"\n");\r
+    printf("    record-memory-win --exe \"Safari.exe /newprocess\" -i 10 -d 7200\n");\r
+    printf("    NOTE: Close all other browser intances to ensure launching in a new process\n");\r
+    printf("          Or, pass the /newprocess (or equivalent) argument to the browser\n");\r
     return E_FAIL;\r
 }\r
 \r
+unsigned int getMemoryInfo(DWORD processID)\r
+{\r
+    unsigned int memInfo = 0;\r
+    HANDLE hProcess;\r
+    PROCESS_MEMORY_COUNTERS_EX pmc;\r
+\r
+    hProcess = OpenProcess(  PROCESS_QUERY_INFORMATION |\r
+                                    PROCESS_VM_READ,\r
+                                    FALSE, processID );\r
+    if (NULL == hProcess)\r
+        return 0;\r
+\r
+    if (GetProcessMemoryInfo( hProcess, (PPROCESS_MEMORY_COUNTERS)&pmc, sizeof(pmc))) {\r
+        memInfo = (pmc.PrivateUsage);\r
+    }\r
+\r
+    CloseHandle( hProcess );\r
+    return memInfo;\r
+}\r
+\r
+void printProcessInfo(DWORD processID)\r
+{\r
+    TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");\r
+   \r
+    // Get a handle to the process.\r
+    HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |\r
+                                   PROCESS_VM_READ,\r
+                                   FALSE, processID );\r
+\r
+    // Get the process name.\r
+    if (NULL != hProcess) {\r
+        HMODULE hMod;       // An array that receives the list of module handles.\r
+        DWORD cbNeeded;     //The number of bytes required to store all module handles in the Module array\r
+\r
+        if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {\r
+            GetModuleBaseName(hProcess, hMod, szProcessName, \r
+                               sizeof(szProcessName)/sizeof(TCHAR));\r
+        }\r
+    }\r
+\r
+    // Print the process name and identifier of matching strings, ignoring case\r
+    _tprintf(TEXT("%s  (PID: %u)\n"), szProcessName, processID);\r
+    \r
+    // Release the handle to the process.\r
+    CloseHandle( hProcess );\r
+}\r
+\r
+int evalProcesses(HANDLE hProcess)\r
+{\r
+    if (NULL == hProcess)\r
+        return 0;\r
+\r
+    unsigned int totalMemUsage = 0;\r
+    DWORD processID = GetProcessId(hProcess);\r
+  \r
+    HANDLE hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);\r
+\r
+    PROCESSENTRY32 processEntry = { 0 };\r
+    processEntry.dwSize = sizeof(PROCESSENTRY32);\r
+\r
+    // Retrieves information about the first process encountered in a system snapshot\r
+    if(Process32First(hProcessSnapshot, &processEntry)) {\r
+        do {\r
+            // if th32processID = processID, we are the parent process!  \r
+            // if th32ParentProcessID = processID, we are a child process!\r
+            if ((processEntry.th32ProcessID == processID) || (processEntry.th32ParentProcessID == processID)) {\r
+                unsigned int procMemUsage = 0;\r
+                // Record parent process memory\r
+                procMemUsage = getMemoryInfo(processEntry.th32ProcessID);\r
+                totalMemUsage += procMemUsage;\r
+            }\r
+          // Retrieves information about the next process recorded in a system snapshot.   \r
+        } while(Process32Next(hProcessSnapshot, &processEntry));\r
+    }\r
+\r
+    CloseHandle(hProcessSnapshot);\r
+    return totalMemUsage;\r
+}\r
+\r
+\r
 void UseImage(void (functionForQueryType(HANDLE)))\r
 {\r
     STARTUPINFO si = {0};\r
@@ -105,7 +183,7 @@ void UseImage(void (functionForQueryType(HANDLE)))
         &pi ))          // Pointer to PROCESS_INFORMATION structure\r
         printf("CreateProcess failed (%d)\n", GetLastError());\r
     else {\r
-        printf("Created process\n");\r
+        printf("Created process with id: %d\n", pi.dwProcessId);\r
         functionForQueryType(pi.hProcess);\r
         // Close process and thread handles. \r
         CloseHandle( pi.hProcess );\r
@@ -118,11 +196,11 @@ void QueryContinuously(HANDLE hProcess)
     Sleep(2000); // give the process some time to launch\r
     bool pastDuration = false;\r
     time_t startTime = time(NULL);\r
-    unsigned int memUsage = gSingleProcess ? OneQuery(hProcess) : OneQueryMP(hProcess);\r
+    unsigned int memUsage = evalProcesses(hProcess);\r
     while(memUsage && !pastDuration) {\r
         printf( "%u\n", memUsage );\r
         Sleep(gQueryInterval*1000);\r
-        memUsage = gSingleProcess ? OneQuery(hProcess) : OneQueryMP(hProcess);\r
+        memUsage = evalProcesses(hProcess);\r
         pastDuration = gDuration > 0 ? ElapsedTime(startTime) > gDuration : false;\r
     } \r
 }\r
@@ -133,55 +211,3 @@ time_t ElapsedTime(time_t startTime)
     time_t currentTime = time(NULL);\r
     return currentTime - startTime;\r
 }\r
-\r
-// returns Commit Size (Private Bytes) in bytes\r
-unsigned int OneQuery(HANDLE hProcess)\r
-{\r
-    PROCESS_MEMORY_COUNTERS_EX pmc;\r
-    if (NULL == hProcess)\r
-        return 0;\r
-    if (GetProcessMemoryInfo(hProcess, (PPROCESS_MEMORY_COUNTERS)&pmc, sizeof(pmc)))\r
-        return (unsigned)pmc.PrivateUsage;\r
-    return 0;\r
-}\r
-\r
-// returns Commit Size (Private Bytes) in bytes for multi-process executables\r
-unsigned int OneQueryMP(HANDLE hProcess)\r
-{\r
-    unsigned int memUsage = 0;\r
-    TCHAR monitoredProcessName[MAX_PATH];\r
-    GetProcessImageFileName(hProcess, monitoredProcessName, sizeof(monitoredProcessName)/sizeof(TCHAR));\r
-    LPTSTR shortProcessName = PathFindFileName(monitoredProcessName);\r
-    DWORD aProcesses[1024], cbNeeded, cProcesses;\r
-    HANDLE hFoundProcess;\r
-    if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))\r
-        return 0;\r
-\r
-    // Calculate how many process identifiers were returned.\r
-    cProcesses = cbNeeded / sizeof(DWORD);\r
-    // find existing process\r
-    for (unsigned int i = 0; i < cProcesses; i++)\r
-        if (aProcesses[i] != 0) {\r
-            DWORD retVal = 0;\r
-            TCHAR foundProcessName[MAX_PATH];\r
-\r
-            // Get a handle to the process.\r
-            hFoundProcess = OpenProcess(PROCESS_QUERY_INFORMATION |\r
-                                   PROCESS_VM_READ,\r
-                                   FALSE, aProcesses[i]);\r
-\r
-            // Get the process name.\r
-            if (NULL != hFoundProcess) {\r
-                HMODULE hMod;\r
-                DWORD cbNeeded;\r
-\r
-                if (EnumProcessModules(hFoundProcess, &hMod, sizeof(hMod), &cbNeeded)) {\r
-                    GetModuleBaseName(hFoundProcess, hMod, foundProcessName, sizeof(foundProcessName)/sizeof(TCHAR));\r
-                    if (wcsstr(foundProcessName, shortProcessName))\r
-                        memUsage += OneQuery(hFoundProcess);\r
-                }\r
-            }\r
-            CloseHandle(hFoundProcess);\r
-        }\r
-    return memUsage;\r
-}\r