Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 243c106

Browse files
committed
Define thread priority enum and set thread priority for all threads in Engine
1 parent 436a346 commit 243c106

File tree

7 files changed

+321
-44
lines changed

7 files changed

+321
-44
lines changed

fml/thread.cc

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <memory>
1010
#include <string>
11+
#include <utility>
1112

1213
#include "flutter/fml/build_config.h"
1314
#include "flutter/fml/message_loop.h"
@@ -23,11 +24,26 @@
2324

2425
namespace fml {
2526

26-
Thread::Thread(const std::string& name) : joined_(false) {
27+
Thread::ThreadConfig::ThreadConfig(const std::string& name,
28+
ThreadPriority priority)
29+
: thread_name_(name), thread_priority_(priority) {}
30+
31+
void Thread::ThreadConfig::SetCurrentThreadName() {
32+
Thread::SetCurrentThreadName(thread_name_);
33+
}
34+
35+
void Thread::ThreadConfig::SetCurrentThreadPriority() {}
36+
37+
Thread::Thread(const std::string& name)
38+
: Thread(ThreadConfig::DefaultConfigure(name)) {}
39+
40+
Thread::Thread(std::unique_ptr<Thread::ThreadConfig> configurer)
41+
: thread_config_(std::move(configurer)), joined_(false) {
2742
fml::AutoResetWaitableEvent latch;
2843
fml::RefPtr<fml::TaskRunner> runner;
29-
thread_ = std::make_unique<std::thread>([&latch, &runner, name]() -> void {
30-
SetCurrentThreadName(name);
44+
thread_ = std::make_unique<std::thread>([&]() -> void {
45+
thread_config_->SetCurrentThreadName();
46+
thread_config_->SetCurrentThreadPriority();
3147
fml::MessageLoop::EnsureInitializedForCurrentThread();
3248
auto& loop = MessageLoop::GetCurrent();
3349
runner = loop.GetTaskRunner();

fml/thread.h

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <atomic>
99
#include <memory>
10+
#include <string>
1011
#include <thread>
1112

1213
#include "flutter/fml/macros.h"
@@ -16,18 +17,65 @@ namespace fml {
1617

1718
class Thread {
1819
public:
19-
explicit Thread(const std::string& name = "");
20+
// Valid values for priority of Thread
21+
enum class ThreadPriority : int {
22+
// Suitable for threads that shouldn't disrupt high priority work.
23+
BACKGROUND,
24+
// Default priority level.
25+
NORMAL,
26+
// Suitable for threads which generate data for the display.
27+
DISPLAY,
28+
// Suitable for thread which raster data
29+
RASTER,
30+
};
31+
32+
/// The ThreadConfig is used for setting thread perorities
33+
class ThreadConfig {
34+
public:
35+
explicit ThreadConfig(const std::string& name = "",
36+
ThreadPriority priority = ThreadPriority::NORMAL);
37+
38+
static std::unique_ptr<ThreadConfig> DefaultConfigure(
39+
const std::string& name = "") {
40+
return std::make_unique<ThreadConfig>(name);
41+
}
42+
43+
ThreadPriority thread_priority() const { return thread_priority_; }
44+
45+
const std::string& thread_name() const { return thread_name_; }
46+
47+
/// Set current thread name
48+
virtual void SetCurrentThreadName();
49+
50+
/// default do nothing, which mean user can use platform api to set priority
51+
/// example: iOS might use pthread_qos set thread priority, Android might
52+
/// use ::setPriority set thread priority
53+
virtual void SetCurrentThreadPriority();
54+
55+
virtual ~ThreadConfig() = default;
56+
57+
private:
58+
const std::string thread_name_;
59+
ThreadPriority thread_priority_;
60+
};
61+
62+
explicit Thread(const std::string& name);
63+
64+
explicit Thread(std::unique_ptr<ThreadConfig> configurer =
65+
ThreadConfig::DefaultConfigure());
2066

2167
~Thread();
2268

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

25-
void Join();
26-
2771
static void SetCurrentThreadName(const std::string& name);
2872

73+
void Join();
74+
2975
private:
3076
std::unique_ptr<std::thread> thread_;
77+
/// ThreadConfigure is used for setting thread configure some like `priority`
78+
std::unique_ptr<ThreadConfig> thread_config_;
3179
fml::RefPtr<fml::TaskRunner> task_runner_;
3280
std::atomic_bool joined_;
3381

fml/thread_unittests.cc

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include "flutter/fml/thread.h"
66

7+
#include <pthread.h>
8+
#include <memory>
79
#include "gtest/gtest.h"
810

911
TEST(Thread, CanStartAndEnd) {
@@ -24,3 +26,77 @@ TEST(Thread, HasARunningMessageLoop) {
2426
thread.Join();
2527
ASSERT_TRUE(done);
2628
}
29+
30+
TEST(Thread, ThreadNameCreatedWithConfig) {
31+
const std::string name = "Thread1";
32+
fml::Thread thread(fml::Thread::ThreadConfig::DefaultConfigure(name));
33+
34+
bool done = false;
35+
constexpr int NAMELEN = 8;
36+
thread.GetTaskRunner()->PostTask([&done, &name]() {
37+
done = true;
38+
char thread_name[NAMELEN];
39+
pthread_t current_thread = pthread_self();
40+
pthread_getname_np(current_thread, thread_name, NAMELEN);
41+
ASSERT_EQ(thread_name, name);
42+
});
43+
thread.Join();
44+
ASSERT_TRUE(done);
45+
}
46+
47+
class MockThreadConfig : public fml::Thread::ThreadConfig {
48+
public:
49+
using fml::Thread::ThreadConfig::ThreadConfig;
50+
51+
/// Using iOS platform thread API to configure thread priority
52+
void SetCurrentThreadPriority() override {
53+
pthread_t tid = pthread_self();
54+
struct sched_param param;
55+
int policy = SCHED_OTHER;
56+
switch (thread_priority()) {
57+
case fml::Thread::ThreadPriority::DISPLAY:
58+
param.sched_priority = 10;
59+
break;
60+
default:
61+
param.sched_priority = 1;
62+
}
63+
pthread_setschedparam(tid, policy, &param);
64+
}
65+
};
66+
67+
TEST(Thread, ThreadPriorityCreatedWithConfig) {
68+
const std::string thread1_name = "Thread1";
69+
const std::string thread2_name = "Thread2";
70+
fml::Thread thread(std::make_unique<MockThreadConfig>(
71+
thread1_name, fml::Thread::ThreadPriority::NORMAL));
72+
73+
bool done = false;
74+
constexpr int NAMELEN = 8;
75+
struct sched_param param;
76+
int policy;
77+
thread.GetTaskRunner()->PostTask([&]() {
78+
done = true;
79+
char thread_name[NAMELEN];
80+
pthread_t current_thread = pthread_self();
81+
pthread_getname_np(current_thread, thread_name, NAMELEN);
82+
pthread_getschedparam(current_thread, &policy, &param);
83+
ASSERT_EQ(thread_name, thread1_name);
84+
ASSERT_EQ(policy, SCHED_OTHER);
85+
ASSERT_EQ(param.sched_priority, 1);
86+
});
87+
88+
fml::Thread thread2(std::make_unique<MockThreadConfig>(
89+
thread2_name, fml::Thread::ThreadPriority::DISPLAY));
90+
thread2.GetTaskRunner()->PostTask([&]() {
91+
done = true;
92+
char thread_name[NAMELEN];
93+
pthread_t current_thread = pthread_self();
94+
pthread_getname_np(current_thread, thread_name, NAMELEN);
95+
pthread_getschedparam(current_thread, &policy, &param);
96+
ASSERT_EQ(thread_name, thread2_name);
97+
ASSERT_EQ(policy, SCHED_OTHER);
98+
ASSERT_EQ(param.sched_priority, 10);
99+
});
100+
thread.Join();
101+
ASSERT_TRUE(done);
102+
}

shell/common/thread_host.cc

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,73 @@
44

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

7+
#include <algorithm>
8+
#include <memory>
9+
#include <string>
10+
#include <utility>
11+
712
namespace flutter {
813

14+
std::string ThreadHost::ThreadName(Type type, const std::string& prefix) {
15+
switch (type) {
16+
case Type::Platform:
17+
return prefix + ".platform";
18+
case Type::UI:
19+
return prefix + ".ui";
20+
case Type::IO:
21+
return prefix + ".io";
22+
case Type::RASTER:
23+
return prefix + ".raster";
24+
case Type::Profiler:
25+
return prefix + ".profiler";
26+
}
27+
}
28+
29+
std::unique_ptr<fml::Thread> ThreadHost::CreateThread(
30+
Type type,
31+
ThreadHost::ThreadConfig configure) {
32+
std::string name = ThreadName(type, name_prefix);
33+
if (configure != nullptr) {
34+
return std::make_unique<fml::Thread>(std::move(configure));
35+
}
36+
return std::make_unique<fml::Thread>(
37+
fml::Thread::ThreadConfig::DefaultConfigure(name));
38+
}
39+
940
ThreadHost::ThreadHost() = default;
1041

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

13-
ThreadHost::ThreadHost(std::string name_prefix_arg, uint64_t mask)
44+
ThreadHost::ThreadHost(std::string name_prefix_arg,
45+
uint64_t mask,
46+
ThreadHostConfig configure_host)
1447
: name_prefix(name_prefix_arg) {
1548
if (mask & ThreadHost::Type::Platform) {
16-
platform_thread = std::make_unique<fml::Thread>(name_prefix + ".platform");
49+
platform_thread =
50+
CreateThread(ThreadHost::Type::Platform,
51+
std::move(configure_host.platform_configure));
1752
}
1853

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

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

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

3169
if (mask & ThreadHost::Type::Profiler) {
32-
profiler_thread = std::make_unique<fml::Thread>(name_prefix + ".profiler");
70+
profiler_thread =
71+
CreateThread(ThreadHost::Type::Profiler,
72+
std::move(configure_host.profiler_configure));
73+
;
3374
}
3475
}
3576

shell/common/thread_host.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#define FLUTTER_SHELL_COMMON_THREAD_HOST_H_
77

88
#include <memory>
9+
#include <string>
910

1011
#include "flutter/fml/macros.h"
1112
#include "flutter/fml/thread.h"
@@ -22,6 +23,19 @@ struct ThreadHost {
2223
Profiler = 1 << 4,
2324
};
2425

26+
static std::string ThreadName(Type type, const std::string& prefix = "");
27+
28+
using ThreadConfig = std::unique_ptr<fml::Thread::ThreadConfig>;
29+
/// The collection of all the thread configures, and we create custom thread
30+
/// configure in engine to info the thread.
31+
struct ThreadHostConfig {
32+
ThreadConfig platform_configure;
33+
ThreadConfig ui_configure;
34+
ThreadConfig raster_configure;
35+
ThreadConfig io_configure;
36+
ThreadConfig profiler_configure;
37+
};
38+
2539
std::string name_prefix;
2640
std::unique_ptr<fml::Thread> platform_thread;
2741
std::unique_ptr<fml::Thread> ui_thread;
@@ -35,9 +49,14 @@ struct ThreadHost {
3549

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

38-
ThreadHost(std::string name_prefix, uint64_t type_mask);
52+
ThreadHost(std::string name_prefix,
53+
uint64_t type_mask,
54+
ThreadHostConfig configure_host = ThreadHostConfig());
3955

4056
~ThreadHost();
57+
58+
private:
59+
std::unique_ptr<fml::Thread> CreateThread(Type type, ThreadConfig configure);
4160
};
4261

4362
} // namespace flutter

0 commit comments

Comments
 (0)