removed Revison keyword since ID keyword exists, deleted unused files
[mirror/winof/.git] / core / complib / cl_perf.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. \r
4  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\r
8  *     Redistribution and use in source and binary forms, with or\r
9  *     without modification, are permitted provided that the following\r
10  *     conditions are met:\r
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\r
16  *      - Redistributions in binary form must reproduce the above\r
17  *        copyright notice, this list of conditions and the following\r
18  *        disclaimer in the documentation and/or other materials\r
19  *        provided with the distribution.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
25  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
26  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
28  * SOFTWARE.\r
29  *\r
30  * $Id$\r
31  */\r
32 \r
33 \r
34 /*\r
35  * Abstract:\r
36  *      Implementation of performance tracking.\r
37  *\r
38  * Environment:\r
39  *      All supported environments.\r
40  */\r
41 \r
42 \r
43 /*\r
44  * Always turn on performance tracking when building this file to allow the\r
45  * performance counter functions to be built into the component library.\r
46  * Users control their use of the functions by defining the PERF_TRACK_ON\r
47  * keyword themselves before including cl_perf.h to enable the macros to\r
48  * resolve to the internal functions.\r
49  */\r
50 #define PERF_TRACK_ON\r
51 \r
52 #include <complib/cl_perf.h>\r
53 #include <complib/cl_debug.h>\r
54 #include <complib/cl_memory.h>\r
55 \r
56 \r
57 \r
58 uint64_t\r
59 __cl_perf_run_calibration(\r
60         IN      cl_perf_t* const p_perf );\r
61 \r
62 \r
63 /*\r
64  * Initialize the state of the performance tracker.\r
65  */\r
66 void\r
67 __cl_perf_construct(\r
68         IN      cl_perf_t* const        p_perf )\r
69 {\r
70         cl_memclr( p_perf, sizeof(cl_perf_t) );\r
71         p_perf->state = CL_UNINITIALIZED;\r
72 }\r
73 \r
74 \r
75 /*\r
76  * Initialize the performance tracker.\r
77  */\r
78 cl_status_t\r
79 __cl_perf_init(\r
80         IN      cl_perf_t* const        p_perf,\r
81         IN      const uintn_t           num_counters )\r
82 {\r
83         cl_status_t             status;\r
84         cl_spinlock_t   lock;\r
85         uintn_t                 i;\r
86         static uint64_t locked_calibration_time = 0;\r
87         static uint64_t normal_calibration_time;\r
88 \r
89         CL_ASSERT( p_perf );\r
90         CL_ASSERT( !p_perf->size && num_counters );\r
91 \r
92         /* Construct the performance tracker. */\r
93         __cl_perf_construct( p_perf );\r
94 \r
95         /* Allocate an array of counters. */\r
96         p_perf->size = num_counters;\r
97         p_perf->data_array = (cl_perf_data_t*)\r
98                 cl_zalloc( sizeof(cl_perf_data_t) * num_counters );\r
99 \r
100         if( !p_perf->data_array )\r
101                 return( CL_INSUFFICIENT_MEMORY );\r
102 \r
103         /* Initialize the user's counters. */\r
104         for( i = 0; i < num_counters; i++ )\r
105         {\r
106                 p_perf->data_array[i].min_time = ((uint64_t)~0);\r
107                 cl_spinlock_construct( &p_perf->data_array[i].lock );\r
108         }\r
109 \r
110         for( i  = 0; i < num_counters; i++ )\r
111         {\r
112                 status = cl_spinlock_init( &p_perf->data_array[i].lock );\r
113                 if( status != CL_SUCCESS )\r
114                 {\r
115                         __cl_perf_destroy( p_perf, FALSE );\r
116                         return( status );\r
117                 }\r
118         }\r
119 \r
120         /*\r
121          * Run the calibration only if it has not been run yet.  Subsequent\r
122          * calls will use the results from the first calibration.\r
123          */\r
124         if( !locked_calibration_time )\r
125         {\r
126                 /*\r
127                  * Perform the calibration under lock to prevent thread context\r
128                  * switches.\r
129                  */\r
130                 cl_spinlock_construct( &lock );\r
131                 status = cl_spinlock_init( &lock );\r
132                 if( status != CL_SUCCESS )\r
133                 {\r
134                         __cl_perf_destroy( p_perf, FALSE );\r
135                         return( status );\r
136                 }\r
137 \r
138                 /* Measure the impact when running at elevated thread priority. */\r
139                 cl_spinlock_acquire( &lock );\r
140                 locked_calibration_time = __cl_perf_run_calibration( p_perf );\r
141                 cl_spinlock_release( &lock );\r
142                 cl_spinlock_destroy( &lock );\r
143 \r
144                 /* Measure the impact when runnin at normal thread priority. */\r
145                 normal_calibration_time = __cl_perf_run_calibration( p_perf );\r
146         }\r
147 \r
148         /* Reset the user's performance counter. */\r
149         p_perf->normal_calibration_time = locked_calibration_time;\r
150         p_perf->locked_calibration_time = normal_calibration_time;\r
151         p_perf->data_array[0].count = 0;\r
152         p_perf->data_array[0].total_time = 0;\r
153         p_perf->data_array[0].min_time = ((uint64_t)~0);\r
154 \r
155         p_perf->state = CL_INITIALIZED;\r
156 \r
157         return( CL_SUCCESS );\r
158 }\r
159 \r
160 \r
161 /*\r
162  * Measure the time to take performance counters.\r
163  */\r
164 uint64_t\r
165 __cl_perf_run_calibration(\r
166         IN      cl_perf_t* const        p_perf )\r
167 {\r
168         uint64_t                start_time;\r
169         uintn_t                 i;\r
170         PERF_DECLARE( 0 );\r
171 \r
172         /* Start timing. */\r
173         start_time = cl_get_time_stamp();\r
174 \r
175         /*\r
176          * Get the performance counter repeatedly in a loop.  Use the first\r
177          * user counter as our test counter.\r
178          */\r
179         for( i = 0; i < PERF_CALIBRATION_TESTS; i++ )\r
180         {\r
181                 cl_perf_start( 0 );\r
182                 cl_perf_stop( p_perf, 0 );\r
183         }\r
184 \r
185         /* Calculate the total time for the calibration. */\r
186         return( cl_get_time_stamp() - start_time );\r
187 }\r
188 \r
189 \r
190 /*\r
191  * Destroy the performance tracker.\r
192  */\r
193 void\r
194 __cl_perf_destroy(\r
195         IN      cl_perf_t* const        p_perf,\r
196         IN      const boolean_t         display )\r
197 {\r
198         uintn_t i;\r
199 \r
200         CL_ASSERT( cl_is_state_valid( p_perf->state ) );\r
201 \r
202         if( !p_perf->data_array )\r
203                 return;\r
204 \r
205         /* Display the performance data as requested. */\r
206         if( display && p_perf->state == CL_INITIALIZED )\r
207                 __cl_perf_display( p_perf );\r
208 \r
209         /* Destroy the user's counters. */\r
210         for( i = 0; i < p_perf->size; i++ )\r
211                 cl_spinlock_destroy( &p_perf->data_array[i].lock );\r
212 \r
213         cl_free( p_perf->data_array );\r
214         p_perf->data_array = NULL;\r
215 \r
216         p_perf->state = CL_UNINITIALIZED;\r
217 }\r
218 \r
219 \r
220 /*\r
221  * Reset the performance counters.\r
222  */\r
223 void\r
224 __cl_perf_reset(\r
225         IN      cl_perf_t* const                p_perf )\r
226 {\r
227         uintn_t i;\r
228 \r
229         for( i = 0; i < p_perf->size; i++ )\r
230         {\r
231                 cl_spinlock_acquire( &p_perf->data_array[i].lock );\r
232                 p_perf->data_array[i].min_time = ((uint64_t)~0);\r
233                 p_perf->data_array[i].total_time = 0;\r
234                 p_perf->data_array[i].count = 0;\r
235                 cl_spinlock_release( &p_perf->data_array[i].lock );\r
236         }\r
237 }\r
238 \r
239 \r
240 /*\r
241  * Display the captured performance data.\r
242  */\r
243 void\r
244 __cl_perf_display(\r
245         IN      const cl_perf_t* const  p_perf )\r
246 {\r
247         uintn_t i;\r
248 \r
249         CL_ASSERT( p_perf );\r
250         CL_ASSERT( p_perf->state == CL_INITIALIZED );\r
251 \r
252         cl_msg_out( "\n\n\nCL Perf:\tPerformance Data\n" );\r
253 \r
254         cl_msg_out( "CL Perf:\tCounter Calibration Time\n" );\r
255         cl_msg_out( "CL Perf:\tLocked TotalTime\tNormal TotalTime\tTest Count\n" );\r
256         cl_msg_out( "CL Perf:\t%"PRIu64"\t%"PRIu64"\t%u\n",\r
257                 p_perf->locked_calibration_time, p_perf->normal_calibration_time,\r
258                 PERF_CALIBRATION_TESTS );\r
259 \r
260         cl_msg_out( "CL Perf:\tUser Performance Counters\n" );\r
261         cl_msg_out( "CL Perf:\tIndex\tTotalTime\tMinTime\tCount\n" );\r
262         for( i = 0; i < p_perf->size; i++ )\r
263         {\r
264                 cl_msg_out( "CL Perf:\t%lu\t%"PRIu64"\t%"PRIu64"\t%"PRIu64"\n",\r
265                         i, p_perf->data_array[i].total_time,\r
266                         p_perf->data_array[i].min_time, p_perf->data_array[i].count );\r
267         }\r
268         cl_msg_out( "CL Perf:\tEnd of User Performance Counters\n" );\r
269 }\r