1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2018 Intel Corporation 3 */ 4 5 #include <string.h> 6 7 #include <rte_lcore.h> 8 #include <rte_cycles.h> 9 #include <rte_atomic.h> 10 #include <rte_malloc.h> 11 #include <inttypes.h> 12 13 #include "rte_power.h" 14 #include "rte_power_empty_poll.h" 15 16 #define INTERVALS_PER_SECOND 100 /* (10ms) */ 17 #define SECONDS_TO_TRAIN_FOR 2 18 #define DEFAULT_MED_TO_HIGH_PERCENT_THRESHOLD 70 19 #define DEFAULT_HIGH_TO_MED_PERCENT_THRESHOLD 30 20 #define DEFAULT_CYCLES_PER_PACKET 800 21 22 static struct ep_params *ep_params; 23 static uint32_t med_to_high_threshold = DEFAULT_MED_TO_HIGH_PERCENT_THRESHOLD; 24 static uint32_t high_to_med_threshold = DEFAULT_HIGH_TO_MED_PERCENT_THRESHOLD; 25 26 static uint32_t avail_freqs[RTE_MAX_LCORE][NUM_FREQS]; 27 28 static uint32_t total_avail_freqs[RTE_MAX_LCORE]; 29 30 static uint32_t freq_index[NUM_FREQ]; 31 32 static uint32_t 33 get_freq_index(enum freq_val index) 34 { 35 return freq_index[index]; 36 } 37 38 39 static int 40 set_power_freq(int lcore_id, enum freq_val freq, bool specific_freq) 41 { 42 int err = 0; 43 uint32_t power_freq_index; 44 if (!specific_freq) 45 power_freq_index = get_freq_index(freq); 46 else 47 power_freq_index = freq; 48 49 err = rte_power_set_freq(lcore_id, power_freq_index); 50 51 return err; 52 } 53 54 55 static __rte_always_inline void 56 exit_training_state(struct priority_worker *poll_stats) 57 { 58 RTE_SET_USED(poll_stats); 59 } 60 61 static __rte_always_inline void 62 enter_training_state(struct priority_worker *poll_stats) 63 { 64 poll_stats->iter_counter = 0; 65 poll_stats->cur_freq = LOW; 66 poll_stats->queue_state = TRAINING; 67 } 68 69 static __rte_always_inline void 70 enter_normal_state(struct priority_worker *poll_stats) 71 { 72 /* Clear the averages arrays and strs */ 73 memset(poll_stats->edpi_av, 0, sizeof(poll_stats->edpi_av)); 74 poll_stats->ec = 0; 75 76 poll_stats->cur_freq = MED; 77 poll_stats->iter_counter = 0; 78 poll_stats->threshold_ctr = 0; 79 poll_stats->queue_state = MED_NORMAL; 80 RTE_LOG(INFO, POWER, "Set the power freq to MED\n"); 81 set_power_freq(poll_stats->lcore_id, MED, false); 82 83 poll_stats->thresh[MED].threshold_percent = med_to_high_threshold; 84 poll_stats->thresh[HGH].threshold_percent = high_to_med_threshold; 85 } 86 87 static __rte_always_inline void 88 enter_busy_state(struct priority_worker *poll_stats) 89 { 90 memset(poll_stats->edpi_av, 0, sizeof(poll_stats->edpi_av)); 91 poll_stats->ec = 0; 92 93 poll_stats->cur_freq = HGH; 94 poll_stats->iter_counter = 0; 95 poll_stats->threshold_ctr = 0; 96 poll_stats->queue_state = HGH_BUSY; 97 set_power_freq(poll_stats->lcore_id, HGH, false); 98 } 99 100 static __rte_always_inline void 101 enter_purge_state(struct priority_worker *poll_stats) 102 { 103 poll_stats->iter_counter = 0; 104 poll_stats->queue_state = LOW_PURGE; 105 } 106 107 static __rte_always_inline void 108 set_state(struct priority_worker *poll_stats, 109 enum queue_state new_state) 110 { 111 enum queue_state old_state = poll_stats->queue_state; 112 if (old_state != new_state) { 113 114 /* Call any old state exit functions */ 115 if (old_state == TRAINING) 116 exit_training_state(poll_stats); 117 118 /* Call any new state entry functions */ 119 if (new_state == TRAINING) 120 enter_training_state(poll_stats); 121 if (new_state == MED_NORMAL) 122 enter_normal_state(poll_stats); 123 if (new_state == HGH_BUSY) 124 enter_busy_state(poll_stats); 125 if (new_state == LOW_PURGE) 126 enter_purge_state(poll_stats); 127 } 128 } 129 130 static __rte_always_inline void 131 set_policy(struct priority_worker *poll_stats, 132 struct ep_policy *policy) 133 { 134 set_state(poll_stats, policy->state); 135 136 if (policy->state == TRAINING) 137 return; 138 139 poll_stats->thresh[MED_NORMAL].base_edpi = policy->med_base_edpi; 140 poll_stats->thresh[HGH_BUSY].base_edpi = policy->hgh_base_edpi; 141 142 poll_stats->thresh[MED_NORMAL].trained = true; 143 poll_stats->thresh[HGH_BUSY].trained = true; 144 145 } 146 147 static void 148 update_training_stats(struct priority_worker *poll_stats, 149 uint32_t freq, 150 bool specific_freq, 151 uint32_t max_train_iter) 152 { 153 RTE_SET_USED(specific_freq); 154 155 uint64_t p0_empty_deq; 156 157 if (poll_stats->cur_freq == freq && 158 poll_stats->thresh[freq].trained == false) { 159 if (poll_stats->thresh[freq].cur_train_iter == 0) { 160 161 set_power_freq(poll_stats->lcore_id, 162 freq, specific_freq); 163 164 poll_stats->empty_dequeues_prev = 165 poll_stats->empty_dequeues; 166 167 poll_stats->thresh[freq].cur_train_iter++; 168 169 return; 170 } else if (poll_stats->thresh[freq].cur_train_iter 171 <= max_train_iter) { 172 173 p0_empty_deq = poll_stats->empty_dequeues - 174 poll_stats->empty_dequeues_prev; 175 176 poll_stats->empty_dequeues_prev = 177 poll_stats->empty_dequeues; 178 179 poll_stats->thresh[freq].base_edpi += p0_empty_deq; 180 poll_stats->thresh[freq].cur_train_iter++; 181 182 } else { 183 if (poll_stats->thresh[freq].trained == false) { 184 poll_stats->thresh[freq].base_edpi = 185 poll_stats->thresh[freq].base_edpi / 186 max_train_iter; 187 188 /* Add on a factor of 0.05% 189 * this should remove any 190 * false negatives when the system is 0% busy 191 */ 192 poll_stats->thresh[freq].base_edpi += 193 poll_stats->thresh[freq].base_edpi / 2000; 194 195 poll_stats->thresh[freq].trained = true; 196 poll_stats->cur_freq++; 197 198 } 199 } 200 } 201 } 202 203 static __rte_always_inline uint32_t 204 update_stats(struct priority_worker *poll_stats) 205 { 206 uint64_t tot_edpi = 0; 207 uint32_t j, percent; 208 209 struct priority_worker *s = poll_stats; 210 211 uint64_t cur_edpi = s->empty_dequeues - s->empty_dequeues_prev; 212 213 s->empty_dequeues_prev = s->empty_dequeues; 214 215 if (s->thresh[s->cur_freq].base_edpi < cur_edpi) { 216 217 /* edpi mean empty poll counter difference per interval */ 218 RTE_LOG(DEBUG, POWER, "cur_edpi is too large " 219 "cur edpi %"PRId64" " 220 "base edpi %"PRId64"\n", 221 cur_edpi, 222 s->thresh[s->cur_freq].base_edpi); 223 /* Value to make us fail need debug log*/ 224 return 1000UL; 225 } 226 227 s->edpi_av[s->ec++ % BINS_AV] = cur_edpi; 228 229 for (j = 0; j < BINS_AV; j++) { 230 tot_edpi += s->edpi_av[j]; 231 } 232 233 tot_edpi = tot_edpi / BINS_AV; 234 235 percent = 100 - (uint32_t)(((float)tot_edpi / 236 (float)s->thresh[s->cur_freq].base_edpi) * 100); 237 238 return (uint32_t)percent; 239 } 240 241 242 static __rte_always_inline void 243 update_stats_normal(struct priority_worker *poll_stats) 244 { 245 uint32_t percent; 246 247 if (poll_stats->thresh[poll_stats->cur_freq].base_edpi == 0) { 248 249 enum freq_val cur_freq = poll_stats->cur_freq; 250 251 /* edpi mean empty poll counter difference per interval */ 252 RTE_LOG(DEBUG, POWER, "cure freq is %d, edpi is %"PRIu64"\n", 253 cur_freq, 254 poll_stats->thresh[cur_freq].base_edpi); 255 return; 256 } 257 258 percent = update_stats(poll_stats); 259 260 if (percent > 100) { 261 /* edpi mean empty poll counter difference per interval */ 262 RTE_LOG(DEBUG, POWER, "Edpi is bigger than threshold\n"); 263 return; 264 } 265 266 if (poll_stats->cur_freq == LOW) 267 RTE_LOG(INFO, POWER, "Purge Mode is not currently supported\n"); 268 else if (poll_stats->cur_freq == MED) { 269 270 if (percent > 271 poll_stats->thresh[MED].threshold_percent) { 272 273 if (poll_stats->threshold_ctr < INTERVALS_PER_SECOND) 274 poll_stats->threshold_ctr++; 275 else { 276 set_state(poll_stats, HGH_BUSY); 277 RTE_LOG(INFO, POWER, "MOVE to HGH\n"); 278 } 279 280 } else { 281 /* reset */ 282 poll_stats->threshold_ctr = 0; 283 } 284 285 } else if (poll_stats->cur_freq == HGH) { 286 287 if (percent < 288 poll_stats->thresh[HGH].threshold_percent) { 289 290 if (poll_stats->threshold_ctr < INTERVALS_PER_SECOND) 291 poll_stats->threshold_ctr++; 292 else { 293 set_state(poll_stats, MED_NORMAL); 294 RTE_LOG(INFO, POWER, "MOVE to MED\n"); 295 } 296 } else { 297 /* reset */ 298 poll_stats->threshold_ctr = 0; 299 } 300 301 } 302 } 303 304 static int 305 empty_poll_training(struct priority_worker *poll_stats, 306 uint32_t max_train_iter) 307 { 308 309 if (poll_stats->iter_counter < INTERVALS_PER_SECOND) { 310 poll_stats->iter_counter++; 311 return 0; 312 } 313 314 315 update_training_stats(poll_stats, 316 LOW, 317 false, 318 max_train_iter); 319 320 update_training_stats(poll_stats, 321 MED, 322 false, 323 max_train_iter); 324 325 update_training_stats(poll_stats, 326 HGH, 327 false, 328 max_train_iter); 329 330 331 if (poll_stats->thresh[LOW].trained == true 332 && poll_stats->thresh[MED].trained == true 333 && poll_stats->thresh[HGH].trained == true) { 334 335 set_state(poll_stats, MED_NORMAL); 336 337 RTE_LOG(INFO, POWER, "LOW threshold is %"PRIu64"\n", 338 poll_stats->thresh[LOW].base_edpi); 339 340 RTE_LOG(INFO, POWER, "MED threshold is %"PRIu64"\n", 341 poll_stats->thresh[MED].base_edpi); 342 343 344 RTE_LOG(INFO, POWER, "HIGH threshold is %"PRIu64"\n", 345 poll_stats->thresh[HGH].base_edpi); 346 347 RTE_LOG(INFO, POWER, "Training is Complete for %d\n", 348 poll_stats->lcore_id); 349 } 350 351 return 0; 352 } 353 354 void 355 rte_empty_poll_detection(struct rte_timer *tim, void *arg) 356 { 357 358 uint32_t i; 359 360 struct priority_worker *poll_stats; 361 362 RTE_SET_USED(tim); 363 364 RTE_SET_USED(arg); 365 366 for (i = 0; i < NUM_NODES; i++) { 367 368 poll_stats = &(ep_params->wrk_data.wrk_stats[i]); 369 370 if (rte_lcore_is_enabled(poll_stats->lcore_id) == 0) 371 continue; 372 373 switch (poll_stats->queue_state) { 374 case(TRAINING): 375 empty_poll_training(poll_stats, 376 ep_params->max_train_iter); 377 break; 378 379 case(HGH_BUSY): 380 case(MED_NORMAL): 381 update_stats_normal(poll_stats); 382 break; 383 384 case(LOW_PURGE): 385 break; 386 default: 387 break; 388 389 } 390 391 } 392 393 } 394 395 int 396 rte_power_empty_poll_stat_init(struct ep_params **eptr, uint8_t *freq_tlb, 397 struct ep_policy *policy) 398 { 399 uint32_t i; 400 /* Allocate the ep_params structure */ 401 ep_params = rte_zmalloc_socket(NULL, 402 sizeof(struct ep_params), 403 0, 404 rte_socket_id()); 405 406 if (!ep_params) 407 return -1; 408 409 if (freq_tlb == NULL) { 410 freq_index[LOW] = 14; 411 freq_index[MED] = 9; 412 freq_index[HGH] = 1; 413 } else { 414 freq_index[LOW] = freq_tlb[LOW]; 415 freq_index[MED] = freq_tlb[MED]; 416 freq_index[HGH] = freq_tlb[HGH]; 417 } 418 419 RTE_LOG(INFO, POWER, "Initialize the Empty Poll\n"); 420 421 /* Train for pre-defined period */ 422 ep_params->max_train_iter = INTERVALS_PER_SECOND * SECONDS_TO_TRAIN_FOR; 423 424 struct stats_data *w = &ep_params->wrk_data; 425 426 *eptr = ep_params; 427 428 /* initialize all wrk_stats state */ 429 for (i = 0; i < NUM_NODES; i++) { 430 431 if (rte_lcore_is_enabled(i) == 0) 432 continue; 433 /*init the freqs table */ 434 total_avail_freqs[i] = rte_power_freqs(i, 435 avail_freqs[i], 436 NUM_FREQS); 437 438 RTE_LOG(INFO, POWER, "total avail freq is %d , lcoreid %d\n", 439 total_avail_freqs[i], 440 i); 441 442 if (get_freq_index(LOW) > total_avail_freqs[i]) 443 return -1; 444 445 if (rte_get_main_lcore() != i) { 446 w->wrk_stats[i].lcore_id = i; 447 set_policy(&w->wrk_stats[i], policy); 448 } 449 } 450 451 return 0; 452 } 453 454 void 455 rte_power_empty_poll_stat_free(void) 456 { 457 458 RTE_LOG(INFO, POWER, "Close the Empty Poll\n"); 459 460 rte_free(ep_params); 461 } 462 463 int 464 rte_power_empty_poll_stat_update(unsigned int lcore_id) 465 { 466 struct priority_worker *poll_stats; 467 468 if (lcore_id >= NUM_NODES) 469 return -1; 470 471 poll_stats = &(ep_params->wrk_data.wrk_stats[lcore_id]); 472 473 if (poll_stats->lcore_id == 0) 474 poll_stats->lcore_id = lcore_id; 475 476 poll_stats->empty_dequeues++; 477 478 return 0; 479 } 480 481 int 482 rte_power_poll_stat_update(unsigned int lcore_id, uint8_t nb_pkt) 483 { 484 485 struct priority_worker *poll_stats; 486 487 if (lcore_id >= NUM_NODES) 488 return -1; 489 490 poll_stats = &(ep_params->wrk_data.wrk_stats[lcore_id]); 491 492 if (poll_stats->lcore_id == 0) 493 poll_stats->lcore_id = lcore_id; 494 495 poll_stats->num_dequeue_pkts += nb_pkt; 496 497 return 0; 498 } 499 500 501 uint64_t 502 rte_power_empty_poll_stat_fetch(unsigned int lcore_id) 503 { 504 struct priority_worker *poll_stats; 505 506 if (lcore_id >= NUM_NODES) 507 return -1; 508 509 poll_stats = &(ep_params->wrk_data.wrk_stats[lcore_id]); 510 511 if (poll_stats->lcore_id == 0) 512 poll_stats->lcore_id = lcore_id; 513 514 return poll_stats->empty_dequeues; 515 } 516 517 uint64_t 518 rte_power_poll_stat_fetch(unsigned int lcore_id) 519 { 520 struct priority_worker *poll_stats; 521 522 if (lcore_id >= NUM_NODES) 523 return -1; 524 525 poll_stats = &(ep_params->wrk_data.wrk_stats[lcore_id]); 526 527 if (poll_stats->lcore_id == 0) 528 poll_stats->lcore_id = lcore_id; 529 530 return poll_stats->num_dequeue_pkts; 531 } 532