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.

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