Update picking of next current allowance to take more than one outstanding allowance into consideration

This commit is contained in:
Phillip Kühne 2025-02-16 12:19:38 +01:00
parent 7a7139360c
commit 33c23cb4f8
Signed by: phillip
GPG Key ID: E4C1C4D2F90902AA
2 changed files with 45 additions and 29 deletions

View File

@ -16,20 +16,23 @@
bool PowerScheduler::tryAccquireCurrentAllowance( bool PowerScheduler::tryAccquireCurrentAllowance(
PowerParameters::PowerConsumers consumer, float neededCurrent, PowerParameters::PowerConsumers consumer, float neededCurrent,
uint16_t requestedDurationMs) { uint16_t requestedDurationMs) {
float existingConsumption = getConsumerCurrent(consumer); float existingConsumption = getConsumerCurrent(consumer);
const bool currentAvailableBelowLimit = const bool currentLimitNotExceeded =
this->freeLimitCurrentBudget + existingConsumption > 0; this->freeLimitCurrentBudget + existingConsumption > 0;
const bool currentAvailableBelowMaximum = const bool neededCurrentAvailableBelowMaximum =
this->freeMaximumCurrentBudget + existingConsumption >= neededCurrent; this->freeMaximumCurrentBudget + existingConsumption >= neededCurrent;
const bool currentIsInsignificant = neededCurrent < 1; const bool currentIsInsignificant =
if (currentIsInsignificant || neededCurrent < PowerParameters::CURRENT_INSIGNIFICANT;
(currentAvailableBelowLimit && currentAvailableBelowMaximum)) { if (currentIsInsignificant ||
(currentLimitNotExceeded && neededCurrentAvailableBelowMaximum)) {
if (existingConsumption > 0) { if (existingConsumption > 0) {
releaseCurrent(consumer); releaseCurrent(consumer);
} }
PowerSchedulerMutex lock(powerSchedulerMutex); PowerSchedulerMutex lock(powerSchedulerMutex);
if (lock.isLocked() == false) { if (lock.isLocked() == false) {
ESP_LOGE(TAG, "Failed to Acquire PowerScheduler Mutex during Current Allocation"); ESP_LOGE(
TAG,
"Failed to Acquire PowerScheduler Mutex during Current Allocation");
return false; return false;
} }
this->currentAllowances.push_back(PowerScheduler::CurrentAllowance{ this->currentAllowances.push_back(PowerScheduler::CurrentAllowance{
@ -110,14 +113,14 @@ bool PowerScheduler::waitForCurrentAllowance(
// Exclude existing consumption from the same consumer, as it will be // Exclude existing consumption from the same consumer, as it will be
// gone if this is granted // gone if this is granted
float existingConsumption = getConsumerCurrent(consumer); float existingConsumption = getConsumerCurrent(consumer);
const bool currentAvailableBelowLimit = const bool currentLimitNotExceeded =
this->freeLimitCurrentBudget + existingConsumption > 0; this->freeLimitCurrentBudget + existingConsumption > 0;
const bool currentAvailableBelowMaximum = const bool neededCurrentAvailableBelowMaximum =
this->freeMaximumCurrentBudget + existingConsumption >= this->freeMaximumCurrentBudget + existingConsumption >=
neededCurrent; neededCurrent;
const bool currentIsInsignificant = neededCurrent < 1; const bool currentIsInsignificant = neededCurrent < 1;
if (currentIsInsignificant || if (currentIsInsignificant ||
(currentAvailableBelowLimit && currentAvailableBelowMaximum)) { (currentLimitNotExceeded && neededCurrentAvailableBelowMaximum)) {
PowerSchedulerMutex lock(powerSchedulerMutex); PowerSchedulerMutex lock(powerSchedulerMutex);
if (lock.isLocked() == false) { if (lock.isLocked() == false) {
return false; return false;
@ -148,7 +151,7 @@ bool PowerScheduler::waitForCurrentAllowance(
} }
if (notificationStatus == pdFALSE) { if (notificationStatus == pdFALSE) {
// We waited long enough... // We waited long enough...
// Remove the task from the list of waiting tasks // Give up and remove the task from the list of waiting tasks
PowerSchedulerMutex lock(powerSchedulerMutex); PowerSchedulerMutex lock(powerSchedulerMutex);
if (lock.isLocked() == false) { if (lock.isLocked() == false) {
return false; return false;
@ -178,8 +181,7 @@ void PowerScheduler::checkWaitingTasks(void) {
// If there are requested allowances, try to grant the one expiring next // If there are requested allowances, try to grant the one expiring next
if (this->currentAllowances.size() > 0) { if (this->currentAllowances.size() > 0) {
PowerScheduler::CurrentAllowance *nextAllowance = PowerScheduler::CurrentAllowance *nextAllowance = getNextAllowance();
getNextExpiringAllowance();
if (nextAllowance != nullptr) { if (nextAllowance != nullptr) {
xTaskNotify(nextAllowance->taskHandle, xTaskNotify(nextAllowance->taskHandle,
PowerScheduler::PowerWakeupReasons::POWER_AVAILABLE, PowerScheduler::PowerWakeupReasons::POWER_AVAILABLE,
@ -237,33 +239,47 @@ PowerScheduler::getCurrentAllowance(TaskHandle_t taskHandle) {
} }
return nullptr; return nullptr;
} }
PowerScheduler::CurrentAllowance * PowerScheduler::CurrentAllowance *PowerScheduler::getNextAllowance(void) {
PowerScheduler::getNextExpiringAllowance(void) {
PowerSchedulerMutex lock(powerSchedulerMutex);
TickType_t minTicks = UINT32_MAX; TickType_t minTicks = UINT32_MAX;
CurrentAllowance *nextAllowance = nullptr; CurrentAllowance *nextAllowance = nullptr;
if (lock.isLocked() == false) {
return nullptr; std::vector<CurrentAllowance> sortedAllowances;
} sortedAllowances.reserve(currentAllowances.size());
for (auto &allowance : currentAllowances) { for (auto &allowance : currentAllowances) {
if (!(allowance.granted)) { if (!(allowance.granted)) {
TickType_t ticks = sortedAllowances.push_back(allowance);
allowance.requestedAt + pdMS_TO_TICKS(allowance.maxSlackTimeMs); }
if (ticks < minTicks) { }
minTicks = ticks; // Sort the not yet granted requests by how much time they have left before
nextAllowance = &allowance; // expiring
} std::sort(sortedAllowances.begin(), sortedAllowances.end(),
[](const CurrentAllowance &a, const CurrentAllowance &b) {
return a.requestedAt + pdMS_TO_TICKS(a.maxSlackTimeMs) <
b.requestedAt + pdMS_TO_TICKS(b.maxSlackTimeMs);
});
// Get the first one whose power requirement can be met
for (CurrentAllowance &allowance : sortedAllowances) {
const float existingConsumerConsumption =
getConsumerCurrent(allowance.consumer);
const bool currentAvailableBelowMaximum =
this->freeMaximumCurrentBudget + existingConsumerConsumption >=
allowance.neededCurrent;
const bool currentInsignificant =
allowance.neededCurrent < PowerParameters::CURRENT_INSIGNIFICANT;
if (currentInsignificant || currentAvailableBelowMaximum) {
return &allowance;
} }
} }
// Will be nullptr if no allowance was found // Will be nullptr if no allowance was found
return nextAllowance; return nullptr;
} }
PowerScheduler &PowerScheduler::getPowerScheduler(float i_limit_ma, PowerScheduler &PowerScheduler::getPowerScheduler(float i_limit_ma,
float i_max_ma) { float i_max_ma) {
if (powerSchedulerInstance == nullptr) { if (powerSchedulerInstance == nullptr) {
powerSchedulerInstance = new PowerScheduler(i_limit_ma, i_max_ma); powerSchedulerInstance = new PowerScheduler(i_limit_ma, i_max_ma);
} }
return *powerSchedulerInstance; return *powerSchedulerInstance;
} }

View File

@ -147,7 +147,7 @@ public:
CurrentAllowance *getCurrentAllowance(TaskHandle_t taskHandle); CurrentAllowance *getCurrentAllowance(TaskHandle_t taskHandle);
// @brief Retrieve the allowance that will expire next // @brief Retrieve the allowance that will expire next
CurrentAllowance *getNextExpiringAllowance(void); CurrentAllowance *getNextAllowance(void);
protected: protected:
// Current above which there will be no new scheduling // Current above which there will be no new scheduling