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
This commit is contained in:
AJFISH 2007-10-04 21:01:21 +00:00
parent dd98e32c6b
commit 33a5a666a4
6 changed files with 409 additions and 20 deletions

View File

@ -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

View File

@ -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

View File

@ -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 <Uefi.h>
#include <Library/DebugLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Guid/VariableInfo.h>
/**
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;
}

View File

@ -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

View File

@ -22,18 +22,23 @@ Revision History
#include "Variable.h"
#include <Guid/FlashMapHob.h>
#include <Guid/VariableInfo.h>
#include <Guid/GlobalVariable.h>
//
// 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;

View File

@ -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