Branch data 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 : 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 : 0 : check_sibling(void *_ctx, uint32_t i) 48 : : { 49 : 0 : struct check_sibling_ctx *ctx = _ctx; 50 : 0 : struct spdk_scheduler_core_info *core = &ctx->cores[i]; 51 : 0 : uint32_t busy_pct = calculate_busy_pct(core); 52 : : 53 : 0 : ctx->busy_pct = spdk_max(ctx->busy_pct, busy_pct); 54 : 0 : } 55 : : 56 : : static void 57 : 0 : 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 : 0 : struct spdk_governor_capabilities capabilities; 62 : : uint32_t busy_pct; 63 : : uint32_t i; 64 : : int rc; 65 : : 66 : 0 : governor = spdk_governor_get(); 67 [ # # ]: 0 : assert(governor != NULL); 68 : : 69 : : /* Gather active/idle statistics */ 70 [ # # ]: 0 : SPDK_ENV_FOREACH_CORE(i) { 71 : 0 : struct spdk_cpuset smt_siblings = {}; 72 : 0 : core = &cores[i]; 73 : : 74 : 0 : rc = governor->get_core_capabilities(core->lcore, &capabilities); 75 [ # # ]: 0 : if (rc < 0) { 76 : 0 : SPDK_ERRLOG("failed to get capabilities for core: %u\n", core->lcore); 77 : 0 : return; 78 : : } 79 : : 80 : 0 : busy_pct = calculate_busy_pct(core); 81 [ # # ]: 0 : if (spdk_env_core_get_smt_cpuset(&smt_siblings, i)) { 82 : 0 : struct check_sibling_ctx ctx = {.cores = cores, .busy_pct = busy_pct}; 83 : : 84 : 0 : spdk_cpuset_for_each_cpu(&smt_siblings, check_sibling, &ctx); 85 : 0 : busy_pct = ctx.busy_pct; 86 : : } 87 : : 88 [ # # ]: 0 : if (busy_pct < g_min_threshold) { 89 : 0 : rc = governor->set_core_freq_min(core->lcore); 90 [ # # ]: 0 : if (rc < 0) { 91 : 0 : SPDK_ERRLOG("setting to minimal frequency for core %u failed\n", core->lcore); 92 : : } 93 [ # # ]: 0 : } else if (busy_pct < g_adjust_threshold) { 94 : 0 : rc = governor->core_freq_down(core->lcore); 95 [ # # ]: 0 : if (rc < 0) { 96 : 0 : SPDK_ERRLOG("lowering frequency for core %u failed\n", core->lcore); 97 : : } 98 [ # # ]: 0 : } else if (busy_pct >= g_max_threshold) { 99 : 0 : rc = governor->set_core_freq_max(core->lcore); 100 [ # # ]: 0 : if (rc < 0) { 101 : 0 : SPDK_ERRLOG("setting to maximal frequency for core %u failed\n", core->lcore); 102 : : } 103 : : } else { 104 : 0 : rc = governor->core_freq_up(core->lcore); 105 [ # # ]: 0 : if (rc < 0) { 106 : 0 : 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 : 2379 : SPDK_SCHEDULER_REGISTER(gscheduler);