bce1a0c38dc2db9a7a8193274cf37ae27e50e010
[deb_dpdk.git] / examples / performance-thread / common / lthread_diag.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2015 Intel Corporation. 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 of Intel Corporation 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 #include <rte_log.h>
35 #include <rte_common.h>
36
37 #include "lthread_diag.h"
38 #include "lthread_queue.h"
39 #include "lthread_pool.h"
40 #include "lthread_objcache.h"
41 #include "lthread_sched.h"
42 #include "lthread_diag_api.h"
43
44
45 /* dummy ref value of default diagnostic callback */
46 static uint64_t dummy_ref;
47
48 #define DIAG_SCHED_STATS_FORMAT \
49 "core %d\n%33s %12s %12s %12s %12s\n"
50
51 #define DIAG_CACHE_STATS_FORMAT \
52 "%20s %12lu %12lu %12lu %12lu %12lu\n"
53
54 #define DIAG_QUEUE_STATS_FORMAT \
55 "%20s %12lu %12lu %12lu\n"
56
57
58 /*
59  * texts used in diagnostic events,
60  * corresponding diagnostic mask bit positions are given as comment
61  */
62 const char *diag_event_text[] = {
63         "LTHREAD_CREATE     ",  /* 00 */
64         "LTHREAD_EXIT       ",  /* 01 */
65         "LTHREAD_JOIN       ",  /* 02 */
66         "LTHREAD_CANCEL     ",  /* 03 */
67         "LTHREAD_DETACH     ",  /* 04 */
68         "LTHREAD_FREE       ",  /* 05 */
69         "LTHREAD_SUSPENDED  ",  /* 06 */
70         "LTHREAD_YIELD      ",  /* 07 */
71         "LTHREAD_RESCHEDULED",  /* 08 */
72         "LTHREAD_SLEEP      ",  /* 09 */
73         "LTHREAD_RESUMED    ",  /* 10 */
74         "LTHREAD_AFFINITY   ",  /* 11 */
75         "LTHREAD_TMR_START  ",  /* 12 */
76         "LTHREAD_TMR_DELETE ",  /* 13 */
77         "LTHREAD_TMR_EXPIRED",  /* 14 */
78         "COND_CREATE        ",  /* 15 */
79         "COND_DESTROY       ",  /* 16 */
80         "COND_WAIT          ",  /* 17 */
81         "COND_SIGNAL        ",  /* 18 */
82         "COND_BROADCAST     ",  /* 19 */
83         "MUTEX_CREATE       ",  /* 20 */
84         "MUTEX_DESTROY      ",  /* 21 */
85         "MUTEX_LOCK         ",  /* 22 */
86         "MUTEX_TRYLOCK      ",  /* 23 */
87         "MUTEX_BLOCKED      ",  /* 24 */
88         "MUTEX_UNLOCKED     ",  /* 25 */
89         "SCHED_CREATE       ",  /* 26 */
90         "SCHED_SHUTDOWN     "   /* 27 */
91 };
92
93
94 /*
95  * set diagnostic ,ask
96  */
97 void lthread_diagnostic_set_mask(DIAG_USED uint64_t mask)
98 {
99 #if LTHREAD_DIAG
100         diag_mask = mask;
101 #else
102         RTE_LOG(INFO, LTHREAD,
103                 "LTHREAD_DIAG is not set, see lthread_diag_api.h\n");
104 #endif
105 }
106
107
108 /*
109  * Check consistency of the scheduler stats
110  * Only sensible run after the schedulers are stopped
111  * Count the number of objects lying in caches and queues
112  * and available in the qnode pool.
113  * This should be equal to the total capacity of all
114  * qnode pools.
115  */
116 void
117 _sched_stats_consistency_check(void);
118 void
119 _sched_stats_consistency_check(void)
120 {
121 #if LTHREAD_DIAG
122         int i;
123         struct lthread_sched *sched;
124         uint64_t count = 0;
125         uint64_t capacity = 0;
126
127         for (i = 0; i < LTHREAD_MAX_LCORES; i++) {
128                 sched = schedcore[i];
129                 if (sched == NULL)
130                         continue;
131
132                 /* each of these queues consumes a stub node */
133                 count += 8;
134                 count += DIAG_COUNT(sched->ready, size);
135                 count += DIAG_COUNT(sched->pready, size);
136                 count += DIAG_COUNT(sched->lthread_cache, available);
137                 count += DIAG_COUNT(sched->stack_cache, available);
138                 count += DIAG_COUNT(sched->tls_cache, available);
139                 count += DIAG_COUNT(sched->per_lthread_cache, available);
140                 count += DIAG_COUNT(sched->cond_cache, available);
141                 count += DIAG_COUNT(sched->mutex_cache, available);
142
143                 /* the node pool does not consume a stub node */
144                 if (sched->qnode_pool->fast_alloc != NULL)
145                         count++;
146                 count += DIAG_COUNT(sched->qnode_pool, available);
147
148                 capacity += DIAG_COUNT(sched->qnode_pool, capacity);
149         }
150         if (count != capacity) {
151                 RTE_LOG(CRIT, LTHREAD,
152                         "Scheduler caches are inconsistent\n");
153         } else {
154                 RTE_LOG(INFO, LTHREAD,
155                         "Scheduler caches are ok\n");
156         }
157 #endif
158 }
159
160
161 #if LTHREAD_DIAG
162 /*
163  * Display node pool stats
164  */
165 static inline void
166 _qnode_pool_display(DIAG_USED struct qnode_pool *p)
167 {
168
169         printf(DIAG_CACHE_STATS_FORMAT,
170                         p->name,
171                         DIAG_COUNT(p, rd),
172                         DIAG_COUNT(p, wr),
173                         DIAG_COUNT(p, available),
174                         DIAG_COUNT(p, prealloc),
175                         DIAG_COUNT(p, capacity));
176         fflush(stdout);
177 }
178 #endif
179
180
181 #if LTHREAD_DIAG
182 /*
183  * Display queue stats
184  */
185 static inline void
186 _lthread_queue_display(DIAG_USED struct lthread_queue *q)
187 {
188 #if DISPLAY_OBJCACHE_QUEUES
189         printf(DIAG_QUEUE_STATS_FORMAT,
190                         q->name,
191                         DIAG_COUNT(q, rd),
192                         DIAG_COUNT(q, wr),
193                         DIAG_COUNT(q, size));
194         fflush(stdout);
195 #else
196         printf("%s: queue stats disabled\n",
197                         q->name);
198
199 #endif
200 }
201 #endif
202
203 #if LTHREAD_DIAG
204 /*
205  * Display objcache stats
206  */
207 static inline void
208 _objcache_display(DIAG_USED struct lthread_objcache *c)
209 {
210
211         printf(DIAG_CACHE_STATS_FORMAT,
212                         c->name,
213                         DIAG_COUNT(c, rd),
214                         DIAG_COUNT(c, wr),
215                         DIAG_COUNT(c, available),
216                         DIAG_COUNT(c, prealloc),
217                         DIAG_COUNT(c, capacity));
218         _lthread_queue_display(c->q);
219         fflush(stdout);
220 }
221 #endif
222
223 /*
224  * Display sched stats
225  */
226 void
227 lthread_sched_stats_display(void)
228 {
229 #if LTHREAD_DIAG
230         int i;
231         struct lthread_sched *sched;
232
233         for (i = 0; i < LTHREAD_MAX_LCORES; i++) {
234                 sched = schedcore[i];
235                 if (sched != NULL) {
236                         printf(DIAG_SCHED_STATS_FORMAT,
237                                         sched->lcore_id,
238                                         "rd",
239                                         "wr",
240                                         "present",
241                                         "nb preallocs",
242                                         "capacity");
243                         _lthread_queue_display(sched->ready);
244                         _lthread_queue_display(sched->pready);
245                         _qnode_pool_display(sched->qnode_pool);
246                         _objcache_display(sched->lthread_cache);
247                         _objcache_display(sched->stack_cache);
248                         _objcache_display(sched->tls_cache);
249                         _objcache_display(sched->per_lthread_cache);
250                         _objcache_display(sched->cond_cache);
251                         _objcache_display(sched->mutex_cache);
252                 fflush(stdout);
253                 }
254         }
255         _sched_stats_consistency_check();
256 #else
257         RTE_LOG(INFO, LTHREAD,
258                 "lthread diagnostics disabled\n"
259                 "hint - set LTHREAD_DIAG in lthread_diag_api.h\n");
260 #endif
261 }
262
263 /*
264  * Defafult diagnostic callback
265  */
266 static uint64_t
267 _lthread_diag_default_cb(uint64_t time, struct lthread *lt, int diag_event,
268                 uint64_t diag_ref, const char *text, uint64_t p1, uint64_t p2)
269 {
270         uint64_t _p2;
271         int lcore = (int) rte_lcore_id();
272
273         switch (diag_event) {
274         case LT_DIAG_LTHREAD_CREATE:
275         case LT_DIAG_MUTEX_CREATE:
276         case LT_DIAG_COND_CREATE:
277                 _p2 = dummy_ref;
278                 break;
279         default:
280                 _p2 = p2;
281                 break;
282         }
283
284         printf("%"PRIu64" %d %8.8lx %8.8lx %s %8.8lx %8.8lx\n",
285                 time,
286                 lcore,
287                 (uint64_t) lt,
288                 diag_ref,
289                 text,
290                 p1,
291                 _p2);
292
293         return dummy_ref++;
294 }
295
296 /*
297  * plug in default diag callback with mask off
298  */
299 void _lthread_diag_ctor(void)__attribute__((constructor));
300 void _lthread_diag_ctor(void)
301 {
302         diag_cb = _lthread_diag_default_cb;
303         diag_mask = 0;
304 }
305
306
307 /*
308  * enable diagnostics
309  */
310 void lthread_diagnostic_enable(DIAG_USED diag_callback cb,
311                                 DIAG_USED uint64_t mask)
312 {
313 #if LTHREAD_DIAG
314         if (cb == NULL)
315                 diag_cb = _lthread_diag_default_cb;
316         else
317                 diag_cb = cb;
318         diag_mask = mask;
319 #else
320         RTE_LOG(INFO, LTHREAD,
321                 "LTHREAD_DIAG is not set, see lthread_diag_api.h\n");
322 #endif
323 }