newline added at end
[people/mcb30/edk2.git] / edk2 / EdkUnixPkg / Library / EdkGenericBdsLib / Performance.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   Performance.c\r
15 \r
16 Abstract:\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
26 VOID\r
27 ClearDebugRegisters (\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
38 STATIC\r
39 VOID\r
40 GetShortPdbFileName (\r
41   CHAR8  *PdbFileName,\r
42   CHAR8  *GaugeString\r
43   )\r
44 /*++\r
45 \r
46 Routine Description:\r
47   \r
48 Arguments:\r
49 \r
50 Returns:\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
93 STATIC\r
94 CHAR8 *\r
95 GetPdbPath (\r
96   VOID *ImageBase\r
97   )\r
98 /*++\r
99 \r
100 Routine Description:\r
101 \r
102   Located PDB path name in PE image\r
103 \r
104 Arguments:\r
105 \r
106   ImageBase - base of PE to search\r
107 \r
108 Returns:\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
127 STATIC\r
128 VOID\r
129 GetNameFromHandle (\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
183 VOID\r
184 WriteBootToOsPerformanceData (\r
185   VOID\r
186   )\r
187 /*++\r
188 \r
189 Routine Description:\r
190   \r
191   Allocates a block of memory and writes performance data of booting to OS into it.\r
192 \r
193 Arguments:\r
194   \r
195   None\r
196   \r
197 Returns:\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
277   Freq                = DivU64x32 (1000000000000ULL, (UINTN) TimerPeriod);\r
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
375 Done:\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