examples/vm_power: fix OOB frequency oscillations
authorDavid Hunt <david.hunt@intel.com>
Wed, 24 Jul 2019 13:18:03 +0000 (14:18 +0100)
committerThomas Monjalon <thomas@monjalon.net>
Tue, 12 Nov 2019 07:21:57 +0000 (08:21 +0100)
The branch ratio algorithm in the vm_power_manager sample application
can be very sensitive at patricular loads in a workload, causing
oscillations between min and max frequency. For example, if a
workload is at 50%, scaling up may change the ratio
enough that it immediately thinks it needs to scale down again.

This patch introduces a sliding window recording the scale up/down
direction for the last 32 samples, and scales up if any samples indicate
we should scale up, otherwise scale down. Each core has it's own window.

Fixes: 4b1a631b8a8a ("examples/vm_power: add oob monitoring functions")
Cc: stable@dpdk.org
Signed-off-by: David Hunt <david.hunt@intel.com>
Acked-by: Anatoly Burakov <anatoly.burakov@intel.com>
examples/vm_power_manager/oob_monitor_x86.c
examples/vm_power_manager/power_manager.c
examples/vm_power_manager/power_manager.h

index ebd96b2..aecfcb2 100644 (file)
@@ -39,6 +39,7 @@ apply_policy(int core)
        int64_t hits_diff, miss_diff;
        float ratio;
        int ret;
+       int freq_window_idx, up_count = 0, i;
 
        g_active = 0;
        ci = get_core_info();
@@ -101,10 +102,37 @@ apply_policy(int core)
 
        ratio = (float)miss_diff * (float)100 / (float)hits_diff;
 
-       if (ratio < ci->branch_ratio_threshold)
-               power_manager_scale_core_min(core);
+       /*
+        * Store the last few directions that the ratio indicates
+        * we should take. If there's on 'up', then we scale up
+        * quickly. If all indicate 'down', only then do we scale
+        * down. Each core_details struct has it's own array.
+        */
+       freq_window_idx = ci->cd[core].freq_window_idx;
+       if (ratio > ci->branch_ratio_threshold)
+               ci->cd[core].freq_directions[freq_window_idx] = 1;
        else
-               power_manager_scale_core_max(core);
+               ci->cd[core].freq_directions[freq_window_idx] = 0;
+
+       freq_window_idx++;
+       freq_window_idx = freq_window_idx & (FREQ_WINDOW_SIZE-1);
+       ci->cd[core].freq_window_idx = freq_window_idx;
+
+       up_count = 0;
+       for (i = 0; i < FREQ_WINDOW_SIZE; i++)
+               up_count +=  ci->cd[core].freq_directions[i];
+
+       if (up_count == 0) {
+               if (ci->cd[core].freq_state != FREQ_MIN) {
+                       power_manager_scale_core_min(core);
+                       ci->cd[core].freq_state = FREQ_MIN;
+               }
+       } else {
+               if (ci->cd[core].freq_state != FREQ_MAX) {
+                       power_manager_scale_core_max(core);
+                       ci->cd[core].freq_state = FREQ_MAX;
+               }
+       }
 
        g_active = 1;
        return ratio;
index 9d4e587..7b4f4b3 100644 (file)
@@ -62,14 +62,13 @@ core_info_init(void)
        ci->core_count = get_nprocs_conf();
        ci->branch_ratio_threshold = BRANCH_RATIO_THRESHOLD;
        ci->cd = malloc(ci->core_count * sizeof(struct core_details));
+       memset(ci->cd, 0, ci->core_count * sizeof(struct core_details));
        if (!ci->cd) {
                RTE_LOG(ERR, POWER_MANAGER, "Failed to allocate memory for core info.");
                return -1;
        }
        for (i = 0; i < ci->core_count; i++) {
                ci->cd[i].global_enabled_cpus = 1;
-               ci->cd[i].oob_enabled = 0;
-               ci->cd[i].msr_fd = 0;
        }
        printf("%d cores in system\n", ci->core_count);
        return 0;
index e81a60a..e324766 100644 (file)
@@ -8,12 +8,24 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
+
+#define FREQ_WINDOW_SIZE 32
+
+enum {
+       FREQ_UNKNOWN,
+       FREQ_MIN,
+       FREQ_MAX
+};
+
 struct core_details {
        uint64_t last_branches;
        uint64_t last_branch_misses;
        uint16_t global_enabled_cpus;
        uint16_t oob_enabled;
        int msr_fd;
+       uint16_t freq_directions[FREQ_WINDOW_SIZE];
+       uint16_t freq_window_idx;
+       uint16_t freq_state;
 };
 
 struct core_info {