320d6b7c44fe59540789205b72508ce17bbe49ac
[mirror_edk2.git] / EdkNt32Pkg / Library / EdkGenericBdsLib / Performance.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Performance.c
15
16 Abstract:
17
18 This file include the file which can help to get the system
19 performance, all the function will only include if the performance
20 switch is set.
21
22 --*/
23
24 #include "Performance.h"
25
26 VOID
27 ClearDebugRegisters (
28 VOID
29 )
30 {
31 AsmWriteDr0 (0);
32 AsmWriteDr1 (0);
33 }
34
35 STATIC
36 VOID
37 GetShortPdbFileName (
38 CHAR8 *PdbFileName,
39 CHAR8 *GaugeString
40 )
41 /*++
42
43 Routine Description:
44
45 Arguments:
46
47 Returns:
48
49 --*/
50 {
51 UINTN Index;
52 UINTN Index1;
53 UINTN StartIndex;
54 UINTN EndIndex;
55
56 if (PdbFileName == NULL) {
57 AsciiStrCpy (GaugeString, " ");
58 } else {
59 StartIndex = 0;
60 for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
61 ;
62
63 for (Index = 0; PdbFileName[Index] != 0; Index++) {
64 if (PdbFileName[Index] == '\\') {
65 StartIndex = Index + 1;
66 }
67
68 if (PdbFileName[Index] == '.') {
69 EndIndex = Index;
70 }
71 }
72
73 Index1 = 0;
74 for (Index = StartIndex; Index < EndIndex; Index++) {
75 GaugeString[Index1] = PdbFileName[Index];
76 Index1++;
77 if (Index1 == PERF_TOKEN_LENGTH - 1) {
78 break;
79 }
80 }
81
82 GaugeString[Index1] = 0;
83 }
84
85 return ;
86 }
87
88 STATIC
89 CHAR8 *
90 GetPdbPath (
91 VOID *ImageBase
92 )
93 /*++
94
95 Routine Description:
96
97 Located PDB path name in PE image
98
99 Arguments:
100
101 ImageBase - base of PE to search
102
103 Returns:
104
105 Pointer into image at offset of PDB file name if PDB file name is found,
106 Otherwise a pointer to an empty string.
107
108 --*/
109 {
110 CHAR8 *PdbPath;
111 UINT32 DirCount;
112 EFI_IMAGE_DOS_HEADER *DosHdr;
113 EFI_IMAGE_NT_HEADERS *NtHdr;
114 EFI_IMAGE_OPTIONAL_HEADER *OptionalHdr;
115 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
116 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
117 VOID *CodeViewEntryPointer;
118
119 CodeViewEntryPointer = NULL;
120 PdbPath = NULL;
121 DosHdr = ImageBase;
122
123 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
124 NtHdr = (EFI_IMAGE_NT_HEADERS *) ((UINT8 *) DosHdr + DosHdr->e_lfanew);
125 OptionalHdr = (VOID *) &NtHdr->OptionalHeader;
126 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
127 if (DirectoryEntry->VirtualAddress != 0) {
128 for (DirCount = 0;
129 (DirCount < DirectoryEntry->Size / sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) && CodeViewEntryPointer == NULL;
130 DirCount++
131 ) {
132 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (DirectoryEntry->VirtualAddress + (UINTN) ImageBase + DirCount * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));
133 if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
134 CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + (UINTN) ImageBase);
135 switch (*(UINT32 *) CodeViewEntryPointer) {
136 case CODEVIEW_SIGNATURE_NB10:
137 PdbPath = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
138 break;
139
140 case CODEVIEW_SIGNATURE_RSDS:
141 PdbPath = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
142 break;
143
144 default:
145 break;
146 }
147 }
148 }
149 }
150 }
151
152 return PdbPath;
153 }
154
155 STATIC
156 VOID
157 GetNameFromHandle (
158 IN EFI_HANDLE Handle,
159 OUT CHAR8 *GaugeString
160 )
161 {
162 EFI_STATUS Status;
163 EFI_LOADED_IMAGE_PROTOCOL *Image;
164 CHAR8 *PdbFileName;
165 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
166
167 AsciiStrCpy (GaugeString, " ");
168
169 //
170 // Get handle name from image protocol
171 //
172 Status = gBS->HandleProtocol (
173 Handle,
174 &gEfiLoadedImageProtocolGuid,
175 &Image
176 );
177
178 if (EFI_ERROR (Status)) {
179 Status = gBS->OpenProtocol (
180 Handle,
181 &gEfiDriverBindingProtocolGuid,
182 (VOID **) &DriverBinding,
183 NULL,
184 NULL,
185 EFI_OPEN_PROTOCOL_GET_PROTOCOL
186 );
187 if (EFI_ERROR (Status)) {
188 return ;
189 }
190 //
191 // Get handle name from image protocol
192 //
193 Status = gBS->HandleProtocol (
194 DriverBinding->ImageHandle,
195 &gEfiLoadedImageProtocolGuid,
196 &Image
197 );
198 }
199
200 PdbFileName = GetPdbPath (Image->ImageBase);
201
202 if (PdbFileName != NULL) {
203 GetShortPdbFileName (PdbFileName, GaugeString);
204 }
205
206 return ;
207 }
208
209
210
211 VOID
212 WriteBootToOsPerformanceData (
213 VOID
214 )
215 /*++
216
217 Routine Description:
218
219 Allocates a block of memory and writes performance data of booting to OS into it.
220
221 Arguments:
222
223 None
224
225 Returns:
226
227 None
228
229 --*/
230 {
231 EFI_STATUS Status;
232 EFI_CPU_ARCH_PROTOCOL *Cpu;
233 EFI_PHYSICAL_ADDRESS mAcpiLowMemoryBase;
234 UINT32 mAcpiLowMemoryLength;
235 UINT32 LimitCount;
236 PERF_HEADER mPerfHeader;
237 PERF_DATA mPerfData;
238 EFI_HANDLE *Handles;
239 UINTN NoHandles;
240 CHAR8 GaugeString[PERF_TOKEN_LENGTH];
241 UINT8 *Ptr;
242 UINT32 mIndex;
243 UINT64 Ticker;
244 UINT64 Freq;
245 UINT32 Duration;
246 UINT64 CurrentTicker;
247 UINT64 TimerPeriod;
248 UINTN LogEntryKey;
249 CONST VOID *Handle;
250 CONST CHAR8 *Token;
251 CONST CHAR8 *Module;
252 UINT64 StartTicker;
253 UINT64 EndTicker;
254
255 //
256 // Retrive time stamp count as early as possilbe
257 //
258 Ticker = AsmReadTsc ();
259
260 //
261 // Allocate a block of memory that contain performance data to OS
262 //
263 Status = gBS->AllocatePages (
264 AllocateAnyPages,
265 EfiACPIReclaimMemory,
266 4,
267 &mAcpiLowMemoryBase
268 );
269 if (EFI_ERROR (Status)) {
270 return ;
271 }
272
273 mAcpiLowMemoryLength = 0x1000;
274
275 Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));
276 LimitCount = (mAcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);
277
278 //
279 // Initialize performance data structure
280 //
281 ZeroMem (&mPerfHeader, sizeof (PERF_HEADER));
282
283 //
284 // Get CPU frequency
285 //
286 Status = gBS->LocateProtocol (
287 &gEfiCpuArchProtocolGuid,
288 NULL,
289 &Cpu
290 );
291 if (EFI_ERROR (Status)) {
292 gBS->FreePages (mAcpiLowMemoryBase, 1);
293 return ;
294 }
295 //
296 // Get Cpu Frequency
297 //
298 Status = Cpu->GetTimerValue (Cpu, 0, &(CurrentTicker), &TimerPeriod);
299 if (EFI_ERROR (Status)) {
300 gBS->FreePages (mAcpiLowMemoryBase, 1);
301 return ;
302 }
303
304 Freq = DivU64x32 (1000000000000, (UINTN) TimerPeriod);
305
306 mPerfHeader.CpuFreq = Freq;
307
308 //
309 // Record BDS raw performance data
310 //
311 mPerfHeader.BDSRaw = Ticker;
312
313 //
314 // Put Detailed performance data into memory
315 //
316 Handles = NULL;
317 Status = gBS->LocateHandleBuffer (
318 AllHandles,
319 NULL,
320 NULL,
321 &NoHandles,
322 &Handles
323 );
324 if (EFI_ERROR (Status)) {
325 gBS->FreePages (mAcpiLowMemoryBase, 1);
326 return ;
327 }
328 //
329 // Get DXE drivers performance
330 //
331 for (mIndex = 0; mIndex < NoHandles; mIndex++) {
332 Ticker = 0;
333 LogEntryKey = 0;
334 while ((LogEntryKey = GetPerformanceMeasurement (
335 LogEntryKey,
336 &Handle,
337 &Token,
338 &Module,
339 &StartTicker,
340 &EndTicker)) != 0) {
341 if ((Handle == Handles[mIndex]) && (StartTicker < EndTicker)) {
342 Ticker += (EndTicker - StartTicker);
343 }
344 }
345
346 Duration = (UINT32) DivU64x32 (
347 Ticker,
348 (UINT32) Freq
349 );
350
351 if (Duration > 0) {
352 ZeroMem (&mPerfData, sizeof (PERF_DATA));
353
354 GetNameFromHandle (Handles[mIndex], GaugeString);
355
356 AsciiStrCpy (mPerfData.Token, GaugeString);
357 mPerfData.Duration = Duration;
358
359 CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
360 Ptr += sizeof (PERF_DATA);
361
362 mPerfHeader.Count++;
363 if (mPerfHeader.Count == LimitCount) {
364 goto Done;
365 }
366 }
367 }
368
369 gBS->FreePool (Handles);
370
371 //
372 // Get inserted performance data
373 //
374 LogEntryKey = 0;
375 while ((LogEntryKey = GetPerformanceMeasurement (
376 LogEntryKey,
377 &Handle,
378 &Token,
379 &Module,
380 &StartTicker,
381 &EndTicker)) != 0) {
382 if ((Handle == NULL) && (StartTicker <= EndTicker)) {
383
384 ZeroMem (&mPerfData, sizeof (PERF_DATA));
385
386 AsciiStrnCpy (mPerfData.Token, Token, DXE_PERFORMANCE_STRING_SIZE);
387 mPerfData.Duration = (UINT32) DivU64x32 (
388 EndTicker - StartTicker,
389 (UINT32) Freq
390 );
391
392 CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
393 Ptr += sizeof (PERF_DATA);
394
395 mPerfHeader.Count++;
396 if (mPerfHeader.Count == LimitCount) {
397 goto Done;
398 }
399 }
400 }
401
402 Done:
403
404 ClearDebugRegisters ();
405
406 mPerfHeader.Signiture = 0x66726550;
407
408 //
409 // Put performance data to memory
410 //
411 CopyMem (
412 (UINT32 *) (UINT32) mAcpiLowMemoryBase,
413 &mPerfHeader,
414 sizeof (PERF_HEADER)
415 );
416
417 gRT->SetVariable (
418 L"PerfDataMemAddr",
419 &gEfiGlobalVariableGuid,
420 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
421 sizeof (UINT32),
422 (VOID *) &mAcpiLowMemoryBase
423 );
424
425 return ;
426 }