[x265] [PATCH 4/6] feat(tme): add CPU frequency adaptive threadpool split
Shashank Pathipati
shashank.pathipati at multicorewareinc.com
Fri Apr 10 09:21:42 UTC 2026
>From 35ed380ad8e4ddd901bb75eb25e2c51f12eedeaf Mon Sep 17 00:00:00 2001
From: Shashank Pathipati <shashank.pathipati at multicorewareinc.com>
Date: Fri, 10 Apr 2026 14:33:41 +0530
Subject: [PATCH 4/6] feat(tme): add CPU frequency adaptive threadpool split
---
source/common/threadpool.cpp | 85 ++++++++++++++++++++++++++++++++++--
source/common/threadpool.h | 14 ++++++
2 files changed, 96 insertions(+), 3 deletions(-)
diff --git a/source/common/threadpool.cpp b/source/common/threadpool.cpp
index 79075425a..b3e29bea4 100644
--- a/source/common/threadpool.cpp
+++ b/source/common/threadpool.cpp
@@ -33,6 +33,15 @@
#include <winnt.h>
#endif
+#if defined(__APPLE__)
+#include <sys/sysctl.h>
+#elif !defined(_WIN32)
+#include <fstream>
+#include <string>
+#include <cstdio>
+#include <cstdlib>
+#endif
+
#if X86_64
#ifdef __GNUC__
@@ -351,7 +360,6 @@ static void distributeThreadsForTme(
}
// Apply calculated threadpool assignment
- // TODO: Make sure this doesn't cause a problem later on
memset(threadsPerPool, 0, sizeof(int) * (numNumaNodes + 2));
memset(nodeMaskPerPool, 0, sizeof(uint64_t) * (numNumaNodes + 2));
@@ -905,16 +913,87 @@ int ThreadPool::configureTmeThreadCount(x265_param* param, int cpuCount)
}
}
+ bool isHighFreq = (getCPUFrequencyMHz() > 1500.0);
+
if (selectedRule >= 0)
{
const TmeRuleConfig& cfg = s_tmeRuleConfig[selectedRule];
param->tmeTaskBlockSize = cfg.widthBasedTaskBlockSize ? ((param->sourceWidth + 480 - 1) / 480) : cfg.taskBlockSize[resClass];
param->tmeNumBufferRows = cfg.numBufferRows[resClass];
- return (cpuCount * cfg.threadPercent[resClass]) / 100;
+ return (!isHighFreq) ? (cpuCount * cfg.threadPercent[resClass]) / 100 : cpuCount / 2;
}
static const int s_defaultThreadPercent[TME_RES_COUNT] = { 80, 80, 70 };
- return (cpuCount * s_defaultThreadPercent[resClass]) / 100;
+ return (!isHighFreq) ? (cpuCount * s_defaultThreadPercent[resClass]) / 100 : cpuCount / 2;
+}
+
+double getCPUFrequencyMHz()
+{
+#if defined(_WIN32)
+ HKEY hKey;
+ DWORD mhz = 0;
+ DWORD size = sizeof(mhz);
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
+ "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0",
+ 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ RegQueryValueExA(hKey, "~MHz", NULL, NULL, (LPBYTE)&mhz, &size);
+ RegCloseKey(hKey);
+ }
+ return (double)mhz;
+
+#elif defined(__APPLE__)
+ uint64_t freq = 0;
+ size_t size = sizeof(freq);
+ if (sysctlbyname("hw.cpufrequency", &freq, &size, NULL, 0) == 0)
+ return (double)freq / 1.0e6;
+ return 0.0;
+
+#else /* Linux */
+ /* scaling_cur_freq reflects the live frequency chosen by the governor
+ * and EPP hint. Iterate over all cpuN entries and return the highest observed value.
+ */
+ {
+ uint64_t maxKhz = 0;
+ char path[64];
+ for (int cpu = 0; ; ++cpu)
+ {
+ snprintf(path, sizeof(path),
+ "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", cpu);
+ std::ifstream f(path);
+ if (!f.is_open())
+ break;
+ uint64_t khz = 0;
+ f >> khz;
+ if (khz > maxKhz)
+ maxKhz = khz;
+ }
+ if (maxKhz > 0)
+ return (double)maxKhz / 1000.0;
+ }
+ /* Fall back to /proc/cpuinfo — collect the max "cpu MHz" across all entries. */
+ {
+ std::ifstream f("/proc/cpuinfo");
+ std::string line;
+ double maxMhz = 0.0;
+ while (std::getline(f, line))
+ {
+ if (line.find("cpu MHz") != std::string::npos)
+ {
+ size_t colon = line.find(':');
+ if (colon != std::string::npos)
+ {
+ double mhz = strtod(line.c_str() + colon + 1, NULL);
+ if (mhz > maxMhz)
+ maxMhz = mhz;
+ }
+ }
+ }
+ if (maxMhz > 0.0)
+ return maxMhz;
+ }
+ return 0.0;
+#endif
}
} // end namespace X265_NS
diff --git a/source/common/threadpool.h b/source/common/threadpool.h
index f223fd010..04e35528e 100644
--- a/source/common/threadpool.h
+++ b/source/common/threadpool.h
@@ -171,6 +171,20 @@ public:
virtual void processTasks(int workerThreadId) = 0;
};
+/**
+ * @brief Return the highest current CPU frequency in MHz across all cores, or 0.0 if unavailable.
+ *
+ * The value reflects the live frequency as reported by the cpufreq subsystem,
+ * which accounts for the active scaling governor and EPP hint.
+ *
+ * Platform support:
+ * Linux – iterates /sys/devices/system/cpu/cpuN/cpufreq/scaling_cur_freq (kHz)
+ * for all cores and returns the maximum; falls back to /proc/cpuinfo
+ * macOS – sysctl hw.cpufrequency (Hz)
+ * Windows – registry ~MHz under CentralProcessor\0
+ */
+double getCPUFrequencyMHz();
+
} // end namespace X265_NS
#endif // ifndef X265_THREADPOOL_H
--
2.52.0.windows.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20260410/6123de31/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0004-feat-tme-add-CPU-frequency-adaptive-threadpool-split.patch
Type: application/octet-stream
Size: 5136 bytes
Desc: 0004-feat-tme-add-CPU-frequency-adaptive-threadpool-split.patch
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20260410/6123de31/attachment-0001.obj>
More information about the x265-devel
mailing list