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