-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reactive policies #74
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
#pragma once | ||
|
||
#include "bets_policy.hpp" | ||
|
||
/** | ||
* In case of temperature threshold overstepping set frequencies to the lowest possible frequency. | ||
* | ||
* Based on imx8_per_slice policy. | ||
*/ | ||
class Bets_hard_throttle : public Bets_policy | ||
{ | ||
public: | ||
Bets_hard_throttle(const std::string &temperature_threshold) : Bets_policy(temperature_threshold) {} | ||
|
||
void execute_policy(CpufreqPolicy *cp, CpuFrequencyHz &freq, Window &win) override { | ||
cp->write_frequency(cp->min_frequency); | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
#pragma once | ||
|
||
#include "_power_policy.hpp" | ||
#include "power_manager.hpp" | ||
#include "lib/file_lib.hpp" | ||
#include <fstream> | ||
#include <iostream> | ||
#include "slice.hpp" | ||
#include <optional> | ||
#include <ctime> | ||
#include <numeric> | ||
#include <vector> | ||
|
||
|
||
/** | ||
* Based on imx8_per_slice policy, intended for Best Effort Task Scheduler (BETS). | ||
*/ | ||
class Bets_policy : public PmPowerPolicy | ||
{ | ||
protected: | ||
// currently, this is hardcoded for i.MX8, but should be quite simply extensible | ||
// for other CPU cluster layouts | ||
std::array<CpufreqPolicy *, 2> policies{ &pm.get_policy("policy0"), &pm.get_policy("policy4") }; | ||
float upper_threshold; | ||
float lower_threshold; | ||
Comment on lines
+24
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. V komentáři (nebo rovnou ve jménu proměnné) zmínit, že se jedna o teplotu. |
||
time_t timer; | ||
const time_t limit = 10; | ||
Comment on lines
+26
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Bylo by lepší použít C++ datové typy ze |
||
bool temperature_inertia_period = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Je divné, že něco, co se nazývá |
||
int level = 0; | ||
const string temp_path_c0 = "/sys/devices/virtual/thermal/thermal_zone0/temp"; | ||
std::vector<float> temperatures; | ||
int oldest = 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Přidat komentář, že se jedná o index do temperatures. A index nemůže být záporný, tak změnit typ na unsigned, nebo size_t. |
||
|
||
public: | ||
Bets_policy(const std::string &temperature_threshold) | ||
{ | ||
upper_threshold = std::stof(temperature_threshold); | ||
lower_threshold = upper_threshold - 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bylo by lepší, kdyby to byl 2. (nepovinný) parametr. |
||
temperatures = std::vector<float>(10); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inicializovat už v definici třídy. |
||
for (auto &p : pm.policy_iter()) | ||
if (!p.available_frequencies) | ||
throw runtime_error("Cannot list available frequencies for the CPU" | ||
" - are you sure you're running DEmOS on an i.MX8?"); | ||
} | ||
|
||
// Validate that the requested frequencies are available | ||
void validate(const Windows &windows) override | ||
{ | ||
for (const Window &win : windows) { | ||
for (const Slice &slice : win.slices) { | ||
if (!slice.requested_frequency) continue; | ||
for (const CpufreqPolicy *policy : policies) { | ||
if (!(slice.cpus & policy->affected_cores)) continue; | ||
policy->validate_frequency(slice.requested_frequency.value()); | ||
} | ||
} | ||
} | ||
} | ||
bool supports_per_slice_frequencies() override { return true; } | ||
|
||
float get_temperature_on_c0(){ | ||
auto is = file_open<std::ifstream>(temp_path_c0); | ||
float temp; | ||
is >> temp; | ||
return temp / 1000.0; | ||
} | ||
|
||
float get_temp(){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lepší jméno by bylo |
||
this->temperatures[oldest] = this->get_temperature_on_c0(); | ||
oldest = (oldest + 1) % temperatures.size(); | ||
float sum = std::accumulate(this->temperatures.begin(), this->temperatures.end(), 0); | ||
return sum / this->temperatures.size(); | ||
} | ||
|
||
virtual void execute_policy(CpufreqPolicy *cp, CpuFrequencyHz &freq, Window &win){ | ||
cp->write_frequency(freq); | ||
} | ||
|
||
void change_level(){ | ||
float avg_temp = this->get_temp(); | ||
if (this->temperature_inertia_period){ | ||
if (time(0) - this->timer >= this->limit){ | ||
this->temperature_inertia_period = false; | ||
} | ||
return; //Change is already in progress | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nevím, jestli by return neměl být jen ve větvi |
||
} | ||
|
||
if (avg_temp > upper_threshold){ | ||
this->temperature_inertia_period = true; | ||
this->timer = time(0); | ||
this->level++; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Myslím, že by fungovalo lépe, kdyby se |
||
std::cout << "level=" << this->level << std::endl; | ||
return; | ||
} | ||
|
||
if (avg_temp < lower_threshold && level > 0){ | ||
this->temperature_inertia_period = true; | ||
this->timer = time(0); | ||
this->level--; | ||
std::cout << "level=" << this->level << std::endl; | ||
return; | ||
} | ||
} | ||
|
||
void on_window_start(Window &win) override | ||
{ | ||
for (CpufreqPolicy *cp : policies) { | ||
std::optional<CpuFrequencyHz> freq = std::nullopt; | ||
for (const Slice &slice : win.slices) { | ||
if (slice.requested_frequency && slice.cpus & cp->affected_cores) { | ||
// slice is requesting a fixed frequency, check that all slices on the | ||
// same CPU cluster request the same frequency. | ||
if (freq.has_value() && freq.value() != slice.requested_frequency) { | ||
throw std::runtime_error(fmt::format( | ||
"Scheduled slices require different frequencies on the CPU(s) " | ||
"{}: '{}', '{}'", | ||
cp->affected_cores.as_list(), | ||
freq.value(), | ||
slice.requested_frequency.value())); | ||
} | ||
freq = slice.requested_frequency; | ||
} | ||
} | ||
if (freq.has_value()) { | ||
change_level(); | ||
if (this->level == 0){ | ||
cp->write_frequency(freq.value()); | ||
} else { | ||
execute_policy(cp, freq.value(), win); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Myslím, že |
||
} | ||
} | ||
} | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
#pragma once | ||
|
||
#include "bets_policy.hpp" | ||
#include <iostream> | ||
#include <vector> | ||
#include <utility> | ||
#include <algorithm> | ||
|
||
|
||
bool cmp(std::pair<std::string, int>& a, std::pair<std::string, int>& b) { | ||
return a.second < b.second; | ||
} | ||
|
||
/** | ||
* In case of temperature threshold overstepping skip a task in a fair fashion. | ||
* | ||
* Based on imx8_per_slice policy. | ||
*/ | ||
class Bets_skip : public Bets_policy | ||
{ | ||
private: | ||
std::vector<std::pair<std::string, int>> candidates; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Co je to za kandidáty? Nějaký komentář by byl vhodný. A nebylo by lepší použít Po přečtení zbytku kódu už to chápu. Myslím, že by bylo lepší používat následující datové sktruktury (nebo něco podobného): struct SliceProxy {
Slice &slice;
SliceProxy(Slice &slice) : slice(slice) {}
};
std::map<Slice*, SliceProxy&> proxies;
std::multimap<chrono::duration, SliceProxy&> Nejsem si jist, jestli bude potřeba |
||
std::vector<std::string> present; | ||
public: | ||
Bets_skip(const std::string &temperature_threshold) : Bets_policy(temperature_threshold) {} | ||
|
||
|
||
void sort_candidates(){ | ||
std::sort(candidates.begin(), candidates.end(), cmp); | ||
} | ||
|
||
void safe_pushback(std::string key){ | ||
for (auto &p : candidates){ | ||
if (p.first == key){ | ||
return; | ||
} | ||
} | ||
candidates.push_back(std::pair<std::string, int>(key, 0)); | ||
} | ||
|
||
Comment on lines
+28
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pokud se použijí datové sktuktury navržené výše, tohle bude zbytečné. |
||
void load(Window &win){ | ||
present = std::vector<std::string>(); | ||
for (auto &s : win.slices){ | ||
std::string key = s.be->get_name(); | ||
if (key.find("sleep") == std::string::npos){ //Sleep process is used for idle time. We are not skipping it. | ||
present.push_back(key); | ||
safe_pushback(key); | ||
} | ||
} | ||
} | ||
|
||
int is_present(std::string key){ | ||
for (int i = 0; i < present.size(); i++){ | ||
if (present[i] == key){ | ||
return i; | ||
} | ||
} | ||
return -1; | ||
} | ||
Comment on lines
+52
to
+59
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pokud se použijí datové sktuktury navržené výše, is_present bude zbytečné. |
||
|
||
void execute_policy(CpufreqPolicy *cp, CpuFrequencyHz &freq, Window &win) override { | ||
cp->write_frequency(freq); | ||
if (cp->name != "policy0"){ //Skip policy works over all clusters, it makes settings only on the first one. | ||
return; | ||
} | ||
|
||
if(this->level > 5){ | ||
this->level = 5; | ||
} | ||
int skip_counter = 0; | ||
for (int j = 0; j < win.slices.size(); j++){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Když iterujete přes container, je přehlednější používat tzv. range-based for: |
||
win.to_be_skipped[j] = false; | ||
} | ||
load(win); | ||
sort_candidates(); | ||
Comment on lines
+74
to
+75
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Myslím, že load a sort_candidate není potřeba volat pokaždé, ale stačilo by to vykonat jednou na začátku. Myslím, že metoda |
||
// Iterate trough candidates, until up to the level amounth of them is skipped, but at least 1 is kept. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Proč je potřeba 1 nechávat? Když by se to hodně přehřívalo, je možné klidně přeskočit všechny. |
||
for(int i = 0; i < candidates.size() && skip_counter < this->level && present.size() - skip_counter > 1; i++){ | ||
int idx = is_present(candidates[i].first); | ||
if (idx != -1){ | ||
win.to_be_skipped[idx] = true; | ||
candidates[i].second += win.length.count(); | ||
skip_counter++; | ||
} | ||
} | ||
} | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#pragma once | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
#include "bets_policy.hpp" | ||
#include <map> | ||
#include <limits> | ||
#include <iostream> | ||
|
||
/** | ||
* In case of temperature threshold overstepping set frequencies to the lowest possible frequency. | ||
* | ||
* Based on imx8_per_slice policy. | ||
*/ | ||
class Bets_skip : public Bets_policy | ||
{ | ||
private: | ||
std::map<std::string, int> skip_counter; | ||
public: | ||
Bets_skip(const std::string &temperature_threshold) : Bets_policy(temperature_threshold) {} | ||
|
||
void execute_policy(CpufreqPolicy *cp, CpuFrequencyHz &freq, Window &win) override { | ||
cp->write_frequency(freq); | ||
|
||
int min = std::numeric_limits<int>::max(); | ||
std::string candidate; | ||
int i = 0; | ||
for (auto &s : win.slices){ | ||
std::string key = s.be->get_name(); | ||
if (!skip_counter.count(key)){ | ||
skip_counter.insert(std::pair<std::string, int>(key, 0)); | ||
min = 0; | ||
candidate = key; | ||
} else { | ||
if (skip_counter[key] < min){ | ||
min = skip_counter[key]; | ||
candidate = key; | ||
} | ||
} | ||
i++; | ||
} | ||
for (auto pair : win.to_){ | ||
win.to_be_skipped[j] = false; | ||
} | ||
|
||
for (int j = 0; j < ) | ||
|
||
win.to_be_skipped[candidate] = true; | ||
} | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#pragma once | ||
|
||
#include "bets_policy.hpp" | ||
|
||
|
||
/** | ||
* In case of temperature threshold overstepping lower frequencies by one step (if possible). | ||
* | ||
* Based on imx8_per_slice policy. | ||
*/ | ||
class Bets_soft_throttle : public Bets_policy | ||
{ | ||
public: | ||
Bets_soft_throttle(const std::string &temperature_threshold) : Bets_policy(temperature_threshold) {} | ||
|
||
void execute_policy(CpufreqPolicy *cp, CpuFrequencyHz &freq, Window &win) override { | ||
if (this->level > 3){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Proč se omezuje jen horní úroveň a ne spodní? |
||
this->level = 3; | ||
} | ||
auto freqs = cp->available_frequencies.value(); | ||
auto it = std::find(freqs.begin(), freqs.end(), freq); | ||
if (it != freqs.end()){ | ||
for(int i = 0; i < this->level; i++){ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bylo by lepší neomezovat level výše, ale ukončit tento cyklus, když se nazazí na začátek |
||
it = it == freqs.begin() ? it : --it; // If it can be lowered, lower it. | ||
} | ||
cp->write_frequency(*it); | ||
} else { | ||
throw std::runtime_error(fmt::format( | ||
"Frequency not found in available frequencies " | ||
"'{}'", | ||
freq)); | ||
} | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
#include <ev++.h> | ||
#include <list> | ||
#include <optional> | ||
#include <vector> | ||
|
||
class Window; | ||
class PowerPolicy; | ||
|
@@ -28,6 +29,7 @@ class Window | |
const std::chrono::milliseconds length; | ||
// use std::list as Slice doesn't have move and copy constructors | ||
std::list<Slice> slices{}; | ||
std::vector<bool> to_be_skipped; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Co je indexem do toho vektoru? Zdá se, že pořadí slice. Pokud to tak je, proč se nepřidá bool proměnná přímo do |
||
|
||
Window(ev::loop_ref loop, std::chrono::milliseconds length, PowerPolicy &power_policy); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bylo by lepší to předělat, aby to nebylo platformě závislé. Podobně jako
per_process.hpp
byla upravena zimx8_per_process.hpp
.