From eb3b9049a9887ebb270123b88caa62c7eda1f29d Mon Sep 17 00:00:00 2001 From: Casper Hornstrup Date: Wed, 15 Jan 2003 19:58:07 +0000 Subject: [PATCH] 2003-01-15 Casper S. Hornstrup * ntoskrnl/dbg/profile.c: New file. * ntoskrnl/Makefile (OBJECTS_KDBG): Add dbg/profile.o. * ntoskrnl/dbg/kdb.h: Define NTOS_MODE_KERNEL. Include . (LdrGetAddressInformation, KdbInitProfiling, KdbInitProfiling2, KdbDisableProfiling, KdbEnableProfiling, KdbProfileInterrupt) Prototype. * ntoskrnl/kd/kdebug.c (KdInitSystem): Add /PROFILE option if KDBG=1. * ntoskrnl/ke/main.c (ExpInitializeExecutive): Call KdbInitProfiling2() if KDBG=1. * ntoskrnl/ke/i386/irq.c: Include <../dbg/kdb.h> if KDBG=1. (KiInterruptDispatch): Call KdbProfileInterrupt() on timer interrupt if KDBG=1. svn path=/trunk/; revision=4001 --- reactos/ChangeLog | 14 + reactos/ntoskrnl/Makefile | 4 +- reactos/ntoskrnl/cc/misc.c | 4 +- reactos/ntoskrnl/dbg/kdb.h | 20 ++ reactos/ntoskrnl/dbg/profile.c | 500 +++++++++++++++++++++++++++++++++ reactos/ntoskrnl/kd/kdebug.c | 8 +- reactos/ntoskrnl/ke/i386/irq.c | 15 +- reactos/ntoskrnl/ke/main.c | 6 +- 8 files changed, 565 insertions(+), 6 deletions(-) create mode 100755 reactos/ntoskrnl/dbg/profile.c diff --git a/reactos/ChangeLog b/reactos/ChangeLog index c3b6c8b8b93..9a2969219b5 100644 --- a/reactos/ChangeLog +++ b/reactos/ChangeLog @@ -1,3 +1,17 @@ +2003-01-15 Casper S. Hornstrup + + * ntoskrnl/dbg/profile.c: New file. + * ntoskrnl/Makefile (OBJECTS_KDBG): Add dbg/profile.o. + * ntoskrnl/dbg/kdb.h: Define NTOS_MODE_KERNEL. Include . + (LdrGetAddressInformation, KdbInitProfiling, KdbInitProfiling2, + KdbDisableProfiling, KdbEnableProfiling, KdbProfileInterrupt) Prototype. + * ntoskrnl/kd/kdebug.c (KdInitSystem): Add /PROFILE option if KDBG=1. + * ntoskrnl/ke/main.c (ExpInitializeExecutive): Call KdbInitProfiling2() + if KDBG=1. + * ntoskrnl/ke/i386/irq.c: Include <../dbg/kdb.h> if KDBG=1. + (KiInterruptDispatch): Call KdbProfileInterrupt() on timer interrupt + if KDBG=1. + 2003-01-15 Casper S. Hornstrup * drivers/fs/vfat/create.c (VfatSupersedeFile): Only notify cache manager diff --git a/reactos/ntoskrnl/Makefile b/reactos/ntoskrnl/Makefile index a98d6e3c9c4..01377f7795c 100644 --- a/reactos/ntoskrnl/Makefile +++ b/reactos/ntoskrnl/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.89 2003/01/07 17:48:11 robd Exp $ +# $Id: Makefile,v 1.90 2003/01/15 19:58:06 chorns Exp $ # # ReactOS Operating System # @@ -27,7 +27,7 @@ endif ifeq ($(KDBG), 1) OBJECTS_KDBG := dbg/kdb.o dbg/kdb_keyboard.o dbg/rdebug.o \ - dbg/i386/kdb_help.o dbg/kdb_stabs.o + dbg/i386/kdb_help.o dbg/kdb_stabs.o dbg/profile.o else OBJECTS_KDBG := endif diff --git a/reactos/ntoskrnl/cc/misc.c b/reactos/ntoskrnl/cc/misc.c index 18bf9cffc12..4ddeb66a3f5 100644 --- a/reactos/ntoskrnl/cc/misc.c +++ b/reactos/ntoskrnl/cc/misc.c @@ -74,7 +74,7 @@ CcSetFileSizes (IN PFILE_OBJECT FileObject, PLIST_ENTRY current_entry; PCACHE_SEGMENT current; - DPRINT("CcSetFileSizes(FileObject %x, FileSizes %x)\n", + DPRINT1("CcSetFileSizes(FileObject %x, FileSizes %x)\n", FileObject, FileSizes); DPRINT("AllocationSize %d, FileSize %d, ValidDataLength %d\n", (ULONG)FileSizes->AllocationSize.QuadPart, @@ -82,6 +82,8 @@ CcSetFileSizes (IN PFILE_OBJECT FileObject, (ULONG)FileSizes->ValidDataLength.QuadPart); Bcb = ((REACTOS_COMMON_FCB_HEADER*)FileObject->FsContext)->Bcb; + + DPRINT1("Bcb 0x%.08x\n", Bcb); KeAcquireSpinLock(&Bcb->BcbLock, &oldirql); diff --git a/reactos/ntoskrnl/dbg/kdb.h b/reactos/ntoskrnl/dbg/kdb.h index 570759ea109..fed6cbc9d7f 100644 --- a/reactos/ntoskrnl/dbg/kdb.h +++ b/reactos/ntoskrnl/dbg/kdb.h @@ -1,3 +1,13 @@ +#define NTOS_MODE_KERNEL +#include + +NTSTATUS +LdrGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo, + IN ULONG_PTR RelativeAddress, + OUT PULONG LineNumber, + OUT PCH FileName OPTIONAL, + OUT PCH FunctionName OPTIONAL); + ULONG KdbTryGetCharKeyboard(VOID); VOID @@ -10,3 +20,13 @@ VOID DbgEnableFile(PCH Filename); VOID DbgDisableFile(PCH Filename); +VOID +KdbInitProfiling(); +VOID +KdbInitProfiling2(); +VOID +KdbDisableProfiling(); +VOID +KdbEnableProfiling(); +VOID +KdbProfileInterrupt(ULONG_PTR Eip); diff --git a/reactos/ntoskrnl/dbg/profile.c b/reactos/ntoskrnl/dbg/profile.c new file mode 100755 index 00000000000..52b5a85acda --- /dev/null +++ b/reactos/ntoskrnl/dbg/profile.c @@ -0,0 +1,500 @@ +/* + * ReactOS kernel + * Copyright (C) 1998-2003 ReactOS Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* $Id: profile.c,v 1.1 2003/01/15 19:58:07 chorns Exp $ + * + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/dbg/profile.c + * PURPOSE: Kernel profiling + * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * UPDATE HISTORY: + * Created 12/01/2003 + */ + +/* INCLUDES *****************************************************************/ + +#define NTOS_MODE_KERNEL +#include +#include +#include "kdb.h" + +#define NDEBUG +#include + +/* FUNCTIONS *****************************************************************/ + +#define PROFILE_SESSION_LENGTH 30 /* Session length in seconds */ + +typedef struct _PROFILE_DATABASE_ENTRY +{ + ULONG_PTR Address; +} PROFILE_DATABASE_ENTRY, *PPROFILE_DATABASE_ENTRY; + +#define PDE_BLOCK_ENTRIES ((PAGE_SIZE - (sizeof(LIST_ENTRY) + sizeof(ULONG))) / sizeof(PROFILE_DATABASE_ENTRY)) + +typedef struct _PROFILE_DATABASE_BLOCK +{ + LIST_ENTRY ListEntry; + ULONG UsedEntries; + PROFILE_DATABASE_ENTRY Entries[PDE_BLOCK_ENTRIES]; +} PROFILE_DATABASE_BLOCK, *PPROFILE_DATABASE_BLOCK; + +typedef struct _PROFILE_DATABASE +{ + LIST_ENTRY ListHead; +} PROFILE_DATABASE, *PPROFILE_DATABASE; + +typedef struct _SAMPLE_GROUP_INFO +{ + ULONG_PTR Address; + ULONG Count; + CHAR Description[128]; + LIST_ENTRY ListEntry; +} SAMPLE_GROUP_INFO, *PSAMPLE_GROUP_INFO; + +static volatile BOOLEAN KdbProfilingInitialized = FALSE; +static volatile BOOLEAN KdbProfilingEnabled = FALSE; +static volatile BOOLEAN KdbProfilingSuspended = FALSE; +static PPROFILE_DATABASE KdbProfileDatabase = NULL; +static KDPC KdbProfilerCollectorDpc; +static HANDLE KdbProfilerThreadHandle; +static CLIENT_ID KdbProfilerThreadCid; +static HANDLE KdbProfilerLogFile; +static KTIMER KdbProfilerTimer; +static KMUTEX KdbProfilerLock; +static BOOLEAN KdbEnableProfiler = FALSE; + +VOID +KdbDeleteProfileDatabase(PPROFILE_DATABASE ProfileDatabase) +{ + PLIST_ENTRY current = NULL; + + current = RemoveHeadList(&ProfileDatabase->ListHead); + while (current != &ProfileDatabase->ListHead) + { + PPROFILE_DATABASE_BLOCK block = CONTAINING_RECORD( + current, PROFILE_DATABASE_BLOCK, ListEntry); + ExFreePool(block); + current = RemoveHeadList(&ProfileDatabase->ListHead); + } +} + +VOID +KdbAddEntryToProfileDatabase(PPROFILE_DATABASE ProfileDatabase, ULONG_PTR Address) +{ + PPROFILE_DATABASE_BLOCK block; + + if (IsListEmpty(&ProfileDatabase->ListHead)) + { + block = ExAllocatePool(NonPagedPool, sizeof(PROFILE_DATABASE_BLOCK)); + assert(block); + block->UsedEntries = 0; + InsertTailList(&ProfileDatabase->ListHead, &block->ListEntry); + block->Entries[block->UsedEntries++].Address = Address; + return; + } + + block = CONTAINING_RECORD(ProfileDatabase->ListHead.Blink, PROFILE_DATABASE_BLOCK, ListEntry); + if (block->UsedEntries >= PDE_BLOCK_ENTRIES) + { + block = ExAllocatePool(NonPagedPool, sizeof(PROFILE_DATABASE_BLOCK)); + assert(block); + block->UsedEntries = 0; + InsertTailList(&ProfileDatabase->ListHead, &block->ListEntry); + } + block->Entries[block->UsedEntries++].Address = Address; +} + +VOID +KdbInitProfiling() +{ + KdbEnableProfiler = TRUE; +} + +VOID +KdbInitProfiling2() +{ + if (KdbEnableProfiler) + { + KdbEnableProfiling(); + KdbProfilingInitialized = TRUE; + } +} + +VOID +KdbSuspendProfiling() +{ + KdbProfilingSuspended = TRUE; +} + +VOID +KdbResumeProfiling() +{ + KdbProfilingSuspended = FALSE; +} + +BOOLEAN +KdbProfilerGetSymbolInfo(PVOID address, OUT PCH NameBuffer) +{ + PLIST_ENTRY current_entry; + MODULE_TEXT_SECTION* current; + extern LIST_ENTRY ModuleTextListHead; + ULONG_PTR RelativeAddress; + NTSTATUS Status; + ULONG LineNumber; + CHAR FileName[256]; + CHAR FunctionName[256]; + + current_entry = ModuleTextListHead.Flink; + + while (current_entry != &ModuleTextListHead && + current_entry != NULL) + { + current = + CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry); + + if (address >= (PVOID)current->Base && + address < (PVOID)(current->Base + current->Length)) + { + RelativeAddress = (ULONG_PTR) address - current->Base; + Status = LdrGetAddressInformation(¤t->SymbolInfo, + RelativeAddress, + &LineNumber, + FileName, + FunctionName); + if (NT_SUCCESS(Status)) + { + sprintf(NameBuffer, "%s (%s)", FileName, FunctionName); + return(TRUE); + } + return(TRUE); + } + current_entry = current_entry->Flink; + } + return(FALSE); +} + +PLIST_ENTRY +KdbProfilerLargestSampleGroup(PLIST_ENTRY SamplesListHead) +{ + PLIST_ENTRY current; + PLIST_ENTRY largest; + ULONG count; + + count = 0; + largest = SamplesListHead->Flink; + current = SamplesListHead->Flink; + while (current != SamplesListHead) + { + PSAMPLE_GROUP_INFO sgi = CONTAINING_RECORD( + current, SAMPLE_GROUP_INFO, ListEntry); + + if (sgi->Count > count) + { + largest = current; + count = sgi->Count; + } + + current = current->Flink; + } + if (count == 0) + { + return NULL; + } + return largest; +} + +VOID +KdbProfilerWriteString(PCH String) +{ + IO_STATUS_BLOCK Iosb; + NTSTATUS Status; + ULONG Length; + + Length = strlen(String); + Status = NtWriteFile(KdbProfilerLogFile, + NULL, + NULL, + NULL, + &Iosb, + String, + Length, + NULL, + NULL); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtWriteFile() failed with status 0x%.08x\n", Status); + } +} + +NTSTATUS +KdbProfilerWriteSampleGroups(PLIST_ENTRY SamplesListHead) +{ + CHAR Buffer[256]; + PLIST_ENTRY current = NULL; + PLIST_ENTRY Largest; + + KdbProfilerWriteString("\r\n\r\n"); + KdbProfilerWriteString("Count Symbol\n"); + KdbProfilerWriteString("--------------------------------------------------\r\n"); + + current = SamplesListHead->Flink; + while (current != SamplesListHead) + { + Largest = KdbProfilerLargestSampleGroup(SamplesListHead); + if (Largest != NULL) + { + PSAMPLE_GROUP_INFO sgi = CONTAINING_RECORD( + Largest, SAMPLE_GROUP_INFO, ListEntry); + + //DbgPrint("%.08d %s\n", sgi->Count, sgi->Description); + + sprintf(Buffer, "%.08d %s\r\n", sgi->Count, sgi->Description); + KdbProfilerWriteString(Buffer); + + RemoveEntryList(Largest); + ExFreePool(sgi); + } + else + { + break; + } + + current = SamplesListHead->Flink; + } + + return STATUS_SUCCESS; +} + +LONG STDCALL +KdbProfilerKeyCompare(IN PVOID Key1, + IN PVOID Key2) +{ + int value = strcmp(Key1, Key2); + + if (value == 0) + return 0; + + return (value < 0) ? -1 : 1; +} + + +NTSTATUS +KdbProfilerAnalyzeSamples() +{ + CHAR NameBuffer[512]; + ULONG KeyLength; + PLIST_ENTRY current = NULL; + HASH_TABLE Hashtable; + LIST_ENTRY SamplesListHead; + ULONG Index; + ULONG_PTR Address; + + if (!ExInitializeHashTable(&Hashtable, 17, KdbProfilerKeyCompare, TRUE)) + { + DPRINT1("ExInitializeHashTable() failed."); + KeBugCheck(0); + } + + InitializeListHead(&SamplesListHead); + + current = RemoveHeadList(&KdbProfileDatabase->ListHead); + while (current != &KdbProfileDatabase->ListHead) + { + PPROFILE_DATABASE_BLOCK block; + + block = CONTAINING_RECORD(current, PROFILE_DATABASE_BLOCK, ListEntry); + + for (Index = 0; Index < block->UsedEntries; Index++) + { + PSAMPLE_GROUP_INFO sgi; + Address = block->Entries[Index].Address; + if (KdbProfilerGetSymbolInfo((PVOID) Address, (PCH) &NameBuffer)) + { + } + else + { + sprintf(NameBuffer, "(0x%.08x)", (ULONG) Address); + } + + KeyLength = strlen(NameBuffer); + if (!ExSearchHashTable(&Hashtable, (PVOID) NameBuffer, KeyLength, (PVOID *) &sgi)) + { + sgi = ExAllocatePool(NonPagedPool, sizeof(SAMPLE_GROUP_INFO)); + assert(sgi); + sgi->Address = Address; + sgi->Count = 1; + strcpy(sgi->Description, NameBuffer); + InsertTailList(&SamplesListHead, &sgi->ListEntry); + ExInsertHashTable(&Hashtable, sgi->Description, KeyLength, (PVOID) sgi); + } + else + { + sgi->Count++; + } + } + + ExFreePool(block); + + current = RemoveHeadList(&KdbProfileDatabase->ListHead); + } + + KdbProfilerWriteSampleGroups(&SamplesListHead); + + ExDeleteHashTable(&Hashtable); + + KdbDeleteProfileDatabase(KdbProfileDatabase); + + return STATUS_SUCCESS; +} + +NTSTATUS +KdbProfilerThreadMain(PVOID Context) +{ + for (;;) + { + KeWaitForSingleObject(&KdbProfilerTimer, Executive, KernelMode, TRUE, NULL); + + KeWaitForSingleObject(&KdbProfilerLock, Executive, KernelMode, FALSE, NULL); + + KdbSuspendProfiling(); + + KdbProfilerAnalyzeSamples(); + + KdbResumeProfiling(); + + KeReleaseMutex(&KdbProfilerLock, FALSE); + } +} + +VOID +KdbDisableProfiling() +{ + if (KdbProfilingEnabled == TRUE) + { + /* FIXME: Implement */ +#if 0 + KdbProfilingEnabled = FALSE; + /* Stop timer */ + /* Close file */ + if (KdbProfileDatabase != NULL) + { + KdbDeleteProfileDatabase(KdbProfileDatabase); + ExFreePool(KdbProfileDatabase); + KdbProfileDatabase = NULL; + } +#endif + } +} + +/* + * SystemArgument1 = EIP + */ +static VOID STDCALL +KdbProfilerCollectorDpcRoutine(PKDPC Dpc, PVOID DeferredContext, + PVOID SystemArgument1, PVOID SystemArgument2) +{ + ULONG_PTR address = (ULONG_PTR) SystemArgument1; + + KdbAddEntryToProfileDatabase(KdbProfileDatabase, address); +} + +VOID +KdbEnableProfiling() +{ + if (KdbProfilingEnabled == FALSE) + { + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING FileName; + IO_STATUS_BLOCK Iosb; + LARGE_INTEGER DueTime; + + RtlInitUnicodeString(&FileName, L"\\SystemRoot\\profiler.log"); + InitializeObjectAttributes(&ObjectAttributes, + &FileName, + 0, + NULL, + NULL); + + Status = NtCreateFile(&KdbProfilerLogFile, + FILE_ALL_ACCESS, + &ObjectAttributes, + &Iosb, + NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_SUPERSEDE, + FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to create profiler log file\n"); + return; + } + + Status = PsCreateSystemThread(&KdbProfilerThreadHandle, + THREAD_ALL_ACCESS, + NULL, + NULL, + &KdbProfilerThreadCid, + KdbProfilerThreadMain, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to create profiler thread\n"); + return; + } + + KeInitializeMutex(&KdbProfilerLock, 0); + + KdbProfileDatabase = ExAllocatePool(NonPagedPool, sizeof(PROFILE_DATABASE)); + assert(KdbProfileDatabase); + InitializeListHead(&KdbProfileDatabase->ListHead); + KeInitializeDpc(&KdbProfilerCollectorDpc, KdbProfilerCollectorDpcRoutine, NULL); + + /* Initialize our periodic timer and its associated DPC object. When the timer + expires, the KdbProfilerSessionEndDpc deferred procedure call (DPC) is queued */ + KeInitializeTimerEx(&KdbProfilerTimer, SynchronizationTimer); + + /* Start the periodic timer with an initial and periodic + relative expiration time of PROFILE_SESSION_LENGTH seconds */ + DueTime.QuadPart = -(LONGLONG) PROFILE_SESSION_LENGTH * 1000 * 10000; + KeSetTimerEx(&KdbProfilerTimer, DueTime, PROFILE_SESSION_LENGTH * 1000, NULL); + + KdbProfilingEnabled = TRUE; + } +} + +VOID +KdbProfileInterrupt(ULONG_PTR Address) +{ + assert(KeGetCurrentIrql() == PROFILE_LEVEL); + + if (KdbProfilingInitialized != TRUE) + { + return; + } + + if ((KdbProfilingEnabled) && (!KdbProfilingSuspended)) + { + (BOOLEAN) KeInsertQueueDpc(&KdbProfilerCollectorDpc, (PVOID) Address, NULL); + } +} diff --git a/reactos/ntoskrnl/kd/kdebug.c b/reactos/ntoskrnl/kd/kdebug.c index 86666844bc5..564d378bc55 100644 --- a/reactos/ntoskrnl/kd/kdebug.c +++ b/reactos/ntoskrnl/kd/kdebug.c @@ -1,4 +1,4 @@ -/* $Id: kdebug.c,v 1.40 2002/09/08 10:23:27 chorns Exp $ +/* $Id: kdebug.c,v 1.41 2003/01/15 19:58:07 chorns Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -216,6 +216,12 @@ KdInitSystem(ULONG Reserved, } } } +#ifdef KDBG + else if (!_strnicmp(p2, "PROFILE", 7)) + { + KdbInitProfiling(); + } +#endif /* KDBG */ p1 = p2; } diff --git a/reactos/ntoskrnl/ke/i386/irq.c b/reactos/ntoskrnl/ke/i386/irq.c index b2f7c70089a..32989e16d33 100644 --- a/reactos/ntoskrnl/ke/i386/irq.c +++ b/reactos/ntoskrnl/ke/i386/irq.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: irq.c,v 1.27 2003/01/02 16:06:49 hbirr Exp $ +/* $Id: irq.c,v 1.28 2003/01/15 19:58:07 chorns Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/i386/irq.c @@ -41,6 +41,9 @@ #include #include #include +#ifdef KDBG +#include <../dbg/kdb.h> +#endif /* KDBG */ #ifdef MP #include @@ -370,6 +373,9 @@ KiInterruptDispatch (ULONG Vector, PKIRQ_TRAPFRAME Trapframe) if (KeGetCurrentProcessorNumber() == 0) { KiUpdateSystemTime(old_level, Trapframe->Eip); +#ifdef KDBG + KdbProfileInterrupt(Trapframe->Eip); +#endif /* KDBG */ } } else @@ -507,6 +513,13 @@ KiInterruptDispatch (ULONG irq, PKIRQ_TRAPFRAME Trapframe) */ KiInterruptDispatch2(irq, old_level); +#ifdef KDBG + if (irq == 0) + { + KdbProfileInterrupt(Trapframe->Eip); + } +#endif /* KDBG */ + /* * Maybe do a reschedule as well. */ diff --git a/reactos/ntoskrnl/ke/main.c b/reactos/ntoskrnl/ke/main.c index 6f3b81fed58..f53f5dd1ed3 100644 --- a/reactos/ntoskrnl/ke/main.c +++ b/reactos/ntoskrnl/ke/main.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: main.c,v 1.146 2002/12/09 23:09:25 ekohl Exp $ +/* $Id: main.c,v 1.147 2003/01/15 19:58:07 chorns Exp $ * * PROJECT: ReactOS kernel * FILE: ntoskrnl/ke/main.c @@ -572,6 +572,10 @@ ExpInitializeExecutive(VOID) DebugLogInit2(); #endif /* DBGPRINT_FILE_LOG */ +#ifdef KDBG + KdbInitProfiling2(); +#endif /* KDBG */ + PiInitDefaultLocale(); -- 2.17.1