1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2021 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 #include "spdk/likely.h" 8 9 #include "spdk_internal/event.h" 10 #include "spdk/thread.h" 11 12 #include "spdk/log.h" 13 #include "spdk/env.h" 14 #include "spdk/scheduler.h" 15 16 static uint32_t g_max_threshold = 99; 17 static uint32_t g_adjust_threshold = 50; 18 static uint32_t g_min_threshold = 1; 19 20 static int 21 init(void) 22 { 23 return spdk_governor_set("dpdk_governor"); 24 } 25 26 static void 27 deinit(void) 28 { 29 spdk_governor_set(NULL); 30 } 31 32 static uint32_t 33 calculate_busy_pct(struct spdk_scheduler_core_info *core) 34 { 35 uint64_t total_tsc; 36 37 total_tsc = core->current_busy_tsc + core->current_idle_tsc; 38 return core->current_busy_tsc * 100 / total_tsc; 39 } 40 41 struct check_sibling_ctx { 42 struct spdk_scheduler_core_info *cores; 43 uint32_t busy_pct; 44 }; 45 46 static void 47 check_sibling(void *_ctx, uint32_t i) 48 { 49 struct check_sibling_ctx *ctx = _ctx; 50 struct spdk_scheduler_core_info *core = &ctx->cores[i]; 51 uint32_t busy_pct = calculate_busy_pct(core); 52 53 ctx->busy_pct = spdk_max(ctx->busy_pct, busy_pct); 54 } 55 56 static void 57 balance(struct spdk_scheduler_core_info *cores, uint32_t core_count) 58 { 59 struct spdk_governor *governor; 60 struct spdk_scheduler_core_info *core; 61 struct spdk_governor_capabilities capabilities; 62 uint32_t busy_pct; 63 uint32_t i; 64 int rc; 65 66 governor = spdk_governor_get(); 67 assert(governor != NULL); 68 69 /* Gather active/idle statistics */ 70 SPDK_ENV_FOREACH_CORE(i) { 71 struct spdk_cpuset smt_siblings = {}; 72 core = &cores[i]; 73 74 rc = governor->get_core_capabilities(core->lcore, &capabilities); 75 if (rc < 0) { 76 SPDK_ERRLOG("failed to get capabilities for core: %u\n", core->lcore); 77 return; 78 } 79 80 busy_pct = calculate_busy_pct(core); 81 if (spdk_env_core_get_smt_cpuset(&smt_siblings, i)) { 82 struct check_sibling_ctx ctx = {.cores = cores, .busy_pct = busy_pct}; 83 84 spdk_cpuset_for_each_cpu(&smt_siblings, check_sibling, &ctx); 85 busy_pct = ctx.busy_pct; 86 } 87 88 if (busy_pct < g_min_threshold) { 89 rc = governor->set_core_freq_min(core->lcore); 90 if (rc < 0) { 91 SPDK_ERRLOG("setting to minimal frequency for core %u failed\n", core->lcore); 92 } 93 } else if (busy_pct < g_adjust_threshold) { 94 rc = governor->core_freq_down(core->lcore); 95 if (rc < 0) { 96 SPDK_ERRLOG("lowering frequency for core %u failed\n", core->lcore); 97 } 98 } else if (busy_pct >= g_max_threshold) { 99 rc = governor->set_core_freq_max(core->lcore); 100 if (rc < 0) { 101 SPDK_ERRLOG("setting to maximal frequency for core %u failed\n", core->lcore); 102 } 103 } else { 104 rc = governor->core_freq_up(core->lcore); 105 if (rc < 0) { 106 SPDK_ERRLOG("increasing frequency for core %u failed\n", core->lcore); 107 } 108 } 109 } 110 } 111 112 static struct spdk_scheduler gscheduler = { 113 .name = "gscheduler", 114 .init = init, 115 .deinit = deinit, 116 .balance = balance, 117 }; 118 119 SPDK_SCHEDULER_REGISTER(gscheduler); 120