git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2367 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			400 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			400 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*++
 | 
						|
 | 
						|
Copyright (c) 2006, 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.             
 | 
						|
 | 
						|
Module Name:
 | 
						|
 | 
						|
  Performance.c
 | 
						|
 | 
						|
Abstract:
 | 
						|
 | 
						|
  This file include the file which can help to get the system
 | 
						|
  performance, all the function will only include if the performance
 | 
						|
  switch is set.
 | 
						|
 | 
						|
--*/
 | 
						|
 | 
						|
#include "Performance.h"
 | 
						|
 | 
						|
VOID
 | 
						|
ClearDebugRegisters (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // BugBug: We should not need to do this. We need to root cause this bug!!!!
 | 
						|
  //
 | 
						|
  AsmWriteDr0 (0);
 | 
						|
  AsmWriteDr1 (0);
 | 
						|
}
 | 
						|
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
GetShortPdbFileName (
 | 
						|
  CHAR8  *PdbFileName,
 | 
						|
  CHAR8  *GaugeString
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
  
 | 
						|
Arguments:
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINTN Index;
 | 
						|
  UINTN Index1;
 | 
						|
  UINTN StartIndex;
 | 
						|
  UINTN EndIndex;
 | 
						|
 | 
						|
  if (PdbFileName == NULL) {
 | 
						|
    AsciiStrCpy (GaugeString, " ");
 | 
						|
  } else {
 | 
						|
    StartIndex = 0;
 | 
						|
    for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
 | 
						|
      ;
 | 
						|
 | 
						|
    for (Index = 0; PdbFileName[Index] != 0; Index++) {
 | 
						|
      if (PdbFileName[Index] == '\\') {
 | 
						|
        StartIndex = Index + 1;
 | 
						|
      }
 | 
						|
 | 
						|
      if (PdbFileName[Index] == '.') {
 | 
						|
        EndIndex = Index;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    Index1 = 0;
 | 
						|
    for (Index = StartIndex; Index < EndIndex; Index++) {
 | 
						|
      GaugeString[Index1] = PdbFileName[Index];
 | 
						|
      Index1++;
 | 
						|
      if (Index1 == PERF_TOKEN_LENGTH - 1) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    GaugeString[Index1] = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
STATIC
 | 
						|
CHAR8 *
 | 
						|
GetPdbPath (
 | 
						|
  VOID *ImageBase
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Located PDB path name in PE image
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  ImageBase - base of PE to search
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  Pointer into image at offset of PDB file name if PDB file name is found,
 | 
						|
  Otherwise a pointer to an empty string.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;
 | 
						|
 | 
						|
  ZeroMem (&ImageContext, sizeof (ImageContext));
 | 
						|
  ImageContext.Handle    = ImageBase;
 | 
						|
  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
 | 
						|
 | 
						|
  PeCoffLoaderGetImageInfo (&ImageContext);
 | 
						|
 | 
						|
  return ImageContext.PdbPointer;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
GetNameFromHandle (
 | 
						|
  IN  EFI_HANDLE     Handle,
 | 
						|
  OUT CHAR8          *GaugeString
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                  Status;
 | 
						|
  EFI_LOADED_IMAGE_PROTOCOL   *Image;
 | 
						|
  CHAR8                       *PdbFileName;
 | 
						|
  EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
 | 
						|
 | 
						|
  AsciiStrCpy (GaugeString, " ");
 | 
						|
 | 
						|
  //
 | 
						|
  // Get handle name from image protocol
 | 
						|
  //
 | 
						|
  Status = gBS->HandleProtocol (
 | 
						|
                  Handle,
 | 
						|
                  &gEfiLoadedImageProtocolGuid,
 | 
						|
                  (VOID **)&Image
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    Status = gBS->OpenProtocol (
 | 
						|
                    Handle,
 | 
						|
                    &gEfiDriverBindingProtocolGuid,
 | 
						|
                    (VOID **) &DriverBinding,
 | 
						|
                    NULL,
 | 
						|
                    NULL,
 | 
						|
                    EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return ;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Get handle name from image protocol
 | 
						|
    //
 | 
						|
    Status = gBS->HandleProtocol (
 | 
						|
                    DriverBinding->ImageHandle,
 | 
						|
                    &gEfiLoadedImageProtocolGuid,
 | 
						|
                    (VOID **)&Image
 | 
						|
                    );
 | 
						|
  }
 | 
						|
 | 
						|
  PdbFileName = GetPdbPath (Image->ImageBase);
 | 
						|
 | 
						|
  if (PdbFileName != NULL) {
 | 
						|
    GetShortPdbFileName (PdbFileName, GaugeString);
 | 
						|
  }
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
VOID
 | 
						|
WriteBootToOsPerformanceData (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
  
 | 
						|
  Allocates a block of memory and writes performance data of booting to OS into it.
 | 
						|
 | 
						|
Arguments:
 | 
						|
  
 | 
						|
  None
 | 
						|
  
 | 
						|
Returns:
 | 
						|
 | 
						|
  None
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_CPU_ARCH_PROTOCOL     *Cpu;
 | 
						|
  EFI_PHYSICAL_ADDRESS      mAcpiLowMemoryBase;
 | 
						|
  UINT32                    mAcpiLowMemoryLength;
 | 
						|
  UINT32                    LimitCount;
 | 
						|
  PERF_HEADER               mPerfHeader;
 | 
						|
  PERF_DATA                 mPerfData;
 | 
						|
  EFI_HANDLE                *Handles;
 | 
						|
  UINTN                     NoHandles;
 | 
						|
  CHAR8                     GaugeString[PERF_TOKEN_LENGTH];
 | 
						|
  UINT8                     *Ptr;
 | 
						|
  UINT32                    mIndex;
 | 
						|
  UINT64                    Ticker;
 | 
						|
  UINT64                    Freq;
 | 
						|
  UINT32                    Duration;
 | 
						|
  UINT64                    CurrentTicker;
 | 
						|
  UINT64                    TimerPeriod;
 | 
						|
  UINTN                     LogEntryKey;
 | 
						|
  CONST VOID                *Handle;
 | 
						|
  CONST CHAR8               *Token;
 | 
						|
  CONST CHAR8               *Module;
 | 
						|
  UINT64                    StartTicker;
 | 
						|
  UINT64                    EndTicker;
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrive time stamp count as early as possilbe
 | 
						|
  //
 | 
						|
  Ticker = AsmReadTsc ();
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate a block of memory that contain performance data to OS
 | 
						|
  //
 | 
						|
  mAcpiLowMemoryBase = 0xFFFFFFFF;
 | 
						|
  Status = gBS->AllocatePages (
 | 
						|
                  AllocateMaxAddress,
 | 
						|
                  EfiReservedMemoryType,
 | 
						|
                  4,
 | 
						|
                  &mAcpiLowMemoryBase
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  mAcpiLowMemoryLength  = EFI_PAGES_TO_SIZE(4);
 | 
						|
 | 
						|
  Ptr                   = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));
 | 
						|
  LimitCount            = (mAcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize performance data structure
 | 
						|
  //
 | 
						|
  ZeroMem (&mPerfHeader, sizeof (PERF_HEADER));
 | 
						|
 | 
						|
  //
 | 
						|
  // Get CPU frequency
 | 
						|
  //
 | 
						|
  Status = gBS->LocateProtocol (
 | 
						|
                  &gEfiCpuArchProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  (VOID **)&Cpu
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->FreePages (mAcpiLowMemoryBase, 4);
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get Cpu Frequency
 | 
						|
  //
 | 
						|
  Status = Cpu->GetTimerValue (Cpu, 0, &(CurrentTicker), &TimerPeriod);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->FreePages (mAcpiLowMemoryBase, 4);
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  Freq                = DivU64x32 (1000000000000ULL, (UINTN) TimerPeriod);
 | 
						|
 | 
						|
  mPerfHeader.CpuFreq = Freq;
 | 
						|
 | 
						|
  //
 | 
						|
  // Record BDS raw performance data
 | 
						|
  //
 | 
						|
  mPerfHeader.BDSRaw = Ticker;
 | 
						|
 | 
						|
  //
 | 
						|
  // Put Detailed performance data into memory
 | 
						|
  //
 | 
						|
  Handles = NULL;
 | 
						|
  Status = gBS->LocateHandleBuffer (
 | 
						|
                  AllHandles,
 | 
						|
                  NULL,
 | 
						|
                  NULL,
 | 
						|
                  &NoHandles,
 | 
						|
                  &Handles
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    gBS->FreePages (mAcpiLowMemoryBase, 4);
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get DXE drivers performance
 | 
						|
  //
 | 
						|
  for (mIndex = 0; mIndex < NoHandles; mIndex++) {
 | 
						|
    Ticker = 0;
 | 
						|
    LogEntryKey = 0;
 | 
						|
    while ((LogEntryKey = GetPerformanceMeasurement (
 | 
						|
                            LogEntryKey,
 | 
						|
                            &Handle,
 | 
						|
                            &Token,
 | 
						|
                            &Module,
 | 
						|
                            &StartTicker,
 | 
						|
                            &EndTicker)) != 0) {
 | 
						|
      if ((Handle == Handles[mIndex]) && (StartTicker < EndTicker)) {
 | 
						|
        Ticker += (EndTicker - StartTicker);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    Duration = (UINT32) DivU64x32 (
 | 
						|
                          Ticker,
 | 
						|
                          (UINT32) Freq
 | 
						|
                          );
 | 
						|
 | 
						|
    if (Duration > 0) {
 | 
						|
      ZeroMem (&mPerfData, sizeof (PERF_DATA));
 | 
						|
 | 
						|
      GetNameFromHandle (Handles[mIndex], GaugeString);
 | 
						|
 | 
						|
      AsciiStrCpy (mPerfData.Token, GaugeString);
 | 
						|
      mPerfData.Duration = Duration;
 | 
						|
 | 
						|
      CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
 | 
						|
      Ptr += sizeof (PERF_DATA);
 | 
						|
 | 
						|
      mPerfHeader.Count++;
 | 
						|
      if (mPerfHeader.Count == LimitCount) {
 | 
						|
        goto Done;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->FreePool (Handles);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get inserted performance data
 | 
						|
  //
 | 
						|
  LogEntryKey = 0;
 | 
						|
  while ((LogEntryKey = GetPerformanceMeasurement (
 | 
						|
                          LogEntryKey,
 | 
						|
                          &Handle,
 | 
						|
                          &Token,
 | 
						|
                          &Module,
 | 
						|
                          &StartTicker,
 | 
						|
                          &EndTicker)) != 0) {
 | 
						|
    if ((Handle == NULL) && (StartTicker <= EndTicker)) {
 | 
						|
 | 
						|
      ZeroMem (&mPerfData, sizeof (PERF_DATA));
 | 
						|
 | 
						|
      AsciiStrnCpy (mPerfData.Token, Token, DXE_PERFORMANCE_STRING_SIZE);
 | 
						|
      mPerfData.Duration = (UINT32) DivU64x32 (
 | 
						|
                                      EndTicker - StartTicker,
 | 
						|
                                      (UINT32) Freq
 | 
						|
                                      );
 | 
						|
 | 
						|
      CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
 | 
						|
      Ptr += sizeof (PERF_DATA);
 | 
						|
 | 
						|
      mPerfHeader.Count++;
 | 
						|
      if (mPerfHeader.Count == LimitCount) {
 | 
						|
        goto Done;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
Done:
 | 
						|
 | 
						|
  ClearDebugRegisters ();
 | 
						|
 | 
						|
  mPerfHeader.Signiture = 0x66726550;
 | 
						|
 | 
						|
  //
 | 
						|
  // Put performance data to memory
 | 
						|
  //
 | 
						|
  CopyMem (
 | 
						|
    (UINT32 *) (UINT32) mAcpiLowMemoryBase,
 | 
						|
    &mPerfHeader,
 | 
						|
    sizeof (PERF_HEADER)
 | 
						|
    );
 | 
						|
 | 
						|
  gRT->SetVariable (
 | 
						|
        L"PerfDataMemAddr",
 | 
						|
        &gEfiGlobalVariableGuid,
 | 
						|
        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | 
						|
        sizeof (UINT32),
 | 
						|
        (VOID *) &mAcpiLowMemoryBase
 | 
						|
        );
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 |