1 /** @file
2   Performance Library
3 
4   This library instance provides infrastructure for DXE phase drivers to log performance
5   data. It consumes PerformanceEx or Performance Protocol published by DxeCorePerformanceLib
6   to log performance data. If both PerformanceEx and Performance Protocol is not available, it does not log any
7   performance information.
8 
9   Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
10 This program and the accompanying materials
11 are licensed and made available under the terms and conditions of the BSD License
12 which accompanies this distribution.  The full text of the license may be found at
13 http://opensource.org/licenses/bsd-license.php
14 
15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
16 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 
18 **/
19 
20 
21 #include <PiDxe.h>
22 
23 #include <Guid/Performance.h>
24 
25 #include <Library/PerformanceLib.h>
26 #include <Library/DebugLib.h>
27 #include <Library/UefiBootServicesTableLib.h>
28 #include <Library/PcdLib.h>
29 
30 //
31 // The cached Performance Protocol and PerformanceEx Protocol interface.
32 //
33 PERFORMANCE_PROTOCOL        *mPerformance = NULL;
34 PERFORMANCE_EX_PROTOCOL     *mPerformanceEx = NULL;
35 
36 /**
37   The function caches the pointers to PerformanceEx protocol and Performance Protocol.
38 
39   The function locates PerformanceEx protocol and Performance Protocol from protocol database.
40 
41   @retval EFI_SUCCESS     PerformanceEx protocol or Performance Protocol is successfully located.
42   @retval EFI_NOT_FOUND   Both PerformanceEx protocol and Performance Protocol are not located to log performance.
43 
44 **/
45 EFI_STATUS
GetPerformanceProtocol(VOID)46 GetPerformanceProtocol (
47   VOID
48   )
49 {
50   EFI_STATUS                Status;
51   PERFORMANCE_PROTOCOL      *Performance;
52   PERFORMANCE_EX_PROTOCOL   *PerformanceEx;
53 
54   if (mPerformanceEx != NULL || mPerformance != NULL) {
55     return EFI_SUCCESS;
56   }
57 
58   Status = gBS->LocateProtocol (&gPerformanceExProtocolGuid, NULL, (VOID **) &PerformanceEx);
59   if (!EFI_ERROR (Status)) {
60     ASSERT (PerformanceEx != NULL);
61     //
62     // Cache PerformanceEx Protocol.
63     //
64     mPerformanceEx = PerformanceEx;
65     return EFI_SUCCESS;
66   }
67 
68   Status = gBS->LocateProtocol (&gPerformanceProtocolGuid, NULL, (VOID **) &Performance);
69   if (!EFI_ERROR (Status)) {
70     ASSERT (Performance != NULL);
71     //
72     // Cache performance protocol.
73     //
74     mPerformance = Performance;
75     return EFI_SUCCESS;
76   }
77 
78   return EFI_NOT_FOUND;
79 }
80 
81 /**
82   Creates a record for the beginning of a performance measurement.
83 
84   Creates a record that contains the Handle, Token, Module and Identifier.
85   If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
86   If TimeStamp is zero, then this function reads the current time stamp
87   and adds that time stamp value to the record as the start time.
88 
89   @param  Handle                  Pointer to environment specific context used
90                                   to identify the component being measured.
91   @param  Token                   Pointer to a Null-terminated ASCII string
92                                   that identifies the component being measured.
93   @param  Module                  Pointer to a Null-terminated ASCII string
94                                   that identifies the module being measured.
95   @param  TimeStamp               64-bit time stamp.
96   @param  Identifier              32-bit identifier. If the value is 0, the created record
97                                   is same as the one created by StartPerformanceMeasurement.
98 
99   @retval RETURN_SUCCESS          The start of the measurement was recorded.
100   @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
101 
102 **/
103 RETURN_STATUS
104 EFIAPI
StartPerformanceMeasurementEx(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp,IN UINT32 Identifier)105 StartPerformanceMeasurementEx (
106   IN CONST VOID   *Handle,  OPTIONAL
107   IN CONST CHAR8  *Token,   OPTIONAL
108   IN CONST CHAR8  *Module,  OPTIONAL
109   IN UINT64       TimeStamp,
110   IN UINT32       Identifier
111   )
112 {
113   EFI_STATUS  Status;
114 
115   Status = GetPerformanceProtocol ();
116   if (EFI_ERROR (Status)) {
117     return RETURN_OUT_OF_RESOURCES;
118   }
119 
120   if (mPerformanceEx != NULL) {
121     Status = mPerformanceEx->StartGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
122   } else if (mPerformance != NULL) {
123     Status = mPerformance->StartGauge (Handle, Token, Module, TimeStamp);
124   } else {
125     ASSERT (FALSE);
126   }
127 
128   return (RETURN_STATUS) Status;
129 }
130 
131 /**
132   Fills in the end time of a performance measurement.
133 
134   Looks up the record that matches Handle, Token and Module.
135   If the record can not be found then return RETURN_NOT_FOUND.
136   If the record is found and TimeStamp is not zero,
137   then TimeStamp is added to the record as the end time.
138   If the record is found and TimeStamp is zero, then this function reads
139   the current time stamp and adds that time stamp value to the record as the end time.
140 
141   @param  Handle                  Pointer to environment specific context used
142                                   to identify the component being measured.
143   @param  Token                   Pointer to a Null-terminated ASCII string
144                                   that identifies the component being measured.
145   @param  Module                  Pointer to a Null-terminated ASCII string
146                                   that identifies the module being measured.
147   @param  TimeStamp               64-bit time stamp.
148   @param  Identifier              32-bit identifier. If the value is 0, the found record
149                                   is same as the one found by EndPerformanceMeasurement.
150 
151   @retval RETURN_SUCCESS          The end of  the measurement was recorded.
152   @retval RETURN_NOT_FOUND        The specified measurement record could not be found.
153 
154 **/
155 RETURN_STATUS
156 EFIAPI
EndPerformanceMeasurementEx(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp,IN UINT32 Identifier)157 EndPerformanceMeasurementEx (
158   IN CONST VOID   *Handle,  OPTIONAL
159   IN CONST CHAR8  *Token,   OPTIONAL
160   IN CONST CHAR8  *Module,  OPTIONAL
161   IN UINT64       TimeStamp,
162   IN UINT32       Identifier
163   )
164 {
165   EFI_STATUS  Status;
166 
167   Status = GetPerformanceProtocol ();
168   if (EFI_ERROR (Status)) {
169     return RETURN_NOT_FOUND;
170   }
171 
172   if (mPerformanceEx != NULL) {
173     Status = mPerformanceEx->EndGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
174   } else if (mPerformance != NULL) {
175     Status = mPerformance->EndGauge (Handle, Token, Module, TimeStamp);
176   } else {
177     ASSERT (FALSE);
178   }
179 
180   return (RETURN_STATUS) Status;
181 }
182 
183 /**
184   Attempts to retrieve a performance measurement log entry from the performance measurement log.
185   It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
186   and then assign the Identifier with 0.
187 
188   Attempts to retrieve the performance log entry specified by LogEntryKey.  If LogEntryKey is
189   zero on entry, then an attempt is made to retrieve the first entry from the performance log,
190   and the key for the second entry in the log is returned.  If the performance log is empty,
191   then no entry is retrieved and zero is returned.  If LogEntryKey is not zero, then the performance
192   log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
193   returned.  If LogEntryKey is the key for the last entry in the log, then the last log entry is
194   retrieved and an implementation specific non-zero key value that specifies the end of the performance
195   log is returned.  If LogEntryKey is equal this implementation specific non-zero key value, then no entry
196   is retrieved and zero is returned.  In the cases where a performance log entry can be returned,
197   the log entry is returned in Handle, Token, Module, StartTimeStamp, EndTimeStamp and Identifier.
198   If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
199   If Handle is NULL, then ASSERT().
200   If Token is NULL, then ASSERT().
201   If Module is NULL, then ASSERT().
202   If StartTimeStamp is NULL, then ASSERT().
203   If EndTimeStamp is NULL, then ASSERT().
204   If Identifier is NULL, then ASSERT().
205 
206   @param  LogEntryKey             On entry, the key of the performance measurement log entry to retrieve.
207                                   0, then the first performance measurement log entry is retrieved.
208                                   On exit, the key of the next performance log entry.
209   @param  Handle                  Pointer to environment specific context used to identify the component
210                                   being measured.
211   @param  Token                   Pointer to a Null-terminated ASCII string that identifies the component
212                                   being measured.
213   @param  Module                  Pointer to a Null-terminated ASCII string that identifies the module
214                                   being measured.
215   @param  StartTimeStamp          Pointer to the 64-bit time stamp that was recorded when the measurement
216                                   was started.
217   @param  EndTimeStamp            Pointer to the 64-bit time stamp that was recorded when the measurement
218                                   was ended.
219   @param  Identifier              Pointer to the 32-bit identifier that was recorded.
220 
221   @return The key for the next performance log entry (in general case).
222 
223 **/
224 UINTN
225 EFIAPI
GetPerformanceMeasurementEx(IN UINTN LogEntryKey,OUT CONST VOID ** Handle,OUT CONST CHAR8 ** Token,OUT CONST CHAR8 ** Module,OUT UINT64 * StartTimeStamp,OUT UINT64 * EndTimeStamp,OUT UINT32 * Identifier)226 GetPerformanceMeasurementEx (
227   IN  UINTN       LogEntryKey,
228   OUT CONST VOID  **Handle,
229   OUT CONST CHAR8 **Token,
230   OUT CONST CHAR8 **Module,
231   OUT UINT64      *StartTimeStamp,
232   OUT UINT64      *EndTimeStamp,
233   OUT UINT32      *Identifier
234   )
235 {
236   EFI_STATUS            Status;
237   GAUGE_DATA_ENTRY_EX   *GaugeData;
238 
239   GaugeData = NULL;
240 
241   ASSERT (Handle != NULL);
242   ASSERT (Token != NULL);
243   ASSERT (Module != NULL);
244   ASSERT (StartTimeStamp != NULL);
245   ASSERT (EndTimeStamp != NULL);
246   ASSERT (Identifier != NULL);
247 
248   Status = GetPerformanceProtocol ();
249   if (EFI_ERROR (Status)) {
250     return 0;
251   }
252 
253   if (mPerformanceEx != NULL) {
254     Status = mPerformanceEx->GetGaugeEx (LogEntryKey++, &GaugeData);
255   } else if (mPerformance != NULL) {
256     Status = mPerformance->GetGauge (LogEntryKey++, (GAUGE_DATA_ENTRY **) &GaugeData);
257   } else {
258     ASSERT (FALSE);
259     return 0;
260   }
261 
262   //
263   // Make sure that LogEntryKey is a valid log entry key,
264   //
265   ASSERT (Status != EFI_INVALID_PARAMETER);
266 
267   if (EFI_ERROR (Status)) {
268     //
269     // The LogEntryKey is the last entry (equals to the total entry number).
270     //
271     return 0;
272   }
273 
274   ASSERT (GaugeData != NULL);
275 
276   *Handle         = (VOID *) (UINTN) GaugeData->Handle;
277   *Token          = GaugeData->Token;
278   *Module         = GaugeData->Module;
279   *StartTimeStamp = GaugeData->StartTimeStamp;
280   *EndTimeStamp   = GaugeData->EndTimeStamp;
281   if (mPerformanceEx != NULL) {
282     *Identifier   = GaugeData->Identifier;
283   } else {
284     *Identifier   = 0;
285   }
286 
287   return LogEntryKey;
288 }
289 
290 /**
291   Creates a record for the beginning of a performance measurement.
292 
293   Creates a record that contains the Handle, Token, and Module.
294   If TimeStamp is not zero, then TimeStamp is added to the record as the start time.
295   If TimeStamp is zero, then this function reads the current time stamp
296   and adds that time stamp value to the record as the start time.
297 
298   @param  Handle                  Pointer to environment specific context used
299                                   to identify the component being measured.
300   @param  Token                   Pointer to a Null-terminated ASCII string
301                                   that identifies the component being measured.
302   @param  Module                  Pointer to a Null-terminated ASCII string
303                                   that identifies the module being measured.
304   @param  TimeStamp               64-bit time stamp.
305 
306   @retval RETURN_SUCCESS          The start of the measurement was recorded.
307   @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
308 
309 **/
310 RETURN_STATUS
311 EFIAPI
StartPerformanceMeasurement(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp)312 StartPerformanceMeasurement (
313   IN CONST VOID   *Handle,  OPTIONAL
314   IN CONST CHAR8  *Token,   OPTIONAL
315   IN CONST CHAR8  *Module,  OPTIONAL
316   IN UINT64       TimeStamp
317   )
318 {
319   return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
320 }
321 
322 /**
323   Fills in the end time of a performance measurement.
324 
325   Looks up the record that matches Handle, Token, and Module.
326   If the record can not be found then return RETURN_NOT_FOUND.
327   If the record is found and TimeStamp is not zero,
328   then TimeStamp is added to the record as the end time.
329   If the record is found and TimeStamp is zero, then this function reads
330   the current time stamp and adds that time stamp value to the record as the end time.
331 
332   @param  Handle                  Pointer to environment specific context used
333                                   to identify the component being measured.
334   @param  Token                   Pointer to a Null-terminated ASCII string
335                                   that identifies the component being measured.
336   @param  Module                  Pointer to a Null-terminated ASCII string
337                                   that identifies the module being measured.
338   @param  TimeStamp               64-bit time stamp.
339 
340   @retval RETURN_SUCCESS          The end of  the measurement was recorded.
341   @retval RETURN_NOT_FOUND        The specified measurement record could not be found.
342 
343 **/
344 RETURN_STATUS
345 EFIAPI
EndPerformanceMeasurement(IN CONST VOID * Handle,OPTIONAL IN CONST CHAR8 * Token,OPTIONAL IN CONST CHAR8 * Module,OPTIONAL IN UINT64 TimeStamp)346 EndPerformanceMeasurement (
347   IN CONST VOID   *Handle,  OPTIONAL
348   IN CONST CHAR8  *Token,   OPTIONAL
349   IN CONST CHAR8  *Module,  OPTIONAL
350   IN UINT64       TimeStamp
351   )
352 {
353   return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
354 }
355 
356 /**
357   Attempts to retrieve a performance measurement log entry from the performance measurement log.
358   It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
359   and then eliminate the Identifier.
360 
361   Attempts to retrieve the performance log entry specified by LogEntryKey.  If LogEntryKey is
362   zero on entry, then an attempt is made to retrieve the first entry from the performance log,
363   and the key for the second entry in the log is returned.  If the performance log is empty,
364   then no entry is retrieved and zero is returned.  If LogEntryKey is not zero, then the performance
365   log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
366   returned.  If LogEntryKey is the key for the last entry in the log, then the last log entry is
367   retrieved and an implementation specific non-zero key value that specifies the end of the performance
368   log is returned.  If LogEntryKey is equal this implementation specific non-zero key value, then no entry
369   is retrieved and zero is returned.  In the cases where a performance log entry can be returned,
370   the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
371   If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
372   If Handle is NULL, then ASSERT().
373   If Token is NULL, then ASSERT().
374   If Module is NULL, then ASSERT().
375   If StartTimeStamp is NULL, then ASSERT().
376   If EndTimeStamp is NULL, then ASSERT().
377 
378   @param  LogEntryKey             On entry, the key of the performance measurement log entry to retrieve.
379                                   0, then the first performance measurement log entry is retrieved.
380                                   On exit, the key of the next performance log entry.
381   @param  Handle                  Pointer to environment specific context used to identify the component
382                                   being measured.
383   @param  Token                   Pointer to a Null-terminated ASCII string that identifies the component
384                                   being measured.
385   @param  Module                  Pointer to a Null-terminated ASCII string that identifies the module
386                                   being measured.
387   @param  StartTimeStamp          Pointer to the 64-bit time stamp that was recorded when the measurement
388                                   was started.
389   @param  EndTimeStamp            Pointer to the 64-bit time stamp that was recorded when the measurement
390                                   was ended.
391 
392   @return The key for the next performance log entry (in general case).
393 
394 **/
395 UINTN
396 EFIAPI
GetPerformanceMeasurement(IN UINTN LogEntryKey,OUT CONST VOID ** Handle,OUT CONST CHAR8 ** Token,OUT CONST CHAR8 ** Module,OUT UINT64 * StartTimeStamp,OUT UINT64 * EndTimeStamp)397 GetPerformanceMeasurement (
398   IN  UINTN       LogEntryKey,
399   OUT CONST VOID  **Handle,
400   OUT CONST CHAR8 **Token,
401   OUT CONST CHAR8 **Module,
402   OUT UINT64      *StartTimeStamp,
403   OUT UINT64      *EndTimeStamp
404   )
405 {
406   UINT32 Identifier;
407   return GetPerformanceMeasurementEx (LogEntryKey, Handle, Token, Module, StartTimeStamp, EndTimeStamp, &Identifier);
408 }
409 
410 /**
411   Returns TRUE if the performance measurement macros are enabled.
412 
413   This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
414   PcdPerformanceLibraryPropertyMask is set.  Otherwise FALSE is returned.
415 
416   @retval TRUE                    The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
417                                   PcdPerformanceLibraryPropertyMask is set.
418   @retval FALSE                   The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
419                                   PcdPerformanceLibraryPropertyMask is clear.
420 
421 **/
422 BOOLEAN
423 EFIAPI
PerformanceMeasurementEnabled(VOID)424 PerformanceMeasurementEnabled (
425   VOID
426   )
427 {
428   return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
429 }
430