[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