webrtc_m130/call/adaptation/resource_adaptation_processor.cc
Henrik Boström 48258acabf [Overuse] Implement Resource and ResourceUsageListener.
The Resource interface (previously a skeleton not used outside of
testing) is updated to inform listeners of changes to resource
usage. Debugging methods are removed (Name, UsageUnitsOfMeasurements,
CurrentUsage). The interface is implemented by
OveruseFrameDetectorResourceAdaptationModule's inner classes
EncodeUsageResource and QualityScalerResource.

The new ResourceUsageListener interface is implemented by
OveruseFrameDetectorResourceAdaptationModule. In order to avoid adding
AdaptationObserverInterface::AdaptReason to the ResourceUsageListener
interface, the module figures out if the reason is "kCpu" or "kQuality"
by looking which Resource object triggered
OnResourceUsageStateMeasured(). These resources no longer need an
explicit reference to OveruseFrameDetectorResourceAdaptationModule and
could potentially be used by a different module.

In this CL, AdaptationObserverInterface::AdaptDown()'s return value is
still needed by QualityScaler. This is mirrored in the return value of
ResourceUsageListener::OnResourceUsageStateMeasured(). A TODO is added
to remove it and a comment explains how the current implementation
seems to break the contract of the method (as was the case prior to
this CL).

Follow-up work include:
- Move EncodeUsageResource and QualityScalerResource to separate files.
- Make resources injectable, allowing fake resources in testing and
  removing OnResourceOveruseForTesting() methods.
  (Investigate adding the necessary input signals to the Resource
  interface or relevant sub-interfaces so that the module does not need
  to know which Resource implementation is used.)
- And more! See whiteboard :)

Bug: webrtc:11222
Change-Id: I0a46ace4a2e617874e3ee97e67e3a199fef420a2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/168180
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Erik Språng <sprang@webrtc.org>
Reviewed-by: Evan Shrubsole <eshr@google.com>
Cr-Commit-Position: refs/heads/master@{#30469}
2020-02-06 12:45:14 +00:00

128 lines
4.6 KiB
C++

/*
* Copyright 2019 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "call/adaptation/resource_adaptation_processor.h"
#include <limits>
#include <utility>
#include "rtc_base/checks.h"
namespace webrtc {
namespace {
ResourceConsumerConfiguration* FindMostPreferredConfiguration(
const std::vector<ResourceConsumerConfiguration*>& configurations) {
if (configurations.empty())
return nullptr;
ResourceConsumerConfiguration* most_preferred_configuration =
configurations[0];
double most_preferred_configuration_preference =
most_preferred_configuration->Preference();
RTC_DCHECK_GE(most_preferred_configuration_preference, 0.0);
for (size_t i = 1; i < configurations.size(); ++i) {
auto* configuration = configurations[i];
double preference = configuration->Preference();
RTC_DCHECK_GE(preference, 0.0);
if (most_preferred_configuration_preference < preference) {
most_preferred_configuration = configuration;
most_preferred_configuration_preference = preference;
}
}
return most_preferred_configuration;
}
} // namespace
ConsumerConfigurationPair::ConsumerConfigurationPair(
ResourceConsumer* consumer,
ResourceConsumerConfiguration* configuration)
: consumer(consumer), configuration(configuration) {}
absl::optional<ConsumerConfigurationPair>
ResourceAdaptationProcessor::FindNextConfiguration() {
ResourceUsageState overall_usage = ResourceUsageState::kUnderuse;
for (auto& resource : resources_) {
if (resource->usage_state() == ResourceUsageState::kStable) {
// If any resource is "stable", we are not underusing.
if (overall_usage == ResourceUsageState::kUnderuse)
overall_usage = ResourceUsageState::kStable;
} else if (resource->usage_state() == ResourceUsageState::kOveruse) {
// If any resource is "overuse", we are overusing.
overall_usage = ResourceUsageState::kOveruse;
break;
}
}
// If we are stable we should neither adapt up or down: stay where we are.
if (overall_usage == ResourceUsageState::kStable)
return absl::nullopt;
if (overall_usage == ResourceUsageState::kOveruse) {
// If we are overusing, we adapt down the most expensive consumer to its
// most preferred lower neighbor.
ResourceConsumer* max_cost_consumer =
FindMostExpensiveConsumerThatCanBeAdaptedDown();
if (!max_cost_consumer)
return absl::nullopt;
ResourceConsumerConfiguration* next_configuration =
FindMostPreferredConfiguration(
max_cost_consumer->configuration()->lower_neighbors());
RTC_DCHECK(next_configuration);
return ConsumerConfigurationPair(max_cost_consumer, next_configuration);
} else {
RTC_DCHECK_EQ(overall_usage, ResourceUsageState::kUnderuse);
// If we are underusing, we adapt up the least expensive consumer to its
// most preferred upper neighbor.
ResourceConsumer* min_cost_consumer =
FindLeastExpensiveConsumerThatCanBeAdaptedUp();
if (!min_cost_consumer)
return absl::nullopt;
ResourceConsumerConfiguration* next_configuration =
FindMostPreferredConfiguration(
min_cost_consumer->configuration()->upper_neighbors());
RTC_DCHECK(next_configuration);
return ConsumerConfigurationPair(min_cost_consumer, next_configuration);
}
}
ResourceConsumer*
ResourceAdaptationProcessor::FindMostExpensiveConsumerThatCanBeAdaptedDown() {
ResourceConsumer* max_cost_consumer = nullptr;
double max_cost = -1.0;
for (auto& consumer : consumers_) {
if (consumer->configuration()->lower_neighbors().empty())
continue;
double cost = consumer->configuration()->Cost();
if (max_cost < cost) {
max_cost_consumer = consumer.get();
max_cost = cost;
}
}
return max_cost_consumer;
}
ResourceConsumer*
ResourceAdaptationProcessor::FindLeastExpensiveConsumerThatCanBeAdaptedUp() {
ResourceConsumer* min_cost_consumer = nullptr;
double min_cost = std::numeric_limits<double>::infinity();
for (auto& consumer : consumers_) {
if (consumer->configuration()->upper_neighbors().empty())
continue;
double cost = consumer->configuration()->Cost();
if (min_cost > cost) {
min_cost_consumer = consumer.get();
min_cost = cost;
}
}
return min_cost_consumer;
}
} // namespace webrtc