1/****************************************************************************
2**+-----------------------------------------------------------------------+**
3**|                                                                       |**
4**| Copyright(c) 1998 - 2008 Texas Instruments. All rights reserved.      |**
5**| All rights reserved.                                                  |**
6**|                                                                       |**
7**| Redistribution and use in source and binary forms, with or without    |**
8**| modification, are permitted provided that the following conditions    |**
9**| are met:                                                              |**
10**|                                                                       |**
11**|  * Redistributions of source code must retain the above copyright     |**
12**|    notice, this list of conditions and the following disclaimer.      |**
13**|  * Redistributions in binary form must reproduce the above copyright  |**
14**|    notice, this list of conditions and the following disclaimer in    |**
15**|    the documentation and/or other materials provided with the         |**
16**|    distribution.                                                      |**
17**|  * Neither the name Texas Instruments nor the names of its            |**
18**|    contributors may be used to endorse or promote products derived    |**
19**|    from this software without specific prior written permission.      |**
20**|                                                                       |**
21**| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |**
22**| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |**
23**| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |**
24**| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |**
25**| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |**
26**| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |**
27**| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |**
28**| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |**
29**| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |**
30**| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |**
31**| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |**
32**|                                                                       |**
33**+-----------------------------------------------------------------------+**
34****************************************************************************/
35
36
37
38#include "esta_drv.h"
39
40
41static void tiwlan_profile_bus_access_start (void *os, unsigned);
42static void tiwlan_profile_bus_access_end (void *os, unsigned);
43static void tiwlan_profile_driver_entry_start (void *os, unsigned);
44static void tiwlan_profile_driver_entry_end (void *os, unsigned);
45static void tiwlan_profile_memory_alloc (void *os, unsigned);
46static void tiwlan_profile_memory_free (void *os, unsigned);
47static void tiwlan_profile_buf_alloc (void * os, unsigned);
48static void tiwlan_profile_timer_create (void * os, unsigned);
49static void tiwlan_profile_timer_destroy (void * os, unsigned);
50
51
52int tiwlan_profile_create (tiwlan_net_dev_t *drv)
53{
54    drv->fpro [0] = NULL;
55    drv->fpro [1] = NULL;
56    drv->fpro [2] = NULL;
57    drv->fpro [3] = NULL;
58    drv->fpro [4] = tiwlan_profile_memory_alloc;
59    drv->fpro [5] = tiwlan_profile_memory_free;
60    drv->fpro [6] = tiwlan_profile_timer_create;
61    drv->fpro [7] = tiwlan_profile_timer_destroy;
62    drv->fpro [8] = tiwlan_profile_buf_alloc;
63
64    drv->cpu_usage_estimator_start_time = 0;
65    drv->cpu_usage_estimator_stop_time = 0;
66    drv->max_heap_bytes_allocated = 0;
67    drv->max_buf_bytes_allocated = 0;
68    drv->cur_heap_bytes_allocated = 0;
69    drv->max_number_of_timers = 0;
70    drv->cur_number_of_timers = 0;
71
72    return 0;
73}
74
75
76/* Call register profiler banchmark */
77int tiwlan_profile (tiwlan_net_dev_t *drv, unsigned bm, unsigned par)
78{
79    if (drv && bm < MAX_PROFILE_BM && drv->fpro [bm])
80    {
81        (*drv->fpro [bm]) (drv, par);
82    }
83
84    return 0;
85}
86
87
88/* Stop CPU estimation for a driver entry and maintains the resolution of the estimator */
89void tiwlan_profile_bus_access_start (void * os, unsigned par)
90{
91    tiwlan_net_dev_t * drv = (tiwlan_net_dev_t *) os;
92
93    if (drv != NULL)
94    {
95        /* Save the current entry's start time */
96        drv->bus_driver_entry_start_time = os_timeStampUs (drv);
97    }
98}
99
100
101/* Starts CPU estimation for a bus driver entry */
102void tiwlan_profile_bus_access_end (void * os, unsigned par)
103{
104    tiwlan_net_dev_t * drv = (tiwlan_net_dev_t *) os;
105    unsigned current_entry_cpu_usage;
106
107    if (drv != NULL)
108    {
109        /* Save the current entry's start time */
110        current_entry_cpu_usage = os_timeStampUs (drv) - drv->bus_driver_entry_start_time;
111
112        /* Make sure that it is not a negative value */
113        if ((int)current_entry_cpu_usage < 0)
114        {
115            printk("\n\n%s: cpu usage estimation corrupted. entry_start=%u, entry_cpu_time = %d\n\n\n",
116                   __FUNCTION__, drv->bus_driver_entry_start_time,  current_entry_cpu_usage);
117        }
118        /* Update the total time of driver CPU usage */
119        else
120        {
121            drv->total_us_of_bus_access_cpu_time += current_entry_cpu_usage;
122        }
123    }
124}
125
126
127/* Starts CPU estimation for a driver entry */
128void tiwlan_profile_driver_entry_start (void * os, unsigned par)
129{
130    tiwlan_net_dev_t * drv = (tiwlan_net_dev_t *) os;
131
132    if (drv != NULL)
133    {
134        drv->driver_entry_start_time = os_timeStampUs (drv);
135    }
136}
137
138
139/* Stop CPU estimation for a driver entry and maintains the resolution of the estimator */
140void tiwlan_profile_driver_entry_end (void * os, unsigned par)
141{
142    tiwlan_net_dev_t * drv = (tiwlan_net_dev_t *) os;
143    unsigned current_entry_cpu_usage, driver_entry_end_time;
144
145    if (drv == NULL)
146        return;
147
148    /* Get the current entry's end time */
149    driver_entry_end_time = os_timeStampUs (drv);
150
151    /* Calculate the current entries CPU run time */
152    current_entry_cpu_usage = driver_entry_end_time - drv->driver_entry_start_time;
153
154    /* Make sure that it is not a negative value */
155    if ((int)current_entry_cpu_usage < 0)
156    {
157        printk("\n\n%s: cpu usage estimation corrupted. entry_start=%u, entry_end=%u, entry_cpu_time = %d\n\n\n",
158               __FUNCTION__, drv->driver_entry_start_time, driver_entry_end_time, current_entry_cpu_usage);
159    }
160    /* Update the total time of driver CPU usage */
161    else
162    {
163        drv->total_us_of_cpu_time += current_entry_cpu_usage;
164    }
165}
166
167
168void tiwlan_profile_memory_alloc (void * os, unsigned size)
169{
170    tiwlan_net_dev_t * drv = (tiwlan_net_dev_t *) os;
171
172    if (drv != NULL)
173    {
174        /* Increase current heap allocation counter */
175        drv->cur_heap_bytes_allocated += size;
176        /* Update maximum if execceded */
177        if (drv->max_heap_bytes_allocated < drv->cur_heap_bytes_allocated)
178        {
179            drv->max_heap_bytes_allocated = drv->cur_heap_bytes_allocated;
180        }
181    }
182}
183
184
185void tiwlan_profile_memory_free (void * os, unsigned size)
186{
187    tiwlan_net_dev_t * drv = (tiwlan_net_dev_t *) os;
188
189    if (drv != NULL)
190    {
191        /* Decrease amount from heap allocation counter */
192        drv->cur_heap_bytes_allocated -= size;
193        /* Check for overflow */
194        if ((int)drv->cur_heap_bytes_allocated < 0)
195        {
196            printk("\n\n%s: memory heap allocation calculation corrupted. Size=%u, Current allocation = %d\n\n\n",
197                   __FUNCTION__, size, drv->cur_heap_bytes_allocated);
198            drv->cur_heap_bytes_allocated = 0;
199        }
200    }
201}
202
203
204void tiwlan_profile_buf_alloc (void * os, unsigned size)
205{
206    tiwlan_net_dev_t * drv = (tiwlan_net_dev_t *) os;
207
208    if (drv != NULL)
209    {
210        drv->max_buf_bytes_allocated += size;
211    }
212}
213
214
215void tiwlan_profile_timer_create (void * os, unsigned par)
216{
217    tiwlan_net_dev_t * drv = (tiwlan_net_dev_t *) os;
218
219    if (drv)
220    {
221        /* Increase the current active timer counter */
222        drv->cur_number_of_timers ++;
223        /* Update maximum if execceded */
224        if (drv->max_number_of_timers < drv->cur_number_of_timers)
225        {
226            drv->max_number_of_timers = drv->cur_number_of_timers;
227        }
228    }
229}
230
231
232void tiwlan_profile_timer_destroy (void * os, unsigned par)
233{
234    tiwlan_net_dev_t * drv = (tiwlan_net_dev_t *) os;
235
236    if (drv)
237    {
238        /* Decrease the current active timer counter */
239        drv->cur_number_of_timers --;
240    }
241}
242
243
244/*
245 * Start CPU estimator
246 * NOTE: this function does not run in a driver context
247 */
248int tiwlan_profile_cpu_usage_estimator_start (tiwlan_net_dev_t * drv, unsigned int resolution)
249{
250    /*
251     *  Reset estimation parameters - no need for spin lock since
252     *  estimator is not running
253     */
254    drv->total_us_of_cpu_time = 0;
255    drv->total_us_of_bus_access_cpu_time = 0;
256    drv->cpu_usage_estimator_start_time = os_timeStampUs (drv);
257    drv->cpu_usage_estimator_stop_time = 0;
258
259    /* Set the new resolution */
260    drv->cpu_usage_estimator_resolution = resolution;
261
262    /* Register profiler banchmarks */
263    drv->fpro [0] = tiwlan_profile_driver_entry_start;
264    drv->fpro [1] = tiwlan_profile_driver_entry_end;
265    drv->fpro [2] = tiwlan_profile_bus_access_start;
266    drv->fpro [3] = tiwlan_profile_bus_access_end;
267
268    return 0;
269}
270
271
272/*
273 * Stop CPU estimator and save the last CPU estimation
274 * NOTE: this function does not run in a driver context
275 */
276int tiwlan_profile_cpu_usage_estimator_stop (tiwlan_net_dev_t * drv)
277{
278    drv->cpu_usage_estimator_stop_time = os_timeStampUs (drv);
279
280    /* Unregister profiler banchmarks */
281    drv->fpro [0] = NULL;
282    drv->fpro [1] = NULL;
283    drv->fpro [2] = NULL;
284    drv->fpro [3] = NULL;
285
286    return 0;
287}
288
289
290/*
291 * Reset CPU estimation
292 * NOTE: this function is not run in a driver context
293 */
294int tiwlan_profile_cpu_usage_estimator_reset (tiwlan_net_dev_t * drv)
295{
296    /* Reset accumulated driver time and the last estimation */
297    drv->total_us_of_cpu_time = 0;
298    drv->total_us_of_bus_access_cpu_time = 0;
299    drv->cpu_usage_estimator_start_time = 0;
300    drv->cpu_usage_estimator_stop_time = 0;
301
302    return 0;
303}
304
305
306/* Print to the screen the latest resource usage and CPU estimation */
307int tiwlan_profile_report (tiwlan_net_dev_t *drv)
308{
309    unsigned total_time, drv_cpu_usage = 0, bus_cpu_usage = 0;
310
311    printk ("\nDriver Resource Usage");
312    printk ("\n=====================");
313    printk ("\nMaximum Heap Memory Allocated: %u (bytes)", drv->max_heap_bytes_allocated);
314    printk ("\nCurrent Heap Memory Allocated: %u (bytes)", drv->cur_heap_bytes_allocated);
315    printk ("\nBuffer Memory Allocated: %u (bytes)", drv->max_buf_bytes_allocated);
316    printk ("\nFirmware Image Memory Allocated: %u (bytes)", (unsigned)drv->firmware_image.size);
317    printk ("\nEEPROM Image Memory Allocated: %u (bytes)", (unsigned)drv->eeprom_image.size);
318    printk ("\nMaximum Active Timers: %u", drv->max_number_of_timers);
319    printk ("\nCurrent Active Timers: %u", drv->cur_number_of_timers);
320
321    /* Check that the estimation has been started and stopped stopped */
322    if (drv->cpu_usage_estimator_stop_time != 0)
323    {
324        total_time = drv->cpu_usage_estimator_stop_time - drv->cpu_usage_estimator_start_time;
325
326        total_time /= 100;
327
328        if ((int)total_time > 0)
329        {
330            drv_cpu_usage = drv->total_us_of_cpu_time / total_time;
331            bus_cpu_usage = drv->total_us_of_bus_access_cpu_time / total_time;
332
333            printk ("\nTotal Test Run Time: %u (usec)", total_time);
334            printk ("\nTotal Driver Run Time: %u (usec)", drv->total_us_of_cpu_time);
335            printk ("\nTotal Bus Access Time: %u (usec)", drv->total_us_of_bus_access_cpu_time);
336            printk ("\nTotal CPU Usage: %u%%", drv_cpu_usage);
337            printk ("\nBus Access CPU Usage: %u%%", bus_cpu_usage);
338            printk ("\n");
339        }
340    }
341
342    return 0;
343}
344
345