0

Create base::ThreadType::kResourceEfficient for WebRTC threads

This patch creates a new kResourceEfficient thread type for work similar
to kDefault but not latency sensitive, therefore can be run efficiently.
The EcoQoS will be enabled for kResourceEfficient threads on Windows to
opportunistically save power.

The overall thread type design document can be found at https://docs.google.com/document/d/15O6EkVtNQz1PYl3LL_uM4_5muylEKk_vPvHUbetf8q0

Bug: 1278628
Change-Id: Iaae60e34a96383c38e3f1e9390fe6459feb71a60
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3754088
Commit-Queue: Zhibo Wang <zhibo1.wang@intel.com>
Reviewed-by: Gabriel Charette <gab@chromium.org>
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Reviewed-by: Markus Handell <handellm@google.com>
Reviewed-by: Philip Jägenstedt <foolip@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1032485}
This commit is contained in:
Zhibo Wang
2022-08-08 09:47:20 +00:00
committed by Chromium LUCI CQ
parent cdc00ad0bc
commit 1ca688e769
14 changed files with 115 additions and 20 deletions

@ -95,6 +95,10 @@ enum class ThreadType : int {
// Suitable for threads that have the least urgency and lowest priority, and
// can be interrupted or delayed by other types.
kBackground,
// Suitable for threads that produce user-visible artifacts but aren't
// latency sensitive. The underlying platform will try to be economic
// in its usage of resources for this thread, if possible.
kResourceEfficient,
// Default type. The thread priority or quality of service will be set to
// platform default. In Chrome, this is suitable for handling user
// interactions (input), only display and audio can get a higher priority.

@ -41,10 +41,10 @@ const ThreadPriorityToNiceValuePairForTest
// - kCompositing and kDisplayCritical corresponds to Android's PRIORITY_DISPLAY
// = -4 value.
// - kRealtimeAudio corresponds to Android's PRIORITY_AUDIO = -16 value.
const ThreadTypeToNiceValuePair kThreadTypeToNiceValueMap[5] = {
{ThreadType::kBackground, 10}, {ThreadType::kDefault, 0},
{ThreadType::kCompositing, -4}, {ThreadType::kDisplayCritical, -4},
{ThreadType::kRealtimeAudio, -16},
const ThreadTypeToNiceValuePair kThreadTypeToNiceValueMap[6] = {
{ThreadType::kBackground, 10}, {ThreadType::kResourceEfficient, 0},
{ThreadType::kDefault, 0}, {ThreadType::kCompositing, -4},
{ThreadType::kDisplayCritical, -4}, {ThreadType::kRealtimeAudio, -16},
};
bool CanSetThreadTypeToRealtimeAudio() {

@ -88,6 +88,7 @@ void SetCurrentThreadTypeImpl(ThreadType thread_type,
MessagePumpType pump_type_hint) {
switch (thread_type) {
case ThreadType::kBackground:
case ThreadType::kResourceEfficient:
case ThreadType::kDefault:
case ThreadType::kCompositing:
break;
@ -114,6 +115,7 @@ ThreadPriorityForTest PlatformThread::GetCurrentThreadPriorityForTest() {
const ThreadType thread_type = PlatformThread::GetCurrentThreadType();
switch (thread_type) {
case ThreadType::kBackground:
case ThreadType::kResourceEfficient:
case ThreadType::kDefault:
case ThreadType::kCompositing:
return ThreadPriorityForTest::kNormal;

@ -27,7 +27,7 @@ struct ThreadPriorityToNiceValuePairForTest {
// The elements must be listed in the order of increasing priority (lowest
// priority first), that is, in the order of decreasing nice values (highest
// nice value first).
extern const ThreadTypeToNiceValuePair kThreadTypeToNiceValueMap[5];
extern const ThreadTypeToNiceValuePair kThreadTypeToNiceValueMap[6];
// The elements must be listed in the order of decreasing priority (highest
// priority first), that is, in the order of increasing nice values (lowest nice

@ -140,6 +140,7 @@ FilePath ThreadTypeToCgroupDirectory(const FilePath& cgroup_filepath,
ThreadType thread_type) {
switch (thread_type) {
case ThreadType::kBackground:
case ThreadType::kResourceEfficient:
return cgroup_filepath.Append(FILE_PATH_LITERAL("non-urgent"));
case ThreadType::kDefault:
return cgroup_filepath;
@ -237,9 +238,9 @@ void SetThreadLatencySensitivity(ProcessId process_id,
return;
switch (thread_type) {
case ThreadType::kDefault:
[[fallthrough]];
case ThreadType::kBackground:
case ThreadType::kResourceEfficient:
case ThreadType::kDefault:
break;
case ThreadType::kCompositing:
case ThreadType::kDisplayCritical:
@ -316,8 +317,9 @@ const ThreadPriorityToNiceValuePairForTest
{ThreadPriorityForTest::kBackground, 10},
};
const ThreadTypeToNiceValuePair kThreadTypeToNiceValueMap[5] = {
{ThreadType::kBackground, 10}, {ThreadType::kDefault, 0},
const ThreadTypeToNiceValuePair kThreadTypeToNiceValueMap[6] = {
{ThreadType::kBackground, 10}, {ThreadType::kResourceEfficient, 0},
{ThreadType::kDefault, 0},
#if BUILDFLAG(IS_CHROMEOS)
{ThreadType::kCompositing, -8},
#else

@ -317,6 +317,7 @@ void SetCurrentThreadTypeImpl(ThreadType thread_type,
priority = ThreadPriorityForTest::kBackground;
[[NSThread currentThread] setThreadPriority:0];
break;
case ThreadType::kResourceEfficient:
case ThreadType::kDefault:
// TODO(1329208): Experiment with prioritizing kCompositing on Mac like on
// other platforms.

@ -244,8 +244,9 @@ TEST(PlatformThreadTest, FunctionTimesTen) {
namespace {
constexpr ThreadType kAllThreadTypes[] = {
ThreadType::kRealtimeAudio, ThreadType::kDisplayCritical,
ThreadType::kCompositing, ThreadType::kDefault, ThreadType::kBackground};
ThreadType::kRealtimeAudio, ThreadType::kDisplayCritical,
ThreadType::kCompositing, ThreadType::kDefault,
ThreadType::kResourceEfficient, ThreadType::kBackground};
class ThreadTypeTestThread : public FunctionTestThread {
public:
@ -428,6 +429,8 @@ TEST(PlatformThreadTest, CanChangeThreadType) {
EXPECT_TRUE(PlatformThread::CanChangeThreadType(type, type));
}
#if BUILDFLAG(IS_FUCHSIA)
EXPECT_FALSE(PlatformThread::CanChangeThreadType(
ThreadType::kBackground, ThreadType::kResourceEfficient));
EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
ThreadType::kDefault));
EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
@ -437,6 +440,9 @@ TEST(PlatformThreadTest, CanChangeThreadType) {
EXPECT_FALSE(PlatformThread::CanChangeThreadType(ThreadType::kCompositing,
ThreadType::kBackground));
#else
EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
ThreadType::kResourceEfficient),
kCanIncreasePriority);
EXPECT_EQ(PlatformThread::CanChangeThreadType(ThreadType::kBackground,
ThreadType::kDefault),
kCanIncreasePriority);
@ -470,6 +476,8 @@ TEST(PlatformThreadTest, CanChangeThreadType) {
TEST(PlatformThreadTest, SetCurrentThreadTypeTest) {
TestPriorityResultingFromThreadType(ThreadType::kBackground,
ThreadPriorityForTest::kBackground);
TestPriorityResultingFromThreadType(ThreadType::kResourceEfficient,
ThreadPriorityForTest::kNormal);
TestPriorityResultingFromThreadType(ThreadType::kDefault,
ThreadPriorityForTest::kNormal);
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)

@ -373,9 +373,9 @@ bool PlatformThread::CanChangeThreadType(ThreadType from, ThreadType to) {
return true;
}
namespace internal {
namespace {
void SetCurrentThreadTypeImpl(ThreadType thread_type,
void SetCurrentThreadPriority(ThreadType thread_type,
MessagePumpType pump_type_hint) {
if (thread_type == ThreadType::kCompositing &&
pump_type_hint == MessagePumpType::UI) {
@ -412,6 +412,7 @@ void SetCurrentThreadTypeImpl(ThreadType thread_type,
? THREAD_PRIORITY_LOWEST
: THREAD_MODE_BACKGROUND_BEGIN;
break;
case ThreadType::kResourceEfficient:
case ThreadType::kDefault:
desired_priority = THREAD_PRIORITY_NORMAL;
break;
@ -445,6 +446,55 @@ void SetCurrentThreadTypeImpl(ThreadType thread_type,
}
}
void SetCurrentThreadQualityOfService(ThreadType thread_type) {
// QoS and power throttling were introduced in Win10 1709
if (win::GetVersion() < win::Version::WIN10_RS3) {
return;
}
static const auto set_thread_information_fn =
reinterpret_cast<decltype(&::SetThreadInformation)>(::GetProcAddress(
::GetModuleHandle(L"kernel32.dll"), "SetThreadInformation"));
DCHECK(set_thread_information_fn);
bool desire_ecoqos = false;
switch (thread_type) {
case ThreadType::kBackground:
case ThreadType::kResourceEfficient:
desire_ecoqos = true;
break;
case ThreadType::kDefault:
case ThreadType::kCompositing:
case ThreadType::kDisplayCritical:
case ThreadType::kRealtimeAudio:
desire_ecoqos = false;
break;
}
THREAD_POWER_THROTTLING_STATE thread_power_throttling_state{
.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION,
.ControlMask =
desire_ecoqos ? THREAD_POWER_THROTTLING_EXECUTION_SPEED : 0ul,
.StateMask =
desire_ecoqos ? THREAD_POWER_THROTTLING_EXECUTION_SPEED : 0ul,
};
[[maybe_unused]] const BOOL success = set_thread_information_fn(
::GetCurrentThread(), ::ThreadPowerThrottling,
&thread_power_throttling_state, sizeof(thread_power_throttling_state));
DPLOG_IF(ERROR, !success)
<< "Failed to set EcoQoS to " << std::boolalpha << desire_ecoqos;
}
} // namespace
namespace internal {
void SetCurrentThreadTypeImpl(ThreadType thread_type,
MessagePumpType pump_type_hint) {
SetCurrentThreadPriority(thread_type, pump_type_hint);
SetCurrentThreadQualityOfService(thread_type);
}
} // namespace internal
// static

@ -16,6 +16,8 @@ EnumTraits<mojo_base::mojom::ThreadType, base::ThreadType>::ToMojom(
switch (thread_type) {
case base::ThreadType::kBackground:
return mojo_base::mojom::ThreadType::kBackground;
case base::ThreadType::kResourceEfficient:
return mojo_base::mojom::ThreadType::kResourceEfficient;
case base::ThreadType::kDefault:
return mojo_base::mojom::ThreadType::kDefault;
case base::ThreadType::kCompositing:
@ -37,6 +39,9 @@ bool EnumTraits<mojo_base::mojom::ThreadType, base::ThreadType>::FromMojom(
case mojo_base::mojom::ThreadType::kBackground:
*out = base::ThreadType::kBackground;
return true;
case mojo_base::mojom::ThreadType::kResourceEfficient:
*out = base::ThreadType::kResourceEfficient;
return true;
case mojo_base::mojom::ThreadType::kDefault:
*out = base::ThreadType::kDefault;
return true;

@ -9,6 +9,10 @@ enum ThreadType {
// Suitable for threads that have the least urgency and lowest priority, and
// can be interrupted or delayed by other types.
kBackground,
// Suitable for threads that produce user-visible artifacts but aren't
// latency sensitive. The underlying platform will try to be economic
// in its usage of resources for this thread, if possible.
kResourceEfficient,
// Default type. The thread priority or quality of service will be set to
// platform default. In Chrome, this is suitable for handling user
// interactions (input), only display and audio can get a higher priority.

@ -1599,5 +1599,8 @@ const base::Feature kScrollUpdateOptimizations{
const base::Feature kClipboardUnsanitizedContent{
"ClipboardUnsanitizedContent", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kWebRtcThreadsUseResourceEfficientType{
"WebRtcThreadsUseResourceEfficientType", base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
} // namespace blink

@ -841,6 +841,11 @@ BLINK_COMMON_EXPORT extern const base::Feature kScrollUpdateOptimizations;
// it is only applicable to HTML format. See crbug.com/1268679.
BLINK_COMMON_EXPORT extern const base::Feature kClipboardUnsanitizedContent;
// If enabled, the WebRTC_* threads in peerconnection module will use
// kResourceEfficient thread type.
BLINK_COMMON_EXPORT extern const base::Feature
kWebRtcThreadsUseResourceEfficientType;
} // namespace features
} // namespace blink

@ -143,14 +143,24 @@ class PeerConnectionStaticDeps {
chrome_network_thread_("WebRTC_Network") {}
void EnsureChromeThreadsStarted() {
if (!chrome_signaling_thread_.IsRunning())
chrome_signaling_thread_.Start();
if (!chrome_network_thread_.IsRunning())
chrome_network_thread_.Start();
if (!chrome_worker_thread_.IsRunning())
chrome_worker_thread_.Start();
base::ThreadType thread_type = base::ThreadType::kDefault;
if (base::FeatureList::IsEnabled(
features::kWebRtcThreadsUseResourceEfficientType)) {
thread_type = base::ThreadType::kResourceEfficient;
}
if (!chrome_signaling_thread_.IsRunning()) {
chrome_signaling_thread_.StartWithOptions(
base::Thread::Options(thread_type));
}
if (!chrome_network_thread_.IsRunning()) {
chrome_network_thread_.StartWithOptions(
base::Thread::Options(thread_type));
}
if (!chrome_worker_thread_.IsRunning()) {
chrome_worker_thread_.StartWithOptions(
base::Thread::Options(thread_type));
}
// To allow sending to the signaling/worker threads.
webrtc::ThreadWrapper::EnsureForCurrentMessageLoop();
webrtc::ThreadWrapper::current()->set_send_allowed(true);

@ -111,6 +111,7 @@ _CONFIG = [
'base::SysInfo',
'base::ThreadChecker',
'base::ThreadTicks',
'base::ThreadType',
'base::TickClock',
'base::Time',
'base::TimeDelta',