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
46 * Always turn on performance tracking when building this file to allow the
\r
47 * performance counter functions to be built into the component library.
\r
48 * Users control their use of the functions by defining the PERF_TRACK_ON
\r
49 * keyword themselves before including cl_perf.h to enable the macros to
\r
50 * resolve to the internal functions.
\r
52 #define PERF_TRACK_ON
\r
54 #include <complib/cl_perf.h>
\r
55 #include <complib/cl_debug.h>
\r
56 #include <complib/cl_memory.h>
\r
61 __cl_perf_run_calibration(
\r
62 IN cl_perf_t* const p_perf );
\r
66 * Initialize the state of the performance tracker.
\r
69 __cl_perf_construct(
\r
70 IN cl_perf_t* const p_perf )
\r
72 cl_memclr( p_perf, sizeof(cl_perf_t) );
\r
73 p_perf->state = CL_UNINITIALIZED;
\r
78 * Initialize the performance tracker.
\r
82 IN cl_perf_t* const p_perf,
\r
83 IN const uintn_t num_counters )
\r
88 static uint64_t locked_calibration_time = 0;
\r
89 static uint64_t normal_calibration_time;
\r
91 CL_ASSERT( p_perf );
\r
92 CL_ASSERT( !p_perf->size && num_counters );
\r
94 /* Construct the performance tracker. */
\r
95 __cl_perf_construct( p_perf );
\r
97 /* Allocate an array of counters. */
\r
98 p_perf->size = num_counters;
\r
99 p_perf->data_array = (cl_perf_data_t*)
\r
100 cl_zalloc( sizeof(cl_perf_data_t) * num_counters );
\r
102 if( !p_perf->data_array )
\r
103 return( CL_INSUFFICIENT_MEMORY );
\r
105 /* Initialize the user's counters. */
\r
106 for( i = 0; i < num_counters; i++ )
\r
108 p_perf->data_array[i].min_time = ((uint64_t)~0);
\r
109 cl_spinlock_construct( &p_perf->data_array[i].lock );
\r
112 for( i = 0; i < num_counters; i++ )
\r
114 status = cl_spinlock_init( &p_perf->data_array[i].lock );
\r
115 if( status != CL_SUCCESS )
\r
117 __cl_perf_destroy( p_perf, FALSE );
\r
123 * Run the calibration only if it has not been run yet. Subsequent
\r
124 * calls will use the results from the first calibration.
\r
126 if( !locked_calibration_time )
\r
129 * Perform the calibration under lock to prevent thread context
\r
132 cl_spinlock_construct( &lock );
\r
133 status = cl_spinlock_init( &lock );
\r
134 if( status != CL_SUCCESS )
\r
136 __cl_perf_destroy( p_perf, FALSE );
\r
140 /* Measure the impact when running at elevated thread priority. */
\r
141 cl_spinlock_acquire( &lock );
\r
142 locked_calibration_time = __cl_perf_run_calibration( p_perf );
\r
143 cl_spinlock_release( &lock );
\r
144 cl_spinlock_destroy( &lock );
\r
146 /* Measure the impact when runnin at normal thread priority. */
\r
147 normal_calibration_time = __cl_perf_run_calibration( p_perf );
\r
150 /* Reset the user's performance counter. */
\r
151 p_perf->normal_calibration_time = locked_calibration_time;
\r
152 p_perf->locked_calibration_time = normal_calibration_time;
\r
153 p_perf->data_array[0].count = 0;
\r
154 p_perf->data_array[0].total_time = 0;
\r
155 p_perf->data_array[0].min_time = ((uint64_t)~0);
\r
157 p_perf->state = CL_INITIALIZED;
\r
159 return( CL_SUCCESS );
\r
164 * Measure the time to take performance counters.
\r
167 __cl_perf_run_calibration(
\r
168 IN cl_perf_t* const p_perf )
\r
170 uint64_t start_time;
\r
174 /* Start timing. */
\r
175 start_time = cl_get_time_stamp();
\r
178 * Get the performance counter repeatedly in a loop. Use the first
\r
179 * user counter as our test counter.
\r
181 for( i = 0; i < PERF_CALIBRATION_TESTS; i++ )
\r
183 cl_perf_start( 0 );
\r
184 cl_perf_stop( p_perf, 0 );
\r
187 /* Calculate the total time for the calibration. */
\r
188 return( cl_get_time_stamp() - start_time );
\r
193 * Destroy the performance tracker.
\r
197 IN cl_perf_t* const p_perf,
\r
198 IN const boolean_t display )
\r
202 CL_ASSERT( cl_is_state_valid( p_perf->state ) );
\r
204 if( !p_perf->data_array )
\r
207 /* Display the performance data as requested. */
\r
208 if( display && p_perf->state == CL_INITIALIZED )
\r
209 __cl_perf_display( p_perf );
\r
211 /* Destroy the user's counters. */
\r
212 for( i = 0; i < p_perf->size; i++ )
\r
213 cl_spinlock_destroy( &p_perf->data_array[i].lock );
\r
215 cl_free( p_perf->data_array );
\r
216 p_perf->data_array = NULL;
\r
218 p_perf->state = CL_UNINITIALIZED;
\r
223 * Reset the performance counters.
\r
227 IN cl_perf_t* const p_perf )
\r
231 for( i = 0; i < p_perf->size; i++ )
\r
233 cl_spinlock_acquire( &p_perf->data_array[i].lock );
\r
234 p_perf->data_array[i].min_time = ((uint64_t)~0);
\r
235 p_perf->data_array[i].total_time = 0;
\r
236 p_perf->data_array[i].count = 0;
\r
237 cl_spinlock_release( &p_perf->data_array[i].lock );
\r
243 * Display the captured performance data.
\r
247 IN const cl_perf_t* const p_perf )
\r
251 CL_ASSERT( p_perf );
\r
252 CL_ASSERT( p_perf->state == CL_INITIALIZED );
\r
254 cl_msg_out( "\n\n\nCL Perf:\tPerformance Data\n" );
\r
256 cl_msg_out( "CL Perf:\tCounter Calibration Time\n" );
\r
257 cl_msg_out( "CL Perf:\tLocked TotalTime\tNormal TotalTime\tTest Count\n" );
\r
258 cl_msg_out( "CL Perf:\t%"PRIu64"\t%"PRIu64"\t%u\n",
\r
259 p_perf->locked_calibration_time, p_perf->normal_calibration_time,
\r
260 PERF_CALIBRATION_TESTS );
\r
262 cl_msg_out( "CL Perf:\tUser Performance Counters\n" );
\r
263 cl_msg_out( "CL Perf:\tIndex\tTotalTime\tMinTime\tCount\n" );
\r
264 for( i = 0; i < p_perf->size; i++ )
\r
266 cl_msg_out( "CL Perf:\t%lu\t%"PRIu64"\t%"PRIu64"\t%"PRIu64"\n",
\r
267 i, p_perf->data_array[i].total_time,
\r
268 p_perf->data_array[i].min_time, p_perf->data_array[i].count );
\r
270 cl_msg_out( "CL Perf:\tEnd of User Performance Counters\n" );
\r