2 * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
\r
3 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
\r
5 * This software is available to you under the OpenIB.org BSD license
\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
12 * - Redistributions of source code must retain the above
\r
13 * copyright notice, this list of conditions and the following
\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
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
36 * Implementation of performance tracking.
\r
39 * All supported environments.
\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
50 #define PERF_TRACK_ON
\r
52 #include <complib/cl_perf.h>
\r
53 #include <complib/cl_debug.h>
\r
54 #include <complib/cl_memory.h>
\r
59 __cl_perf_run_calibration(
\r
60 IN cl_perf_t* const p_perf );
\r
64 * Initialize the state of the performance tracker.
\r
67 __cl_perf_construct(
\r
68 IN cl_perf_t* const p_perf )
\r
70 cl_memclr( p_perf, sizeof(cl_perf_t) );
\r
71 p_perf->state = CL_UNINITIALIZED;
\r
76 * Initialize the performance tracker.
\r
80 IN cl_perf_t* const p_perf,
\r
81 IN const uintn_t num_counters )
\r
86 static uint64_t locked_calibration_time = 0;
\r
87 static uint64_t normal_calibration_time;
\r
89 CL_ASSERT( p_perf );
\r
90 CL_ASSERT( !p_perf->size && num_counters );
\r
92 /* Construct the performance tracker. */
\r
93 __cl_perf_construct( p_perf );
\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
100 if( !p_perf->data_array )
\r
101 return( CL_INSUFFICIENT_MEMORY );
\r
103 /* Initialize the user's counters. */
\r
104 for( i = 0; i < num_counters; i++ )
\r
106 p_perf->data_array[i].min_time = ((uint64_t)~0);
\r
107 cl_spinlock_construct( &p_perf->data_array[i].lock );
\r
110 for( i = 0; i < num_counters; i++ )
\r
112 status = cl_spinlock_init( &p_perf->data_array[i].lock );
\r
113 if( status != CL_SUCCESS )
\r
115 __cl_perf_destroy( p_perf, FALSE );
\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
124 if( !locked_calibration_time )
\r
127 * Perform the calibration under lock to prevent thread context
\r
130 cl_spinlock_construct( &lock );
\r
131 status = cl_spinlock_init( &lock );
\r
132 if( status != CL_SUCCESS )
\r
134 __cl_perf_destroy( p_perf, FALSE );
\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
144 /* Measure the impact when runnin at normal thread priority. */
\r
145 normal_calibration_time = __cl_perf_run_calibration( p_perf );
\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
155 p_perf->state = CL_INITIALIZED;
\r
157 return( CL_SUCCESS );
\r
162 * Measure the time to take performance counters.
\r
165 __cl_perf_run_calibration(
\r
166 IN cl_perf_t* const p_perf )
\r
168 uint64_t start_time;
\r
172 /* Start timing. */
\r
173 start_time = cl_get_time_stamp();
\r
176 * Get the performance counter repeatedly in a loop. Use the first
\r
177 * user counter as our test counter.
\r
179 for( i = 0; i < PERF_CALIBRATION_TESTS; i++ )
\r
181 cl_perf_start( 0 );
\r
182 cl_perf_stop( p_perf, 0 );
\r
185 /* Calculate the total time for the calibration. */
\r
186 return( cl_get_time_stamp() - start_time );
\r
191 * Destroy the performance tracker.
\r
195 IN cl_perf_t* const p_perf,
\r
196 IN const boolean_t display )
\r
200 CL_ASSERT( cl_is_state_valid( p_perf->state ) );
\r
202 if( !p_perf->data_array )
\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
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
213 cl_free( p_perf->data_array );
\r
214 p_perf->data_array = NULL;
\r
216 p_perf->state = CL_UNINITIALIZED;
\r
221 * Reset the performance counters.
\r
225 IN cl_perf_t* const p_perf )
\r
229 for( i = 0; i < p_perf->size; i++ )
\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
241 * Display the captured performance data.
\r
245 IN const cl_perf_t* const p_perf )
\r
249 CL_ASSERT( p_perf );
\r
250 CL_ASSERT( p_perf->state == CL_INITIALIZED );
\r
252 cl_msg_out( "\n\n\nCL Perf:\tPerformance Data\n" );
\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
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
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
268 cl_msg_out( "CL Perf:\tEnd of User Performance Counters\n" );
\r