Line data Source code
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 0 : init(void) 22 : { 23 0 : return spdk_governor_set("dpdk_governor"); 24 : } 25 : 26 : static void 27 0 : deinit(void) 28 : { 29 0 : spdk_governor_set(NULL); 30 0 : } 31 : 32 : static uint32_t 33 0 : calculate_busy_pct(struct spdk_scheduler_core_info *core) 34 : { 35 : uint64_t total_tsc; 36 : 37 0 : total_tsc = core->current_busy_tsc + core->current_idle_tsc; 38 0 : if (total_tsc == 0) { 39 0 : return 0; 40 : } else { 41 0 : return core->current_busy_tsc * 100 / total_tsc; 42 : } 43 : } 44 : 45 : struct check_sibling_ctx { 46 : struct spdk_scheduler_core_info *cores; 47 : uint32_t busy_pct; 48 : }; 49 : 50 : static void 51 0 : check_sibling(void *_ctx, uint32_t i) 52 : { 53 0 : struct check_sibling_ctx *ctx = _ctx; 54 0 : struct spdk_scheduler_core_info *core = &ctx->cores[i]; 55 0 : uint32_t busy_pct = calculate_busy_pct(core); 56 : 57 0 : ctx->busy_pct = spdk_max(ctx->busy_pct, busy_pct); 58 0 : } 59 : 60 : static void 61 0 : balance(struct spdk_scheduler_core_info *cores, uint32_t core_count) 62 : { 63 : struct spdk_governor *governor; 64 : struct spdk_scheduler_core_info *core; 65 0 : struct spdk_governor_capabilities capabilities; 66 : uint32_t busy_pct; 67 : uint32_t i; 68 : int rc; 69 : 70 0 : governor = spdk_governor_get(); 71 0 : assert(governor != NULL); 72 : 73 : /* Gather active/idle statistics */ 74 0 : SPDK_ENV_FOREACH_CORE(i) { 75 0 : struct spdk_cpuset smt_siblings = {}; 76 0 : core = &cores[i]; 77 : 78 0 : rc = governor->get_core_capabilities(core->lcore, &capabilities); 79 0 : if (rc < 0) { 80 0 : SPDK_ERRLOG("failed to get capabilities for core: %u\n", core->lcore); 81 0 : return; 82 : } 83 : 84 0 : busy_pct = calculate_busy_pct(core); 85 0 : if (spdk_env_core_get_smt_cpuset(&smt_siblings, i)) { 86 0 : struct check_sibling_ctx ctx = {.cores = cores, .busy_pct = busy_pct}; 87 : 88 0 : spdk_cpuset_for_each_cpu(&smt_siblings, check_sibling, &ctx); 89 0 : busy_pct = ctx.busy_pct; 90 : } 91 : 92 0 : if (busy_pct < g_min_threshold) { 93 0 : rc = governor->set_core_freq_min(core->lcore); 94 0 : if (rc < 0) { 95 0 : SPDK_ERRLOG("setting to minimal frequency for core %u failed\n", core->lcore); 96 : } 97 0 : } else if (busy_pct < g_adjust_threshold) { 98 0 : rc = governor->core_freq_down(core->lcore); 99 0 : if (rc < 0) { 100 0 : SPDK_ERRLOG("lowering frequency for core %u failed\n", core->lcore); 101 : } 102 0 : } else if (busy_pct >= g_max_threshold) { 103 0 : rc = governor->set_core_freq_max(core->lcore); 104 0 : if (rc < 0) { 105 0 : SPDK_ERRLOG("setting to maximal frequency for core %u failed\n", core->lcore); 106 : } 107 : } else { 108 0 : rc = governor->core_freq_up(core->lcore); 109 0 : if (rc < 0) { 110 0 : SPDK_ERRLOG("increasing frequency for core %u failed\n", core->lcore); 111 : } 112 : } 113 : } 114 : } 115 : 116 : static struct spdk_scheduler gscheduler = { 117 : .name = "gscheduler", 118 : .init = init, 119 : .deinit = deinit, 120 : .balance = balance, 121 : }; 122 : 123 0 : SPDK_SCHEDULER_REGISTER(gscheduler);