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

@ -17,19 +17,22 @@ 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 =
neededCurrent < PowerParameters::CURRENT_INSIGNIFICANT;
if (currentIsInsignificant || if (currentIsInsignificant ||
(currentAvailableBelowLimit && currentAvailableBelowMaximum)) { (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,26 +239,40 @@ 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;
nextAllowance = &allowance;
} }
} }
// Sort the not yet granted requests by how much time they have left before
// 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,

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