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
  • Loading branch information
JsouLiang committed Feb 9, 2022
1 parent f3ebba5 commit c32e510
Show file tree
Hide file tree
Showing 7 changed files with 333 additions and 45 deletions.
34 changes: 25 additions & 9 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,17 +24,32 @@

namespace fml {

Thread::Thread(const std::string& name) : joined_(false) {
Thread::ThreadConfig::ThreadConfig(const std::string& name,
ThreadPriority priority)
: thread_name_(name), thread_priority_(priority) {}

void Thread::ThreadConfig::SetCurrentThreadName() const {
Thread::SetCurrentThreadName(thread_name_);
}

void Thread::ThreadConfig::SetCurrentThreadPriority() const {}

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

Thread::Thread(std::unique_ptr<ThreadConfig> config) : 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();
});
thread_ = std::make_unique<std::thread>(
[&latch, &runner, threadConfig = std::move(config)]() -> void {
threadConfig->SetCurrentThreadName();
threadConfig->SetCurrentThreadPriority();
fml::MessageLoop::EnsureInitializedForCurrentThread();
auto& loop = MessageLoop::GetCurrent();
runner = loop.GetTaskRunner();
latch.Signal();
loop.Run();
});
latch.Wait();
task_runner_ = runner;
}
Expand Down
48 changes: 47 additions & 1 deletion fml/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

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

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

class Thread {
public:
explicit Thread(const std::string& name = "");
/// 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 used for setting thread perorities.
class ThreadConfig {
public:
explicit ThreadConfig(const std::string& name = "",
ThreadPriority priority = ThreadPriority::NORMAL);

static std::unique_ptr<ThreadConfig> MakeDefaultConfigure(
const std::string& name = "") {
return std::make_unique<ThreadConfig>(name);
}

ThreadPriority GetThreadPriority() const { return thread_priority_; }

const std::string& GetThreadName() const { return thread_name_; }

/// Set current thread name.
virtual void SetCurrentThreadName() const;

/// default do nothing, which mean user can use platform api to set priority
/// example: iOS might use pthread_qos set thread priority, Android might
/// use ::setPriority set thread priority
virtual void SetCurrentThreadPriority() const;

virtual ~ThreadConfig() = default;

private:
const std::string thread_name_;
ThreadPriority thread_priority_;
};

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

explicit Thread(std::unique_ptr<ThreadConfig> config =
ThreadConfig::MakeDefaultConfigure());

~Thread();

Expand Down
85 changes: 85 additions & 0 deletions fml/thread_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

#include "flutter/fml/thread.h"

#define FLUTTER_PTHREAD_SUPPORTED \
defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_ANDROID)

#ifdef FLUTTER_PTHREAD_SUPPORTED
#include <pthread.h>
#else
#error "Doesn't has pthead.h"
#endif

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

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

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

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

class MockThreadConfig : public fml::Thread::ThreadConfig {
public:
using fml::Thread::ThreadConfig::ThreadConfig;

void SetCurrentThreadPriority() const override {
pthread_t tid = pthread_self();
struct sched_param param;
int policy = SCHED_OTHER;
switch (GetThreadPriority()) {
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(std::make_unique<MockThreadConfig>(
thread1_name, fml::Thread::ThreadPriority::NORMAL));

bool done = false;
constexpr int NAMELEN = 8;
struct sched_param param;
int policy;
thread.GetTaskRunner()->PostTask([&]() {
done = true;
char thread_name[NAMELEN];
pthread_t current_thread = pthread_self();
pthread_getname_np(current_thread, thread_name, NAMELEN);
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(std::make_unique<MockThreadConfig>(
thread2_name, fml::Thread::ThreadPriority::DISPLAY));
thread2.GetTaskRunner()->PostTask([&]() {
done = true;
char thread_name[NAMELEN];
pthread_t current_thread = pthread_self();
pthread_getname_np(current_thread, thread_name, NAMELEN);
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
55 changes: 49 additions & 6 deletions shell/common/thread_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,75 @@

#include "flutter/shell/common/thread_host.h"

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

namespace flutter {

std::string ThreadHost::ThreadHostConfig::MakeThreadName(
Type type,
const std::string& prefix) {
switch (type) {
case Type::Platform:
return prefix + ".platform";
case Type::UI:
return prefix + ".ui";
case Type::IO:
return prefix + ".io";
case Type::RASTER:
return prefix + ".raster";
case Type::Profiler:
return prefix + ".profiler";
}
}

std::unique_ptr<fml::Thread> ThreadHost::CreateThread(
Type type,
ThreadHost::ThreadConfig configure) {
std::string name = ThreadHostConfig::MakeThreadName(type, name_prefix);
if (configure != nullptr) {
return std::make_unique<fml::Thread>(std::move(configure));
}
return std::make_unique<fml::Thread>(
fml::Thread::ThreadConfig::MakeDefaultConfigure(name));
}

ThreadHost::ThreadHost() = default;

ThreadHost::ThreadHost(ThreadHost&&) = default;

ThreadHost::ThreadHost(std::string name_prefix_arg, uint64_t mask)
ThreadHost::ThreadHost(std::string name_prefix_arg,
uint64_t mask,
ThreadHostConfig configure_host)
: name_prefix(name_prefix_arg) {
if (mask & ThreadHost::Type::Platform) {
platform_thread = std::make_unique<fml::Thread>(name_prefix + ".platform");
platform_thread =
CreateThread(ThreadHost::Type::Platform,
std::move(configure_host.platform_configure));
}

if (mask & ThreadHost::Type::UI) {
ui_thread = std::make_unique<fml::Thread>(name_prefix + ".ui");
ui_thread = CreateThread(ThreadHost::Type::UI,
std::move(configure_host.ui_configure));
}

if (mask & ThreadHost::Type::RASTER) {
raster_thread = std::make_unique<fml::Thread>(name_prefix + ".raster");
raster_thread = CreateThread(ThreadHost::Type::RASTER,
std::move(configure_host.raster_configure));
}

if (mask & ThreadHost::Type::IO) {
io_thread = std::make_unique<fml::Thread>(name_prefix + ".io");
io_thread = CreateThread(ThreadHost::Type::IO,
std::move(configure_host.io_configure));
}

if (mask & ThreadHost::Type::Profiler) {
profiler_thread = std::make_unique<fml::Thread>(name_prefix + ".profiler");
profiler_thread =
CreateThread(ThreadHost::Type::Profiler,
std::move(configure_host.profiler_configure));
;
}
}

Expand Down
22 changes: 21 additions & 1 deletion shell/common/thread_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define FLUTTER_SHELL_COMMON_THREAD_HOST_H_

#include <memory>
#include <string>

#include "flutter/fml/macros.h"
#include "flutter/fml/thread.h"
Expand All @@ -22,6 +23,20 @@ struct ThreadHost {
Profiler = 1 << 4,
};

using ThreadConfig = std::unique_ptr<fml::Thread::ThreadConfig>;
/// The collection of all the thread configures, and we create custom thread
/// configure in engine to info the thread.
struct ThreadHostConfig {
ThreadConfig platform_configure;
ThreadConfig ui_configure;
ThreadConfig raster_configure;
ThreadConfig io_configure;
ThreadConfig profiler_configure;

static std::string MakeThreadName(Type type,
const std::string& prefix = "");
};

std::string name_prefix;
std::unique_ptr<fml::Thread> platform_thread;
std::unique_ptr<fml::Thread> ui_thread;
Expand All @@ -35,9 +50,14 @@ struct ThreadHost {

ThreadHost& operator=(ThreadHost&&) = default;

ThreadHost(std::string name_prefix, uint64_t type_mask);
ThreadHost(std::string name_prefix,
uint64_t type_mask,
ThreadHostConfig configure_host = ThreadHostConfig());

~ThreadHost();

private:
std::unique_ptr<fml::Thread> CreateThread(Type type, ThreadConfig configure);
};

} // namespace flutter
Expand Down
Loading

0 comments on commit c32e510

Please sign in to comment.