Skip to content

Commit 9a18171

Browse files
committed
[Linux] Remove RT threads
https://bugs.webkit.org/show_bug.cgi?id=319535 Reviewed by Carlos Garcia Campos. (reland due to macOS regression; now there is no behaviour change on darwin) Patch 1 of 2, the second removes sched_yield. RT threads showed a 10% win on MotionMark clamped to two cores. This goes away if you turn off DVFS, so I believe the biggest mechanism behind this is the increased effective clock speed. We can recover that by setting the min clamp for DVFS directly. Most WPE workloads probably won't be using DVFS (that is, they will be set to performance), but this seems like the right call to me for desktop anyway. Finally, in this 2-core case, we use nice to lower the priority of the jit workers, and this gives us a small but noticable bump on SP3. We use RTKit still to raise the priority of the former RT threads, which gives a further small boost. Canonical link: https://commits.webkit.org/318709@main * Source/JavaScriptCore/jit/JITWorklistThread.cpp: (JSC::JITWorklistThread::JITWorklistThread): * Source/JavaScriptCore/wasm/WasmWorklist.cpp: * Source/WTF/wtf/AutomaticThread.cpp: (WTF::AutomaticThread::AutomaticThread): (WTF::AutomaticThread::start): * Source/WTF/wtf/AutomaticThread.h: * Source/WTF/wtf/PlatformGTK.cmake: * Source/WTF/wtf/PlatformJSCOnly.cmake: * Source/WTF/wtf/PlatformWPE.cmake: * Source/WTF/wtf/Threading.cpp: (WTF::Thread::entryPoint): (WTF::Thread::create): (WTF::Thread::setCurrentThreadIsUserInteractive): (WTF::Thread::setCurrentThreadIsUserInitiated): (WTF::Thread::setCurrentThreadQOS): (WTF::Thread::currentThreadQOS): (WTF::Thread::currentThreadIsRealtime): * Source/WTF/wtf/Threading.h: * Source/WTF/wtf/ThreadingEnums.h: (WTF::compilerThreadQOS): * Source/WTF/wtf/linux/HighPriorityThreads.cpp: Added. (WTF::HighPriorityThreads::singleton): (WTF::HighPriorityThreads::HighPriorityThreads): (WTF::HighPriorityThreads::registerThread): (WTF::HighPriorityThreads::setEnabled): (WTF::HighPriorityThreads::applyState): (WTF::realTimeKitGetProperty): (WTF::HighPriorityThreads::realTimeKitMakeThreadHighPriority): (WTF::HighPriorityThreads::scheduleDiscardRealTimeKitProxy): (WTF::HighPriorityThreads::discardRealTimeKitProxyTimerFired): * Source/WTF/wtf/linux/HighPriorityThreads.h: Renamed from Source/WTF/wtf/linux/RealTimeThreads.h. * Source/WTF/wtf/linux/RealTimeThreads.cpp: Removed. * Source/WTF/wtf/posix/ThreadingPOSIX.cpp: (WTF::schedulingAttributesForQOS): (WTF::logSchedulingAttributesFailure): (WTF::Thread::establishHandle): (WTF::Thread::updateSchedulingAttributes const): (WTF::Thread::initializeSchedulingAttributes): (WTF::Thread::initializeCurrentTLS): * Source/WTF/wtf/win/ThreadingWin.cpp: (WTF::Thread::updateSchedulingAttributes const): (WTF::Thread::initializeSchedulingAttributes): (WTF::Thread::initializeCurrentTLS): * Source/WebCore/platform/audio/RealtimeAudioThread.cpp: (WebCore::shouldCreateRealtimeThread): (WebCore::createMaybeRealtimeAudioThread): (): Deleted. * Source/WebKit/WebProcess/WebProcess.cpp: (WebKit::WebProcess::createWebPage): (WebKit::WebProcess::removeWebPage): (WebKit::WebProcess::pageActivityStateDidChange): * Source/WebKit/WebProcess/glib/WebProcessGLib.cpp: (WebKit::WebProcess::platformInitializeProcess): * Tools/TestWebKitAPI/Tests/WTF/Threading.cpp: (TestWebKitAPI::TEST(WTF_Thread, SchedulingAttributesFollowQOS)): (TestWebKitAPI::TEST(WTF_Thread, HighPriorityThreadsRestoresClampWhenReenabled)): Canonical link: https://commits.webkit.org/319617@main
1 parent 24279dc commit 9a18171

19 files changed

Lines changed: 581 additions & 441 deletions

Source/JavaScriptCore/jit/JITWorklistThread.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (C) 2021 Apple Inc. All rights reserved.
3+
* Copyright (C) 2026 Igalia S.L.
34
*
45
* Redistribution and use in source and binary forms, with or without
56
* modification, are permitted provided that the following conditions
@@ -78,7 +79,7 @@ JITWorklistThread::JITWorklistThread(const AbstractLocker& locker, JITWorklist&
7879
}
7980
#else
8081
JITWorklistThread::JITWorklistThread(const AbstractLocker& locker, JITWorklist& worklist)
81-
: AutomaticThread(locker, worklist.m_lock, worklist.m_planEnqueued.copyRef(), ThreadType::Compiler)
82+
: AutomaticThread(locker, worklist.m_lock, worklist.m_planEnqueued.copyRef(), ThreadType::Compiler, compilerThreadQOS())
8283
, m_worklist(worklist)
8384
{
8485
}

Source/JavaScriptCore/wasm/WasmWorklist.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (C) 2017-2023 Apple Inc. All rights reserved.
3+
* Copyright (C) 2026 Igalia S.L.
34
*
45
* Redistribution and use in source and binary forms, with or without
56
* modification, are permitted provided that the following conditions
@@ -62,7 +63,7 @@ class Worklist::Thread final : public AutomaticThread {
6263

6364
private:
6465
Thread(const AbstractLocker& locker, Worklist& work)
65-
: Base(locker, work.m_lock, work.m_planEnqueued.copyRef(), ThreadType::Compiler)
66+
: Base(locker, work.m_lock, work.m_planEnqueued.copyRef(), ThreadType::Compiler, compilerThreadQOS())
6667
, worklist(work)
6768
{
6869

Source/WTF/wtf/AutomaticThread.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,16 @@ AutomaticThread::AutomaticThread(const AbstractLocker& locker, Box<Lock> lock, R
110110
}
111111

112112
AutomaticThread::AutomaticThread(const AbstractLocker& locker, Box<Lock> lock, Ref<AutomaticThreadCondition>&& condition, ThreadType type, Seconds timeout)
113+
: AutomaticThread(locker, lock, WTF::move(condition), type, Thread::defaultQOS, timeout)
114+
{
115+
}
116+
117+
AutomaticThread::AutomaticThread(const AbstractLocker& locker, Box<Lock> lock, Ref<AutomaticThreadCondition>&& condition, ThreadType type, ThreadQOS qos, Seconds timeout)
113118
: m_lock(lock)
114119
, m_condition(WTF::move(condition))
115120
, m_timeout(timeout)
116121
, m_threadType(type)
122+
, m_qos(qos)
117123
{
118124
if (verbose)
119125
dataLog(RawPointer(this), ": Allocated AutomaticThread.\n");
@@ -245,7 +251,7 @@ void AutomaticThread::start(const AbstractLocker&)
245251
}
246252
RELEASE_ASSERT(result == WorkResult::Continue);
247253
}
248-
}, m_threadType, Thread::defaultQOS, Thread::defaultSchedulingPolicy, stackSpec)->detach();
254+
}, m_threadType, m_qos, Thread::defaultSchedulingPolicy, stackSpec)->detach();
249255
}
250256

251257
void AutomaticThread::threadDidStart()

Source/WTF/wtf/AutomaticThread.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,9 @@ class WTF_EXPORT_PRIVATE AutomaticThread : public ThreadSafeRefCounted<Automatic
140140
AutomaticThread(const AbstractLocker&, Box<Lock>, Ref<AutomaticThreadCondition>&&, Seconds timeout = 10_s);
141141

142142
AutomaticThread(const AbstractLocker&, Box<Lock>, Ref<AutomaticThreadCondition>&&, ThreadType, Seconds timeout = 10_s);
143-
143+
144+
AutomaticThread(const AbstractLocker&, Box<Lock>, Ref<AutomaticThreadCondition>&&, ThreadType, ThreadQOS, Seconds timeout = 10_s);
145+
144146
// To understand PollResult and WorkResult, imagine that poll() and work() are being called like
145147
// so:
146148
//
@@ -198,6 +200,7 @@ class WTF_EXPORT_PRIVATE AutomaticThread : public ThreadSafeRefCounted<Automatic
198200
const Ref<AutomaticThreadCondition> m_condition;
199201
Seconds m_timeout;
200202
ThreadType m_threadType { ThreadType::Unknown };
203+
ThreadQOS m_qos { defaultThreadQOS };
201204
bool m_isRunning { true };
202205
bool m_isWaiting { false };
203206
bool m_hasUnderlyingThread { false };

Source/WTF/wtf/PlatformGTK.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ list(APPEND WTF_PUBLIC_HEADERS
5454
glib/WTFGType.h
5555

5656
linux/CurrentProcessMemoryStatus.h
57+
linux/HighPriorityThreads.h
5758
linux/ProcessMemoryFootprint.h
58-
linux/RealTimeThreads.h
5959

6060
posix/SocketPOSIX.h
6161

@@ -65,8 +65,8 @@ list(APPEND WTF_PUBLIC_HEADERS
6565
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
6666
list(APPEND WTF_SOURCES
6767
linux/CurrentProcessMemoryStatus.cpp
68+
linux/HighPriorityThreads.cpp
6869
linux/MemoryFootprintLinux.cpp
69-
linux/RealTimeThreads.cpp
7070

7171
unix/MemoryPressureHandlerUnix.cpp
7272
)

Source/WTF/wtf/PlatformJSCOnly.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ elseif (APPLE)
107107
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux")
108108
list(APPEND WTF_SOURCES
109109
linux/CurrentProcessMemoryStatus.cpp
110+
linux/HighPriorityThreads.cpp
110111
linux/MemoryFootprintLinux.cpp
111-
linux/RealTimeThreads.cpp
112112

113113
unix/MemoryPressureHandlerUnix.cpp
114114
)

Source/WTF/wtf/PlatformWPE.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ list(APPEND WTF_SOURCES
2121
glib/URLGLib.cpp
2222

2323
linux/CurrentProcessMemoryStatus.cpp
24-
linux/RealTimeThreads.cpp
24+
linux/HighPriorityThreads.cpp
2525

2626
posix/CPUTimePOSIX.cpp
2727
posix/FileHandlePOSIX.cpp
@@ -75,8 +75,8 @@ list(APPEND WTF_PUBLIC_HEADERS
7575
glib/WTFGType.h
7676

7777
linux/CurrentProcessMemoryStatus.h
78+
linux/HighPriorityThreads.h
7879
linux/ProcessMemoryFootprint.h
79-
linux/RealTimeThreads.h
8080

8181
posix/SocketPOSIX.h
8282

Source/WTF/wtf/Threading.cpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (C) 2008-2024 Apple Inc. All rights reserved.
3+
* Copyright (C) 2026 Igalia S.L.
34
*
45
* Redistribution and use in source and binary forms, with or without
56
* modification, are permitted provided that the following conditions
@@ -39,10 +40,6 @@
3940
#include <wtf/text/AtomString.h>
4041
#include <wtf/threads/Signals.h>
4142

42-
#if OS(LINUX)
43-
#include <wtf/linux/RealTimeThreads.h>
44-
#endif
45-
4643
#if PLATFORM(COCOA)
4744
#include <wtf/cocoa/Entitlements.h>
4845
#include <wtf/darwin/LibraryPathDiagnostics.h>
@@ -249,6 +246,7 @@ void Thread::entryPoint(NewThreadContext* newThreadContext)
249246

250247
Ref thread = WTF::move(context->thread);
251248
thread->initializeInThread();
249+
thread->initializeSchedulingAttributes();
252250

253251
Thread::initializeTLS(WTF::move(thread));
254252

@@ -267,7 +265,7 @@ Ref<Thread> Thread::create(ASCIILiteral name, Function<void()>&& entryPoint, Thr
267265
{
268266
WTF::initialize();
269267

270-
Ref thread = adoptRef(*new Thread(schedulingPolicy, Thread::IsMain::No));
268+
Ref thread = adoptRef(*new Thread(qos, schedulingPolicy, Thread::IsMain::No));
271269

272270
Ref context = adoptRef(*new NewThreadContext { name, WTF::move(entryPoint), thread.get() });
273271
{
@@ -386,14 +384,9 @@ void Thread::setCurrentThreadIsUserInteractive(int relativePriority)
386384
ASSERT(relativePriority <= 0);
387385
ASSERT(relativePriority >= QOS_MIN_RELATIVE_PRIORITY);
388386
pthread_set_qos_class_self_np(adjustedQOSClass(QOS_CLASS_USER_INTERACTIVE), relativePriority);
389-
#elif OS(LINUX)
390-
// We don't allow to make the main thread real time. This is used by secondary processes to match the
391-
// UI process, but in linux the UI process is not real time.
392-
if (!isMainThread())
393-
RealTimeThreads::singleton().registerThread(currentSingleton());
394-
UNUSED_PARAM(relativePriority);
395387
#else
396388
UNUSED_PARAM(relativePriority);
389+
setCurrentThreadQOS(QOS::UserInteractive);
397390
#endif
398391
}
399392

@@ -405,9 +398,17 @@ void Thread::setCurrentThreadIsUserInitiated(int relativePriority)
405398
pthread_set_qos_class_self_np(adjustedQOSClass(QOS_CLASS_USER_INITIATED), relativePriority);
406399
#else
407400
UNUSED_PARAM(relativePriority);
401+
setCurrentThreadQOS(QOS::UserInitiated);
408402
#endif
409403
}
410404

405+
void Thread::setCurrentThreadQOS(QOS qos)
406+
{
407+
Thread& thread = currentSingleton();
408+
thread.m_qos = qos;
409+
thread.initializeSchedulingAttributes();
410+
}
411+
411412
#if HAVE(QOS_CLASSES)
412413
static Thread::QOS NODELETE toQOS(qos_class_t qosClass)
413414
{
@@ -436,13 +437,13 @@ auto Thread::currentThreadQOS() -> QOS
436437
pthread_get_qos_class_np(pthread_self(), &qos, &relativePriority);
437438
return toQOS(qos);
438439
#else
439-
return QOS::Default;
440+
return currentSingleton().qos();
440441
#endif
441442
}
442443

443444
bool Thread::currentThreadIsRealtime()
444445
{
445-
return Thread::currentSingleton().m_isRealtime;
446+
return Thread::currentSingleton().isRealtime();
446447
}
447448

448449
#if HAVE(QOS_CLASSES)

Source/WTF/wtf/Threading.h

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* Copyright (C) 2007-2020 Apple Inc. All rights reserved.
33
* Copyright (C) 2007 Justin Haygood <[email protected]>
44
* Copyright (C) 2017 Yusuke Suzuki <[email protected]>
5+
* Copyright (C) 2026 Igalia S.L.
56
*
67
* Redistribution and use in source and binary forms, with or without
78
* modification, are permitted provided that the following conditions
@@ -99,6 +100,9 @@ class WTF_CAPABILITY("is current") Thread : public ThreadSafeRefCountedAndCanMak
99100
public:
100101
friend class ThreadGroup;
101102
friend WTF_EXPORT_PRIVATE void initialize();
103+
#if OS(LINUX)
104+
friend class HighPriorityThreads;
105+
#endif
102106

103107
class ClientData : public ThreadSafeRefCounted<ClientData> {
104108
public:
@@ -120,11 +124,10 @@ class WTF_CAPABILITY("is current") Thread : public ThreadSafeRefCountedAndCanMak
120124

121125
using QOS = ThreadQOS;
122126
using SchedulingPolicy = ThreadSchedulingPolicy;
127+
using SchedulingState = ThreadSchedulingState;
123128

124-
// These are not necessarily the system defaults, but they are what WebKit
125-
// chooses to be the default for newly created WTF::Threads
126-
static constexpr QOS defaultQOS = QOS::UserInitiated;
127-
static constexpr SchedulingPolicy defaultSchedulingPolicy = SchedulingPolicy::Other;
129+
static constexpr QOS defaultQOS = defaultThreadQOS;
130+
static constexpr SchedulingPolicy defaultSchedulingPolicy = defaultThreadSchedulingPolicy;
128131

129132
#if HAVE(QOS_CLASSES)
130133
static dispatch_qos_class_t dispatchQOSClass(QOS);
@@ -209,7 +212,9 @@ class WTF_CAPABILITY("is current") Thread : public ThreadSafeRefCountedAndCanMak
209212
WTF_EXPORT_PRIVATE static void setCurrentThreadIsUserInitiated(int relativePriority = 0);
210213
WTF_EXPORT_PRIVATE static QOS currentThreadQOS();
211214
WTF_EXPORT_PRIVATE static bool currentThreadIsRealtime();
212-
bool isRealtime() const { return m_isRealtime; }
215+
bool isRealtime() const { return m_schedulingPolicy == SchedulingPolicy::Realtime; }
216+
217+
QOS qos() const { return m_qos; }
213218

214219
#if HAVE(QOS_CLASSES)
215220
WTF_EXPORT_PRIVATE static void setGlobalMaxQOSClass(qos_class_t);
@@ -225,7 +230,7 @@ class WTF_CAPABILITY("is current") Thread : public ThreadSafeRefCountedAndCanMak
225230
// Helpful for platforms where the thread name must be set from within the thread.
226231
static void initializeCurrentThreadInternal(const char* threadName);
227232
static void NODELETE initializeCurrentThreadEvenIfNonWTFCreated();
228-
233+
229234
WTF_EXPORT_PRIVATE static void yield();
230235

231236
WTF_EXPORT_PRIVATE static bool exchangeIsCompilationThread(bool newValue);
@@ -301,11 +306,19 @@ class WTF_CAPABILITY("is current") Thread : public ThreadSafeRefCountedAndCanMak
301306
static Thread* currentMayBeNull();
302307
#endif
303308

309+
private:
310+
void updateSchedulingAttributes(SchedulingState) const;
311+
// updateSchedulingAttributes for the first time + initialization bookkeeping
312+
void initializeSchedulingAttributes();
313+
314+
static void setCurrentThreadQOS(QOS);
315+
304316
protected:
305317
enum class IsMain : uint8_t { No, Yes, Unknown };
306318

307-
explicit Thread(SchedulingPolicy schedulingPolicy, IsMain isMain = IsMain::Unknown)
308-
: m_isRealtime(schedulingPolicy == SchedulingPolicy::Realtime)
319+
explicit Thread(QOS qos, SchedulingPolicy schedulingPolicy, IsMain isMain = IsMain::Unknown)
320+
: m_qos(qos)
321+
, m_schedulingPolicy(schedulingPolicy)
309322
, m_uid(isMain == IsMain::Yes ? 1 : ++s_uid)
310323
{
311324
}
@@ -382,7 +395,8 @@ class WTF_CAPABILITY("is current") Thread : public ThreadSafeRefCountedAndCanMak
382395
bool m_isJSThread : 1 { false };
383396
unsigned m_gcThreadType : 2 { static_cast<unsigned>(GCThreadType::None) };
384397

385-
bool m_isRealtime : 1 { false };
398+
QOS m_qos { defaultQOS };
399+
SchedulingPolicy m_schedulingPolicy { SchedulingPolicy::Other };
386400

387401
// Lock & ParkingLot rely on ThreadSpecific. But Thread object can be destroyed even after ThreadSpecific things are destroyed.
388402
// Use WordLock since WordLock does not depend on ThreadSpecific and this "Thread".

Source/WTF/wtf/ThreadingEnums.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (C) 2025 Apple Inc. All rights reserved.
3+
* Copyright (C) 2026 Igalia S.L.
34
*
45
* Redistribution and use in source and binary forms, with or without
56
* modification, are permitted provided that the following conditions
@@ -26,6 +27,7 @@
2627
#pragma once
2728

2829
#include <cstdint>
30+
#include <wtf/NumberOfCores.h>
2931

3032
namespace WTF {
3133

@@ -58,16 +60,33 @@ enum class ThreadQOS {
5860
Background
5961
};
6062

63+
enum class ThreadSchedulingState : bool { Demoted, Full };
64+
6165
enum class ThreadSchedulingPolicy : uint8_t {
6266
Other = 0,
6367
FIFO,
6468
Realtime,
6569
};
6670

71+
constexpr ThreadQOS defaultThreadQOS = ThreadQOS::UserInitiated;
72+
constexpr ThreadSchedulingPolicy defaultThreadSchedulingPolicy = ThreadSchedulingPolicy::Other;
73+
74+
inline ThreadQOS compilerThreadQOS()
75+
{
76+
#if OS(LINUX)
77+
if (numberOfProcessorCores() <= 4)
78+
return ThreadQOS::Utility;
79+
#endif
80+
return defaultThreadQOS;
81+
}
82+
6783
} // namespace WTF
6884

6985
using WTF::CanBeGCThread;
7086
using WTF::GCThreadType;
7187
using WTF::ThreadQOS;
7288
using WTF::ThreadSchedulingPolicy;
7389
using WTF::ThreadType;
90+
using WTF::compilerThreadQOS;
91+
using WTF::defaultThreadQOS;
92+
using WTF::defaultThreadSchedulingPolicy;

0 commit comments

Comments
 (0)