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