From 33a5a666a4c98521195d1d4137a1141e670f7e62 Mon Sep 17 00:00:00 2001 From: AJFISH Date: Thu, 4 Oct 2007 21:01:21 +0000 Subject: [PATCH] Add Profiling support for Variable store and added a specialized caching algorithm git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4015 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/Include/Guid/VariableInfo.h | 44 ++++ MdeModulePkg/MdeModulePkg.dec | 4 +- .../Variable/Application/VariableInfo.c | 90 +++++++ .../Variable/Application/VariableInfo.inf | 50 ++++ .../Universal/Variable/RuntimeDxe/Variable.c | 234 ++++++++++++++++-- .../RuntimeDxe/VariableRuntimeDxe.inf | 7 + 6 files changed, 409 insertions(+), 20 deletions(-) create mode 100644 MdeModulePkg/Include/Guid/VariableInfo.h create mode 100644 MdeModulePkg/Universal/Variable/Application/VariableInfo.c create mode 100644 MdeModulePkg/Universal/Variable/Application/VariableInfo.inf diff --git a/MdeModulePkg/Include/Guid/VariableInfo.h b/MdeModulePkg/Include/Guid/VariableInfo.h new file mode 100644 index 0000000000..d6eb734d94 --- /dev/null +++ b/MdeModulePkg/Include/Guid/VariableInfo.h @@ -0,0 +1,44 @@ +/*++ + +Copyright (c) 2006 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + +--*/ + +#ifndef __VARIABLE_INFO_GUID_H__ +#define __VARIABLE_INFO_GUID_H__ + +// {DDCF3616-3275-4164-98B6-FE85707FFE7D} +#define EFI_VARIABLE_INFO_GUID \ + { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d } } + +extern EFI_GUID gEfiVariableInfoGuid; + + +typedef struct _VARIABLE_INFO_ENTRY VARIABLE_INFO_ENTRY; + +// +// This list gets put in the EFI system table. It is produced by the Variable driver at +// Boot Services time and records read and write access to a given variable +// +struct _VARIABLE_INFO_ENTRY { + VARIABLE_INFO_ENTRY *Next; + EFI_GUID VendorGuid; + CHAR16 *Name; + UINT32 Attributes; + UINT32 ReadCount; + UINT32 WriteCount; + UINT32 DeleteCount; + UINT32 CacheCount; + BOOLEAN Volatile; +}; + + +#endif diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 4ed02e1a86..851f934c97 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -59,12 +59,11 @@ gEfiCapsuleVendorGuid = { 0x711C703F, 0xC285, 0x4B10, { 0xA3, 0xB0, 0x36, 0xEC, 0xBD, 0x3C, 0x8B, 0xE2 }} gPeiPerformanceHobGuid = { 0xEC4DF5AF, 0x4395, 0x4CC9, { 0x94, 0xDE, 0x77, 0x50, 0x6D, 0x12, 0xC7, 0xB8 }} gEfiGenericPlatformVariableGuid = { 0x59d1c24f, 0x50f1, 0x401a, { 0xb1, 0x01, 0xf3, 0x3e, 0x0d, 0xae, 0xd4, 0x43 }} - gEfiShellFileGuid = { 0xC57AD6B7, 0x0515, 0x40A8, { 0x9D, 0x21, 0x55, 0x16, 0x52, 0x85, 0x4E, 0x37 }} gEfiFlashMapHobGuid = { 0xB091E7D2, 0x05A0, 0x4198, { 0x94, 0xF0, 0x74, 0xB7, 0xB8, 0xC5, 0x54, 0x59 }} gEfiStandardErrorDeviceGuid = { 0xD3B36F2D, 0xD551, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }} - gEfiPeiPeCoffLoaderGuid = { 0xD8117CFF, 0x94A6, 0x11D4, { 0x9A, 0x3A, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }} + gEfiVariableInfoGuid = { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d }} [Protocols.common] @@ -113,6 +112,7 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathFromText|FALSE|BOOLEAN|0x00010038 gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplBuildShareCodeHobs|FALSE|BOOLEAN|0x0001003c gEfiMdeModulePkgTokenSpaceGuid.PcdNtEmulatorEnable|FALSE|BOOLEAN|0x0001003e + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics|FALSE|BOOLEAN|0x0001003f [PcdsFixedAtBuild.common] gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPcdCallBackNumberPerPcdEntry|0x08|UINT32|0x0001000f diff --git a/MdeModulePkg/Universal/Variable/Application/VariableInfo.c b/MdeModulePkg/Universal/Variable/Application/VariableInfo.c new file mode 100644 index 0000000000..89866266db --- /dev/null +++ b/MdeModulePkg/Universal/Variable/Application/VariableInfo.c @@ -0,0 +1,90 @@ +/** @file + If the Variable services have PcdVariableCollectStatistics set to TRUE then + the EFI system table will contain statistical information about variable usage + an this utility will print out the information. You can use console redirection + to capture the data. + + Copyright (c) 2006 - 2007, Intel Corporation + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + + +/** + The user Entry Point for Application. The user code starts with this function + as the real entry point for the image goes into a library that calls this + function. + + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + VARIABLE_INFO_ENTRY *VariableInfo; + VARIABLE_INFO_ENTRY *Entry; + + Status = EfiGetSystemConfigurationTable (&gEfiVariableInfoGuid, (VOID **)&Entry); + if (!EFI_ERROR (Status) && (Entry != NULL)) { + Print (L"Non-Volatile EFI Variables:\n"); + VariableInfo = Entry; + do { + if (!VariableInfo->Volatile) { + Print ( + L"%g R%03d(%03d) W%03d D%03d:%s\n", + &VariableInfo->VendorGuid, + VariableInfo->ReadCount, + VariableInfo->CacheCount, + VariableInfo->WriteCount, + VariableInfo->DeleteCount, + VariableInfo->Name + ); + } + + VariableInfo = VariableInfo->Next; + } while (VariableInfo != NULL); + + Print (L"Volatile EFI Variables:\n"); + VariableInfo = Entry; + do { + if (VariableInfo->Volatile) { + Print ( + L"%g R%03d(%03d) W%03d D%03d:%s\n", + &VariableInfo->VendorGuid, + VariableInfo->ReadCount, + VariableInfo->CacheCount, + VariableInfo->WriteCount, + VariableInfo->DeleteCount, + VariableInfo->Name + ); + } + VariableInfo = VariableInfo->Next; + } while (VariableInfo != NULL); + + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Universal/Variable/Application/VariableInfo.inf b/MdeModulePkg/Universal/Variable/Application/VariableInfo.inf new file mode 100644 index 0000000000..4f4e608905 --- /dev/null +++ b/MdeModulePkg/Universal/Variable/Application/VariableInfo.inf @@ -0,0 +1,50 @@ +#/** @file +# Sample UEFI Application Reference Module +# +# This is a shell application that will display Hello World. +# Copyright (c) 2007, Intel Corporation. +# +# All rights reserved. This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = VariableInfo + FILE_GUID = 202A2922-8C27-4943-9855-26180BF9F113 + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + EDK_RELEASE_VERSION = 0x00020000 + EFI_SPECIFICATION_VERSION = 0x00020000 + + ENTRY_POINT = UefiMain + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources.common] + VariableInfo.c + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + + +[LibraryClasses] + UefiBootServicesTableLib + UefiApplicationEntryPoint + UefiLib + DebugLib + +[Guids] + gEfiVariableInfoGuid diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c index ef8f72d38a..8627c7dd9d 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c @@ -22,18 +22,23 @@ Revision History #include "Variable.h" #include +#include +#include + + + // // Don't use module globals after the SetVirtualAddress map is signaled // ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal; + // // This is a temperary function which will be removed // when EfiAcquireLock in UefiLib can handle the // the call in UEFI Runtimer driver in RT phase. // -STATIC VOID AcquireLockOnlyAtBootTime ( IN EFI_LOCK *Lock @@ -49,7 +54,6 @@ AcquireLockOnlyAtBootTime ( // when EfiAcquireLock in UefiLib can handle the // the call in UEFI Runtimer driver in RT phase. // -STATIC VOID ReleaseLockOnlyAtBootTime ( IN EFI_LOCK *Lock @@ -60,6 +64,76 @@ ReleaseLockOnlyAtBootTime ( } } + +GLOBAL_REMOVE_IF_UNREFERENCED VARIABLE_INFO_ENTRY *gVariableInfo = NULL; + + +VOID +UpdateVariableInfo ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN BOOLEAN Volatile, + IN BOOLEAN Read, + IN BOOLEAN Write, + IN BOOLEAN Delete, + IN BOOLEAN Cache + ) +{ + VARIABLE_INFO_ENTRY *Entry; + + if (FeaturePcdGet (PcdVariableCollectStatistics)) { + + if (EfiAtRuntime ()) { + // Don't collect statistics at runtime + return; + } + + if (gVariableInfo == NULL) { + gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY)); + CopyGuid (&gVariableInfo->VendorGuid, VendorGuid); + gVariableInfo->Name = AllocatePool (StrLen (VariableName)); + StrCpy (gVariableInfo->Name, VariableName); + gVariableInfo->Volatile = Volatile; + + gBS->InstallConfigurationTable (&gEfiVariableInfoGuid, gVariableInfo); + } + + + for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) { + if (CompareGuid (VendorGuid, &Entry->VendorGuid)) { + if (StrCmp (VariableName, Entry->Name) == 0) { + if (Read) { + Entry->ReadCount++; + } + if (Write) { + Entry->WriteCount++; + } + if (Delete) { + Entry->DeleteCount++; + } + if (Cache) { + Entry->CacheCount++; + } + + return; + } + } + + if (Entry->Next == NULL) { + Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY)); + + CopyGuid (&Entry->Next->VendorGuid, VendorGuid); + Entry->Next->Name = AllocatePool (StrLen (VariableName)); + StrCpy (Entry->Next->Name, VariableName); + Entry->Next->Volatile = Volatile; + } + + } + } +} + + + STATIC BOOLEAN EFIAPI @@ -485,9 +559,111 @@ Returns: return Status; } -STATIC +typedef struct { + EFI_GUID *Guid; + CHAR16 *Name; + UINT32 Attributes; + UINTN DataSize; + VOID *Data; +} VARIABLE_CACHE_ENTRY; + +// +// The current Hii implementation accesses this variable a larg # of times on every boot. +// Other common variables are only accessed a single time. This is why this cache algorithm +// only targets a single variable. Probably to get an performance improvement out of +// a Cache you would need a cache that improves the search performance for a variable. +// +VARIABLE_CACHE_ENTRY mVariableCache[] = { + { + &gEfiGlobalVariableGuid, + L"Lang", + 0x00000000, + 0x00, + NULL + } +}; + +VOID +UpdateVariableCache ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 Attributes, + IN OUT UINTN DataSize, + OUT VOID *Data + ) +{ + VARIABLE_CACHE_ENTRY *Entry; + UINTN Index; + + if (EfiAtRuntime ()) { + // Don't use the cache at runtime + return; + } + + for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) { + if (CompareGuid (VendorGuid, Entry->Guid)) { + if (StrCmp (VariableName, Entry->Name) == 0) { + Entry->Attributes = Attributes; + if (DataSize == 0) { + // Delete Case + if (Entry->DataSize != 0) { + FreePool (Entry->Data); + } + Entry->DataSize = DataSize; + } else if (DataSize == Entry->DataSize) { + CopyMem (Entry->Data, Data, DataSize); + } else { + Entry->Data = AllocatePool (DataSize); + Entry->DataSize = DataSize; + CopyMem (Entry->Data, Data, DataSize); + } + } + } + } +} + + +EFI_STATUS +FindVariableInCache ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + VARIABLE_CACHE_ENTRY *Entry; + UINTN Index; + + if (EfiAtRuntime ()) { + // Don't use the cache at runtime + return EFI_NOT_FOUND; + } + + for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) { + if (CompareGuid (VendorGuid, Entry->Guid)) { + if (StrCmp (VariableName, Entry->Name) == 0) { + if (Entry->DataSize == 0) { + return EFI_NOT_FOUND; + } else if (Entry->DataSize != *DataSize) { + *DataSize = Entry->DataSize; + return EFI_BUFFER_TOO_SMALL; + } else { + CopyMem (Data, Entry->Data, Entry->DataSize); + if (Attributes != NULL) { + *Attributes = Entry->Attributes; + } + return EFI_SUCCESS; + } + } + } + } + + return EFI_NOT_FOUND; +} + + EFI_STATUS -EFIAPI FindVariable ( IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, @@ -527,10 +703,10 @@ Returns: AcquireLockOnlyAtBootTime(&Global->VariableServicesLock); // - // 0: Non-Volatile, 1: Volatile + // 0: Volatile, 1: Non-Volatile // - VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase); - VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase); + VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase); + VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase); // // Start Pointers for the variable. @@ -543,7 +719,7 @@ Returns: return EFI_INVALID_PARAMETER; } // - // Find the variable by walk through non-volatile and volatile variable store + // Find the variable by walk through volatile and then non-volatile variable store // for (Index = 0; Index < 2; Index++) { PtrTrack->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1); @@ -554,13 +730,13 @@ Returns: if (!EfiAtRuntime () || (Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) { if (VariableName[0] == 0) { PtrTrack->CurrPtr = Variable[Index]; - PtrTrack->Volatile = (BOOLEAN) Index; + PtrTrack->Volatile = (BOOLEAN)(Index == 0); return EFI_SUCCESS; } else { if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) { if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), Variable[Index]->NameSize)) { PtrTrack->CurrPtr = Variable[Index]; - PtrTrack->Volatile = (BOOLEAN) Index; + PtrTrack->Volatile = (BOOLEAN)(Index == 0); return EFI_SUCCESS; } } @@ -570,17 +746,12 @@ Returns: Variable[Index] = GetNextVariablePtr (Variable[Index]); } - // - // While (...) - // } - // - // for (...) - // PtrTrack->CurrPtr = NULL; return EFI_NOT_FOUND; } + EFI_STATUS EFIAPI GetVariable ( @@ -626,14 +797,22 @@ Returns: if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) { return EFI_INVALID_PARAMETER; } + // // Find existing variable // + Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data); + if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){ + // Hit in the Cache + UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE); + return Status; + } + Status = FindVariable (VariableName, VendorGuid, &Variable, Global); - if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) { goto Done; } + // // Get data size // @@ -650,6 +829,9 @@ Returns: } *DataSize = VarDataSize; + UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE); + UpdateVariableCache (VariableName, VendorGuid, Variable.CurrPtr->Attributes, VarDataSize, Data); + Status = EFI_SUCCESS; goto Done; } else { @@ -901,6 +1083,10 @@ Returns: sizeof (UINT8), &State ); + if (!EFI_ERROR (Status)) { + UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, FALSE, FALSE, TRUE, FALSE); + UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data); + } goto Done; } // @@ -909,6 +1095,8 @@ Returns: // if (Variable.CurrPtr->DataSize == DataSize && (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)) { + + UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, FALSE, TRUE, FALSE, FALSE); Status = EFI_SUCCESS; goto Done; } else if ((Variable.CurrPtr->State == VAR_ADDED) || @@ -930,7 +1118,7 @@ Returns: ); if (EFI_ERROR (Status)) { goto Done; - } + } } } else if (Status == EFI_NOT_FOUND) { // @@ -1010,6 +1198,7 @@ Returns: // // Create a nonvolatile variable // + Variable.Volatile = FALSE; if ((UINT32) (VarSize +*NonVolatileOffset) > ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size @@ -1099,6 +1288,7 @@ Returns: // // Create a volatile variable // + Variable.Volatile = TRUE; if ((UINT32) (VarSize +*VolatileOffset) > ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size) { @@ -1155,10 +1345,18 @@ Returns: sizeof (UINT8), &State ); + + if (!EFI_ERROR (Status)) { + UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, FALSE, TRUE, FALSE, FALSE); + UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data); + } goto Done; } Status = EFI_SUCCESS; + UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, FALSE, TRUE, FALSE, FALSE); + UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data); + Done: ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock); return Status; diff --git a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf index 954f6a20b6..8c3e1d8c02 100644 --- a/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf +++ b/MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf @@ -63,9 +63,16 @@ gEfiVariableWriteArchProtocolGuid # PROTOCOL ALWAYS_PRODUCED gEfiVariableArchProtocolGuid # PROTOCOL ALWAYS_PRODUCED +[Guids] + gEfiVariableInfoGuid + gEfiGlobalVariableGuid + [Pcd.common] gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase + +[FeaturePcd.IA32] + gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics [Depex] gEfiFirmwareVolumeBlockProtocolGuid AND gEfiAlternateFvBlockGuid AND gEfiFaultTolerantWriteLiteProtocolGuid -- 2.39.2