1 /** @file
2 This file include the file which can help to get the system
3 performance, all the function will only include if the performance
4 switch is set.
5
6 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "InternalBm.h"
18
19 PERF_HEADER mBmPerfHeader;
20 PERF_DATA mBmPerfData;
21 EFI_PHYSICAL_ADDRESS mBmAcpiLowMemoryBase = 0x0FFFFFFFFULL;
22
23 /**
24 Get the short verion of PDB file name to be
25 used in performance data logging.
26
27 @param PdbFileName The long PDB file name.
28 @param GaugeString The output string to be logged by performance logger.
29 @param StringSize The buffer size of GaugeString in bytes.
30
31 **/
32 VOID
BmGetShortPdbFileName(IN CONST CHAR8 * PdbFileName,OUT CHAR8 * GaugeString,IN UINTN StringSize)33 BmGetShortPdbFileName (
34 IN CONST CHAR8 *PdbFileName,
35 OUT CHAR8 *GaugeString,
36 IN UINTN StringSize
37 )
38 {
39 UINTN Index;
40 UINTN Index1;
41 UINTN StartIndex;
42 UINTN EndIndex;
43
44 if (PdbFileName == NULL) {
45 AsciiStrCpyS (GaugeString, StringSize, " ");
46 } else {
47 StartIndex = 0;
48 for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
49 ;
50
51 for (Index = 0; PdbFileName[Index] != 0; Index++) {
52 if (PdbFileName[Index] == '\\') {
53 StartIndex = Index + 1;
54 }
55
56 if (PdbFileName[Index] == '.') {
57 EndIndex = Index;
58 }
59 }
60
61 Index1 = 0;
62 for (Index = StartIndex; Index < EndIndex; Index++) {
63 GaugeString[Index1] = PdbFileName[Index];
64 Index1++;
65 if (Index1 == StringSize - 1) {
66 break;
67 }
68 }
69
70 GaugeString[Index1] = 0;
71 }
72
73 return ;
74 }
75
76 /**
77 Get the name from the Driver handle, which can be a handle with
78 EFI_LOADED_IMAGE_PROTOCOL or EFI_DRIVER_BINDING_PROTOCOL installed.
79 This name can be used in performance data logging.
80
81 @param Handle Driver handle.
82 @param GaugeString The output string to be logged by performance logger.
83 @param StringSize The buffer size of GaugeString in bytes.
84
85 **/
86 VOID
BmGetNameFromHandle(IN EFI_HANDLE Handle,OUT CHAR8 * GaugeString,IN UINTN StringSize)87 BmGetNameFromHandle (
88 IN EFI_HANDLE Handle,
89 OUT CHAR8 *GaugeString,
90 IN UINTN StringSize
91 )
92 {
93 EFI_STATUS Status;
94 EFI_LOADED_IMAGE_PROTOCOL *Image;
95 CHAR8 *PdbFileName;
96 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
97
98 AsciiStrCpyS (GaugeString, StringSize, " ");
99
100 //
101 // Get handle name from image protocol
102 //
103 Status = gBS->HandleProtocol (
104 Handle,
105 &gEfiLoadedImageProtocolGuid,
106 (VOID **) &Image
107 );
108
109 if (EFI_ERROR (Status)) {
110 Status = gBS->OpenProtocol (
111 Handle,
112 &gEfiDriverBindingProtocolGuid,
113 (VOID **) &DriverBinding,
114 NULL,
115 NULL,
116 EFI_OPEN_PROTOCOL_GET_PROTOCOL
117 );
118 if (EFI_ERROR (Status)) {
119 return ;
120 }
121 //
122 // Get handle name from image protocol
123 //
124 Status = gBS->HandleProtocol (
125 DriverBinding->ImageHandle,
126 &gEfiLoadedImageProtocolGuid,
127 (VOID **) &Image
128 );
129 }
130
131 PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);
132
133 if (PdbFileName != NULL) {
134 BmGetShortPdbFileName (PdbFileName, GaugeString, StringSize);
135 }
136
137 return ;
138 }
139
140 /**
141
142 Writes performance data of booting into the allocated memory.
143 OS can process these records.
144
145 @param Event The triggered event.
146 @param Context Context for this event.
147
148 **/
149 VOID
150 EFIAPI
BmWriteBootToOsPerformanceData(IN EFI_EVENT Event,IN VOID * Context)151 BmWriteBootToOsPerformanceData (
152 IN EFI_EVENT Event,
153 IN VOID *Context
154 )
155 {
156 EFI_STATUS Status;
157 UINT32 LimitCount;
158 EFI_HANDLE *Handles;
159 UINTN NoHandles;
160 CHAR8 GaugeString[PERF_TOKEN_SIZE];
161 UINT8 *Ptr;
162 UINT32 Index;
163 UINT64 Ticker;
164 UINT64 Freq;
165 UINT32 Duration;
166 UINTN LogEntryKey;
167 CONST VOID *Handle;
168 CONST CHAR8 *Token;
169 CONST CHAR8 *Module;
170 UINT64 StartTicker;
171 UINT64 EndTicker;
172 UINT64 StartValue;
173 UINT64 EndValue;
174 BOOLEAN CountUp;
175 UINTN VarSize;
176 BOOLEAN Found;
177
178 //
179 // Record the performance data for End of BDS
180 //
181 PERF_END(NULL, "BDS", NULL, 0);
182
183 //
184 // Retrieve time stamp count as early as possible
185 //
186 Ticker = GetPerformanceCounter ();
187
188 Freq = GetPerformanceCounterProperties (&StartValue, &EndValue);
189
190 Freq = DivU64x32 (Freq, 1000);
191
192 mBmPerfHeader.CpuFreq = Freq;
193
194 //
195 // Record BDS raw performance data
196 //
197 if (EndValue >= StartValue) {
198 mBmPerfHeader.BDSRaw = Ticker - StartValue;
199 CountUp = TRUE;
200 } else {
201 mBmPerfHeader.BDSRaw = StartValue - Ticker;
202 CountUp = FALSE;
203 }
204
205 //
206 // Reset the entry count
207 //
208 mBmPerfHeader.Count = 0;
209
210 if (mBmAcpiLowMemoryBase == 0x0FFFFFFFF) {
211 VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
212 Status = gRT->GetVariable (
213 L"PerfDataMemAddr",
214 &gPerformanceProtocolGuid,
215 NULL,
216 &VarSize,
217 &mBmAcpiLowMemoryBase
218 );
219 if (EFI_ERROR (Status)) {
220 //
221 // Fail to get the variable, return.
222 //
223 return;
224 }
225 }
226
227 //
228 // Put Detailed performance data into memory
229 //
230 Handles = NULL;
231 Status = gBS->LocateHandleBuffer (
232 AllHandles,
233 NULL,
234 NULL,
235 &NoHandles,
236 &Handles
237 );
238 if (EFI_ERROR (Status)) {
239 return ;
240 }
241
242 Ptr = (UINT8 *) ((UINT32) mBmAcpiLowMemoryBase + sizeof (PERF_HEADER));
243 LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);
244
245 //
246 // Get performance data
247 //
248 LogEntryKey = 0;
249 while ((LogEntryKey = GetPerformanceMeasurement (
250 LogEntryKey,
251 &Handle,
252 &Token,
253 &Module,
254 &StartTicker,
255 &EndTicker)) != 0) {
256 if (EndTicker != 0) {
257 if (StartTicker == 1) {
258 StartTicker = StartValue;
259 }
260 if (EndTicker == 1) {
261 EndTicker = StartValue;
262 }
263 Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
264
265 Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
266 if (Duration == 0) {
267 continue;
268 }
269
270 ZeroMem (&mBmPerfData, sizeof (PERF_DATA));
271
272 mBmPerfData.Duration = Duration;
273
274 //
275 // See if the Handle is in the handle buffer
276 //
277 Found = FALSE;
278 for (Index = 0; Index < NoHandles; Index++) {
279 if (Handle == Handles[Index]) {
280 BmGetNameFromHandle (Handles[Index], GaugeString, PERF_TOKEN_SIZE);
281 AsciiStrCpyS (mBmPerfData.Token, PERF_TOKEN_SIZE, GaugeString);
282 Found = TRUE;
283 break;
284 }
285 }
286
287 if (!Found) {
288 AsciiStrnCpyS (mBmPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH);
289 }
290
291 CopyMem (Ptr, &mBmPerfData, sizeof (PERF_DATA));
292 Ptr += sizeof (PERF_DATA);
293
294 mBmPerfHeader.Count++;
295 if (mBmPerfHeader.Count == LimitCount) {
296 goto Done;
297 }
298 }
299 }
300
301 Done:
302
303 FreePool (Handles);
304
305 mBmPerfHeader.Signiture = PERFORMANCE_SIGNATURE;
306
307 //
308 // Put performance data to Reserved memory
309 //
310 CopyMem (
311 (UINTN *) (UINTN) mBmAcpiLowMemoryBase,
312 &mBmPerfHeader,
313 sizeof (PERF_HEADER)
314 );
315
316 return ;
317 }
318