Source code of Windows XP (NT5)
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
13 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. pcall.c
  5. Abstract:
  6. This module contains the Windows NT system call display status.
  7. Author:
  8. Lou Perazzoli (LouP) 5-feb-1992.
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <assert.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <ctype.h>
  20. #define NUMBER_SERVICE_TABLES 2
  21. //
  22. // Define forward referenced routine prototypes.
  23. //
  24. VOID
  25. SortUlongData (
  26. IN ULONG Count,
  27. IN ULONG Index[],
  28. IN ULONG Data[]
  29. );
  30. #define BUFFER_SIZE 1024
  31. #define DELAY_TIME 1000
  32. #define TOP_CALLS 15
  33. extern UCHAR *CallTable[];
  34. ULONG Index[BUFFER_SIZE];
  35. ULONG CountBuffer1[BUFFER_SIZE];
  36. ULONG CountBuffer2[BUFFER_SIZE];
  37. ULONG CallData[BUFFER_SIZE];
  38. SYSTEM_CONTEXT_SWITCH_INFORMATION SystemSwitchInformation1;
  39. SYSTEM_CONTEXT_SWITCH_INFORMATION SystemSwitchInformation2;
  40. int
  41. __cdecl
  42. main(
  43. int argc,
  44. char *argv[]
  45. )
  46. {
  47. BOOLEAN Active;
  48. BOOLEAN CountSort;
  49. NTSTATUS status;
  50. ULONG i;
  51. COORD dest,cp;
  52. SMALL_RECT Sm;
  53. CHAR_INFO ci;
  54. CONSOLE_SCREEN_BUFFER_INFO sbi;
  55. KPRIORITY SetBasePriority;
  56. INPUT_RECORD InputRecord;
  57. HANDLE ScreenHandle;
  58. DWORD NumRead;
  59. SMALL_RECT Window;
  60. PSYSTEM_CALL_COUNT_INFORMATION CallCountInfo[2];
  61. PSYSTEM_CALL_COUNT_INFORMATION CurrentCallCountInfo;
  62. PSYSTEM_CALL_COUNT_INFORMATION PreviousCallCountInfo;
  63. PULONG CallCountTable[2];
  64. PULONG CurrentCallCountTable;
  65. PULONG PreviousCallCountTable;
  66. PSYSTEM_CONTEXT_SWITCH_INFORMATION SwitchInfo[2];
  67. PSYSTEM_CONTEXT_SWITCH_INFORMATION CurrentSwitchInfo;
  68. PSYSTEM_CONTEXT_SWITCH_INFORMATION PreviousSwitchInfo;
  69. ULONG Current;
  70. ULONG Previous;
  71. LARGE_INTEGER TimeDifference;
  72. ULONG ContextSwitches;
  73. ULONG FindAny;
  74. ULONG FindLast;
  75. ULONG IdleAny;
  76. ULONG IdleCurrent;
  77. ULONG IdleLast;
  78. ULONG PreemptAny;
  79. ULONG PreemptCurrent;
  80. ULONG PreemptLast;
  81. ULONG SwitchToIdle;
  82. ULONG TotalSystemCalls;
  83. ULONG SleepTime=1000;
  84. BOOLEAN ConsoleMode=TRUE;
  85. ULONG TopCalls=TOP_CALLS;
  86. BOOLEAN LoopMode = FALSE;
  87. BOOLEAN ShowSwitches = TRUE;
  88. PULONG p;
  89. ULONG NumberOfCounts;
  90. while (argc > 1) {
  91. argv++;
  92. if (_stricmp(argv[0],"-l") == 0) {
  93. LoopMode = TRUE;
  94. ConsoleMode = FALSE;
  95. TopCalls = BUFFER_SIZE;
  96. argc--;
  97. continue;
  98. }
  99. if (_stricmp(argv[0],"-s") == 0) {
  100. ShowSwitches = FALSE;
  101. argc--;
  102. continue;
  103. }
  104. SleepTime = atoi(argv[0]) * 1000;
  105. ConsoleMode = FALSE;
  106. TopCalls = BUFFER_SIZE;
  107. argc--;
  108. }
  109. SetBasePriority = (KPRIORITY)12;
  110. NtSetInformationProcess(
  111. NtCurrentProcess(),
  112. ProcessBasePriority,
  113. (PVOID) &SetBasePriority,
  114. sizeof(SetBasePriority)
  115. );
  116. Current = 0;
  117. Previous = 1;
  118. CallCountInfo[0] = (PVOID)CountBuffer1;
  119. CallCountInfo[1] = (PVOID)CountBuffer2;
  120. CallCountTable[0] = (PULONG)(CallCountInfo[0] + 1) + NUMBER_SERVICE_TABLES;
  121. CallCountTable[1] = (PULONG)(CallCountInfo[1] + 1) + NUMBER_SERVICE_TABLES;
  122. SwitchInfo[0] = &SystemSwitchInformation1;
  123. SwitchInfo[1] = &SystemSwitchInformation2;
  124. Current = 0;
  125. Previous = 1;
  126. CurrentCallCountInfo = CallCountInfo[0];
  127. CurrentCallCountTable = CallCountTable[0];
  128. CurrentSwitchInfo = SwitchInfo[0];
  129. PreviousCallCountInfo = CallCountInfo[1];
  130. PreviousCallCountTable = CallCountTable[1];
  131. PreviousSwitchInfo = SwitchInfo[1];
  132. //
  133. // Query system information and get the initial call count data.
  134. //
  135. status = NtQuerySystemInformation(SystemCallCountInformation,
  136. (PVOID)PreviousCallCountInfo,
  137. BUFFER_SIZE * sizeof(ULONG),
  138. NULL);
  139. if (NT_SUCCESS(status) == FALSE) {
  140. printf("Query count information failed %lx\n",status);
  141. return(status);
  142. }
  143. //
  144. // Make sure that the number of tables reported by the kernel matches
  145. // our list.
  146. //
  147. if (PreviousCallCountInfo->NumberOfTables != NUMBER_SERVICE_TABLES) {
  148. printf("System call table count (%d) doesn't match PCALL's count (%d)\n",
  149. PreviousCallCountInfo->NumberOfTables, NUMBER_SERVICE_TABLES);
  150. return STATUS_UNSUCCESSFUL;
  151. }
  152. //
  153. // Make sure call count information is available for base services.
  154. //
  155. p = (PULONG)(PreviousCallCountInfo + 1);
  156. if (p[0] == 0) {
  157. printf("No system call count information available for base services\n");
  158. return STATUS_UNSUCCESSFUL;
  159. }
  160. //
  161. // If there is a hole in the count information (i.e., one set of services
  162. // doesn't have counting enabled, but a subsequent one does, then our
  163. // indexes will be off, and we'll display the wrong service names.
  164. //
  165. for ( i = 2; i < NUMBER_SERVICE_TABLES; i++ ) {
  166. if ((p[i] != 0) && (p[i-1] == 0)) {
  167. printf("One or more call count tables empty. PCALL can't run\n");
  168. return STATUS_UNSUCCESSFUL;
  169. }
  170. }
  171. NumberOfCounts = (PreviousCallCountInfo->Length
  172. - sizeof(SYSTEM_CALL_COUNT_INFORMATION)
  173. - NUMBER_SERVICE_TABLES * sizeof(ULONG)) / sizeof(ULONG);
  174. //
  175. // Query system information and get the performance data.
  176. //
  177. if (ShowSwitches) {
  178. status = NtQuerySystemInformation(SystemContextSwitchInformation,
  179. (PVOID)PreviousSwitchInfo,
  180. sizeof(SYSTEM_CONTEXT_SWITCH_INFORMATION),
  181. NULL);
  182. if (NT_SUCCESS(status) == FALSE) {
  183. printf("Query context switch information failed %lx\n",status);
  184. return(status);
  185. }
  186. }
  187. if (ConsoleMode) {
  188. GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &sbi);
  189. Window.Left = 0;
  190. Window.Top = 0;
  191. Window.Right = 79;
  192. Window.Bottom = 23;
  193. dest.X = 0;
  194. dest.Y = 23;
  195. ci.Char.AsciiChar = ' ';
  196. ci.Attributes = sbi.wAttributes;
  197. SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE),
  198. TRUE,
  199. &Window);
  200. cp.X = 0;
  201. cp.Y = 0;
  202. Sm.Left = 0;
  203. Sm.Top = 0;
  204. Sm.Right = 79;
  205. Sm.Bottom = 22;
  206. ScrollConsoleScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE),
  207. &Sm,
  208. NULL,
  209. dest,
  210. &ci);
  211. SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cp);
  212. }
  213. //
  214. // Display title.
  215. //
  216. printf( " Count System Service\n");
  217. printf( "_______________________________________________________________\n");
  218. cp.X = 0;
  219. cp.Y = 2;
  220. Sm.Left = 0;
  221. Sm.Top = 2;
  222. Sm.Right = 79;
  223. Sm.Bottom = 22;
  224. ScreenHandle = GetStdHandle(STD_INPUT_HANDLE);
  225. Active = TRUE;
  226. CountSort = TRUE;
  227. while(TRUE) {
  228. Sleep(SleepTime);
  229. while (PeekConsoleInput (ScreenHandle, &InputRecord, 1, &NumRead) && NumRead != 0) {
  230. if (!ReadConsoleInput (ScreenHandle, &InputRecord, 1, &NumRead)) {
  231. break;
  232. }
  233. if (InputRecord.EventType == KEY_EVENT) {
  234. switch (InputRecord.Event.KeyEvent.uChar.AsciiChar) {
  235. case 'p':
  236. case 'P':
  237. Active = FALSE;
  238. break;
  239. case 'q':
  240. case 'Q':
  241. ExitProcess(0);
  242. break;
  243. default:
  244. Active = TRUE;
  245. break;
  246. }
  247. }
  248. }
  249. //
  250. // If not active, then sleep for 1000ms and attempt to get input
  251. // from the keyboard again.
  252. //
  253. if (Active == FALSE) {
  254. Sleep(1000);
  255. continue;
  256. }
  257. if (ConsoleMode) {
  258. //
  259. // Scroll the screen buffer down to make room for the next display.
  260. //
  261. ScrollConsoleScreenBuffer(GetStdHandle(STD_OUTPUT_HANDLE),
  262. &Sm,
  263. NULL,
  264. dest,
  265. &ci);
  266. SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cp);
  267. }
  268. //
  269. // Query system information and get the call count data.
  270. //
  271. status = NtQuerySystemInformation(SystemCallCountInformation,
  272. (PVOID)CurrentCallCountInfo,
  273. BUFFER_SIZE * sizeof(ULONG),
  274. NULL);
  275. if (NT_SUCCESS(status) == FALSE) {
  276. printf("Query count information failed %lx\n",status);
  277. return(status);
  278. }
  279. //
  280. // Query system information and get the performance data.
  281. //
  282. if (ShowSwitches) {
  283. status = NtQuerySystemInformation(SystemContextSwitchInformation,
  284. (PVOID)CurrentSwitchInfo,
  285. sizeof(SYSTEM_CONTEXT_SWITCH_INFORMATION),
  286. NULL);
  287. if (NT_SUCCESS(status) == FALSE) {
  288. printf("Query context switch information failed %lx\n",status);
  289. return(status);
  290. }
  291. }
  292. //
  293. // Compute number of system calls for each service, the total
  294. // number of system calls, and the total time for each serviced.
  295. //
  296. TotalSystemCalls = 0;
  297. for (i = 0; i < NumberOfCounts; i += 1) {
  298. CallData[i] = CurrentCallCountTable[i] - PreviousCallCountTable[i];
  299. TotalSystemCalls += CallData[i];
  300. }
  301. //
  302. // Sort the system call data.
  303. //
  304. SortUlongData(NumberOfCounts, Index, CallData);
  305. //
  306. // Compute context switch information.
  307. //
  308. if (ShowSwitches) {
  309. ContextSwitches =
  310. CurrentSwitchInfo->ContextSwitches - PreviousSwitchInfo->ContextSwitches;
  311. FindAny = CurrentSwitchInfo->FindAny - PreviousSwitchInfo->FindAny;
  312. FindLast = CurrentSwitchInfo->FindLast - PreviousSwitchInfo->FindLast;
  313. IdleAny = CurrentSwitchInfo->IdleAny - PreviousSwitchInfo->IdleAny;
  314. IdleCurrent = CurrentSwitchInfo->IdleCurrent - PreviousSwitchInfo->IdleCurrent;
  315. IdleLast = CurrentSwitchInfo->IdleLast - PreviousSwitchInfo->IdleLast;
  316. PreemptAny = CurrentSwitchInfo->PreemptAny - PreviousSwitchInfo->PreemptAny;
  317. PreemptCurrent = CurrentSwitchInfo->PreemptCurrent - PreviousSwitchInfo->PreemptCurrent;
  318. PreemptLast = CurrentSwitchInfo->PreemptLast - PreviousSwitchInfo->PreemptLast;
  319. SwitchToIdle = CurrentSwitchInfo->SwitchToIdle - PreviousSwitchInfo->SwitchToIdle;
  320. }
  321. //
  322. // Display the top services.
  323. //
  324. printf("\n");
  325. for (i = 0; i < TopCalls; i += 1) {
  326. if (CallData[Index[i]] == 0) {
  327. break;
  328. }
  329. printf("%8ld %s\n",
  330. CallData[Index[i]],
  331. CallTable[Index[i]]);
  332. }
  333. printf("\n");
  334. printf("Total System Calls %6ld\n", TotalSystemCalls);
  335. if (ShowSwitches) {
  336. printf("\n");
  337. printf("Context Switch Information\n");
  338. printf(" Find any processor %6ld\n", FindAny);
  339. printf(" Find last processor %6ld\n", FindLast);
  340. printf(" Idle any processor %6ld\n", IdleAny);
  341. printf(" Idle current processor %6ld\n", IdleCurrent);
  342. printf(" Idle last processor %6ld\n", IdleLast);
  343. printf(" Preempt any processor %6ld\n", PreemptAny);
  344. printf(" Preempt current processor %6ld\n", PreemptCurrent);
  345. printf(" Preempt last processor %6ld\n", PreemptLast);
  346. printf(" Switch to idle %6ld\n", SwitchToIdle);
  347. printf("\n");
  348. printf(" Total context switches %6ld\n", ContextSwitches);
  349. }
  350. //
  351. // Delay for the sleep interval swap the information buffers and
  352. // perform another iteration.
  353. //
  354. if (!ConsoleMode) {
  355. _flushall();
  356. }
  357. if ((ConsoleMode == FALSE) && (LoopMode == FALSE)) {
  358. ExitProcess(0);
  359. }
  360. Current = 1 - Current;
  361. Previous = 1 - Previous;
  362. CurrentCallCountInfo = CallCountInfo[Current];
  363. CurrentCallCountTable = CallCountTable[Current];
  364. CurrentSwitchInfo = SwitchInfo[Current];
  365. PreviousCallCountInfo = CallCountInfo[Previous];
  366. PreviousCallCountTable = CallCountTable[Previous];
  367. PreviousSwitchInfo = SwitchInfo[Previous];
  368. }
  369. }