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:

committed by
Chromium LUCI CQ

parent
cdc00ad0bc
commit
1ca688e769
base/threading
platform_thread.hplatform_thread_android.ccplatform_thread_fuchsia.ccplatform_thread_internal_posix.hplatform_thread_linux.ccplatform_thread_mac.mmplatform_thread_unittest.ccplatform_thread_win.cc
mojo/public
third_party/blink
common
public
common
renderer
modules
peerconnection
tools
blinkpy
presubmit
@ -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.
|
||||
|
3
third_party/blink/common/features.cc
vendored
3
third_party/blink/common/features.cc
vendored
@ -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
|
||||
|
5
third_party/blink/public/common/features.h
vendored
5
third_party/blink/public/common/features.h
vendored
@ -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',
|
||||
|
Reference in New Issue
Block a user