Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1679 lines
66 KiB

  1. #include "priv.h"
  2. #include "shlwapip.h"
  3. #include "mshtmdbg.h"
  4. #define STOPWATCH_MAX_DESC 256
  5. #define STOPWATCH_MAX_TITLE 192
  6. #define STOPWATCH_MAX_BUF 1024
  7. // Perftags defines and typedefs
  8. typedef PERFTAG (WINAPI *PFN_PERFREGISTER)(char *, char *, char *);
  9. typedef void (WINAPIV *PFN_PERFLOGFN)(PERFTAG, void *, const char *, ...);
  10. typedef char *(WINAPI *PFN_DECODEMESSAGE)(INT);
  11. // IceCAP function typedefs
  12. typedef void (WINAPI *PFN_ICAP)(void);
  13. // MemWatch function typedefs
  14. typedef HRESULT (WINAPI *PFN_MWCONFIG)(DWORD, DWORD, DWORD);
  15. typedef HRESULT (WINAPI *PFN_MWBEGIN)(BOOL, BOOL);
  16. typedef HRESULT (WINAPI *PFN_MWSNAPSHOT)();
  17. typedef HRESULT (WINAPI *PFN_MWEND)(char *);
  18. typedef HRESULT (WINAPI *PFN_MWMARK)(char *);
  19. typedef HRESULT (WINAPI *PFN_MWEXIT)();
  20. #ifndef NO_ETW_TRACING
  21. #include <wmistr.h>
  22. #include <evntrace.h>
  23. typedef TRACEHANDLE (WINAPI *PFN_GTLOGHANDLE)(PVOID);
  24. typedef ULONG (WINAPI *PFN_REGTRACE)(WMIDPREQUEST,
  25. PVOID,
  26. LPCGUID,
  27. ULONG,
  28. PTRACE_GUID_REGISTRATION,
  29. LPCTSTR,
  30. LPCTSTR,
  31. PTRACEHANDLE
  32. );
  33. typedef ULONG (WINAPI *PFN_UNREGTRACE)(TRACEHANDLE);
  34. typedef ULONG (WINAPI *PFN_TRACE)(TRACEHANDLE, PEVENT_TRACE_HEADER);
  35. #endif
  36. // Stopwatch memory buffer
  37. typedef struct _STOPWATCH
  38. {
  39. DWORD dwId; // Node identifier
  40. DWORD dwTID; // Thread ID;
  41. DWORD dwType; // Node type - start, lap, stop, emtpy
  42. DWORD dwCount; // Tick count
  43. DWORD dwFlags; // Node flags - memlog, debugout
  44. TCHAR szDesc[STOPWATCH_MAX_DESC];
  45. } STOPWATCH, *PSTOPWATCH;
  46. // Global stopwatch info data
  47. typedef struct _STOPWATCHINFO
  48. {
  49. DWORD dwStopWatchMode;
  50. DWORD dwStopWatchProfile;
  51. DWORD dwStopWatchListIndex;
  52. DWORD dwStopWatchListMax;
  53. DWORD dwStopWatchPaintInterval;
  54. // SPMODE_MSGTRACE data
  55. DWORD dwStopWatchMaxDispatchTime;
  56. DWORD dwStopWatchMaxMsgTime;
  57. DWORD dwStopWatchMsgInterval;
  58. DWORD dwcStopWatchOverflow;
  59. DWORD dwStopWatchLastLocation;
  60. DWORD dwStopWatchTraceMsg;
  61. DWORD dwStopWatchTraceMsgCnt;
  62. DWORD *pdwStopWatchMsgTime;
  63. // SPMODE_MEMWATCH config data and function pointers
  64. DWORD dwMemWatchPages;
  65. DWORD dwMemWatchTime;
  66. DWORD dwMemWatchFlags;
  67. BOOL fMemWatchConfig;
  68. HMODULE hModMemWatch;
  69. PFN_MWCONFIG pfnMemWatchConfig;
  70. PFN_MWBEGIN pfnMemWatchBegin;
  71. PFN_MWSNAPSHOT pfnMemWatchSnapShot;
  72. PFN_MWEND pfnMemWatchEnd;
  73. PFN_MWMARK pfnMemWatchMark;
  74. PFN_MWEXIT pfnMemWatchExit;
  75. // Perftag data and function pointers
  76. PERFTAG tagStopWatchStart;
  77. PERFTAG tagStopWatchStop;
  78. PERFTAG tagStopWatchLap;
  79. PFN_PERFREGISTER pfnPerfRegister;
  80. PFN_PERFLOGFN pfnPerfLogFn;
  81. PFN_DECODEMESSAGE pfnDecodeMessage;
  82. #ifndef NO_ETW_TRACING
  83. DWORD dwEventTraceMode;
  84. PFN_GTLOGHANDLE pfnGetLogHandle;
  85. PFN_REGTRACE pfnRegisterTraceGuids;
  86. PFN_UNREGTRACE pfnUnRegisterTraceGuids;
  87. PFN_TRACE pfnTraceEvent;
  88. #endif
  89. LPTSTR pszClassNames;
  90. PSTOPWATCH pStopWatchList;
  91. // IceCAP data and function pointers
  92. HMODULE hModICAP;
  93. PFN_ICAP pfnStartCAPAll;
  94. PFN_ICAP pfnStopCAPAll;
  95. HANDLE hMapHtmPerfCtl;
  96. HTMPERFCTL *pHtmPerfCtl;
  97. } STOPWATCHINFO, *PSTOPWATCHINFO;
  98. #ifndef NO_ETW_TRACING
  99. #define c_szBrowserResourceName TEXT("Browse")
  100. // Used to turn on/off event tracing. Setting the registry key enable event
  101. // tracing use, but doesn't turn it on.
  102. // {5576F62E-4142-45a8-9516-262A510C13F0}
  103. const GUID c_BrowserControlGuid = {
  104. 0x5576f62e,
  105. 0x4142,
  106. 0x45a8,
  107. 0x95, 0x16, 0x26, 0x2a, 0x51, 0xc, 0x13, 0xf0};
  108. // Maps to the structure sent to ETW. ETW definition in
  109. // \nt\sdktools\trace\tracedmp\mofdata.guid
  110. // {2B992163-736F-4a68-9153-95BC5F34D884}
  111. const GUID c_BrowserTraceGuid = {
  112. 0x2b992163,
  113. 0x736f,
  114. 0x4a68,
  115. 0x91, 0x53, 0x95, 0xbc, 0x5f, 0x34, 0xd8, 0x84};
  116. TRACE_GUID_REGISTRATION g_BrowserTraceGuidReg[] =
  117. {
  118. { (LPGUID)&c_BrowserTraceGuid,
  119. NULL
  120. }
  121. };
  122. //
  123. // The mof fields point to the following data.
  124. // MOF_FIELD MofData[0]; // Holds ptr to Url Name
  125. //
  126. typedef struct _ETW_BROWSER_EVENT {
  127. EVENT_TRACE_HEADER Header;
  128. MOF_FIELD MofData[1];
  129. } ETW_BROWSER_EVENT, *PETW_BROWSER_EVENT;
  130. static TRACEHANDLE s_hEtwBrowserRegHandle;
  131. static TRACEHANDLE s_hEtwBrowserLogHandle;
  132. // For SHInterlockedCompareExchange
  133. static BOOL s_fTRUE = TRUE;
  134. static PVOID s_pvEtwBrowserTraceOnFlag = NULL;
  135. static PVOID s_pvEtwBrowserRegistered = NULL;
  136. static PVOID s_pvEtwBrowserRegistering = NULL;
  137. #endif
  138. PSTOPWATCHINFO g_pswi = NULL;
  139. const TCHAR c_szDefClassNames[] = {STOPWATCH_DEFAULT_CLASSNAMES};
  140. void StopWatch_SignalEvent();
  141. //===========================================================================================
  142. // INTERNAL FUNCTIONS
  143. //===========================================================================================
  144. //===========================================================================================
  145. //===========================================================================================
  146. void PerfCtlCallback(DWORD dwArg1, void * pvArg2)
  147. {
  148. const TCHAR c_szFmtBrowserStop[] = TEXT("Browser Frame Stop (%s)");
  149. TCHAR szTitle[STOPWATCH_MAX_TITLE];
  150. TCHAR szText[STOPWATCH_MAX_TITLE + ARRAYSIZE(c_szFmtBrowserStop) + 1];
  151. LPTSTR ptr = szTitle;
  152. #ifndef UNICODE
  153. INT rc;
  154. #endif
  155. if(g_pswi->dwStopWatchMode & SPMODE_BROWSER) // Temp hack to deal with ansi,unicode. This code will go away when we impl hook in mshtml.
  156. {
  157. // GetWindowText(hwnd, szTitle, ARRAYSIZE(szTitle)-1);
  158. #ifndef UNICODE
  159. rc = WideCharToMultiByte(CP_ACP, 0, pvArg2, -1, szTitle, STOPWATCH_MAX_TITLE - 1, NULL, NULL);
  160. if(!rc)
  161. StrCpyN(szTitle, "ERROR converting wide to multi", ARRAYSIZE(szTitle) - 1);
  162. #else
  163. ptr = (LPTSTR) pvArg2;
  164. #endif
  165. wnsprintf(szText, ARRAYSIZE(szText), c_szFmtBrowserStop, ptr);
  166. StopWatch_Stop(SWID_BROWSER_FRAME, szText, SPMODE_BROWSER | SPMODE_DEBUGOUT);
  167. if((g_pswi->dwStopWatchMode & (SPMODE_EVENT | SPMODE_BROWSER)) == (SPMODE_EVENT | SPMODE_BROWSER))
  168. {
  169. StopWatch_SignalEvent();
  170. }
  171. }
  172. }
  173. #ifndef NO_ETW_TRACING
  174. /*++
  175. Routine Name:
  176. ulEtwBrowserControlCallback()
  177. Routine Description:
  178. This is the function we provide to the ETW subsystem as a callback, it is used to
  179. start and stop the trace events.
  180. Arguments:
  181. IN WMIDPREQUESTCODE RequestCode : The function to provide (enable/disable)
  182. IN PVOID Context : Not used by us.
  183. IN OUT ULONG *InOutBufferSize : The Buffersize
  184. IN OUT PVOID Buffer : The buffer to use for the events
  185. Returns ERROR_SUCCESS on success, or an error code.
  186. --*/
  187. ULONG
  188. ulEtwBrowserControlCallback(
  189. IN WMIDPREQUESTCODE RequestCode,
  190. IN PVOID pvContext,
  191. IN OUT ULONG *InOutBufferSize,
  192. IN OUT PVOID pvBuffer
  193. )
  194. {
  195. ULONG Status;
  196. if (!s_pvEtwBrowserRegistered) {
  197. // Registration hasn't happened yet.
  198. return ERROR_GEN_FAILURE;
  199. }
  200. Status = ERROR_SUCCESS;
  201. switch (RequestCode)
  202. {
  203. case WMI_ENABLE_EVENTS:
  204. {
  205. #if STOPWATCH_DEBUG
  206. OutputDebugString("shperf.c:ulEtwBrowserControlCallback enable\n");
  207. #endif
  208. ASSERT(g_pswi->pfnGetLogHandle);
  209. s_hEtwBrowserLogHandle = g_pswi->pfnGetLogHandle( pvBuffer );
  210. #if STOPWATCH_DEBUG
  211. if (s_hEtwBrowserLogHandle == INVALID_HANDLE_VALUE) {
  212. TCHAR szDbg[256];
  213. wnsprintf(szDbg, ARRAYSIZE(szDbg) - 1,
  214. "ulEtwBrowserControlCallback GLE=%u\n", GetLastError());
  215. OutputDebugString(szDbg);
  216. }
  217. #endif
  218. SHInterlockedCompareExchange(&s_pvEtwBrowserTraceOnFlag, &s_fTRUE, NULL);
  219. break;
  220. }
  221. case WMI_DISABLE_EVENTS:
  222. {
  223. #if STOPWATCH_DEBUG
  224. OutputDebugString("shperf.c:ulEtwBrowserControlCallback disable\n");
  225. #endif
  226. SHInterlockedCompareExchange(&s_pvEtwBrowserTraceOnFlag, NULL, &s_fTRUE);
  227. s_hEtwBrowserLogHandle = 0;
  228. break;
  229. }
  230. default:
  231. {
  232. Status = ERROR_INVALID_PARAMETER;
  233. break;
  234. }
  235. }
  236. *InOutBufferSize = 0;
  237. return(Status);
  238. }
  239. /*++
  240. Routine Name:
  241. RegisterTracing()
  242. Routine Description:
  243. Registers us to the ETW tools
  244. Arguments:
  245. Returns ERROR_SUCCESS on success of all registrations.
  246. --*/
  247. ULONG RegisterTracing()
  248. {
  249. ULONG Status = ERROR_SUCCESS;
  250. TCHAR szImagePath[MAX_PATH];
  251. Status = GetModuleFileName(NULL, szImagePath, sizeof(szImagePath)/sizeof(TCHAR));
  252. if (Status == 0) {
  253. Status = ERROR_FILE_NOT_FOUND;
  254. }
  255. else {
  256. if (g_pswi->dwEventTraceMode & SPTRACE_BROWSER) {
  257. PVOID fRegOn;
  258. // If browser tracing is not registered, register it, preventing
  259. // anybody else from trying to do this at the same time.
  260. fRegOn = SHInterlockedCompareExchange(&s_pvEtwBrowserRegistering, &s_fTRUE, NULL);
  261. if (!fRegOn) {
  262. if (!s_pvEtwBrowserRegistered) {
  263. ASSERT(g_pswi->pfnRegisterTraceGuids);
  264. Status = g_pswi->pfnRegisterTraceGuids(
  265. ulEtwBrowserControlCallback,
  266. NULL,
  267. (LPGUID)&c_BrowserControlGuid,
  268. 1,
  269. g_BrowserTraceGuidReg,
  270. szImagePath,
  271. c_szBrowserResourceName,
  272. &s_hEtwBrowserRegHandle);
  273. if (Status == ERROR_SUCCESS) {
  274. SHInterlockedCompareExchange(&s_pvEtwBrowserRegistered, &s_fTRUE, NULL);
  275. }
  276. #if STOPWATCH_DEBUG
  277. else {
  278. OutputDebugString("shperf.c:Registration of event tracing guids failed.\n");
  279. }
  280. #endif
  281. }
  282. SHInterlockedCompareExchange(&s_pvEtwBrowserRegistering, NULL, &s_fTRUE);
  283. }
  284. }
  285. }
  286. return Status;
  287. }
  288. /*++
  289. Routine Name:
  290. UnRegisterTracing()
  291. Routine Description:
  292. Deregisters us from the ETW tools
  293. Arguments:
  294. Returns ERROR_SUCCESS on success. a Winerror otherwise.
  295. --*/
  296. ULONG UnRegisterTracing()
  297. {
  298. ULONG Status = ERROR_SUCCESS;
  299. // If browser tracing is registered, unregister it.
  300. if (s_pvEtwBrowserRegistered) {
  301. SHInterlockedCompareExchange(&s_pvEtwBrowserTraceOnFlag, NULL, &s_fTRUE);
  302. if(g_pswi && g_pswi->pfnUnRegisterTraceGuids) {
  303. Status = g_pswi->pfnUnRegisterTraceGuids(s_hEtwBrowserRegHandle);
  304. }
  305. if (Status == ERROR_SUCCESS) {
  306. SHInterlockedCompareExchange(&s_pvEtwBrowserRegistered, NULL, &s_fTRUE);
  307. }
  308. #if STOPWATCH_DEBUG
  309. else {
  310. OutputDebugString("shperf.c:UnRegistration of event tracing guids failed.\n");
  311. }
  312. #endif
  313. }
  314. return Status;
  315. }
  316. /*++
  317. Routine Name:
  318. EventTraceHandler()
  319. Routine Description:
  320. If tracing is turned on, this sends the event to the WMI subsystem.
  321. Arguments:
  322. UCHAR EventType : Kind of trace event
  323. PVOID Data : Data associated with event
  324. --*/
  325. void WINAPI EventTraceHandler(UCHAR uchEventType, PVOID pvData)
  326. {
  327. if ((g_pswi->dwEventTraceMode & SPTRACE_BROWSER))
  328. {
  329. if (s_pvEtwBrowserTraceOnFlag)
  330. {
  331. ETW_BROWSER_EVENT EtwEvent;
  332. ULONG Status;
  333. LPWSTR wszUrl = pvData;
  334. //
  335. // Record data.
  336. //
  337. ZeroMemory(&EtwEvent, sizeof(EtwEvent));
  338. EtwEvent.Header.Size = sizeof(ETW_BROWSER_EVENT);
  339. EtwEvent.Header.Flags = (WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR);
  340. EtwEvent.Header.Class.Type = uchEventType;
  341. EtwEvent.Header.Guid = c_BrowserTraceGuid;
  342. EtwEvent.MofData[0].DataPtr = (ULONG64)wszUrl;
  343. EtwEvent.MofData[0].Length = (wszUrl
  344. ? (wcslen(wszUrl)+1)*sizeof(WCHAR)
  345. : 0);
  346. ASSERT(g_pswi->pfnTraceEvent);
  347. Status = g_pswi->pfnTraceEvent(
  348. s_hEtwBrowserLogHandle,
  349. (PEVENT_TRACE_HEADER) &EtwEvent);
  350. #if STOPWATCH_DEBUG
  351. if (Status != ERROR_SUCCESS) {
  352. TCHAR szDbg[256];
  353. wnsprintf(szDbg, ARRAYSIZE(szDbg) - 1,
  354. "shperf.c:Call to trace event failed %I64x GLE=%u\n",
  355. s_hEtwBrowserLogHandle, Status);
  356. OutputDebugString(szDbg);
  357. }
  358. #endif
  359. }
  360. // Signal event when full web page is downloaded.
  361. if ((uchEventType == EVENT_TRACE_TYPE_BROWSE_LOADEDPARSED) &&
  362. (g_pswi->dwStopWatchMode & SPMODE_EVENT)) {
  363. StopWatch_SignalEvent();
  364. }
  365. }
  366. }
  367. // Called through a pointer in the shared memory map section.
  368. void PerfCtlEvntCallback(DWORD dwArg1, void * pvArg2)
  369. {
  370. EventTraceHandler((UCHAR)dwArg1, pvArg2);
  371. }
  372. #endif
  373. //===========================================================================================
  374. //===========================================================================================
  375. HRESULT SetPerfCtl(DWORD dwFlags)
  376. {
  377. if (dwFlags == HTMPF_CALLBACK_ONLOAD ||
  378. dwFlags == HTMPF_CALLBACK_ONEVENT)
  379. {
  380. char achName[sizeof(HTMPERFCTL_NAME) + 8 + 1];
  381. StringCchPrintfA(achName, ARRAYSIZE(achName), "%s%08lX", HTMPERFCTL_NAME, GetCurrentProcessId());
  382. if (g_pswi->hMapHtmPerfCtl == NULL)
  383. g_pswi->hMapHtmPerfCtl = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 4096, achName);
  384. if (g_pswi->hMapHtmPerfCtl == NULL)
  385. return(E_FAIL);
  386. if (g_pswi->pHtmPerfCtl == NULL)
  387. g_pswi->pHtmPerfCtl = (HTMPERFCTL *)MapViewOfFile(g_pswi->hMapHtmPerfCtl, FILE_MAP_WRITE, 0, 0, 0);
  388. if (g_pswi->pHtmPerfCtl == NULL)
  389. return(E_FAIL);
  390. g_pswi->pHtmPerfCtl->dwSize = sizeof(HTMPERFCTL);
  391. g_pswi->pHtmPerfCtl->dwFlags = dwFlags;
  392. #ifndef NO_ETW_TRACING
  393. if (dwFlags == HTMPF_CALLBACK_ONEVENT) {
  394. RegisterTracing();
  395. // Used by clients, like mshtml, to log events.
  396. g_pswi->pHtmPerfCtl->pfnCall = PerfCtlEvntCallback;
  397. }
  398. else
  399. #endif
  400. g_pswi->pHtmPerfCtl->pfnCall = PerfCtlCallback;
  401. g_pswi->pHtmPerfCtl->pvHost = NULL;
  402. }
  403. return S_OK;
  404. }
  405. //===========================================================================================
  406. //===========================================================================================
  407. void StopWatch_SignalEvent()
  408. {
  409. static HANDLE hEvent = NULL;
  410. if(hEvent == NULL)
  411. {
  412. TCHAR szEventName[256];
  413. wnsprintf(szEventName, ARRAYSIZE(szEventName), TEXT("%s%x"), TEXT("STOPWATCH_STOP_EVENT"), GetCurrentProcessId());
  414. hEvent = CreateEvent((LPSECURITY_ATTRIBUTES)NULL, FALSE, FALSE, szEventName);
  415. }
  416. if(hEvent != NULL)
  417. SetEvent(hEvent);
  418. }
  419. //===========================================================================================
  420. //===========================================================================================
  421. HRESULT DoMemWatchConfig(VOID)
  422. {
  423. HRESULT hr = ERROR_SUCCESS;
  424. if(g_pswi->hModMemWatch == NULL)
  425. {
  426. if((g_pswi->hModMemWatch = LoadLibrary("mwshelp.dll")) != NULL)
  427. {
  428. g_pswi->pfnMemWatchConfig = (PFN_MWCONFIG) GetProcAddress(g_pswi->hModMemWatch, "MemWatchConfigure");
  429. g_pswi->pfnMemWatchBegin = (PFN_MWBEGIN) GetProcAddress(g_pswi->hModMemWatch, "MemWatchBegin");
  430. g_pswi->pfnMemWatchSnapShot = (PFN_MWSNAPSHOT) GetProcAddress(g_pswi->hModMemWatch, "MemWatchSnapShot");
  431. g_pswi->pfnMemWatchEnd = (PFN_MWEND) GetProcAddress(g_pswi->hModMemWatch, "MemWatchEnd");
  432. g_pswi->pfnMemWatchMark = (PFN_MWMARK) GetProcAddress(g_pswi->hModMemWatch, "MemWatchMark");
  433. g_pswi->pfnMemWatchExit = (PFN_MWEXIT) GetProcAddress(g_pswi->hModMemWatch, "MemWatchExit");
  434. if(g_pswi->pfnMemWatchConfig != NULL)
  435. {
  436. hr = g_pswi->pfnMemWatchConfig(g_pswi->dwMemWatchPages, g_pswi->dwMemWatchTime, g_pswi->dwMemWatchFlags);
  437. if(FAILED(hr))
  438. g_pswi->dwStopWatchMode &= ~SPMODE_MEMWATCH;
  439. else
  440. g_pswi->fMemWatchConfig = TRUE;
  441. }
  442. }
  443. else
  444. {
  445. g_pswi->hModMemWatch = (HMODULE)1;
  446. }
  447. }
  448. return(hr);
  449. }
  450. //===========================================================================================
  451. // Function: VOID InitStopWatchMode(VOID)
  452. //
  453. // If HKLM\software\microsoft\windows\currentversion\explorer\performance\mode key value
  454. // is set to one of the values described below, the stopwatch mode will be enabled by
  455. // setting the global variable g_pswi->dwStopWatchMode.
  456. //
  457. // SPMODE_SHELL - Allows the flushing of stopwatch timings to a log file
  458. // SPMODE_DEBUGOUT - Display timing via OutputDebugString. Only timings marked with SPMODE_DEBUGOUT
  459. // through the StopWatch_* calls will be displayed.
  460. // SPMODE_TEST - Used to display test output. This allow another level of SPMODE_DEBUGOUT
  461. // like output.
  462. //
  463. // If HKLM\software\microsoft\windows\currentversion\explorer\performance\nodes key value
  464. // is set, the size of the timing array will be set to this value. The default is 100 nodes.
  465. //===========================================================================================
  466. #define REGKEY_PERFMODE REGSTR_PATH_EXPLORER TEXT("\\Performance")
  467. VOID InitStopWatchMode(VOID)
  468. {
  469. HKEY hkeyPerfMode;
  470. DWORD dwVal = 0;
  471. DWORD cbBuffer;
  472. DWORD dwType;
  473. TCHAR szClassNames[256];
  474. #if STOPWATCH_DEBUG
  475. TCHAR szDbg[256];
  476. #endif
  477. if(NO_ERROR == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY_PERFMODE, 0L, MAXIMUM_ALLOWED, &hkeyPerfMode))
  478. {
  479. cbBuffer = SIZEOF(dwVal);
  480. if(NO_ERROR == RegQueryValueEx(hkeyPerfMode, TEXT("Mode"), NULL, &dwType, (LPBYTE)&dwVal, &cbBuffer))
  481. {
  482. if((dwVal & SPMODES) == 0) // Low word is mode, high word is paint timer interval
  483. dwVal |= SPMODE_SHELL;
  484. if((g_pswi = (PSTOPWATCHINFO)LocalAlloc(LPTR, SIZEOF(STOPWATCHINFO))) == NULL)
  485. dwVal = 0;
  486. }
  487. if(dwVal != 0)
  488. {
  489. g_pswi->dwStopWatchMode = dwVal;
  490. g_pswi->dwStopWatchListMax = STOPWATCH_MAX_NODES;
  491. g_pswi->dwStopWatchPaintInterval = STOPWATCH_DEFAULT_PAINT_INTERVAL;
  492. g_pswi->dwStopWatchMaxDispatchTime = STOPWATCH_DEFAULT_MAX_DISPATCH_TIME;
  493. g_pswi->dwStopWatchMaxMsgTime = STOPWATCH_DEFAULT_MAX_MSG_TIME;
  494. g_pswi->dwStopWatchMsgInterval = STOPWATCH_DEFAULT_MAX_MSG_INTERVAL;
  495. g_pswi->pszClassNames = (LPTSTR)c_szDefClassNames;
  496. g_pswi->dwMemWatchPages = MEMWATCH_DEFAULT_PAGES;
  497. g_pswi->dwMemWatchTime = MEMWATCH_DEFAULT_TIME;
  498. g_pswi->dwMemWatchFlags = MEMWATCH_DEFAULT_FLAGS;
  499. #ifndef NO_ETW_TRACING
  500. g_pswi->dwEventTraceMode = 0;
  501. #endif
  502. cbBuffer = SIZEOF(dwVal);
  503. if(NO_ERROR == RegQueryValueEx(hkeyPerfMode, TEXT("Profile"), NULL, &dwType, (LPBYTE)&dwVal, &cbBuffer))
  504. g_pswi->dwStopWatchProfile = dwVal;
  505. cbBuffer = SIZEOF(dwVal);
  506. if(NO_ERROR == RegQueryValueEx(hkeyPerfMode, TEXT("Nodes"), NULL, &dwType, (LPBYTE)&dwVal, &cbBuffer))
  507. g_pswi->dwStopWatchListMax = dwVal;
  508. cbBuffer = SIZEOF(szClassNames);
  509. if(NO_ERROR == RegQueryValueEx(hkeyPerfMode, TEXT("ClassNames"), NULL, &dwType, (LPBYTE)&szClassNames, &cbBuffer))
  510. {
  511. if((g_pswi->pszClassNames = (LPTSTR)LocalAlloc(LPTR, SIZEOF(LPTSTR) * cbBuffer)) != NULL)
  512. CopyMemory(g_pswi->pszClassNames, szClassNames, SIZEOF(LPTSTR) * cbBuffer);
  513. }
  514. cbBuffer = SIZEOF(dwVal);
  515. // begin - Remove this after StopWatch users convert to using PaintInterval key
  516. g_pswi->dwStopWatchPaintInterval = HIWORD(g_pswi->dwStopWatchMode) ?HIWORD(g_pswi->dwStopWatchMode) :STOPWATCH_DEFAULT_PAINT_INTERVAL; // Use high word of mode reg key value for interval
  517. // end - Remove this after StopWatch users convert to using PaintInterval key
  518. if(NO_ERROR == RegQueryValueEx(hkeyPerfMode, TEXT("PaintInterval"), NULL, &dwType, (LPBYTE)&dwVal, &cbBuffer))
  519. g_pswi->dwStopWatchPaintInterval = dwVal;
  520. // Get MemWatch data
  521. cbBuffer = SIZEOF(dwVal);
  522. if(NO_ERROR == RegQueryValueEx(hkeyPerfMode, TEXT("MWPages"), NULL, &dwType, (LPBYTE)&dwVal, &cbBuffer))
  523. g_pswi->dwMemWatchPages = dwVal;
  524. cbBuffer = SIZEOF(dwVal);
  525. if(NO_ERROR == RegQueryValueEx(hkeyPerfMode, TEXT("MWTime"), NULL, &dwType, (LPBYTE)&dwVal, &cbBuffer))
  526. g_pswi->dwMemWatchTime = dwVal;
  527. cbBuffer = SIZEOF(dwVal);
  528. if(NO_ERROR == RegQueryValueEx(hkeyPerfMode, TEXT("MWFlags"), NULL, &dwType, (LPBYTE)&dwVal, &cbBuffer))
  529. g_pswi->dwMemWatchFlags = dwVal;
  530. #ifndef NO_ETW_TRACING
  531. if (g_pswi->dwStopWatchMode & SPMODE_EVENTTRACE) {
  532. // Load the ETW operations individually to make sure the system
  533. // this proc is running on supports them.
  534. HMODULE hMod;
  535. if ((hMod = LoadLibrary("advapi32.dll")) != NULL) {
  536. g_pswi->pfnGetLogHandle = (PFN_GTLOGHANDLE) GetProcAddress(hMod, "GetTraceLoggerHandle");
  537. g_pswi->pfnUnRegisterTraceGuids = (PFN_UNREGTRACE) GetProcAddress(hMod, "UnregisterTraceGuids");
  538. g_pswi->pfnTraceEvent = (PFN_TRACE) GetProcAddress(hMod, "TraceEvent");
  539. g_pswi->pfnRegisterTraceGuids =
  540. #if defined(UNICODE) || defined(_UNICODE)
  541. (PFN_REGTRACE) GetProcAddress(hMod, "RegisterTraceGuidsW");
  542. #else
  543. (PFN_REGTRACE) GetProcAddress(hMod, "RegisterTraceGuidsA");
  544. #endif
  545. }
  546. else {
  547. g_pswi->pfnGetLogHandle = NULL;
  548. g_pswi->pfnUnRegisterTraceGuids = NULL;
  549. g_pswi->pfnTraceEvent = NULL;
  550. g_pswi->pfnRegisterTraceGuids = NULL;
  551. }
  552. if (!hMod ||
  553. !g_pswi->pfnGetLogHandle ||
  554. !g_pswi->pfnUnRegisterTraceGuids ||
  555. !g_pswi->pfnTraceEvent ||
  556. !g_pswi->pfnRegisterTraceGuids) {
  557. // Event trace calls will never be made now.
  558. #if STOPWATCH_DEBUG
  559. wnsprintf(szDbg, ARRAYSIZE(szDbg) - 1, "~SPMODE_EVENTTRACE load procs from advapi32.dll failed.\n");
  560. OutputDebugString(szDbg);
  561. #endif
  562. g_pswi->dwStopWatchMode &= ~SPMODE_EVENTTRACE;
  563. }
  564. else {
  565. // Set type of event tracing before setting up the call back.
  566. cbBuffer = SIZEOF(dwVal);
  567. if(NO_ERROR == RegQueryValueEx(hkeyPerfMode, TEXT("EventTrace"), NULL,
  568. &dwType, (LPBYTE)&dwVal, &cbBuffer)) {
  569. g_pswi->dwEventTraceMode = dwVal;
  570. // You can only have one callback, so don't allow browser
  571. // stopwatch and browser event tracing.
  572. g_pswi->dwStopWatchMode &= ~SPMODE_BROWSER;
  573. }
  574. }
  575. }
  576. #endif
  577. if(g_pswi->dwStopWatchMode & SPMODES)
  578. {
  579. #ifndef NO_ETW_TRACING
  580. SetPerfCtl(g_pswi->dwStopWatchMode & SPMODE_EVENTTRACE
  581. // See mshtmdbg.h
  582. ? HTMPF_CALLBACK_ONEVENT
  583. : HTMPF_CALLBACK_ONLOAD);
  584. #else
  585. SetPerfCtl(HTMPF_CALLBACK_ONLOAD);
  586. #endif
  587. }
  588. if(g_pswi->dwStopWatchMode & SPMODE_MSGTRACE)
  589. {
  590. cbBuffer = SIZEOF(dwVal);
  591. if(NO_ERROR == RegQueryValueEx(hkeyPerfMode, TEXT("MaxDispatchTime"), NULL, &dwType, (LPBYTE)&dwVal, &cbBuffer))
  592. g_pswi->dwStopWatchMaxDispatchTime = dwVal;
  593. cbBuffer = SIZEOF(dwVal);
  594. if(NO_ERROR == RegQueryValueEx(hkeyPerfMode, TEXT("MaxMsgTime"), NULL, &dwType, (LPBYTE)&dwVal, &cbBuffer))
  595. g_pswi->dwStopWatchMaxMsgTime = dwVal;
  596. cbBuffer = SIZEOF(dwVal);
  597. if(NO_ERROR == RegQueryValueEx(hkeyPerfMode, TEXT("MsgInterval"), NULL, &dwType, (LPBYTE)&dwVal, &cbBuffer))
  598. g_pswi->dwStopWatchMsgInterval = dwVal;
  599. cbBuffer = SIZEOF(dwVal);
  600. if(NO_ERROR == RegQueryValueEx(hkeyPerfMode, TEXT("TraceMsg"), NULL, &dwType, (LPBYTE)&dwVal, &cbBuffer))
  601. g_pswi->dwStopWatchTraceMsg = dwVal;
  602. if((g_pswi->pdwStopWatchMsgTime = (DWORD *)LocalAlloc(LPTR, sizeof(DWORD) * (g_pswi->dwStopWatchMaxMsgTime / g_pswi->dwStopWatchMsgInterval))) == NULL)
  603. g_pswi->dwStopWatchMode &= ~SPMODE_MSGTRACE;
  604. }
  605. if((g_pswi->pStopWatchList = (PSTOPWATCH)LocalAlloc(LPTR, sizeof(STOPWATCH)* g_pswi->dwStopWatchListMax)) == NULL) {
  606. g_pswi->dwStopWatchMode = 0;
  607. #ifndef NO_ETW_TRACING
  608. // Just in case this didn't fail too.
  609. UnRegisterTracing();
  610. #endif
  611. }
  612. if(g_pswi->dwStopWatchMode & SPMODE_PERFTAGS)
  613. {
  614. HMODULE hMod;
  615. if((hMod = LoadLibrary("mshtmdbg.dll")) != NULL)
  616. {
  617. g_pswi->pfnPerfRegister = (PFN_PERFREGISTER) GetProcAddress(hMod, "DbgExPerfRegister");
  618. g_pswi->pfnPerfLogFn = (PFN_PERFLOGFN) GetProcAddress(hMod, "DbgExPerfLogFn");
  619. g_pswi->pfnDecodeMessage = (PFN_DECODEMESSAGE) GetProcAddress(hMod, "DbgExDecodeMessage");
  620. }
  621. else
  622. {
  623. #if STOPWATCH_DEBUG
  624. wnsprintf(szDbg, ARRAYSIZE(szDbg) - 1, "~SPMODE_PERFTAGS loadlib mshtmdbg.dll failed GLE=0x%x\n", GetLastError());
  625. OutputDebugString(szDbg);
  626. #endif
  627. g_pswi->dwStopWatchMode &= ~SPMODE_PERFTAGS;
  628. }
  629. if(g_pswi->pfnPerfRegister != NULL)
  630. {
  631. g_pswi->tagStopWatchStart = g_pswi->pfnPerfRegister("tagStopWatchStart", "StopWatchStart", "SHLWAPI StopWatch start time");
  632. g_pswi->tagStopWatchStop = g_pswi->pfnPerfRegister("tagStopWatchStop", "StopWatchStop", "SHLWAPI StopWatch stop time");
  633. g_pswi->tagStopWatchLap = g_pswi->pfnPerfRegister("tagStopWatchLap", "StopWatchLap", "SHLWAPI StopWatch lap time");
  634. }
  635. }
  636. #ifdef STOPWATCH_DEBUG
  637. // Display option values
  638. {
  639. LPCTSTR ptr;
  640. wnsprintf(szDbg, ARRAYSIZE(szDbg) - 1, TEXT("StopWatch Mode=0x%x Profile=0x%x Nodes=%d PaintInterval=%d MemBuf=%d bytes\n"),
  641. g_pswi->dwStopWatchMode, g_pswi->dwStopWatchProfile, g_pswi->dwStopWatchListMax, g_pswi->dwStopWatchPaintInterval, g_pswi->dwStopWatchListMax * sizeof(STOPWATCH));
  642. OutputDebugString(szDbg);
  643. OutputDebugString(TEXT("Stopwatch ClassNames="));
  644. ptr = g_pswi->pszClassNames;
  645. while(*ptr)
  646. {
  647. wnsprintf(szDbg, ARRAYSIZE(szDbg) - 1, TEXT("'%s' "), ptr);
  648. OutputDebugString(szDbg);
  649. ptr = ptr + (lstrlen(ptr) + 1);
  650. }
  651. OutputDebugString(TEXT("\n"));
  652. if(g_pswi->dwStopWatchMode & SPMODE_MSGTRACE)
  653. {
  654. wnsprintf(szDbg, ARRAYSIZE(szDbg)-1, TEXT("StopWatch MaxDispatchTime=%dms MaxMsgTime=%dms MsgInterval=%dms TraceMsg=0x%x MemBuf=%d bytes\n"),
  655. g_pswi->dwStopWatchMaxDispatchTime, g_pswi->dwStopWatchMaxMsgTime, g_pswi->dwStopWatchMsgInterval, g_pswi->dwStopWatchTraceMsg, sizeof(DWORD) * (g_pswi->dwStopWatchMaxMsgTime / g_pswi->dwStopWatchMsgInterval));
  656. OutputDebugString(szDbg);
  657. }
  658. if(g_pswi->dwStopWatchMode & SPMODE_MEMWATCH)
  659. {
  660. wnsprintf(szDbg, ARRAYSIZE(szDbg)-1, TEXT("StopWatch MemWatch Pages=%d Time=%dms Flags=%d\n"),
  661. g_pswi->dwMemWatchPages, g_pswi->dwMemWatchTime, g_pswi->dwMemWatchFlags);
  662. OutputDebugString(szDbg);
  663. }
  664. }
  665. #endif
  666. } // if(dwVal != 0)
  667. RegCloseKey(hkeyPerfMode);
  668. }
  669. }
  670. //===========================================================================================
  671. // EXPORTED FUNCTIONS
  672. //===========================================================================================
  673. //===========================================================================================
  674. // Function: DWORD WINAPI StopWatchMode(VOID)
  675. //
  676. // Returns: The value of the global mode variable. Modules should use this call, set their
  677. // own global, and use this global to minimize and overhead when stopwatch mode
  678. // is not enabled.
  679. //===========================================================================================
  680. DWORD WINAPI StopWatchMode(VOID)
  681. {
  682. if(g_pswi != NULL)
  683. return(g_pswi->dwStopWatchMode);
  684. else
  685. return(0);
  686. }
  687. //===========================================================================================
  688. //===========================================================================================
  689. const TCHAR c_szBrowserStop[] = TEXT("Browser Frame Stop (%s)");
  690. DWORD MakeStopWatchDesc(DWORD dwId, DWORD dwMarkType, LPCTSTR pszDesc, LPTSTR *ppszText, DWORD dwTextLen)
  691. {
  692. LPSTR lpszFmt = NULL;
  693. DWORD dwRC = 0;
  694. switch(SWID(dwId))
  695. {
  696. case SWID_BROWSER_FRAME:
  697. lpszFmt = (LPSTR)c_szBrowserStop;
  698. break;
  699. default:
  700. return(dwRC);
  701. }
  702. if(((DWORD)(lstrlen(lpszFmt) + lstrlen(pszDesc)) - 1) < dwTextLen)
  703. dwRC = wnsprintf(*ppszText, dwTextLen - 1, lpszFmt, pszDesc);
  704. else
  705. StrCpyN(*ppszText, TEXT("ERROR:Desc too long!"), dwTextLen -1);
  706. return(dwRC);
  707. }
  708. #define STARTCAPALL 1
  709. #define STOPCAPALL 2
  710. #define iStartCAPAll() CallICAP(STARTCAPALL)
  711. #define iStopCAPAll() CallICAP(STOPCAPALL)
  712. //===========================================================================================
  713. //===========================================================================================
  714. VOID CallICAP(DWORD dwFunc)
  715. {
  716. if(g_pswi->hModICAP == NULL)
  717. {
  718. if((g_pswi->hModICAP = LoadLibrary("icap.dll")) != NULL)
  719. {
  720. g_pswi->pfnStartCAPAll = (PFN_ICAP) GetProcAddress(g_pswi->hModICAP, "StartCAPAll");
  721. g_pswi->pfnStopCAPAll = (PFN_ICAP) GetProcAddress(g_pswi->hModICAP, "StopCAPAll");
  722. }
  723. else
  724. {
  725. g_pswi->hModICAP = (HMODULE)1;
  726. }
  727. }
  728. switch(dwFunc)
  729. {
  730. case STARTCAPALL:
  731. if(g_pswi->pfnStartCAPAll != NULL)
  732. g_pswi->pfnStartCAPAll();
  733. break;
  734. case STOPCAPALL:
  735. if(g_pswi->pfnStopCAPAll != NULL)
  736. g_pswi->pfnStopCAPAll();
  737. break;
  738. }
  739. }
  740. //===========================================================================================
  741. //===========================================================================================
  742. VOID CapBreak(BOOL fStart)
  743. {
  744. if((g_pswi->dwStopWatchMode & SPMODE_PROFILE) || (g_pswi->pHtmPerfCtl->dwFlags & HTMPF_ENABLE_PROFILE))
  745. {
  746. if(fStart)
  747. iStartCAPAll();
  748. else
  749. iStopCAPAll();
  750. }
  751. if((g_pswi->dwStopWatchMode & SPMODE_MEMWATCH) || (g_pswi->pHtmPerfCtl->dwFlags & HTMPF_ENABLE_MEMWATCH))
  752. {
  753. if(g_pswi->hModMemWatch == NULL)
  754. DoMemWatchConfig();
  755. if(fStart)
  756. {
  757. if(g_pswi->pfnMemWatchBegin != NULL)
  758. {
  759. g_pswi->pfnMemWatchBegin(TRUE, FALSE); // synchronous and don't use timer
  760. }
  761. }
  762. else
  763. {
  764. if(g_pswi->pfnMemWatchSnapShot != NULL)
  765. {
  766. g_pswi->pfnMemWatchSnapShot();
  767. }
  768. if(g_pswi->pfnMemWatchEnd != NULL)
  769. {
  770. CHAR szOutFile[MAX_PATH];
  771. DWORD dwLen;
  772. HRESULT hr;
  773. #if STOPWATCH_DEBUG
  774. CHAR szDbg[256];
  775. #endif
  776. *szOutFile = '\0';
  777. GetWindowsDirectoryA(szOutFile, ARRAYSIZE(szOutFile) - 1);
  778. dwLen = lstrlenA(szOutFile);
  779. if ((dwLen > 0) && (szOutFile[dwLen-1] == '\\'))
  780. {
  781. // See if windows is installed in the root
  782. szOutFile[dwLen-1] = '\0';
  783. }
  784. StringCchCatA(szOutFile, ARRAYSIZE(szOutFile), "\\shperf.mws");
  785. hr = g_pswi->pfnMemWatchEnd(szOutFile);
  786. #if STOPWATCH_DEBUG
  787. switch(hr)
  788. {
  789. case E_FAIL:
  790. wnsprintfA(szDbg, ARRAYSIZE(szDbg) - 1, "MemWatch SaveBuffer:%s failed. GLE:0x%x\n", szOutFile, GetLastError());
  791. OutputDebugStringA(szDbg);
  792. break;
  793. case E_ABORT:
  794. wnsprintfA(szDbg, ARRAYSIZE(szDbg) - 1, "MemWatch SaveBuffer: No data to save.\n");
  795. OutputDebugStringA(szDbg);
  796. break;
  797. }
  798. #endif
  799. if(g_pswi->pfnMemWatchExit != NULL)
  800. {
  801. g_pswi->pfnMemWatchExit();
  802. }
  803. }
  804. }
  805. }
  806. if(g_pswi->dwStopWatchMode & SPMODE_DEBUGBREAK)
  807. {
  808. DebugBreak();
  809. }
  810. }
  811. //===========================================================================================
  812. // Function: DWORD WINAPI StopWatch(
  813. // DWORD dwId, // The unique identifier, SWID_*, used to associate start, lap, and
  814. // // stop timings for a given timing sequence.
  815. // LPCSTR pszDesc, // Descriptive text for the timing.
  816. // DWORD dwMarkType, // START_NODE, LAP_NODE, STOP_NODE
  817. // DWORD dwFlags, // SPMODE_SHELL, SPMODE_DEBUGOUT, SPMODE_*. The timing call is used
  818. // only if g_pswi->dwStopWatchMode contains dwFlags
  819. // DWORD dwID) // Unique ID (Thread ID or user-supplied value)
  820. //
  821. // Macros: StopWatch_Start(dwId, pszDesc, dwFlags)
  822. // StopWatch_Lap(dwId, pszDesc, dwFlags)
  823. // StopWatch_Stop(dwId, pszDesc, dwFlags)
  824. //
  825. // Returns: ERROR_SUCCESS or ERROR_NOT_ENOUGH_MEMORY if out of nodes
  826. //===========================================================================================
  827. DWORD _StopWatch(DWORD dwId, LPCTSTR pszDesc, DWORD dwMarkType, DWORD dwFlags, DWORD dwCount, DWORD dwUniqueID)
  828. {
  829. PSTOPWATCH psp;
  830. #ifdef STOPWATCH_DEBUG
  831. PSTOPWATCH pspPrev;
  832. #endif
  833. DWORD dwDelta = 0;
  834. DWORD dwRC = ERROR_SUCCESS;
  835. DWORD dwIndex;
  836. TCHAR szText[STOPWATCH_MAX_DESC];
  837. LPTSTR psz;
  838. if((SWID(dwId) && g_pswi->dwStopWatchProfile) && (dwMarkType == STOP_NODE))
  839. {
  840. CapBreak(FALSE);
  841. }
  842. if((g_pswi->pStopWatchList != NULL) && ((dwFlags & g_pswi->dwStopWatchMode) & SPMODES))
  843. {
  844. ENTERCRITICAL;
  845. dwIndex = g_pswi->dwStopWatchListIndex++;
  846. LEAVECRITICAL;
  847. if(dwIndex < (g_pswi->dwStopWatchListMax-1))
  848. {
  849. psp = g_pswi->pStopWatchList + (dwIndex);
  850. psp->dwCount = (dwCount != 0 ?dwCount :GetPerfTime()); // Save the data
  851. psp->dwId = dwId;
  852. psp->dwTID = dwUniqueID ? dwUniqueID : GetCurrentThreadId();
  853. psp->dwType = dwMarkType;
  854. psp->dwFlags = dwFlags;
  855. psz = (LPTSTR)pszDesc;
  856. if(dwFlags & SPMODE_FORMATTEXT)
  857. {
  858. psz = (LPTSTR)szText;
  859. MakeStopWatchDesc(dwId, dwMarkType, pszDesc, &psz, ARRAYSIZE(szText));
  860. }
  861. StrCpyN(psp->szDesc, psz, ARRAYSIZE(psp->szDesc)-1);
  862. if((g_pswi->dwStopWatchMode & SPMODE_PERFTAGS) && (g_pswi->pfnPerfLogFn != NULL))
  863. {
  864. if(dwMarkType == START_NODE)
  865. g_pswi->pfnPerfLogFn(g_pswi->tagStopWatchStart, IntToPtr(dwId), psz);
  866. if(dwMarkType == STOP_NODE)
  867. g_pswi->pfnPerfLogFn(g_pswi->tagStopWatchStop, IntToPtr(dwId), psz);
  868. if(dwMarkType == LAP_NODE)
  869. g_pswi->pfnPerfLogFn(g_pswi->tagStopWatchLap, IntToPtr(dwId), psz);
  870. }
  871. #ifdef STOPWATCH_DEBUG
  872. if(g_pswi->dwStopWatchMode & SPMODE_DEBUGOUT)
  873. {
  874. const TCHAR c_szFmt_StopWatch_DbgOut[] = TEXT("StopWatch: 0x%x: %s: Time: %u ms\r\n");
  875. TCHAR szBuf[STOPWATCH_MAX_DESC + ARRAYSIZE(c_szFmt_StopWatch_DbgOut) + 40]; // 8=dwTID 10=dwDelta
  876. if(psp->dwType > START_NODE) // Find the previous associated node to get delta time
  877. {
  878. pspPrev = psp - 1;
  879. while(pspPrev >= g_pswi->pStopWatchList)
  880. {
  881. if((SWID(pspPrev->dwId) == SWID(psp->dwId)) && // Found a match
  882. (pspPrev->dwTID == psp->dwTID) &&
  883. (pspPrev->dwType == START_NODE))
  884. {
  885. dwDelta = psp->dwCount - pspPrev->dwCount;
  886. break;
  887. }
  888. pspPrev--;
  889. }
  890. }
  891. wnsprintf((LPTSTR)szBuf, ARRAYSIZE(szBuf), c_szFmt_StopWatch_DbgOut, psp->dwTID, psp->szDesc, dwDelta);
  892. OutputDebugString(szBuf);
  893. }
  894. #endif
  895. if((dwMarkType == STOP_NODE) && (g_pswi->dwStopWatchMode & SPMODE_FLUSH) && (SWID(dwId) == SWID_FRAME))
  896. {
  897. StopWatchFlush();
  898. }
  899. }
  900. else
  901. {
  902. psp = g_pswi->pStopWatchList + (g_pswi->dwStopWatchListMax-1); // Set the last node to a message so the user knows we ran out or mem
  903. psp->dwId = 0;
  904. psp->dwType = OUT_OF_NODES;
  905. psp->dwFlags = dwFlags;
  906. wnsprintf(psp->szDesc, STOPWATCH_MAX_DESC, TEXT("Out of perf timing nodes."));
  907. #ifdef STOPWATCH_DEBUG
  908. if(g_pswi->dwStopWatchMode & SPMODE_DEBUGOUT)
  909. OutputDebugString(psp->szDesc);
  910. #endif
  911. dwRC = ERROR_NOT_ENOUGH_MEMORY;
  912. }
  913. }
  914. if((SWID(dwId) && g_pswi->dwStopWatchProfile) && (dwMarkType == START_NODE))
  915. {
  916. CapBreak(TRUE);
  917. }
  918. return(dwRC);
  919. }
  920. //===========================================================================================
  921. //===========================================================================================
  922. DWORD WINAPI StopWatchA(DWORD dwId, LPCSTR pszDesc, DWORD dwMarkType, DWORD dwFlags, DWORD dwCount)
  923. {
  924. #ifdef UNICODE
  925. INT rc;
  926. WCHAR wszDesc[STOPWATCH_MAX_DESC];
  927. rc = MultiByteToWideChar(CP_ACP, 0, pszDesc, -1, wszDesc, STOPWATCH_MAX_DESC);
  928. if(!rc)
  929. return(ERROR_NOT_ENOUGH_MEMORY);
  930. return(_StopWatch(dwId, (LPCTSTR)wszDesc, dwMarkType, dwFlags, dwCount, 0));
  931. #else
  932. return(_StopWatch(dwId, (LPCTSTR)pszDesc, dwMarkType, dwFlags, dwCount, 0));
  933. #endif
  934. }
  935. //===========================================================================================
  936. //===========================================================================================
  937. DWORD WINAPI StopWatchW(DWORD dwId, LPCWSTR pwszDesc, DWORD dwMarkType, DWORD dwFlags, DWORD dwCount)
  938. {
  939. #ifndef UNICODE
  940. INT rc;
  941. CHAR szDesc[STOPWATCH_MAX_DESC];
  942. rc = WideCharToMultiByte(CP_ACP, 0, pwszDesc, -1, szDesc, STOPWATCH_MAX_DESC, NULL, NULL);
  943. if(!rc)
  944. return(ERROR_NOT_ENOUGH_MEMORY);
  945. return(_StopWatch(dwId, (LPCTSTR)szDesc, dwMarkType, dwFlags, dwCount, 0));
  946. #else
  947. return(_StopWatch(dwId, (LPCTSTR)pwszDesc, dwMarkType, dwFlags, dwCount, 0));
  948. #endif
  949. }
  950. //===========================================================================================
  951. //===========================================================================================
  952. DWORD WINAPI StopWatchExA(DWORD dwId, LPCSTR pszDesc, DWORD dwMarkType, DWORD dwFlags, DWORD dwCount, DWORD dwCookie)
  953. {
  954. #ifdef UNICODE
  955. INT rc;
  956. WCHAR wszDesc[STOPWATCH_MAX_DESC];
  957. rc = MultiByteToWideChar(CP_ACP, 0, pszDesc, -1, wszDesc, STOPWATCH_MAX_DESC);
  958. if(!rc)
  959. return(ERROR_NOT_ENOUGH_MEMORY);
  960. return(_StopWatch(dwId, (LPCTSTR)wszDesc, dwMarkType, dwFlags, dwCount, dwCookie));
  961. #else
  962. return(_StopWatch(dwId, (LPCTSTR)pszDesc, dwMarkType, dwFlags, dwCount, dwCookie));
  963. #endif
  964. }
  965. //===========================================================================================
  966. //===========================================================================================
  967. DWORD WINAPI StopWatchExW(DWORD dwId, LPCWSTR pwszDesc, DWORD dwMarkType, DWORD dwFlags, DWORD dwCount, DWORD dwCookie)
  968. {
  969. #ifndef UNICODE
  970. INT rc;
  971. CHAR szDesc[STOPWATCH_MAX_DESC];
  972. rc = WideCharToMultiByte(CP_ACP, 0, pwszDesc, -1, szDesc, STOPWATCH_MAX_DESC, NULL, NULL);
  973. if(!rc)
  974. return(ERROR_NOT_ENOUGH_MEMORY);
  975. return(_StopWatch(dwId, (LPCTSTR)szDesc, dwMarkType, dwFlags, dwCount, dwCookie));
  976. #else
  977. return(_StopWatch(dwId, (LPCTSTR)pwszDesc, dwMarkType, dwFlags, dwCount, dwCookie));
  978. #endif
  979. }
  980. //===========================================================================================
  981. // Function: DWORD WINAPI StopWatchFlush(VOID)
  982. //
  983. // This function will flush any SPMODE_SHELL nodes to windir\shperf.log. Calling this function
  984. // will also clear all nodes.
  985. //
  986. // Return: ERROR_SUCCESS if the log file was generated
  987. // ERROR_NO_DATA if the timing array is empty
  988. // ERROR_INVALID_DATA if stopwatch mode is not enabled or the timing array does
  989. // not exist.
  990. //===========================================================================================
  991. DWORD WINAPI StopWatchFlush(VOID)
  992. {
  993. PSTOPWATCH psp;
  994. PSTOPWATCH psp1 = NULL;
  995. BOOL fWroteStartData;
  996. DWORD dwRC = ERROR_SUCCESS;
  997. DWORD dwWritten;
  998. DWORD dwDelta;
  999. DWORD dwPrevCount;
  1000. DWORD dwCummDelta;
  1001. DWORD dwLen = 0;
  1002. HANDLE hFile;
  1003. SYSTEMTIME st;
  1004. TCHAR szBuf[STOPWATCH_MAX_BUF];
  1005. TCHAR szFileName[MAX_PATH];
  1006. #ifdef STOPWATCH_DEBUG
  1007. TCHAR szDbg[512];
  1008. #endif
  1009. if((!g_pswi->dwStopWatchMode) || (g_pswi->pStopWatchList == NULL))
  1010. {
  1011. SetLastError(ERROR_INVALID_DATA);
  1012. return(ERROR_INVALID_DATA);
  1013. }
  1014. GetSystemTime(&st);
  1015. if(g_pswi->dwStopWatchListIndex > 0)
  1016. {
  1017. ENTERCRITICAL;
  1018. if(g_pswi->dwStopWatchListIndex > 0)
  1019. {
  1020. g_pswi->dwStopWatchListIndex = 0;
  1021. if(g_pswi->dwStopWatchMode & SPMODES)
  1022. {
  1023. #ifdef STOPWATCH_DEBUG
  1024. if(g_pswi->dwStopWatchMode & SPMODE_DEBUGOUT)
  1025. {
  1026. OutputDebugString(TEXT("Flushing shell perf data to shperf.log\r\n"));
  1027. }
  1028. #endif
  1029. // Used below as well to create msg trace log file
  1030. dwLen = GetWindowsDirectory(szFileName, ARRAYSIZE(szFileName) - 1);
  1031. szFileName[dwLen] = 0;
  1032. if (dwLen && szFileName[dwLen-1] == TEXT('\\'))
  1033. {
  1034. // See if windows is installed in the root
  1035. szFileName[dwLen-1] = TEXT('\0');
  1036. }
  1037. StringCchCat(szFileName, ARRAYSIZE(szFileName), TEXT("\\shperf.log"));
  1038. if((hFile = CreateFile(szFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
  1039. {
  1040. SetFilePointer(hFile, 0, NULL, FILE_END);
  1041. psp = g_pswi->pStopWatchList;
  1042. while(psp->dwType != EMPTY_NODE)
  1043. {
  1044. #ifdef STOPWATCH_DEBUG
  1045. if(g_pswi->dwStopWatchMode & SPMODE_DEBUGOUT)
  1046. {
  1047. wnsprintf(szDbg, ARRAYSIZE(szDbg), TEXT("ID:%d TID:0x%x Type:%d Flgs:%d %s\r\n"),
  1048. psp->dwId, psp->dwTID, psp->dwType, psp->dwFlags, psp->szDesc);
  1049. OutputDebugString(szDbg);
  1050. }
  1051. #endif
  1052. if(psp->dwType == START_NODE)
  1053. {
  1054. wnsprintf(szBuf, ARRAYSIZE(szBuf), TEXT("%02d%02d%02d%02d%02d%02d\t0x%x\t%s\t%lu\t"),
  1055. st.wYear, st.wMonth, st.wDay,
  1056. st.wHour, st.wMinute, st.wSecond,
  1057. psp->dwId, psp->szDesc, psp->dwCount);
  1058. #ifdef STOPWATCH_DEBUG
  1059. if(g_pswi->dwStopWatchMode & SPMODE_DEBUGOUT)
  1060. OutputDebugString(TEXT("Found Start Node\r\n"));
  1061. #endif
  1062. dwDelta = dwCummDelta = 0;
  1063. dwPrevCount = psp->dwCount;
  1064. psp1 = psp + 1;
  1065. fWroteStartData = FALSE;
  1066. while(psp1->dwType != EMPTY_NODE)
  1067. {
  1068. #ifdef STOPWATCH_DEBUG
  1069. if(g_pswi->dwStopWatchMode & SPMODE_DEBUGOUT)
  1070. {
  1071. wnsprintf(szDbg, ARRAYSIZE(szDbg), TEXT(" ID:%d TID:0x%x Type:%d Flgs:%d %s\r\n"),
  1072. psp1->dwId, psp1->dwTID, psp1->dwType, psp1->dwFlags, psp1->szDesc);
  1073. OutputDebugString(szDbg);
  1074. }
  1075. #endif
  1076. if((SWID(psp1->dwId) == SWID(psp->dwId)) &&
  1077. (psp1->dwTID == psp->dwTID)) // Found a matching LAP or STOP node
  1078. {
  1079. if(psp1->dwType != START_NODE)
  1080. {
  1081. dwDelta = psp1->dwCount - dwPrevCount;
  1082. dwCummDelta += dwDelta;
  1083. if(!fWroteStartData)
  1084. {
  1085. fWroteStartData = TRUE;
  1086. WriteFile(hFile, szBuf, lstrlen(szBuf), &dwWritten, NULL); // Write out start node data
  1087. }
  1088. wnsprintf(szBuf, ARRAYSIZE(szBuf), TEXT("%s\t%lu,%lu,%lu\t"), psp1->szDesc, psp1->dwCount, dwDelta, dwCummDelta);
  1089. WriteFile(hFile, szBuf, lstrlen(szBuf), &dwWritten, NULL);
  1090. #ifdef STOPWATCH_DEBUG
  1091. if(g_pswi->dwStopWatchMode & SPMODE_DEBUGOUT)
  1092. OutputDebugString(TEXT(" Found Lap/Stop Node\r\n"));
  1093. #endif
  1094. dwPrevCount = psp1->dwCount;
  1095. if(psp1->dwType == STOP_NODE && !(g_pswi->dwStopWatchMode & SPMODE_MARS))
  1096. break;
  1097. }
  1098. else // We have another start node that matches our Id/TID and we haven't had a stop. Log as a missing stop.
  1099. {
  1100. if(!fWroteStartData)
  1101. {
  1102. fWroteStartData = TRUE;
  1103. WriteFile(hFile, szBuf, lstrlen(szBuf), &dwWritten, NULL); // Write out start node data
  1104. }
  1105. wnsprintf(szBuf, ARRAYSIZE(szBuf), TEXT("ERROR: missing stop time"), psp1->szDesc, psp1->dwCount, dwDelta, dwCummDelta);
  1106. WriteFile(hFile, szBuf, lstrlen(szBuf), &dwWritten, NULL);
  1107. break;
  1108. }
  1109. }
  1110. psp1++;
  1111. }
  1112. WriteFile(hFile, TEXT("\r\n"), 2, &dwWritten, NULL);
  1113. }
  1114. else if(psp->dwType == OUT_OF_NODES)
  1115. {
  1116. wnsprintf(szBuf, ARRAYSIZE(szBuf), TEXT("%02d%02d%02d%02d%02d%02d\t0x%x\t%s\n"),
  1117. st.wYear, st.wMonth, st.wDay,
  1118. st.wHour, st.wMinute, st.wSecond,
  1119. psp->dwId, psp->szDesc);
  1120. WriteFile(hFile, szBuf, lstrlen(szBuf), &dwWritten, NULL);
  1121. }
  1122. psp->dwType = EMPTY_NODE;
  1123. psp++;
  1124. }
  1125. FlushFileBuffers(hFile);
  1126. CloseHandle(hFile);
  1127. }
  1128. else
  1129. {
  1130. #ifdef STOPWATCH_DEBUG
  1131. wnsprintf(szBuf, ARRAYSIZE(szBuf) - 1, TEXT("CreateFile failed on '%s'. GLE=%d\n"), szFileName, GetLastError());
  1132. OutputDebugString(szBuf);
  1133. #endif
  1134. dwRC = ERROR_NO_DATA;
  1135. }
  1136. }
  1137. else // !(g_pswi->dwStopWatchMode)
  1138. {
  1139. psp = g_pswi->pStopWatchList;
  1140. while(psp->dwType != EMPTY_NODE)
  1141. {
  1142. psp->dwType = EMPTY_NODE;
  1143. psp++;
  1144. }
  1145. }
  1146. } // (g_pswi->dwStopWatchListIndex > 0)
  1147. LEAVECRITICAL;
  1148. }
  1149. if(g_pswi->dwStopWatchMode & SPMODE_MSGTRACE)
  1150. {
  1151. int i;
  1152. StringCchCopy(&szFileName[dwLen], ARRAYSIZE(szFileName) - dwLen, TEXT("\\msgtrace.log"));
  1153. if((hFile = CreateFile(szFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
  1154. {
  1155. SetFilePointer(hFile, 0, NULL, FILE_END);
  1156. for (i = 0; i < (int)(g_pswi->dwStopWatchMaxMsgTime / g_pswi->dwStopWatchMsgInterval); ++i)
  1157. {
  1158. wnsprintf(szBuf, ARRAYSIZE(szBuf) - 1, TEXT("%02d%02d%02d%02d%02d%02d\tMsgTrace\t%4d - %4dms\t%d\r\n"),
  1159. st.wYear, st.wMonth, st.wDay,
  1160. st.wHour, st.wMinute, st.wSecond,
  1161. i * g_pswi->dwStopWatchMsgInterval, (i+1)*g_pswi->dwStopWatchMsgInterval-1, *(g_pswi->pdwStopWatchMsgTime + i));
  1162. WriteFile(hFile, szBuf, lstrlen(szBuf), &dwWritten, NULL);
  1163. #ifdef STOPWATCH_DEBUG
  1164. if(g_pswi->dwStopWatchMode & SPMODE_DEBUGOUT)
  1165. OutputDebugString(szBuf);
  1166. #endif
  1167. }
  1168. wnsprintf(szBuf, ARRAYSIZE(szBuf) - 1, TEXT("%02d%02d%02d%02d%02d%02d\tMsgTrace\tmsgs >= %dms\t%d\r\n"),
  1169. st.wYear, st.wMonth, st.wDay,
  1170. st.wHour, st.wMinute, st.wSecond,
  1171. g_pswi->dwStopWatchMaxMsgTime, g_pswi->dwcStopWatchOverflow);
  1172. WriteFile(hFile, szBuf, lstrlen(szBuf), &dwWritten, NULL);
  1173. #ifdef STOPWATCH_DEBUG
  1174. if(g_pswi->dwStopWatchMode & SPMODE_DEBUGOUT)
  1175. OutputDebugString(szBuf);
  1176. #endif
  1177. if(g_pswi->dwStopWatchTraceMsg > 0)
  1178. {
  1179. wnsprintf(szBuf, ARRAYSIZE(szBuf) - 1, TEXT("%02d%02d%02d%02d%02d%02d\tMsgTrace\tmsg 0x%x occured %d times.\r\n"),
  1180. st.wYear, st.wMonth, st.wDay,
  1181. st.wHour, st.wMinute, st.wSecond,
  1182. g_pswi->dwStopWatchTraceMsg, g_pswi->dwStopWatchTraceMsgCnt);
  1183. WriteFile(hFile, szBuf, lstrlen(szBuf), &dwWritten, NULL);
  1184. #ifdef STOPWATCH_DEBUG
  1185. if(g_pswi->dwStopWatchMode & SPMODE_DEBUGOUT)
  1186. OutputDebugString(szBuf);
  1187. #endif
  1188. }
  1189. FlushFileBuffers(hFile);
  1190. CloseHandle(hFile);
  1191. }
  1192. else
  1193. {
  1194. #ifdef STOPWATCH_DEBUG
  1195. wnsprintf(szBuf, ARRAYSIZE(szBuf) - 1, TEXT("CreateFile failed on '%s'. GLE=%d\n"), szFileName, GetLastError());
  1196. OutputDebugString(szBuf);
  1197. #endif
  1198. dwRC = ERROR_NO_DATA;
  1199. }
  1200. }
  1201. return(dwRC);
  1202. }
  1203. //===========================================================================================
  1204. // The following StopWatch messages are used to drive the timer msg handler. The timer proc is used
  1205. // as a means of delaying while watching paint messages. If the defined number of timer ticks has
  1206. // passed without getting any paint messages, then we mark the time of the last paint message we've
  1207. // saved as the stop time.
  1208. //===========================================================================================
  1209. VOID CALLBACK StopWatch_TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
  1210. {
  1211. StopWatch_TimerHandler(hwnd, 1, SWMSG_TIMER, NULL);
  1212. }
  1213. //===========================================================================================
  1214. //===========================================================================================
  1215. BOOL WINAPI StopWatch_TimerHandler(HWND hwnd, UINT uInc, DWORD dwFlag, MSG* pmsg)
  1216. {
  1217. static INT iNumTimersRcvd = 0;
  1218. static DWORD dwCnt = 0;
  1219. static BOOL bActive = FALSE;
  1220. static BOOL bHaveFirstPaintMsg = FALSE;
  1221. switch(dwFlag)
  1222. {
  1223. case SWMSG_PAINT:
  1224. if(bActive)
  1225. {
  1226. dwCnt = GetPerfTime(); // Save tick for last paint message
  1227. iNumTimersRcvd = 0; // Reset timers received count
  1228. if(!bHaveFirstPaintMsg)
  1229. {
  1230. TCHAR szClassName[40]; // If the class matches and its the first paint msg mark a lap time
  1231. LPCTSTR ptr;
  1232. GetClassName(pmsg->hwnd, szClassName, ARRAYSIZE(szClassName)-1);
  1233. ptr = g_pswi->pszClassNames;
  1234. while(*ptr)
  1235. {
  1236. if(lstrcmpi(szClassName, ptr) == 0)
  1237. {
  1238. bHaveFirstPaintMsg = TRUE;
  1239. StopWatch_LapTimed(SWID_FRAME, TEXT("Shell Frame 1st Paint"), SPMODE_SHELL | SPMODE_DEBUGOUT, dwCnt);
  1240. break;
  1241. }
  1242. ptr = ptr + (lstrlen(ptr) + 1);
  1243. }
  1244. }
  1245. }
  1246. break;
  1247. case SWMSG_TIMER:
  1248. iNumTimersRcvd += uInc;
  1249. if(iNumTimersRcvd >= 3) // If we've received this arbitrary # of timer msgs, mark stop time using the saved last paint tick count
  1250. {
  1251. const TCHAR c_szFmtShellStop[] = TEXT("Shell Frame Stop (%s)");
  1252. TCHAR szTitle[STOPWATCH_MAX_TITLE];
  1253. TCHAR szText[ARRAYSIZE(c_szFmtShellStop) + STOPWATCH_MAX_TITLE + 1];
  1254. KillTimer(hwnd, ID_STOPWATCH_TIMER);
  1255. GetWindowText(hwnd, szTitle, ARRAYSIZE(szTitle)-1);
  1256. wnsprintf(szText, ARRAYSIZE(szText), c_szFmtShellStop, szTitle);
  1257. StopWatch_StopTimed(SWID_FRAME, szText, SPMODE_SHELL | SPMODE_DEBUGOUT, dwCnt);
  1258. bHaveFirstPaintMsg = FALSE;
  1259. bActive = FALSE; // Done timing
  1260. if((g_pswi->dwStopWatchMode & (SPMODE_EVENT | SPMODE_SHELL)) == (SPMODE_EVENT | SPMODE_SHELL))
  1261. {
  1262. StopWatch_SignalEvent();
  1263. }
  1264. }
  1265. break;
  1266. case SWMSG_CREATE:
  1267. dwCnt = GetPerfTime(); // Save initial tick in case we don't have a paint when we exceed the # of SWMSG_TIMER above
  1268. iNumTimersRcvd = 0;
  1269. bHaveFirstPaintMsg = FALSE;
  1270. bActive = (BOOL)SetTimer(hwnd, ID_STOPWATCH_TIMER, g_pswi->dwStopWatchPaintInterval, StopWatch_TimerProc); // Use timer to determine when painting is done
  1271. break;
  1272. case SWMSG_STATUS:
  1273. break;
  1274. }
  1275. return(bActive); // Timing status active or not
  1276. }
  1277. //===========================================================================================
  1278. // This function is used to key off of WM_KEYDOWN to start timing when navigating inplace
  1279. //===========================================================================================
  1280. VOID WINAPI StopWatch_CheckMsg(HWND hwnd, MSG msg, LPCSTR lpStr)
  1281. {
  1282. TCHAR szText[80];
  1283. #ifdef STOPWATCH_DEBUG
  1284. if(g_pswi->dwStopWatchMode & SPMODE_TEST) // Used to verify message assumptions
  1285. {
  1286. wnsprintf((LPTSTR)szText, ARRAYSIZE(szText), TEXT("Hwnd=0x%08x Msg=0x%x\r\n"), msg.hwnd, msg.message);
  1287. OutputDebugString(szText);
  1288. }
  1289. #endif
  1290. if(g_pswi->dwStopWatchMode & SPMODE_SHELL)
  1291. {
  1292. if(!StopWatch_TimerHandler(hwnd, 0, SWMSG_STATUS, &msg) &&
  1293. (((msg.message == WM_KEYDOWN) && (msg.wParam == VK_RETURN)) ||
  1294. ((msg.message == WM_KEYDOWN) && (msg.wParam == VK_BACK)))
  1295. ) // Navigating within the same window
  1296. {
  1297. wnsprintf(szText, ARRAYSIZE(szText), TEXT("Shell Frame Same%s"), lpStr);
  1298. StopWatch_TimerHandler(hwnd, 0, SWMSG_CREATE, &msg);
  1299. StopWatch_Start(SWID_FRAME, szText, SPMODE_SHELL | SPMODE_DEBUGOUT);
  1300. }
  1301. }
  1302. // Compute the time it took to get the message. Then increment approp MsgTime bucket
  1303. if(g_pswi->dwStopWatchMode & SPMODE_MSGTRACE)
  1304. {
  1305. DWORD dwTick = GetTickCount();
  1306. DWORD dwElapsed;
  1307. #ifdef STOPWATCH_DEBUG
  1308. TCHAR szMsg[256];
  1309. #endif
  1310. g_pswi->dwStopWatchLastLocation = 0;
  1311. if(dwTick > msg.time)
  1312. {
  1313. dwElapsed = dwTick - msg.time;
  1314. if(dwElapsed >= g_pswi->dwStopWatchMaxMsgTime)
  1315. {
  1316. ++g_pswi->dwcStopWatchOverflow;
  1317. #ifdef STOPWATCH_DEBUG
  1318. if(g_pswi->dwStopWatchMode & SPMODE_DEBUGOUT)
  1319. {
  1320. TCHAR szClassName[40];
  1321. TCHAR szMsgName[20];
  1322. GetClassName(msg.hwnd, szClassName, ARRAYSIZE(szClassName) - 1);
  1323. if(g_pswi->pfnDecodeMessage != NULL)
  1324. StrCpyN(szMsgName, g_pswi->pfnDecodeMessage(msg.message), ARRAYSIZE(szMsgName) - 1);
  1325. else
  1326. wnsprintf(szMsgName, ARRAYSIZE(szMsgName) - 1, "0x%x", msg.message);
  1327. wnsprintf(szMsg, ARRAYSIZE(szMsg) - 1, TEXT("MsgTrace (%s) loc=%d, ms=%d >= %d, hwnd=%x, wndproc=%x, msg=%s, w=%x, l=%x\r\n"),
  1328. szClassName, g_pswi->dwStopWatchLastLocation, dwElapsed, g_pswi->dwStopWatchMaxMsgTime, msg.hwnd, GetClassLongPtr(msg.hwnd, GCLP_WNDPROC), szMsgName, msg.wParam, msg.lParam);
  1329. OutputDebugString(szMsg);
  1330. }
  1331. #endif
  1332. }
  1333. else
  1334. {
  1335. ++(*(g_pswi->pdwStopWatchMsgTime + (dwElapsed / g_pswi->dwStopWatchMsgInterval)));
  1336. }
  1337. }
  1338. if(g_pswi->dwStopWatchTraceMsg == msg.message)
  1339. ++g_pswi->dwStopWatchTraceMsgCnt;
  1340. g_pswi->dwStopWatchLastLocation = 0;
  1341. }
  1342. }
  1343. //===========================================================================================
  1344. //===========================================================================================
  1345. VOID WINAPI StopWatch_SetMsgLastLocation(DWORD dwLast)
  1346. {
  1347. g_pswi->dwStopWatchLastLocation = dwLast;
  1348. }
  1349. //===========================================================================================
  1350. // Logs messages that took longer than g_pswi->dwStopWatchMaxDispatchTime to be dispatched
  1351. //===========================================================================================
  1352. DWORD WINAPI StopWatch_DispatchTime(BOOL fStartTime, MSG msg, DWORD dwStart)
  1353. {
  1354. DWORD dwTime = 0;
  1355. TCHAR szMsg[256];
  1356. if(fStartTime)
  1357. {
  1358. if(g_pswi->dwStopWatchTraceMsg == msg.message)
  1359. CapBreak(TRUE);
  1360. StopWatch(SWID_MSGDISPATCH, TEXT("+Dispatch"), START_NODE, SPMODE_MSGTRACE | SPMODE_DEBUGOUT, dwStart);
  1361. dwTime = GetPerfTime();
  1362. }
  1363. else
  1364. {
  1365. dwTime = GetPerfTime();
  1366. if(g_pswi->dwStopWatchTraceMsg == msg.message)
  1367. CapBreak(FALSE);
  1368. if((dwTime - dwStart) >= g_pswi->dwStopWatchMaxDispatchTime)
  1369. {
  1370. TCHAR szClassName[40];
  1371. TCHAR szMsgName[20];
  1372. GetClassName(msg.hwnd, szClassName, ARRAYSIZE(szClassName) - 1);
  1373. if(g_pswi->pfnDecodeMessage != NULL)
  1374. StrCpyN(szMsgName, g_pswi->pfnDecodeMessage(msg.message), ARRAYSIZE(szMsgName) - 1);
  1375. else
  1376. wnsprintf(szMsgName, ARRAYSIZE(szMsgName) - 1, "0x%x", msg.message);
  1377. wnsprintf(szMsg, ARRAYSIZE(szMsg) - 1, TEXT("-Dispatch (%s) ms=%d > %d, hwnd=%x, wndproc=%x, msg=%s(%x), w=%x, l=%x"),
  1378. szClassName, dwTime - dwStart, g_pswi->dwStopWatchMaxDispatchTime, msg.hwnd, GetClassLongPtr(msg.hwnd, GCLP_WNDPROC), szMsgName, msg.message, msg.wParam, msg.lParam);
  1379. StopWatch(SWID_MSGDISPATCH, szMsg, STOP_NODE, SPMODE_MSGTRACE | SPMODE_DEBUGOUT, dwTime);
  1380. #ifdef STOPWATCH_DEBUG
  1381. if(g_pswi->dwStopWatchMode & SPMODE_DEBUGOUT)
  1382. {
  1383. lstrcat(szMsg, "\n");
  1384. OutputDebugString(szMsg);
  1385. }
  1386. #endif
  1387. }
  1388. }
  1389. return(dwTime);
  1390. }
  1391. //===========================================================================================
  1392. // Mark shell/browser frame creation start time
  1393. //===========================================================================================
  1394. VOID WINAPI StopWatch_MarkFrameStart(LPCSTR lpExplStr)
  1395. {
  1396. TCHAR szText[80];
  1397. DWORD dwTime = GetPerfTime();
  1398. if(g_pswi->dwStopWatchMode & SPMODE_SHELL)
  1399. {
  1400. wnsprintf(szText, ARRAYSIZE(szText), TEXT("Shell Frame Start%s"), lpExplStr);
  1401. StopWatch_StartTimed(SWID_FRAME, szText, SPMODE_SHELL | SPMODE_DEBUGOUT, dwTime);
  1402. }
  1403. if(g_pswi->dwStopWatchMode & SPMODE_BROWSER) // Used to get the start of browser total download time
  1404. {
  1405. StopWatch_LapTimed(SWID_BROWSER_FRAME, TEXT("Thread Start"), SPMODE_BROWSER | SPMODE_DEBUGOUT, dwTime);
  1406. }
  1407. if(g_pswi->dwStopWatchMode & SPMODE_JAVA) // Used to get the start of java applet load time
  1408. {
  1409. StopWatch_StartTimed(SWID_JAVA_APP, TEXT("Java Applet Start"), SPMODE_JAVA | SPMODE_DEBUGOUT, dwTime);
  1410. }
  1411. }
  1412. //===========================================================================================
  1413. // Mark shell/browser navigate in same frame start time
  1414. //===========================================================================================
  1415. VOID WINAPI StopWatch_MarkSameFrameStart(HWND hwnd)
  1416. {
  1417. DWORD dwTime = GetPerfTime();
  1418. if(g_pswi->dwStopWatchMode & SPMODE_SHELL)
  1419. {
  1420. StopWatch_TimerHandler(hwnd, 0, SWMSG_CREATE, NULL);
  1421. StopWatch_StartTimed(SWID_FRAME, TEXT("Shell Frame Same"), SPMODE_SHELL | SPMODE_DEBUGOUT, dwTime);
  1422. }
  1423. if(g_pswi->dwStopWatchMode & SPMODE_BROWSER) // Used to get browser total download time
  1424. {
  1425. StopWatch_StartTimed(SWID_BROWSER_FRAME, TEXT("Browser Frame Same"), SPMODE_BROWSER | SPMODE_DEBUGOUT, dwTime);
  1426. }
  1427. if(g_pswi->dwStopWatchMode & SPMODE_JAVA) // Used to get java applet load time
  1428. {
  1429. StopWatch_StartTimed(SWID_JAVA_APP, TEXT("Java Applet Same"), SPMODE_JAVA | SPMODE_DEBUGOUT, dwTime);
  1430. }
  1431. }
  1432. //===========================================================================================
  1433. // When browser or java perf timing mode is enabled, use "Done" or "Applet Started"
  1434. // in the status bar to get load time.
  1435. //===========================================================================================
  1436. VOID WINAPI StopWatch_MarkJavaStop(LPCSTR lpStringToSend, HWND hwnd, BOOL fChType)
  1437. {
  1438. const TCHAR c_szFmtJavaStop[] = TEXT("Java Applet Stop (%s)");
  1439. TCHAR szTitle[STOPWATCH_MAX_TITLE];
  1440. TCHAR szText[STOPWATCH_MAX_TITLE + ARRAYSIZE(c_szFmtJavaStop) + 1];
  1441. if(g_pswi->dwStopWatchMode & SPMODE_JAVA)
  1442. {
  1443. if((lpStringToSend != NULL) && (lstrncmpW((LPWSTR)lpStringToSend, TEXTW("Applet started"), ARRAYSIZE(TEXTW("Applet started"))) == 0))
  1444. {
  1445. GetWindowText(hwnd, szTitle, ARRAYSIZE(szTitle)-1);
  1446. wnsprintf(szText, ARRAYSIZE(szText), c_szFmtJavaStop, szTitle);
  1447. StopWatch_Stop(SWID_JAVA_APP, szText, SPMODE_SHELL | SPMODE_DEBUGOUT);
  1448. }
  1449. }
  1450. }
  1451. //===========================================================================================
  1452. //===========================================================================================
  1453. DWORD WINAPI GetPerfTime(VOID)
  1454. {
  1455. static __int64 freq;
  1456. __int64 curtime;
  1457. if (!freq)
  1458. QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
  1459. QueryPerformanceCounter((LARGE_INTEGER *)&curtime);
  1460. ASSERT((((curtime * 1000) / freq) >> 32) == 0);
  1461. return (DWORD)((curtime * 1000) / freq);
  1462. }