/*++ Copyright (c) 1989 Microsoft Corporation Module Name: ioPerf.c Abstract: This module contains the routines to collect performance info for driver calls... Author: Mike Fortin (mrfortin) May 8, 2000 Revision History: --*/ #include "iomgr.h" #if (( defined(_X86_) ) && ( FPO )) #pragma optimize( "y", off ) // disable FPO for consistent stack traces #endif NTSTATUS IoPerfInit( ); NTSTATUS IoPerfReset( ); NTSTATUS FASTCALL IoPerfCallDriver( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ); VOID FASTCALL IoPerfCompleteRequest ( IN PIRP Irp, IN CCHAR PriorityBoost ); #ifndef NTPERF #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGEWMI, IoPerfCallDriver) #pragma alloc_text(PAGEWMI, IoPerfInit) #pragma alloc_text(PAGEWMI, IoPerfReset) #endif #endif // NTPERF NTSTATUS IoPerfInit( ) { if ( IopVerifierOn ){ // We will not log driver hooks if the verifier has // also been turned on // Probably want to log some event or make a testenv note about // the perf implications of having the verifier turned on // return STATUS_UNSUCCESSFUL; } // // Enable and hook in the Perf Routines // InterlockedExchangePointer((PVOID *)&pIofCallDriver, (PVOID) IoPerfCallDriver); InterlockedExchangePointer((PVOID *)&pIofCompleteRequest, (PVOID) IoPerfCompleteRequest); ASSERT(KeGetCurrentIrql() <= APC_LEVEL); return STATUS_SUCCESS; } NTSTATUS IoPerfReset( ) { if ( IopVerifierOn ){ // We did not replace the function ptrs if the verifier // also was turned on, so just return // return STATUS_UNSUCCESSFUL; } // // Reset to init values, see IopSetIoRoutines // InterlockedExchangePointer((PVOID *)&pIofCallDriver, (PVOID) IopfCallDriver); InterlockedExchangePointer((PVOID *)&pIofCompleteRequest, (PVOID) IopfCompleteRequest); ASSERT(KeGetCurrentIrql() <= APC_LEVEL); return STATUS_SUCCESS; } ULONG IopPerfDriverUniqueMatchId=0; NTSTATUS FASTCALL IoPerfCallDriver( IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp ) /*++ Routine Description: This routine is invoked to pass an I/O Request Packet (IRP) to another driver at its dispatch routine, logging perf data along the way. Arguments: DeviceObject - Pointer to device object to which the IRP should be passed. Irp - Pointer to IRP for request. Return Value: Return status from driver's dispatch routine. --*/ { PIO_STACK_LOCATION irpSp; PDRIVER_OBJECT driverObject; NTSTATUS status; PVOID PerfInfoRoutineAddr; ULONG MatchId; #ifdef NTPERF ULONGLONG PerfInfoTimeOfCall = PerfGetCycleCount(); #endif // NTPERF // // Ensure that this is really an I/O Request Packet. // ASSERT( Irp->Type == IO_TYPE_IRP ); irpSp = IoGetNextIrpStackLocation( Irp ); // // Invoke the driver at its dispatch routine entry point. // driverObject = DeviceObject->DriverObject; // // Prevent the driver from unloading. // ObReferenceObject(DeviceObject); MatchId = InterlockedIncrement( &IopPerfDriverUniqueMatchId ); PerfInfoRoutineAddr = driverObject->MajorFunction[irpSp->MajorFunction]; // // Log the Call Event // if (PERFINFO_IS_GROUP_ON(PERF_DRIVERS)) { PERFINFO_DRIVER_MAJORFUNCTION MFInfo; MFInfo.MajorFunction = irpSp->MajorFunction; MFInfo.MinorFunction = irpSp->MinorFunction; MFInfo.RoutineAddr = driverObject->MajorFunction[irpSp->MajorFunction]; MFInfo.Irp = Irp; MFInfo.UniqMatchId = MatchId; if (Irp->Flags & IRP_ASSOCIATED_IRP) { ASSERT (Irp->AssociatedIrp.MasterIrp != NULL); if (Irp->AssociatedIrp.MasterIrp != NULL) { // // The check for MasterIrp is defensive code. // We have hit a bugcechk when a filter driver set the // IRP_ASSOCIATED_IRP bit while MasterIrp pointing to NULL. // // The ASSERT above was to catch similar problems before we release. // MFInfo.FileNamePointer = Irp->AssociatedIrp.MasterIrp->Tail.Overlay.OriginalFileObject; } else { MFInfo.FileNamePointer = NULL; } } else { MFInfo.FileNamePointer = Irp->Tail.Overlay.OriginalFileObject; } PerfInfoLogBytes( PERFINFO_LOG_TYPE_DRIVER_MAJORFUNCTION_CALL, &MFInfo, sizeof(MFInfo) ); } // // Do the normal IopfCallDriver work // status = IopfCallDriver(DeviceObject, Irp ); // // Log the Return // if (PERFINFO_IS_GROUP_ON(PERF_DRIVERS)) { PERFINFO_DRIVER_MAJORFUNCTION_RET MFInfo; MFInfo.Irp = Irp; MFInfo.UniqMatchId = MatchId; PERFINFO_DRIVER_INTENTIONAL_DELAY(); PerfInfoLogBytes( PERFINFO_LOG_TYPE_DRIVER_MAJORFUNCTION_RETURN, &MFInfo, sizeof(MFInfo) ); PERFINFO_DRIVER_STACKTRACE(); } ObDereferenceObject(DeviceObject); return status; } VOID FASTCALL IoPerfCompleteRequest ( IN PIRP Irp, IN CCHAR PriorityBoost ) /*++ Routine Description: This routine is invoked when a driver completes an IRP, logging perf data along the way. Arguments: Irp - Pointer to IRP for completed request. PriorityBoost - Priority boost specified by the driver completing the IRP. Return Value: None. --*/ { PERFINFO_DRIVER_COMPLETE_REQUEST CompleteRequest; PERFINFO_DRIVER_COMPLETE_REQUEST_RET CompleteRequestRet; PIO_STACK_LOCATION irpSp; PVOID DriverRoutineAddr; ULONG MatchId; // // Initialize locals. // DriverRoutineAddr = NULL; // // If the packet looks weird/improper pass it on to the real IO completion routine // directly. // if (Irp->Type != IO_TYPE_IRP || Irp->CurrentLocation > (CCHAR) (Irp->StackCount + 1)) { IopfCompleteRequest(Irp, PriorityBoost); return; } // // Get current stack location and save the driver routine address to // identify the driver that was processing the IRP when it got completed. If // device object is NULL, try to get the completion routine addr. // irpSp = IoGetCurrentIrpStackLocation( Irp ); if (irpSp->DeviceObject) { // // We don't want to cause a bugcheck in this code even when something else is // corrupt. // ASSERT(irpSp->DeviceObject->DriverObject); if (irpSp->DeviceObject->DriverObject) { ASSERT(irpSp->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION); if (irpSp->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION) { DriverRoutineAddr = irpSp->DeviceObject->DriverObject->MajorFunction[irpSp->MajorFunction]; } } } else { DriverRoutineAddr = irpSp->CompletionRoutine; } // // Bump the ID that gets used to match COMPLETE_REQUEST and COMPLETE_REQUEST_RET // entries logged for an IRP completion. // MatchId = InterlockedIncrement( &IopPerfDriverUniqueMatchId ); // // Log the start of the completion. // if (PERFINFO_IS_GROUP_ON(PERF_DRIVERS)) { CompleteRequest.Irp = Irp; CompleteRequest.UniqMatchId = MatchId; CompleteRequest.RoutineAddr = DriverRoutineAddr; PerfInfoLogBytes( PERFINFO_LOG_TYPE_DRIVER_COMPLETE_REQUEST, &CompleteRequest, sizeof(CompleteRequest) ); } // // Do the normal IopfCompleteIrp work. // IopfCompleteRequest(Irp, PriorityBoost); // // After this point no fields of Irp should be accessed. E.g. the Irp may // have been freed / reallocated etc. by a completion routine. // // // Log the return. // if (PERFINFO_IS_GROUP_ON(PERF_DRIVERS)) { CompleteRequestRet.Irp = Irp; CompleteRequestRet.UniqMatchId = MatchId; PerfInfoLogBytes( PERFINFO_LOG_TYPE_DRIVER_COMPLETE_REQUEST_RETURN, &CompleteRequestRet, sizeof(CompleteRequestRet) ); } return; } VOID IopPerfLogFileCreate( IN PFILE_OBJECT FileObject, IN PUNICODE_STRING CompleteName ) { PERFINFO_LOG_FILE_CREATE(FileObject, CompleteName); }