0

[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:
Sergey Ulanov
2021-07-24 01:56:24 +00:00
committed by Chromium LUCI CQ
parent dfe51235e5
commit 47efa9ef37
20 changed files with 161 additions and 17 deletions

@ -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

@ -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