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.

459 lines
16 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. perfdiag.cxx
  5. Abstract:
  6. Performance diagnostics
  7. Contents:
  8. WininetPerfLog
  9. PerfSleep
  10. PerfSelect
  11. PerfWaitForSingleObject
  12. (CPerfDiag::get_next_record)
  13. CPerfDiag::CPerfDiag
  14. CPerfDiag::~CPerfDiag
  15. CPerfDiag::Log(DWORD, DWORD)
  16. CPerfDiag::Log(DWORD, DWORD, DWORD, HINTERNET)
  17. CPerfDiag::Log(DWORD, DWORD, DWORD, DWORD, HINTERNET)
  18. CPerfDiag::Dump
  19. (map_perf_event)
  20. (map_callback_status)
  21. (map_async_request)
  22. (map_thread_pri)
  23. (map_length)
  24. Author:
  25. Richard L Firth (rfirth) 24-Jan-1997
  26. Revision History:
  27. 24-Jan-1997 rfirth
  28. Created
  29. --*/
  30. #include <wininetp.h>
  31. #if defined(USE_PERF_DIAG)
  32. #include <perfdiag.hxx>
  33. //
  34. // global data
  35. //
  36. GLOBAL CPerfDiag * GlobalPerfDiag = NULL;
  37. GLOBAL BOOL GlobalDumpPerfToFile = TRUE;
  38. //
  39. // private prototypes
  40. //
  41. PRIVATE LPSTR map_perf_event(DWORD dwEvent);
  42. PRIVATE LPSTR map_callback_status(DWORD dwStatus);
  43. PRIVATE LPSTR map_async_request(DWORD dwRequest);
  44. PRIVATE LPSTR map_thread_pri(DWORD dwPriority);
  45. PRIVATE LPSTR map_length(DWORD dwLength, LPSTR lpBuf);
  46. //
  47. // APIs
  48. //
  49. INTERNETAPI
  50. VOID
  51. WINAPI
  52. WininetPerfLog(
  53. IN DWORD dwEvent,
  54. IN DWORD dwInfo1,
  55. IN DWORD dwInfo2,
  56. IN HINTERNET hInternet
  57. ) {
  58. if (!GlobalPerfDiag) {
  59. GlobalPerfDiag = New CPerfDiag;
  60. }
  61. if (GlobalPerfDiag) {
  62. GlobalPerfDiag->Log(dwEvent, dwInfo1, dwInfo2, GetCurrentThreadId(), hInternet);
  63. }
  64. }
  65. //
  66. // functions
  67. //
  68. VOID PerfSleep(DWORD dwMilliseconds) {
  69. PERF_LOG(PE_YIELD_SLEEP_START);
  70. Sleep(dwMilliseconds);
  71. PERF_LOG(PE_YIELD_SLEEP_END);
  72. }
  73. int PerfSelect(int nfds,
  74. fd_set FAR * readfds,
  75. fd_set FAR * writefds,
  76. fd_set FAR * exceptfds,
  77. const struct timeval FAR * timeout
  78. ) {
  79. PERF_LOG(PE_YIELD_SELECT_START);
  80. int n = _I_select(nfds, readfds, writefds, exceptfds, timeout);
  81. PERF_LOG(PE_YIELD_SELECT_END);
  82. return n;
  83. }
  84. DWORD PerfWaitForSingleObject(
  85. HANDLE hObject,
  86. DWORD dwTimeout
  87. ) {
  88. PERF_LOG(PE_YIELD_OBJECT_WAIT_START);
  89. DWORD result = WaitForSingleObject(hObject, dwTimeout);
  90. PERF_LOG(PE_YIELD_OBJECT_WAIT_END);
  91. return result;
  92. }
  93. //
  94. // private methods
  95. //
  96. LPPERF_INFO CPerfDiag::get_next_record(VOID) {
  97. if (!m_lpbPerfBuffer || m_bFull) {
  98. return NULL;
  99. }
  100. LPBYTE lpbCurrent;
  101. LPBYTE lpbNext;
  102. LPBYTE result;
  103. do {
  104. lpbCurrent = m_lpbNext;
  105. lpbNext = lpbCurrent + sizeof(PERF_INFO);
  106. result = (LPBYTE)InterlockedExchangePointer((PVOID*)&m_lpbNext, lpbNext);
  107. } while ((result != (LPBYTE)lpbCurrent) && (lpbCurrent < m_lpbEnd));
  108. if (lpbCurrent >= m_lpbEnd) {
  109. m_bFull = TRUE;
  110. OutputDebugString("*** Wininet performance log is full!\n");
  111. lpbCurrent = NULL;
  112. }
  113. return (LPPERF_INFO)lpbCurrent;
  114. }
  115. //
  116. // public methods
  117. //
  118. CPerfDiag::CPerfDiag() {
  119. m_lpbPerfBuffer = NULL;
  120. m_dwPerfBufferLen = 0;
  121. m_lpbEnd = NULL;
  122. m_lpbNext = NULL;
  123. m_bFull = FALSE;
  124. m_bStarted = FALSE;
  125. m_bStartFinished = FALSE;
  126. m_liStartTime.QuadPart = 0i64;
  127. perf_start();
  128. }
  129. CPerfDiag::~CPerfDiag() {
  130. free_perf_buffer();
  131. }
  132. VOID CPerfDiag::Log(DWORD dwEvent, DWORD dwInfo) {
  133. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  134. if (lpThreadInfo) {
  135. Log(dwEvent, dwInfo, 0, lpThreadInfo->ThreadId, lpThreadInfo->hObject);
  136. }
  137. }
  138. VOID CPerfDiag::Log(DWORD dwEvent, DWORD dwInfo, DWORD dwThreadId, HINTERNET hInternet) {
  139. Log(dwEvent, dwInfo, 0, dwThreadId, hInternet);
  140. }
  141. VOID CPerfDiag::Log(DWORD dwEvent, DWORD dwInfo, DWORD dwInfo2, DWORD dwThreadId, HINTERNET hInternet) {
  142. //if (!m_bStarted) {
  143. // perf_start();
  144. //}
  145. LPPERF_INFO lpInfo = get_next_record();
  146. if (!lpInfo) {
  147. return;
  148. }
  149. lpInfo->hInternet = hInternet;
  150. lpInfo->dwThreadId = dwThreadId;
  151. lpInfo->dwThreadPriority = GetThreadPriority(GetCurrentThread());
  152. lpInfo->dwEvent = dwEvent;
  153. lpInfo->dwInfo = dwInfo;
  154. lpInfo->dwInfo2 = dwInfo2;
  155. get_time(lpInfo);
  156. }
  157. VOID CPerfDiag::Dump(VOID) {
  158. HANDLE hFile = INVALID_HANDLE_VALUE;
  159. static const char PerfFileName[] = "WININET.PRF";
  160. if (GlobalDumpPerfToFile) {
  161. hFile = CreateFile((LPCSTR)PerfFileName,
  162. GENERIC_WRITE,
  163. FILE_SHARE_READ,
  164. NULL,
  165. CREATE_ALWAYS,
  166. FILE_ATTRIBUTE_NORMAL,
  167. INVALID_HANDLE_VALUE
  168. );
  169. if (hFile == INVALID_HANDLE_VALUE) {
  170. OutputDebugString("failed to create perf file ");
  171. OutputDebugString((LPCSTR)PerfFileName);
  172. OutputDebugString("\n");
  173. GlobalDumpPerfToFile = FALSE;
  174. }
  175. }
  176. LARGE_INTEGER liFrequency;
  177. LONGLONG div1;
  178. LONGLONG div2;
  179. QueryPerformanceFrequency(&liFrequency);
  180. div1 = liFrequency.QuadPart;
  181. div2 = div1 / 1000000;
  182. LPPERF_INFO lpInfo;
  183. int record = 1;
  184. for (lpInfo = (LPPERF_INFO)m_lpbPerfBuffer; lpInfo != (LPPERF_INFO)m_lpbNext; ++lpInfo) {
  185. char buf[1024];
  186. LONGLONG ticks;
  187. DWORD microseconds;
  188. DWORD seconds;
  189. DWORD minutes;
  190. ticks = lpInfo->liTime.QuadPart - m_liStartTime.QuadPart;
  191. seconds = (DWORD)(ticks / div1);
  192. microseconds = (DWORD)((ticks % div1) / div2);
  193. //
  194. // don't understand why I have to do this? Win95 only (you could have guessed)
  195. // rounding error?
  196. //
  197. while (microseconds >= 1000000) {
  198. microseconds -= 1000000;
  199. ++seconds;
  200. }
  201. minutes = seconds / 60;
  202. seconds = seconds % 60;
  203. char lenbuf[32];
  204. char lenbuf2[32];
  205. int nChars = wsprintf(buf,
  206. "%5d: Delta=%.2d:%.2d.%.6d TID=%08x Pri=%-8s hReq=%06x Info=%08x %-24s %-22s %s\r\n",
  207. record,
  208. minutes,
  209. seconds,
  210. microseconds,
  211. lpInfo->dwThreadId,
  212. map_thread_pri(lpInfo->dwThreadPriority),
  213. lpInfo->hInternet,
  214. lpInfo->dwInfo,
  215. map_perf_event(lpInfo->dwEvent),
  216. ((lpInfo->dwEvent == PE_APP_CALLBACK_START)
  217. || (lpInfo->dwEvent == PE_APP_CALLBACK_END))
  218. ? map_callback_status(lpInfo->dwInfo)
  219. : (((lpInfo->dwEvent == PE_WORKER_REQUEST_START)
  220. || (lpInfo->dwEvent == PE_WORKER_REQUEST_END)
  221. || (lpInfo->dwEvent == PE_CLIENT_REQUEST_START)
  222. || (lpInfo->dwEvent == PE_CLIENT_REQUEST_END)
  223. || (lpInfo->dwEvent == PE_CLIENT_REQUEST_QUEUED))
  224. ? map_async_request(lpInfo->dwInfo)
  225. : (((lpInfo->dwEvent == PE_SEND_END)
  226. || (lpInfo->dwEvent == PE_RECEIVE_END))
  227. ? map_length(lpInfo->dwInfo2, lenbuf)
  228. : (((lpInfo->dwEvent == PE_ENTER_PATH)
  229. || (lpInfo->dwEvent == PE_LEAVE_PATH)
  230. || (lpInfo->dwEvent == PE_TRACE_PATH))
  231. ? (LPSTR)lpInfo->dwInfo2
  232. : ""))),
  233. (((lpInfo->dwEvent == PE_CLIENT_REQUEST_END)
  234. || (lpInfo->dwEvent == PE_WORKER_REQUEST_END))
  235. && ((lpInfo->dwInfo == AR_INTERNET_READ_FILE)
  236. || (lpInfo->dwInfo == AR_INTERNET_QUERY_DATA_AVAILABLE)))
  237. ? map_length(lpInfo->dwInfo2, lenbuf2)
  238. : ""
  239. );
  240. if (GlobalDumpPerfToFile) {
  241. DWORD nWritten;
  242. WriteFile(hFile, buf, nChars, &nWritten, NULL);
  243. } else {
  244. OutputDebugString(buf);
  245. }
  246. ++record;
  247. }
  248. if (hFile != INVALID_HANDLE_VALUE) {
  249. CloseHandle(hFile);
  250. }
  251. }
  252. PRIVATE LPSTR map_perf_event(DWORD dwEvent) {
  253. switch (dwEvent) {
  254. case PE_START: return "START";
  255. case PE_END: return "END";
  256. case PE_CLIENT_REQUEST_START: return "CLIENT_REQUEST_START";
  257. case PE_CLIENT_REQUEST_END: return "CLIENT_REQUEST_END";
  258. case PE_CLIENT_REQUEST_QUEUED: return "CLIENT_REQUEST_QUEUED";
  259. case PE_WORKER_REQUEST_START: return "WORKER_REQUEST_START";
  260. case PE_WORKER_REQUEST_END: return "WORKER_REQUEST_END";
  261. case PE_APP_CALLBACK_START: return "APP_CALLBACK_START";
  262. case PE_APP_CALLBACK_END: return "APP_CALLBACK_END";
  263. case PE_NAMERES_START: return "NAMERES_START";
  264. case PE_NAMERES_END: return "NAMERES_END";
  265. case PE_CONNECT_START: return "CONNECT_START";
  266. case PE_CONNECT_END: return "CONNECT_END";
  267. case PE_SEND_START: return "SEND_START";
  268. case PE_SEND_END: return "SEND_END";
  269. case PE_RECEIVE_START: return "RECEIVE_START";
  270. case PE_RECEIVE_END: return "RECEIVE_END";
  271. case PE_PEEK_RECEIVE_START: return "PEEK_RECEIVE_START";
  272. case PE_PEEK_RECEIVE_END: return "PEEK_RECEIVE_END";
  273. case PE_SOCKET_CLOSE_START: return "SOCKET_CLOSE_START";
  274. case PE_SOCKET_CLOSE_END: return "SOCKET_CLOSE_END";
  275. case PE_ACQUIRE_KEEP_ALIVE: return "ACQUIRE_KEEP_ALIVE";
  276. case PE_RELEASE_KEEP_ALIVE: return "RELEASE_KEEP_ALIVE";
  277. case PE_SOCKET_ERROR: return "SOCKET_ERROR";
  278. case PE_CACHE_READ_CHECK_START: return "CACHE_READ_CHECK_START";
  279. case PE_CACHE_READ_CHECK_END: return "CACHE_READ_CHECK_END";
  280. case PE_CACHE_WRITE_CHECK_START: return "CACHE_WRITE_CHECK_START";
  281. case PE_CACHE_WRITE_CHECK_END: return "CACHE_WRITE_CHECK_END";
  282. case PE_CACHE_RETRIEVE_START: return "CACHE_RETRIEVE_START";
  283. case PE_CACHE_RETRIEVE_END: return "CACHE_RETRIEVE_END";
  284. case PE_CACHE_READ_START: return "CACHE_READ_START";
  285. case PE_CACHE_READ_END: return "CACHE_READ_END";
  286. case PE_CACHE_WRITE_START: return "CACHE_WRITE_START";
  287. case PE_CACHE_WRITE_END: return "CACHE_WRITE_END";
  288. case PE_CACHE_CREATE_FILE_START: return "CACHE_CREATE_FILE_START";
  289. case PE_CACHE_CREATE_FILE_END: return "CACHE_CREATE_FILE_END";
  290. case PE_CACHE_CLOSE_FILE_START: return "CACHE_CLOSE_FILE_START";
  291. case PE_CACHE_CLOSE_FILE_END: return "CACHE_CLOSE_FILE_END";
  292. case PE_CACHE_EXPIRY_CHECK_START: return "CACHE_EXPIRY_CHECK_START";
  293. case PE_CACHE_EXPIRY_CHECK_END: return "CACHE_EXPIRY_CHECK_END";
  294. case PE_YIELD_SELECT_START: return "YIELD_SELECT_START";
  295. case PE_YIELD_SELECT_END: return "YIELD_SELECT_END";
  296. case PE_YIELD_OBJECT_WAIT_START: return "YIELD_OBJECT_WAIT_START";
  297. case PE_YIELD_OBJECT_WAIT_END: return "YIELD_OBJECT_WAIT_END";
  298. case PE_YIELD_SLEEP_START: return "YIELD_SLEEP_START";
  299. case PE_YIELD_SLEEP_END: return "YIELD_SLEEP_END";
  300. case PE_TRACE: return "TRACE";
  301. case PE_ENTER_PATH: return "ENTER_PATH";
  302. case PE_LEAVE_PATH: return "LEAVE_PATH";
  303. case PE_TRACE_PATH: return "TRACE_PATH";
  304. }
  305. return "?";
  306. }
  307. PRIVATE LPSTR map_callback_status(DWORD dwStatus) {
  308. switch (dwStatus) {
  309. case WINHTTP_CALLBACK_STATUS_RESOLVING_NAME: return "RESOLVING_NAME";
  310. case WINHTTP_CALLBACK_STATUS_NAME_RESOLVED: return "NAME_RESOLVED";
  311. case WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER: return "CONNECTING_TO_SERVER";
  312. case WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER: return "CONNECTED_TO_SERVER";
  313. case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST: return "SENDING_REQUEST";
  314. case WINHTTP_CALLBACK_STATUS_REQUEST_SENT: return "REQUEST_SENT";
  315. case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE: return "RECEIVING_RESPONSE";
  316. case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED: return "RESPONSE_RECEIVED";
  317. case WINHTTP_CALLBACK_STATUS_CTL_RESPONSE_RECEIVED: return "CTL_RESPONSE_RECEIVED";
  318. case WINHTTP_CALLBACK_STATUS_PREFETCH: return "PREFETCH";
  319. case WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION: return "CLOSING_CONNECTION";
  320. case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED: return "CONNECTION_CLOSED";
  321. case WINHTTP_CALLBACK_STATUS_HANDLE_CREATED: return "HANDLE_CREATED";
  322. case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING: return "HANDLE_CLOSING";
  323. case WINHTTP_CALLBACK_STATUS_REQUEST_COMPLETE: return "REQUEST_COMPLETE";
  324. case WINHTTP_CALLBACK_STATUS_REDIRECT: return "REDIRECT";
  325. case WINHTTP_CALLBACK_STATUS_STATE_CHANGE: return "STATE_CHANGE";
  326. case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: return "HEADERS_AVAILABLE";
  327. case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE: return "DATA_AVAILABLE";
  328. case WINHTTP_CALLBACK_STATUS_READ_COMPLETE: return "READ_COMPLETE";
  329. case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE: return "WRITE_COMPLETE";
  330. case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR: return "REQUEST_ERROR";
  331. }
  332. return "?";
  333. }
  334. PRIVATE LPSTR map_async_request(DWORD dwRequest) {
  335. switch (dwRequest) {
  336. case AR_INTERNET_CONNECT: return "InternetConnect";
  337. case AR_INTERNET_OPEN_URL: return "InternetOpenUrl";
  338. case AR_INTERNET_READ_FILE: return "InternetReadFile";
  339. case AR_INTERNET_WRITE_FILE: return "InternetWriteFile";
  340. case AR_INTERNET_QUERY_DATA_AVAILABLE: return "InternetQueryDataAvailable";
  341. case AR_INTERNET_FIND_NEXT_FILE: return "InternetFindNextFile";
  342. case AR_FTP_FIND_FIRST_FILE: return "FtpFindFirstFile";
  343. case AR_FTP_GET_FILE: return "FtpGetFile";
  344. case AR_FTP_PUT_FILE: return "FtpPutFile";
  345. case AR_FTP_DELETE_FILE: return "FtpDeleteFile";
  346. case AR_FTP_RENAME_FILE: return "FtpRenameFile";
  347. case AR_FTP_OPEN_FILE: return "FtpOpenFile";
  348. case AR_FTP_CREATE_DIRECTORY: return "FtpCreateDirectory";
  349. case AR_FTP_REMOVE_DIRECTORY: return "FtpRemoveDirectory";
  350. case AR_FTP_SET_CURRENT_DIRECTORY: return "FtpSetCurrentDirectory";
  351. case AR_FTP_GET_CURRENT_DIRECTORY: return "FtpGetCurrentDirectory";
  352. case AR_GOPHER_FIND_FIRST_FILE: return "GopherFindFirstFile";
  353. case AR_GOPHER_OPEN_FILE: return "GopherOpenFile";
  354. case AR_GOPHER_GET_ATTRIBUTE: return "GopherGetAttribute";
  355. case AR_HTTP_SEND_REQUEST: return "HttpSendRequest";
  356. case AR_READ_PREFETCH: return "READ_PREFETCH";
  357. case AR_SYNC_EVENT: return "SYNC_EVENT";
  358. case AR_TIMER_EVENT: return "TIMER_EVENT";
  359. }
  360. return "?";
  361. }
  362. PRIVATE LPSTR map_thread_pri(DWORD dwPriority) {
  363. switch (dwPriority) {
  364. case THREAD_PRIORITY_ABOVE_NORMAL:
  365. return "ABOVE";
  366. case THREAD_PRIORITY_BELOW_NORMAL:
  367. return "BELOW";
  368. case THREAD_PRIORITY_HIGHEST:
  369. return "HIGHEST";
  370. case THREAD_PRIORITY_IDLE:
  371. return "IDLE";
  372. case THREAD_PRIORITY_LOWEST:
  373. return "LOWEST";
  374. case THREAD_PRIORITY_NORMAL:
  375. return "NORMAL";
  376. case THREAD_PRIORITY_TIME_CRITICAL:
  377. return "TIMECRIT";
  378. }
  379. return "?";
  380. }
  381. PRIVATE LPSTR map_length(DWORD dwLength, LPSTR lpBuf) {
  382. wsprintf(lpBuf, "%d", dwLength);
  383. return lpBuf;
  384. }
  385. #endif // defined(USE_PERF_DIAG)