]> git.proxmox.com Git - mirror_edk2.git/blame - EdkUnixPkg/Library/EdkGenericBdsLib/Performance.c
newline added at end
[mirror_edk2.git] / EdkUnixPkg / Library / EdkGenericBdsLib / Performance.c
CommitLineData
c9093a06 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 //\r
32 // BugBug: We should not need to do this. We need to root cause this bug!!!!\r
33 //\r
34 AsmWriteDr0 (0);\r
35 AsmWriteDr1 (0);\r
36}\r
37\r
38STATIC\r
39VOID\r
40GetShortPdbFileName (\r
41 CHAR8 *PdbFileName,\r
42 CHAR8 *GaugeString\r
43 )\r
44/*++\r
45\r
46Routine Description:\r
47 \r
48Arguments:\r
49\r
50Returns:\r
51\r
52--*/\r
53{\r
54 UINTN Index;\r
55 UINTN Index1;\r
56 UINTN StartIndex;\r
57 UINTN EndIndex;\r
58\r
59 if (PdbFileName == NULL) {\r
60 AsciiStrCpy (GaugeString, " ");\r
61 } else {\r
62 StartIndex = 0;\r
63 for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)\r
64 ;\r
65\r
66 for (Index = 0; PdbFileName[Index] != 0; Index++) {\r
67 if (PdbFileName[Index] == '\\') {\r
68 StartIndex = Index + 1;\r
69 }\r
70\r
71 if (PdbFileName[Index] == '.') {\r
72 EndIndex = Index;\r
73 }\r
74 }\r
75\r
76 Index1 = 0;\r
77 for (Index = StartIndex; Index < EndIndex; Index++) {\r
78 GaugeString[Index1] = PdbFileName[Index];\r
79 Index1++;\r
80 if (Index1 == PERF_TOKEN_LENGTH - 1) {\r
81 break;\r
82 }\r
83 }\r
84\r
85 GaugeString[Index1] = 0;\r
86 }\r
87\r
88 return ;\r
89}\r
90\r
91\r
92\r
93STATIC\r
94CHAR8 *\r
95GetPdbPath (\r
96 VOID *ImageBase\r
97 )\r
98/*++\r
99\r
100Routine Description:\r
101\r
102 Located PDB path name in PE image\r
103\r
104Arguments:\r
105\r
106 ImageBase - base of PE to search\r
107\r
108Returns:\r
109\r
110 Pointer into image at offset of PDB file name if PDB file name is found,\r
111 Otherwise a pointer to an empty string.\r
112\r
113--*/\r
114{\r
115 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
116\r
117 ZeroMem (&ImageContext, sizeof (ImageContext));\r
118 ImageContext.Handle = ImageBase;\r
119 ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
120\r
121 PeCoffLoaderGetImageInfo (&ImageContext);\r
122\r
123 return ImageContext.PdbPointer;\r
124}\r
125\r
126\r
127STATIC\r
128VOID\r
129GetNameFromHandle (\r
130 IN EFI_HANDLE Handle,\r
131 OUT CHAR8 *GaugeString\r
132 )\r
133{\r
134 EFI_STATUS Status;\r
135 EFI_LOADED_IMAGE_PROTOCOL *Image;\r
136 CHAR8 *PdbFileName;\r
137 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
138\r
139 AsciiStrCpy (GaugeString, " ");\r
140\r
141 //\r
142 // Get handle name from image protocol\r
143 //\r
144 Status = gBS->HandleProtocol (\r
145 Handle,\r
146 &gEfiLoadedImageProtocolGuid,\r
147 (VOID **)&Image\r
148 );\r
149\r
150 if (EFI_ERROR (Status)) {\r
151 Status = gBS->OpenProtocol (\r
152 Handle,\r
153 &gEfiDriverBindingProtocolGuid,\r
154 (VOID **) &DriverBinding,\r
155 NULL,\r
156 NULL,\r
157 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
158 );\r
159 if (EFI_ERROR (Status)) {\r
160 return ;\r
161 }\r
162 //\r
163 // Get handle name from image protocol\r
164 //\r
165 Status = gBS->HandleProtocol (\r
166 DriverBinding->ImageHandle,\r
167 &gEfiLoadedImageProtocolGuid,\r
168 (VOID **)&Image\r
169 );\r
170 }\r
171\r
172 PdbFileName = GetPdbPath (Image->ImageBase);\r
173\r
174 if (PdbFileName != NULL) {\r
175 GetShortPdbFileName (PdbFileName, GaugeString);\r
176 }\r
177\r
178 return ;\r
179}\r
180\r
181\r
182\r
183VOID\r
184WriteBootToOsPerformanceData (\r
185 VOID\r
186 )\r
187/*++\r
188\r
189Routine Description:\r
190 \r
191 Allocates a block of memory and writes performance data of booting to OS into it.\r
192\r
193Arguments:\r
194 \r
195 None\r
196 \r
197Returns:\r
198\r
199 None\r
200\r
201--*/\r
202{\r
203 EFI_STATUS Status;\r
204 EFI_CPU_ARCH_PROTOCOL *Cpu;\r
205 EFI_PHYSICAL_ADDRESS mAcpiLowMemoryBase;\r
206 UINT32 mAcpiLowMemoryLength;\r
207 UINT32 LimitCount;\r
208 PERF_HEADER mPerfHeader;\r
209 PERF_DATA mPerfData;\r
210 EFI_HANDLE *Handles;\r
211 UINTN NoHandles;\r
212 CHAR8 GaugeString[PERF_TOKEN_LENGTH];\r
213 UINT8 *Ptr;\r
214 UINT32 mIndex;\r
215 UINT64 Ticker;\r
216 UINT64 Freq;\r
217 UINT32 Duration;\r
218 UINT64 CurrentTicker;\r
219 UINT64 TimerPeriod;\r
220 UINTN LogEntryKey;\r
221 CONST VOID *Handle;\r
222 CONST CHAR8 *Token;\r
223 CONST CHAR8 *Module;\r
224 UINT64 StartTicker;\r
225 UINT64 EndTicker;\r
226\r
227 //\r
228 // Retrive time stamp count as early as possilbe\r
229 //\r
230 Ticker = AsmReadTsc ();\r
231\r
232 //\r
233 // Allocate a block of memory that contain performance data to OS\r
234 //\r
235 mAcpiLowMemoryBase = 0xFFFFFFFF;\r
236 Status = gBS->AllocatePages (\r
237 AllocateMaxAddress,\r
238 EfiReservedMemoryType,\r
239 4,\r
240 &mAcpiLowMemoryBase\r
241 );\r
242 if (EFI_ERROR (Status)) {\r
243 return ;\r
244 }\r
245\r
246 mAcpiLowMemoryLength = EFI_PAGES_TO_SIZE(4);\r
247\r
248 Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));\r
249 LimitCount = (mAcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);\r
250\r
251 //\r
252 // Initialize performance data structure\r
253 //\r
254 ZeroMem (&mPerfHeader, sizeof (PERF_HEADER));\r
255\r
256 //\r
257 // Get CPU frequency\r
258 //\r
259 Status = gBS->LocateProtocol (\r
260 &gEfiCpuArchProtocolGuid,\r
261 NULL,\r
262 (VOID **)&Cpu\r
263 );\r
264 if (EFI_ERROR (Status)) {\r
265 gBS->FreePages (mAcpiLowMemoryBase, 4);\r
266 return ;\r
267 }\r
268 //\r
269 // Get Cpu Frequency\r
270 //\r
271 Status = Cpu->GetTimerValue (Cpu, 0, &(CurrentTicker), &TimerPeriod);\r
272 if (EFI_ERROR (Status)) {\r
273 gBS->FreePages (mAcpiLowMemoryBase, 4);\r
274 return ;\r
275 }\r
276\r
997e26f6 277 Freq = DivU64x32 (1000000000000ULL, (UINTN) TimerPeriod);\r
c9093a06 278\r
279 mPerfHeader.CpuFreq = Freq;\r
280\r
281 //\r
282 // Record BDS raw performance data\r
283 //\r
284 mPerfHeader.BDSRaw = Ticker;\r
285\r
286 //\r
287 // Put Detailed performance data into memory\r
288 //\r
289 Handles = NULL;\r
290 Status = gBS->LocateHandleBuffer (\r
291 AllHandles,\r
292 NULL,\r
293 NULL,\r
294 &NoHandles,\r
295 &Handles\r
296 );\r
297 if (EFI_ERROR (Status)) {\r
298 gBS->FreePages (mAcpiLowMemoryBase, 4);\r
299 return ;\r
300 }\r
301 //\r
302 // Get DXE drivers performance\r
303 //\r
304 for (mIndex = 0; mIndex < NoHandles; mIndex++) {\r
305 Ticker = 0;\r
306 LogEntryKey = 0;\r
307 while ((LogEntryKey = GetPerformanceMeasurement (\r
308 LogEntryKey,\r
309 &Handle,\r
310 &Token,\r
311 &Module,\r
312 &StartTicker,\r
313 &EndTicker)) != 0) {\r
314 if ((Handle == Handles[mIndex]) && (StartTicker < EndTicker)) {\r
315 Ticker += (EndTicker - StartTicker);\r
316 }\r
317 }\r
318\r
319 Duration = (UINT32) DivU64x32 (\r
320 Ticker,\r
321 (UINT32) Freq\r
322 );\r
323\r
324 if (Duration > 0) {\r
325 ZeroMem (&mPerfData, sizeof (PERF_DATA));\r
326\r
327 GetNameFromHandle (Handles[mIndex], GaugeString);\r
328\r
329 AsciiStrCpy (mPerfData.Token, GaugeString);\r
330 mPerfData.Duration = Duration;\r
331\r
332 CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));\r
333 Ptr += sizeof (PERF_DATA);\r
334\r
335 mPerfHeader.Count++;\r
336 if (mPerfHeader.Count == LimitCount) {\r
337 goto Done;\r
338 }\r
339 }\r
340 }\r
341\r
342 gBS->FreePool (Handles);\r
343\r
344 //\r
345 // Get inserted performance data\r
346 //\r
347 LogEntryKey = 0;\r
348 while ((LogEntryKey = GetPerformanceMeasurement (\r
349 LogEntryKey,\r
350 &Handle,\r
351 &Token,\r
352 &Module,\r
353 &StartTicker,\r
354 &EndTicker)) != 0) {\r
355 if ((Handle == NULL) && (StartTicker <= EndTicker)) {\r
356\r
357 ZeroMem (&mPerfData, sizeof (PERF_DATA));\r
358\r
359 AsciiStrnCpy (mPerfData.Token, Token, DXE_PERFORMANCE_STRING_SIZE);\r
360 mPerfData.Duration = (UINT32) DivU64x32 (\r
361 EndTicker - StartTicker,\r
362 (UINT32) Freq\r
363 );\r
364\r
365 CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));\r
366 Ptr += sizeof (PERF_DATA);\r
367\r
368 mPerfHeader.Count++;\r
369 if (mPerfHeader.Count == LimitCount) {\r
370 goto Done;\r
371 }\r
372 }\r
373 }\r
374\r
375Done:\r
376\r
377 ClearDebugRegisters ();\r
378\r
379 mPerfHeader.Signiture = 0x66726550;\r
380\r
381 //\r
382 // Put performance data to memory\r
383 //\r
384 CopyMem (\r
385 (UINT32 *) (UINT32) mAcpiLowMemoryBase,\r
386 &mPerfHeader,\r
387 sizeof (PERF_HEADER)\r
388 );\r
389\r
390 gRT->SetVariable (\r
391 L"PerfDataMemAddr",\r
392 &gEfiGlobalVariableGuid,\r
393 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
394 sizeof (UINT32),\r
395 (VOID *) &mAcpiLowMemoryBase\r
396 );\r
397\r
398 return ;\r
399}\r