[Fuchsia] Partially implement thread priorities
This adds base::PlatformThread support for the DISPLAY and REALTIME_AUDIO thread priorities on Fuchsia. These are implemented using the fuchsia.media.ProfileProvider API, which allows to set scheduling profile for a thread. Bug: 1174811, 1181421, 1224707 Change-Id: I333bf6a2dbbf44e71f4cd6e6666971eca09d2775 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2987902 Reviewed-by: Daniel Cheng <dcheng@chromium.org> Reviewed-by: Hongchan Choi <hongchan@chromium.org> Reviewed-by: Wez <wez@chromium.org> Reviewed-by: Dale Curtis <dalecurtis@chromium.org> Commit-Queue: Sergey Ulanov <sergeyu@chromium.org> Cr-Commit-Position: refs/heads/master@{#904992}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
dfe51235e5
commit
47efa9ef37
base
build/config/fuchsia
content/shell/fuchsia
fuchsia
engine
http
runners
media
sandbox/policy/fuchsia
third_party/blink/renderer/modules/webaudio
@ -1646,6 +1646,7 @@ component("base") {
|
||||
"fuchsia/koid.h",
|
||||
"fuchsia/process_context.cc",
|
||||
"fuchsia/process_context.h",
|
||||
"fuchsia/scheduler.h",
|
||||
"fuchsia/scoped_fx_logger.cc",
|
||||
"fuchsia/scoped_fx_logger.h",
|
||||
"fuchsia/scoped_service_binding.h",
|
||||
@ -1715,6 +1716,7 @@ component("base") {
|
||||
]
|
||||
|
||||
deps += [
|
||||
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.media",
|
||||
"//third_party/fuchsia-sdk/sdk/fidl/fuchsia.sys",
|
||||
"//third_party/fuchsia-sdk/sdk/pkg/async-default",
|
||||
"//third_party/fuchsia-sdk/sdk/pkg/async-loop-cpp",
|
||||
|
37
base/fuchsia/scheduler.h
Normal file
37
base/fuchsia/scheduler.h
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2021 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_FUCHSIA_SCHEDULER_H_
|
||||
#define BASE_FUCHSIA_SCHEDULER_H_
|
||||
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/time/time.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Scheduling interval to use for realtime audio threads.
|
||||
// TODO(crbug.com/1224707): Add scheduling period to Thread::Options and remove
|
||||
// this constants.
|
||||
constexpr TimeDelta kAudioSchedulingPeriod = TimeDelta::FromMilliseconds(10);
|
||||
|
||||
// Reserve 10% or one CPU core for audio threads.
|
||||
// TODO(crbug.com/1174811): A different value may need to be used for WebAudio
|
||||
// threads (see media::FuchsiaAudioOutputDevice). A higher capacity may need to
|
||||
// be allocated in that case.
|
||||
constexpr float kAudioSchedulingCapacity = 0.1;
|
||||
|
||||
// Scheduling interval to use for display threads.
|
||||
// TODO(crbug.com/1224707): Add scheduling period to Thread::Options and remove
|
||||
// this constants.
|
||||
constexpr TimeDelta kDisplaySchedulingPeriod = TimeDelta::FromSeconds(1) / 60;
|
||||
|
||||
// Reserve 50% of one CPU core for display threads.
|
||||
// TODO(crbug.com/1181421): Currently DISPLAY priority is not enabled for any
|
||||
// thread on Fuchsia. The value below will need to be fine-tuned when it's
|
||||
// enabled.
|
||||
const float kDisplaySchedulingCapacity = 0.5;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_FUCHSIA_SCHEDULER_H_
|
@ -225,7 +225,7 @@ class BASE_EXPORT PlatformThread {
|
||||
// A thread may not be able to raise its priority back up after lowering it if
|
||||
// the process does not have a proper permission, e.g. CAP_SYS_NICE on Linux.
|
||||
// A thread may not be able to lower its priority back down after raising it
|
||||
// to REALTIME_AUDIO.
|
||||
// to DISPLAY or REALTIME_AUDIO.
|
||||
//
|
||||
// This function must not be called from the main thread on Mac. This is to
|
||||
// avoid performance regressions (https://crbug.com/601270).
|
||||
|
@ -8,11 +8,82 @@
|
||||
#include <sched.h>
|
||||
#include <zircon/syscalls.h>
|
||||
|
||||
#include <fuchsia/media/cpp/fidl.h>
|
||||
#include <lib/fdio/directory.h>
|
||||
#include <lib/sys/cpp/component_context.h>
|
||||
|
||||
#include "base/fuchsia/fuchsia_logging.h"
|
||||
#include "base/fuchsia/process_context.h"
|
||||
#include "base/fuchsia/scheduler.h"
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/threading/platform_thread_internal_posix.h"
|
||||
#include "base/threading/thread_id_name_manager.h"
|
||||
#include "base/threading/thread_local_storage.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace {
|
||||
|
||||
fuchsia::media::ProfileProviderSyncPtr ConnectProfileProvider() {
|
||||
fuchsia::media::ProfileProviderSyncPtr profile_provider;
|
||||
base::ComponentContextForProcess()->svc()->Connect(
|
||||
profile_provider.NewRequest());
|
||||
return profile_provider;
|
||||
}
|
||||
|
||||
void ScheduleAsMediaThread(StringPiece name, TimeDelta period, float capacity) {
|
||||
DCHECK(!period.is_zero());
|
||||
DCHECK_GT(capacity, 0.0);
|
||||
DCHECK_LT(capacity, 1.0);
|
||||
|
||||
static const base::NoDestructor<fuchsia::media::ProfileProviderSyncPtr>
|
||||
profile_provider(ConnectProfileProvider());
|
||||
|
||||
zx::thread dup_thread;
|
||||
zx_status_t status =
|
||||
zx::thread::self()->duplicate(ZX_RIGHT_SAME_RIGHTS, &dup_thread);
|
||||
ZX_CHECK(status == ZX_OK, status) << "zx_object_duplicate";
|
||||
|
||||
int64_t out_period, out_capacity;
|
||||
status = (*profile_provider)
|
||||
->RegisterHandlerWithCapacity(
|
||||
std::move(dup_thread), std::string(name),
|
||||
period.ToZxDuration(), capacity, &out_period, &out_capacity);
|
||||
|
||||
if (status != ZX_OK) {
|
||||
ZX_LOG(WARNING, status)
|
||||
<< "Failed to register a realtime thread. Is "
|
||||
"fuchsia.media.ProfileProvider in the component sandbox?";
|
||||
}
|
||||
}
|
||||
|
||||
// Return ThreadLocalStorage slot used to store priority of the current thread.
|
||||
// The value is stored as an integer value converted to a pointer. 1 is added to
|
||||
// the integer value in order to distinguish the case when the TLS slot is not
|
||||
// initialized.
|
||||
base::ThreadLocalStorage::Slot* GetThreadPriorityTlsSlot() {
|
||||
static base::NoDestructor<base::ThreadLocalStorage::Slot> tls_slot;
|
||||
return tls_slot.get();
|
||||
}
|
||||
|
||||
void SaveThreadPriorityToTls(ThreadPriority priority) {
|
||||
GetThreadPriorityTlsSlot()->Set(
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(priority) + 1));
|
||||
}
|
||||
|
||||
ThreadPriority GetThreadPriorityFromTls() {
|
||||
uintptr_t value =
|
||||
reinterpret_cast<uintptr_t>(GetThreadPriorityTlsSlot()->Get());
|
||||
|
||||
// Thread priority is set to NORMAL by default.
|
||||
if (value == 0)
|
||||
return ThreadPriority::NORMAL;
|
||||
|
||||
return static_cast<ThreadPriority>(value - 1);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void InitThreading() {}
|
||||
|
||||
void TerminateOnThread() {}
|
||||
@ -32,17 +103,35 @@ void PlatformThread::SetName(const std::string& name) {
|
||||
|
||||
// static
|
||||
bool PlatformThread::CanIncreaseThreadPriority(ThreadPriority priority) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void PlatformThread::SetCurrentThreadPriorityImpl(ThreadPriority priority) {
|
||||
// TODO(https://crbug.com/926583): Fuchsia does not currently support this.
|
||||
switch (priority) {
|
||||
case ThreadPriority::BACKGROUND:
|
||||
case ThreadPriority::NORMAL:
|
||||
DCHECK(GetThreadPriorityFromTls() != ThreadPriority::DISPLAY &&
|
||||
GetThreadPriorityFromTls() != ThreadPriority::REALTIME_AUDIO);
|
||||
break;
|
||||
|
||||
case ThreadPriority::DISPLAY:
|
||||
ScheduleAsMediaThread("chromium.base.threading.display",
|
||||
kDisplaySchedulingPeriod, kAudioSchedulingCapacity);
|
||||
break;
|
||||
|
||||
case ThreadPriority::REALTIME_AUDIO:
|
||||
ScheduleAsMediaThread("chromium.base.threading.realtime-audio",
|
||||
kAudioSchedulingPeriod, kDisplaySchedulingCapacity);
|
||||
break;
|
||||
}
|
||||
|
||||
SaveThreadPriorityToTls(priority);
|
||||
}
|
||||
|
||||
// static
|
||||
ThreadPriority PlatformThread::GetCurrentThreadPriority() {
|
||||
return ThreadPriority::NORMAL;
|
||||
return GetThreadPriorityFromTls();
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
@ -317,9 +317,6 @@ TEST(PlatformThreadTest, CanIncreaseThreadPriority) {
|
||||
// On Ubuntu, RLIMIT_NICE and RLIMIT_RTPRIO are 0 by default, so we won't be
|
||||
// able to increase priority to any level.
|
||||
constexpr bool kCanIncreasePriority = false;
|
||||
#elif defined(OS_FUCHSIA)
|
||||
// Fuchsia doesn't support thread priorities.
|
||||
constexpr bool kCanIncreasePriority = false;
|
||||
#else
|
||||
constexpr bool kCanIncreasePriority = true;
|
||||
#endif
|
||||
|
@ -16,6 +16,7 @@
|
||||
"fuchsia.fonts.Provider",
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
"fuchsia.logger.LogSink",
|
||||
"fuchsia.media.ProfileProvider",
|
||||
"fuchsia.memorypressure.Provider",
|
||||
"fuchsia.process.Launcher",
|
||||
"fuchsia.sys.Environment",
|
||||
|
@ -21,6 +21,7 @@
|
||||
"services": [
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
"fuchsia.logger.LogSink",
|
||||
"fuchsia.media.ProfileProvider",
|
||||
"fuchsia.process.Launcher",
|
||||
"fuchsia.sys.Launcher",
|
||||
"fuchsia.sys.Loader"
|
||||
|
@ -15,6 +15,7 @@
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
"fuchsia.logger.LogSink",
|
||||
"fuchsia.media.Audio",
|
||||
"fuchsia.media.ProfileProvider",
|
||||
"fuchsia.media.SessionAudioConsumerFactory",
|
||||
"fuchsia.media.drm.Widevine",
|
||||
"fuchsia.mediacodec.CodecFactory",
|
||||
|
@ -11,6 +11,7 @@
|
||||
"fuchsia.feedback.ComponentDataRegister",
|
||||
"fuchsia.feedback.CrashReportingProductRegister",
|
||||
"fuchsia.logger.LogSink",
|
||||
"fuchsia.media.ProfileProvider",
|
||||
"fuchsia.sys.Environment",
|
||||
"fuchsia.sys.Loader"
|
||||
]
|
||||
|
@ -13,6 +13,7 @@
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
"fuchsia.logger.LogSink",
|
||||
"fuchsia.media.Audio",
|
||||
"fuchsia.media.ProfileProvider",
|
||||
"fuchsia.media.SessionAudioConsumerFactory",
|
||||
"fuchsia.media.drm.Widevine",
|
||||
"fuchsia.mediacodec.CodecFactory",
|
||||
|
@ -19,6 +19,7 @@
|
||||
"fuchsia.legacymetrics.MetricsRecorder",
|
||||
"fuchsia.logger.LogSink",
|
||||
"fuchsia.media.Audio",
|
||||
"fuchsia.media.ProfileProvider",
|
||||
"fuchsia.media.SessionAudioConsumerFactory",
|
||||
"fuchsia.media.drm.PlayReady",
|
||||
"fuchsia.media.drm.Widevine",
|
||||
|
@ -8,6 +8,7 @@
|
||||
"fuchsia.device.NameProvider",
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
"fuchsia.logger.LogSink",
|
||||
"fuchsia.media.ProfileProvider",
|
||||
"fuchsia.net.NameLookup",
|
||||
"fuchsia.net.interfaces.State",
|
||||
"fuchsia.net.name.Lookup",
|
||||
|
@ -42,6 +42,7 @@ static constexpr const char* kServices[] = {
|
||||
"fuchsia.input.virtualkeyboard.ControllerCreator",
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
"fuchsia.logger.LogSink",
|
||||
"fuchsia.media.ProfileProvider",
|
||||
"fuchsia.media.SessionAudioConsumerFactory",
|
||||
"fuchsia.media.drm.PlayReady",
|
||||
"fuchsia.media.drm.Widevine",
|
||||
|
@ -16,6 +16,7 @@
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
"fuchsia.logger.LogSink",
|
||||
"fuchsia.media.Audio",
|
||||
"fuchsia.media.ProfileProvider",
|
||||
"fuchsia.media.SessionAudioConsumerFactory",
|
||||
"fuchsia.media.drm.PlayReady",
|
||||
"fuchsia.media.drm.Widevine",
|
||||
|
@ -14,6 +14,7 @@
|
||||
"fuchsia.intl.PropertyProvider",
|
||||
"fuchsia.logger.LogSink",
|
||||
"fuchsia.media.Audio",
|
||||
"fuchsia.media.ProfileProvider",
|
||||
"fuchsia.media.SessionAudioConsumerFactory",
|
||||
"fuchsia.media.drm.Widevine",
|
||||
"fuchsia.mediacodec.CodecFactory",
|
||||
|
@ -22,6 +22,7 @@ AudioThreadImpl::AudioThreadImpl()
|
||||
#elif defined(OS_FUCHSIA)
|
||||
// FIDL-based APIs require async_t, which is initialized on IO thread.
|
||||
thread_options.message_pump_type = base::MessagePumpType::IO;
|
||||
thread_options.priority = base::ThreadPriority::REALTIME_AUDIO;
|
||||
#endif
|
||||
CHECK(thread_.StartWithOptions(std::move(thread_options)));
|
||||
|
||||
|
@ -7,7 +7,9 @@
|
||||
#include <memory>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "base/fuchsia/scheduler.h"
|
||||
#include "media/audio/fuchsia/audio_output_stream_fuchsia.h"
|
||||
#include "media/base/audio_timestamp_helper.h"
|
||||
#include "media/base/media_switches.h"
|
||||
|
||||
namespace media {
|
||||
@ -65,8 +67,11 @@ AudioParameters AudioManagerFuchsia::GetInputStreamParameters(
|
||||
// the default configuration used in the AudioCapturer implementation.
|
||||
// Assume that the system-provided AudioConsumer supports echo cancellation,
|
||||
// noise suppression and automatic gain control.
|
||||
const size_t kSampleRate = 16000;
|
||||
const size_t kPeriodSamples = AudioTimestampHelper::TimeToFrames(
|
||||
base::kAudioSchedulingPeriod, kSampleRate);
|
||||
AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
|
||||
CHANNEL_LAYOUT_MONO, 16000, 160);
|
||||
CHANNEL_LAYOUT_MONO, kSampleRate, kPeriodSamples);
|
||||
params.set_effects(AudioParameters::ECHO_CANCELLER |
|
||||
AudioParameters::NOISE_SUPPRESSION |
|
||||
AudioParameters::AUTOMATIC_GAIN_CONTROL);
|
||||
@ -80,8 +85,11 @@ AudioParameters AudioManagerFuchsia::GetPreferredOutputStreamParameters(
|
||||
// TODO(crbug.com/852834): Fuchsia currently doesn't provide an API to get
|
||||
// device configuration. Update this method when that functionality is
|
||||
// implemented.
|
||||
const size_t kSampleRate = 48000;
|
||||
const size_t kPeriodFrames = AudioTimestampHelper::TimeToFrames(
|
||||
base::kAudioSchedulingPeriod, kSampleRate);
|
||||
return AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
|
||||
CHANNEL_LAYOUT_STEREO, 48000, 480);
|
||||
CHANNEL_LAYOUT_STEREO, kSampleRate, kPeriodFrames);
|
||||
}
|
||||
|
||||
const char* AudioManagerFuchsia::GetName() {
|
||||
|
@ -36,10 +36,9 @@ constexpr base::TimeDelta kLeadTimeExtra =
|
||||
class DefaultAudioThread {
|
||||
public:
|
||||
DefaultAudioThread() : thread_("FuchsiaAudioOutputDevice") {
|
||||
// TODO(crbug.com/1153909): Consider applying media-specific scheduling
|
||||
// policy to the thread.
|
||||
thread_.StartWithOptions(
|
||||
base::Thread::Options(base::MessagePumpType::IO, 0));
|
||||
base::Thread::Options options(base::MessagePumpType::IO, 0);
|
||||
options.priority = base::ThreadPriority::REALTIME_AUDIO;
|
||||
thread_.StartWithOptions(std::move(options));
|
||||
}
|
||||
~DefaultAudioThread() = default;
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <fuchsia/fonts/cpp/fidl.h>
|
||||
#include <fuchsia/intl/cpp/fidl.h>
|
||||
#include <fuchsia/logger/cpp/fidl.h>
|
||||
#include <fuchsia/media/cpp/fidl.h>
|
||||
#include <fuchsia/mediacodec/cpp/fidl.h>
|
||||
#include <fuchsia/memorypressure/cpp/fidl.h>
|
||||
#include <fuchsia/net/cpp/fidl.h>
|
||||
@ -66,6 +67,8 @@ struct SandboxConfig {
|
||||
|
||||
constexpr SandboxConfig kGpuConfig = {
|
||||
base::make_span((const char* const[]){
|
||||
// TODO(crbug.com/1224707): Use the fuchsia.scheduler API instead.
|
||||
fuchsia::media::ProfileProvider::Name_,
|
||||
fuchsia::sysmem::Allocator::Name_,
|
||||
"fuchsia.vulkan.loader.Loader",
|
||||
fuchsia::ui::scenic::Scenic::Name_,
|
||||
@ -86,6 +89,8 @@ constexpr SandboxConfig kNetworkConfig = {
|
||||
constexpr SandboxConfig kRendererConfig = {
|
||||
base::make_span((const char* const[]){
|
||||
fuchsia::fonts::Provider::Name_,
|
||||
// TODO(crbug.com/1224707): Use the fuchsia.scheduler API instead.
|
||||
fuchsia::media::ProfileProvider::Name_,
|
||||
fuchsia::mediacodec::CodecFactory::Name_,
|
||||
fuchsia::memorypressure::Provider::Name_,
|
||||
fuchsia::sysmem::Allocator::Name_,
|
||||
|
@ -417,10 +417,6 @@ class AudioWorkletThreadPriorityTest
|
||||
} else {
|
||||
EXPECT_EQ(actual_priority, expected_priority);
|
||||
}
|
||||
#elif defined(OS_FUCHSIA)
|
||||
// The thread priority is no-op on Fuchsia. It's always NORMAL priority.
|
||||
// See crbug.com/1090245.
|
||||
EXPECT_EQ(actual_priority, base::ThreadPriority::NORMAL);
|
||||
#else
|
||||
EXPECT_EQ(actual_priority, expected_priority);
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user