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.

374 lines
9.6 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. ioPerf.c
  5. Abstract:
  6. This module contains the routines to collect performance info for driver calls...
  7. Author:
  8. Mike Fortin (mrfortin) May 8, 2000
  9. Revision History:
  10. --*/
  11. #include "iomgr.h"
  12. #if (( defined(_X86_) ) && ( FPO ))
  13. #pragma optimize( "y", off ) // disable FPO for consistent stack traces
  14. #endif
  15. NTSTATUS
  16. IoPerfInit(
  17. );
  18. NTSTATUS
  19. IoPerfReset(
  20. );
  21. NTSTATUS
  22. FASTCALL
  23. IoPerfCallDriver(
  24. IN PDEVICE_OBJECT DeviceObject,
  25. IN OUT PIRP Irp
  26. );
  27. VOID
  28. FASTCALL
  29. IoPerfCompleteRequest (
  30. IN PIRP Irp,
  31. IN CCHAR PriorityBoost
  32. );
  33. #ifndef NTPERF
  34. #ifdef ALLOC_PRAGMA
  35. #pragma alloc_text(PAGEWMI, IoPerfCallDriver)
  36. #pragma alloc_text(PAGEWMI, IoPerfInit)
  37. #pragma alloc_text(PAGEWMI, IoPerfReset)
  38. #endif
  39. #endif // NTPERF
  40. NTSTATUS
  41. IoPerfInit(
  42. )
  43. {
  44. if ( IopVerifierOn ){
  45. // We will not log driver hooks if the verifier has
  46. // also been turned on
  47. // Probably want to log some event or make a testenv note about
  48. // the perf implications of having the verifier turned on
  49. //
  50. return STATUS_UNSUCCESSFUL;
  51. }
  52. //
  53. // Enable and hook in the Perf Routines
  54. //
  55. InterlockedExchangePointer((PVOID *)&pIofCallDriver, (PVOID) IoPerfCallDriver);
  56. InterlockedExchangePointer((PVOID *)&pIofCompleteRequest, (PVOID) IoPerfCompleteRequest);
  57. ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
  58. return STATUS_SUCCESS;
  59. }
  60. NTSTATUS
  61. IoPerfReset(
  62. )
  63. {
  64. if ( IopVerifierOn ){
  65. // We did not replace the function ptrs if the verifier
  66. // also was turned on, so just return
  67. //
  68. return STATUS_UNSUCCESSFUL;
  69. }
  70. //
  71. // Reset to init values, see IopSetIoRoutines
  72. //
  73. InterlockedExchangePointer((PVOID *)&pIofCallDriver, (PVOID) IopfCallDriver);
  74. InterlockedExchangePointer((PVOID *)&pIofCompleteRequest, (PVOID) IopfCompleteRequest);
  75. ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
  76. return STATUS_SUCCESS;
  77. }
  78. ULONG IopPerfDriverUniqueMatchId=0;
  79. NTSTATUS
  80. FASTCALL
  81. IoPerfCallDriver(
  82. IN PDEVICE_OBJECT DeviceObject,
  83. IN OUT PIRP Irp
  84. )
  85. /*++
  86. Routine Description:
  87. This routine is invoked to pass an I/O Request Packet (IRP) to another
  88. driver at its dispatch routine, logging perf data along the way.
  89. Arguments:
  90. DeviceObject - Pointer to device object to which the IRP should be passed.
  91. Irp - Pointer to IRP for request.
  92. Return Value:
  93. Return status from driver's dispatch routine.
  94. --*/
  95. {
  96. PIO_STACK_LOCATION irpSp;
  97. PDRIVER_OBJECT driverObject;
  98. NTSTATUS status;
  99. PVOID PerfInfoRoutineAddr;
  100. ULONG MatchId;
  101. #ifdef NTPERF
  102. ULONGLONG PerfInfoTimeOfCall = PerfGetCycleCount();
  103. #endif // NTPERF
  104. //
  105. // Ensure that this is really an I/O Request Packet.
  106. //
  107. ASSERT( Irp->Type == IO_TYPE_IRP );
  108. irpSp = IoGetNextIrpStackLocation( Irp );
  109. //
  110. // Invoke the driver at its dispatch routine entry point.
  111. //
  112. driverObject = DeviceObject->DriverObject;
  113. //
  114. // Prevent the driver from unloading.
  115. //
  116. ObReferenceObject(DeviceObject);
  117. MatchId = InterlockedIncrement( &IopPerfDriverUniqueMatchId );
  118. PerfInfoRoutineAddr = driverObject->MajorFunction[irpSp->MajorFunction];
  119. //
  120. // Log the Call Event
  121. //
  122. if (PERFINFO_IS_GROUP_ON(PERF_DRIVERS)) {
  123. PERFINFO_DRIVER_MAJORFUNCTION MFInfo;
  124. MFInfo.MajorFunction = irpSp->MajorFunction;
  125. MFInfo.MinorFunction = irpSp->MinorFunction;
  126. MFInfo.RoutineAddr = driverObject->MajorFunction[irpSp->MajorFunction];
  127. MFInfo.Irp = Irp;
  128. MFInfo.UniqMatchId = MatchId;
  129. if (Irp->Flags & IRP_ASSOCIATED_IRP) {
  130. ASSERT (Irp->AssociatedIrp.MasterIrp != NULL);
  131. if (Irp->AssociatedIrp.MasterIrp != NULL) {
  132. //
  133. // The check for MasterIrp is defensive code.
  134. // We have hit a bugcechk when a filter driver set the
  135. // IRP_ASSOCIATED_IRP bit while MasterIrp pointing to NULL.
  136. //
  137. // The ASSERT above was to catch similar problems before we release.
  138. //
  139. MFInfo.FileNamePointer = Irp->AssociatedIrp.MasterIrp->Tail.Overlay.OriginalFileObject;
  140. } else {
  141. MFInfo.FileNamePointer = NULL;
  142. }
  143. } else {
  144. MFInfo.FileNamePointer = Irp->Tail.Overlay.OriginalFileObject;
  145. }
  146. PerfInfoLogBytes(
  147. PERFINFO_LOG_TYPE_DRIVER_MAJORFUNCTION_CALL,
  148. &MFInfo,
  149. sizeof(MFInfo)
  150. );
  151. }
  152. //
  153. // Do the normal IopfCallDriver work
  154. //
  155. status = IopfCallDriver(DeviceObject, Irp );
  156. //
  157. // Log the Return
  158. //
  159. if (PERFINFO_IS_GROUP_ON(PERF_DRIVERS)) {
  160. PERFINFO_DRIVER_MAJORFUNCTION_RET MFInfo;
  161. MFInfo.Irp = Irp;
  162. MFInfo.UniqMatchId = MatchId;
  163. PERFINFO_DRIVER_INTENTIONAL_DELAY();
  164. PerfInfoLogBytes(
  165. PERFINFO_LOG_TYPE_DRIVER_MAJORFUNCTION_RETURN,
  166. &MFInfo,
  167. sizeof(MFInfo)
  168. );
  169. PERFINFO_DRIVER_STACKTRACE();
  170. }
  171. ObDereferenceObject(DeviceObject);
  172. return status;
  173. }
  174. VOID
  175. FASTCALL
  176. IoPerfCompleteRequest (
  177. IN PIRP Irp,
  178. IN CCHAR PriorityBoost
  179. )
  180. /*++
  181. Routine Description:
  182. This routine is invoked when a driver completes an IRP, logging perf data
  183. along the way.
  184. Arguments:
  185. Irp - Pointer to IRP for completed request.
  186. PriorityBoost - Priority boost specified by the driver completing the IRP.
  187. Return Value:
  188. None.
  189. --*/
  190. {
  191. PERFINFO_DRIVER_COMPLETE_REQUEST CompleteRequest;
  192. PERFINFO_DRIVER_COMPLETE_REQUEST_RET CompleteRequestRet;
  193. PIO_STACK_LOCATION irpSp;
  194. PVOID DriverRoutineAddr;
  195. ULONG MatchId;
  196. //
  197. // Initialize locals.
  198. //
  199. DriverRoutineAddr = NULL;
  200. //
  201. // If the packet looks weird/improper pass it on to the real IO completion routine
  202. // directly.
  203. //
  204. if (Irp->Type != IO_TYPE_IRP || Irp->CurrentLocation > (CCHAR) (Irp->StackCount + 1)) {
  205. IopfCompleteRequest(Irp, PriorityBoost);
  206. return;
  207. }
  208. //
  209. // Get current stack location and save the driver routine address to
  210. // identify the driver that was processing the IRP when it got completed. If
  211. // device object is NULL, try to get the completion routine addr.
  212. //
  213. irpSp = IoGetCurrentIrpStackLocation( Irp );
  214. if (irpSp->DeviceObject) {
  215. //
  216. // We don't want to cause a bugcheck in this code even when something else is
  217. // corrupt.
  218. //
  219. ASSERT(irpSp->DeviceObject->DriverObject);
  220. if (irpSp->DeviceObject->DriverObject) {
  221. ASSERT(irpSp->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION);
  222. if (irpSp->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION) {
  223. DriverRoutineAddr = irpSp->DeviceObject->DriverObject->MajorFunction[irpSp->MajorFunction];
  224. }
  225. }
  226. } else {
  227. DriverRoutineAddr = irpSp->CompletionRoutine;
  228. }
  229. //
  230. // Bump the ID that gets used to match COMPLETE_REQUEST and COMPLETE_REQUEST_RET
  231. // entries logged for an IRP completion.
  232. //
  233. MatchId = InterlockedIncrement( &IopPerfDriverUniqueMatchId );
  234. //
  235. // Log the start of the completion.
  236. //
  237. if (PERFINFO_IS_GROUP_ON(PERF_DRIVERS)) {
  238. CompleteRequest.Irp = Irp;
  239. CompleteRequest.UniqMatchId = MatchId;
  240. CompleteRequest.RoutineAddr = DriverRoutineAddr;
  241. PerfInfoLogBytes(
  242. PERFINFO_LOG_TYPE_DRIVER_COMPLETE_REQUEST,
  243. &CompleteRequest,
  244. sizeof(CompleteRequest)
  245. );
  246. }
  247. //
  248. // Do the normal IopfCompleteIrp work.
  249. //
  250. IopfCompleteRequest(Irp, PriorityBoost);
  251. //
  252. // After this point no fields of Irp should be accessed. E.g. the Irp may
  253. // have been freed / reallocated etc. by a completion routine.
  254. //
  255. //
  256. // Log the return.
  257. //
  258. if (PERFINFO_IS_GROUP_ON(PERF_DRIVERS)) {
  259. CompleteRequestRet.Irp = Irp;
  260. CompleteRequestRet.UniqMatchId = MatchId;
  261. PerfInfoLogBytes(
  262. PERFINFO_LOG_TYPE_DRIVER_COMPLETE_REQUEST_RETURN,
  263. &CompleteRequestRet,
  264. sizeof(CompleteRequestRet)
  265. );
  266. }
  267. return;
  268. }
  269. VOID
  270. IopPerfLogFileCreate(
  271. IN PFILE_OBJECT FileObject,
  272. IN PUNICODE_STRING CompleteName
  273. )
  274. {
  275. PERFINFO_LOG_FILE_CREATE(FileObject, CompleteName);
  276. }