Skip to content

Commit

Permalink
Define thread priority enum and set thread priority for all threads i…
Browse files Browse the repository at this point in the history
…n Engine (#30605)

* Define thread priority enum and set thread priority for all threads in Engine

* Split out the thread data and the thread data set operator
  • Loading branch information
JsouLiang authored Feb 11, 2022
1 parent e031e07 commit 5140a44
Show file tree
Hide file tree
Showing 14 changed files with 417 additions and 106 deletions.
4 changes: 2 additions & 2 deletions fml/concurrent_message_loop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ ConcurrentMessageLoop::ConcurrentMessageLoop(size_t worker_count)
: worker_count_(std::max<size_t>(worker_count, 1ul)) {
for (size_t i = 0; i < worker_count_; ++i) {
workers_.emplace_back([i, this]() {
fml::Thread::SetCurrentThreadName(
std::string{"io.worker." + std::to_string(i + 1)});
fml::Thread::SetCurrentThreadName(fml::Thread::ThreadConfig(
std::string{"io.worker." + std::to_string(i + 1)}));
WorkerMain();
});
}
Expand Down
77 changes: 44 additions & 33 deletions fml/thread.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <memory>
#include <string>
#include <utility>

#include "flutter/fml/build_config.h"
#include "flutter/fml/message_loop.h"
Expand All @@ -23,38 +24,6 @@

namespace fml {

Thread::Thread(const std::string& name) : joined_(false) {
fml::AutoResetWaitableEvent latch;
fml::RefPtr<fml::TaskRunner> runner;
thread_ = std::make_unique<std::thread>([&latch, &runner, name]() -> void {
SetCurrentThreadName(name);
fml::MessageLoop::EnsureInitializedForCurrentThread();
auto& loop = MessageLoop::GetCurrent();
runner = loop.GetTaskRunner();
latch.Signal();
loop.Run();
});
latch.Wait();
task_runner_ = runner;
}

Thread::~Thread() {
Join();
}

fml::RefPtr<fml::TaskRunner> Thread::GetTaskRunner() const {
return task_runner_;
}

void Thread::Join() {
if (joined_) {
return;
}
joined_ = true;
task_runner_->PostTask([]() { MessageLoop::GetCurrent().Terminate(); });
thread_->join();
}

#if defined(FML_OS_WIN)
// The information on how to set the thread name comes from
// a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx
Expand All @@ -67,7 +36,7 @@ typedef struct tagTHREADNAME_INFO {
} THREADNAME_INFO;
#endif

void Thread::SetCurrentThreadName(const std::string& name) {
void SetThreadName(const std::string& name) {
if (name == "") {
return;
}
Expand All @@ -94,4 +63,46 @@ void Thread::SetCurrentThreadName(const std::string& name) {
#endif
}

void Thread::SetCurrentThreadName(const Thread::ThreadConfig& config) {
SetThreadName(config.name);
}

Thread::Thread(const std::string& name)
: Thread(Thread::SetCurrentThreadName, ThreadConfig(name)) {}

Thread::Thread(const ThreadConfigSetter& setter, const ThreadConfig& config)
: joined_(false) {
fml::AutoResetWaitableEvent latch;
fml::RefPtr<fml::TaskRunner> runner;

thread_ = std::make_unique<std::thread>(
[&latch, &runner, setter, config]() -> void {
setter(config);
fml::MessageLoop::EnsureInitializedForCurrentThread();
auto& loop = MessageLoop::GetCurrent();
runner = loop.GetTaskRunner();
latch.Signal();
loop.Run();
});
latch.Wait();
task_runner_ = runner;
}

Thread::~Thread() {
Join();
}

fml::RefPtr<fml::TaskRunner> Thread::GetTaskRunner() const {
return task_runner_;
}

void Thread::Join() {
if (joined_) {
return;
}
joined_ = true;
task_runner_->PostTask([]() { MessageLoop::GetCurrent().Terminate(); });
thread_->join();
}

} // namespace fml
37 changes: 36 additions & 1 deletion fml/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
#define FLUTTER_FML_THREAD_H_

#include <atomic>
#include <functional>
#include <memory>
#include <string>
#include <thread>

#include "flutter/fml/macros.h"
Expand All @@ -16,19 +18,52 @@ namespace fml {

class Thread {
public:
/// Valid values for priority of Thread.
enum class ThreadPriority : int {
/// Suitable for threads that shouldn't disrupt high priority work.
BACKGROUND,
/// Default priority level.
NORMAL,
/// Suitable for threads which generate data for the display.
DISPLAY,
/// Suitable for thread which raster data.
RASTER,
};

/// The ThreadConfig is the thread info include thread name, thread priority.
struct ThreadConfig {
ThreadConfig(const std::string& name, ThreadPriority priority)
: name(name), priority(priority) {}

explicit ThreadConfig(const std::string& name)
: ThreadConfig(name, ThreadPriority::NORMAL) {}

ThreadConfig() : ThreadConfig("", ThreadPriority::NORMAL) {}

std::string name;
ThreadPriority priority;
};

using ThreadConfigSetter = std::function<void(const ThreadConfig&)>;

explicit Thread(const std::string& name = "");

explicit Thread(const ThreadConfigSetter& setter,
const ThreadConfig& config = ThreadConfig());

~Thread();

fml::RefPtr<fml::TaskRunner> GetTaskRunner() const;

void Join();

static void SetCurrentThreadName(const std::string& name);
static void SetCurrentThreadName(const ThreadConfig& config);

private:
std::unique_ptr<std::thread> thread_;

fml::RefPtr<fml::TaskRunner> task_runner_;

std::atomic_bool joined_;

FML_DISALLOW_COPY_AND_ASSIGN(Thread);
Expand Down
86 changes: 86 additions & 0 deletions fml/thread_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@

#include "flutter/fml/thread.h"

#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_ANDROID)
#define FLUTTER_PTHREAD_SUPPORTED 1
#else
#define FLUTTER_PTHREAD_SUPPORTED 0
#endif

#if FLUTTER_PTHREAD_SUPPORTED
#include <pthread.h>
#else
#endif

#include <memory>
#include "gtest/gtest.h"

TEST(Thread, CanStartAndEnd) {
Expand All @@ -24,3 +36,77 @@ TEST(Thread, HasARunningMessageLoop) {
thread.Join();
ASSERT_TRUE(done);
}

#if FLUTTER_PTHREAD_SUPPORTED
TEST(Thread, ThreadNameCreatedWithConfig) {
const std::string name = "Thread1";
fml::Thread thread(name);

bool done = false;
thread.GetTaskRunner()->PostTask([&done, &name]() {
done = true;
char thread_name[8];
pthread_t current_thread = pthread_self();
pthread_getname_np(current_thread, thread_name, 8);
ASSERT_EQ(thread_name, name);
});
thread.Join();
ASSERT_TRUE(done);
}

static void MockThreadConfigSetter(const fml::Thread::ThreadConfig& config) {
// set thread name
fml::Thread::SetCurrentThreadName(config);

pthread_t tid = pthread_self();
struct sched_param param;
int policy = SCHED_OTHER;
switch (config.priority) {
case fml::Thread::ThreadPriority::DISPLAY:
param.sched_priority = 10;
break;
default:
param.sched_priority = 1;
}
pthread_setschedparam(tid, policy, &param);
}

TEST(Thread, ThreadPriorityCreatedWithConfig) {
const std::string thread1_name = "Thread1";
const std::string thread2_name = "Thread2";

fml::Thread thread(MockThreadConfigSetter,
fml::Thread::ThreadConfig(
thread1_name, fml::Thread::ThreadPriority::NORMAL));
bool done = false;

struct sched_param param;
int policy;
thread.GetTaskRunner()->PostTask([&]() {
done = true;
char thread_name[8];
pthread_t current_thread = pthread_self();
pthread_getname_np(current_thread, thread_name, 8);
pthread_getschedparam(current_thread, &policy, &param);
ASSERT_EQ(thread_name, thread1_name);
ASSERT_EQ(policy, SCHED_OTHER);
ASSERT_EQ(param.sched_priority, 1);
});

fml::Thread thread2(MockThreadConfigSetter,
fml::Thread::ThreadConfig(
thread2_name, fml::Thread::ThreadPriority::DISPLAY));
thread2.GetTaskRunner()->PostTask([&]() {
done = true;
char thread_name[8];
pthread_t current_thread = pthread_self();
pthread_getname_np(current_thread, thread_name, 8);
pthread_getschedparam(current_thread, &policy, &param);
ASSERT_EQ(thread_name, thread2_name);
ASSERT_EQ(policy, SCHED_OTHER);
ASSERT_EQ(param.sched_priority, 10);
});
thread.Join();
ASSERT_TRUE(done);
}
#endif
12 changes: 6 additions & 6 deletions lib/ui/ui_benchmarks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ class Fixture : public testing::FixtureTest {
};

static void BM_PlatformMessageResponseDartComplete(benchmark::State& state) {
ThreadHost thread_host("test",
ThreadHost::Type::Platform | ThreadHost::Type::RASTER |
ThreadHost::Type::IO | ThreadHost::Type::UI);
ThreadHost thread_host(ThreadHost::ThreadHostConfig(
"test", ThreadHost::Type::Platform | ThreadHost::Type::RASTER |
ThreadHost::Type::IO | ThreadHost::Type::UI));
TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
Expand Down Expand Up @@ -68,9 +68,9 @@ static void BM_PlatformMessageResponseDartComplete(benchmark::State& state) {
}

static void BM_PathVolatilityTracker(benchmark::State& state) {
ThreadHost thread_host("test",
ThreadHost::Type::Platform | ThreadHost::Type::RASTER |
ThreadHost::Type::IO | ThreadHost::Type::UI);
ThreadHost thread_host(ThreadHost::ThreadHostConfig(
"test", ThreadHost::Type::Platform | ThreadHost::Type::RASTER |
ThreadHost::Type::IO | ThreadHost::Type::UI));
TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
Expand Down
4 changes: 2 additions & 2 deletions shell/common/shell_benchmarks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ static void StartupAndShutdownShell(benchmark::State& state,
};
}

thread_host = std::make_unique<ThreadHost>(
thread_host = std::make_unique<ThreadHost>(ThreadHost::ThreadHostConfig(
"io.flutter.bench.", ThreadHost::Type::Platform |
ThreadHost::Type::RASTER |
ThreadHost::Type::IO | ThreadHost::Type::UI);
ThreadHost::Type::IO | ThreadHost::Type::UI));

TaskRunners task_runners("test",
thread_host->platform_thread->GetTaskRunner(),
Expand Down
17 changes: 10 additions & 7 deletions shell/common/shell_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,10 @@ TEST_F(ShellTest, InitializeWithInvalidThreads) {
TEST_F(ShellTest, InitializeWithDifferentThreads) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
Settings settings = CreateSettingsForFixture();
ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".",
ThreadHost::Type::Platform | ThreadHost::Type::RASTER |
ThreadHost::Type::IO | ThreadHost::Type::UI);
ThreadHost thread_host(ThreadHost::ThreadHostConfig(
"io.flutter.test." + GetCurrentTestName() + ".",
ThreadHost::Type::Platform | ThreadHost::Type::RASTER |
ThreadHost::Type::IO | ThreadHost::Type::UI));
TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
thread_host.raster_thread->GetTaskRunner(),
thread_host.ui_thread->GetTaskRunner(),
Expand Down Expand Up @@ -3116,8 +3117,9 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeAppends) {
TEST_F(ShellTest, UpdateAssetResolverByTypeNull) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
Settings settings = CreateSettingsForFixture();
ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".",
ThreadHost::Type::Platform);
ThreadHost thread_host(ThreadHost::ThreadHostConfig(
"io.flutter.test." + GetCurrentTestName() + ".",
ThreadHost::Type::Platform));
auto task_runner = thread_host.platform_thread->GetTaskRunner();
TaskRunners task_runners("test", task_runner, task_runner, task_runner,
task_runner);
Expand Down Expand Up @@ -3153,8 +3155,9 @@ TEST_F(ShellTest, UpdateAssetResolverByTypeNull) {
TEST_F(ShellTest, UpdateAssetResolverByTypeDoesNotReplaceMismatchType) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
Settings settings = CreateSettingsForFixture();
ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".",
ThreadHost::Type::Platform);
ThreadHost thread_host(ThreadHost::ThreadHostConfig(
"io.flutter.test." + GetCurrentTestName() + ".",
ThreadHost::Type::Platform));
auto task_runner = thread_host.platform_thread->GetTaskRunner();
TaskRunners task_runners("test", task_runner, task_runner, task_runner,
task_runner);
Expand Down
Loading

0 comments on commit 5140a44

Please sign in to comment.