summaryrefslogtreecommitdiff
path: root/indra/llcommon/llprocessor.cpp
diff options
context:
space:
mode:
authorJonathan "Geenz" Goodman <geenz@lindenlab.com>2026-10-13 14:30:21 -0400
committerGitHub <noreply@github.com>2026-10-13 14:30:21 -0400
commit8ba5d1a8adc47c21b23d9482e72de9517f9a98fc (patch)
treef97d67c8ee574c6ebaac8d0d8ba120d041dca051 /indra/llcommon/llprocessor.cpp
parent18648fc51e2a0c750182d8aa3814ed5b6bf8445e (diff)
parentefc7d2d7bb542ac905cb7ebd82ee329523f95608 (diff)
Merge pull request #6193 from secondlife/release/26.4
Release/26.4
Diffstat (limited to 'indra/llcommon/llprocessor.cpp')
-rw-r--r--indra/llcommon/llprocessor.cpp158
1 files changed, 139 insertions, 19 deletions
diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp
index 0778b123ea..456f2b02d4 100644
--- a/indra/llcommon/llprocessor.cpp
+++ b/indra/llcommon/llprocessor.cpp
@@ -123,6 +123,9 @@ namespace
eSSE4_1_Features = 38,
eSSE4_2_Features = 39,
eSSE4a_Features = 40,
+ eAVX_Features = 41,
+ eAVX2_Features = 42,
+ eAVX512F_Features = 43,
};
const char* cpu_feature_names[] =
@@ -170,6 +173,9 @@ namespace
"SSE4.1 Instructions",
"SSE4.2 Instructions",
"SSE4a Instructions",
+ "AVX Instructions", // 41
+ "AVX2 Instructions", // 42
+ "AVX-512F Instructions", // 43
};
std::string intel_CPUFamilyName(int composed_family)
@@ -283,6 +289,21 @@ public:
return hasExtension(cpu_feature_names[eSSE4a_Features]);
}
+ bool hasAVX() const
+ {
+ return hasExtension(cpu_feature_names[eAVX_Features]);
+ }
+
+ bool hasAVX2() const
+ {
+ return hasExtension(cpu_feature_names[eAVX2_Features]);
+ }
+
+ bool hasAVX512F() const
+ {
+ return hasExtension(cpu_feature_names[eAVX512F_Features]);
+ }
+
bool hasAltivec() const
{
return hasExtension("Altivec");
@@ -572,6 +593,12 @@ private:
setExtension(cpu_feature_names[eSSE4_2_Features]);
}
+ // AVX: CPUID leaf 1, ECX bit 28, OSXSAVE + XCR0[1:2] enabled
+ if ((cpu_info[2] & 0x18000000) == 0x18000000 && ((_xgetbv(0) & 0x6) == 0x6))
+ {
+ setExtension(cpu_feature_names[eAVX_Features]);
+ }
+
unsigned int feature_info = (unsigned int) cpu_info[3];
for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1)
{
@@ -581,6 +608,27 @@ private:
}
}
}
+ else if (i == 7)
+ {
+ // AVX2/AVX-512* require AVX to be usable (OSXSAVE + XCR0 state)
+ if (hasExtension(cpu_feature_names[eAVX_Features]))
+ {
+ int cpu_info7[4] = { -1 };
+ __cpuidex(cpu_info7, 7, 0);
+ // AVX2: EBX bit 5
+ if (cpu_info7[1] & 0x20)
+ {
+ setExtension(cpu_feature_names[eAVX2_Features]);
+ }
+
+ // AVX-512F: EBX bit 16; ZMM state in XCR0 (bits 5-7)
+ const unsigned long long xcr0 = _xgetbv(0);
+ if ((cpu_info7[1] & 0x10000) && ((xcr0 & 0xE6) == 0xE6))
+ {
+ setExtension(cpu_feature_names[eAVX512F_Features]);
+ }
+ }
+ }
}
// Calling __cpuid with 0x80000000 as the InfoType argument
@@ -779,10 +827,47 @@ private:
// Not supposed to happen?
setExtension(cpu_feature_names[eSSE4a_Features]);
}
+ if (cpu_features_str.find(" AVX1.0 ") != std::string::npos)
+ {
+ setExtension(cpu_feature_names[eAVX_Features]);
+ }
+
+ // AVX2 and AVX-512F are reported in machdep.cpu.leaf7_features on macOS
+ char cpu_leaf7_features[1024];
+ len = sizeof(cpu_leaf7_features);
+ memset(cpu_leaf7_features, 0, len);
+ sysctlbyname("machdep.cpu.leaf7_features", (void*)cpu_leaf7_features, &len, NULL, 0);
+
+ std::string cpu_leaf7_str(cpu_leaf7_features);
+ cpu_leaf7_str = " " + cpu_leaf7_str + " ";
+
+ if (cpu_leaf7_str.find(" AVX2 ") != std::string::npos)
+ {
+ setExtension(cpu_feature_names[eAVX2_Features]);
+ }
+
+ if (cpu_leaf7_str.find(" AVX512F ") != std::string::npos)
+ {
+ setExtension(cpu_feature_names[eAVX512F_Features]);
+ }
}
};
#elif LL_LINUX
+
+// *NOTE:Mani - eww, macros! srry.
+#define LLPI_SET_INFO_STRING(llpi_id, cpuinfo_id) \
+ if (!cpuinfo[cpuinfo_id].empty()) \
+ { setInfo(llpi_id, cpuinfo[cpuinfo_id]);}
+
+#define LLPI_SET_INFO_INT(llpi_id, cpuinfo_id) \
+ {\
+ S32 result; \
+ if (!cpuinfo[cpuinfo_id].empty() \
+ && LLStringUtil::convertToS32(cpuinfo[cpuinfo_id], result)) \
+ { setInfo(llpi_id, result);} \
+ }
+
const char CPUINFO_FILE[] = "/proc/cpuinfo";
class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl
@@ -794,12 +879,36 @@ public:
}
virtual ~LLProcessorInfoLinuxImpl() {}
+
private:
+ F64 getCPUMaxMHZ()
+ {
+ // Nicky: We just look into cpu0. In theory we could iterate over all cores
+ // "/sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_max_freq"
+ // But those should not fluctuate that much?
+ llifstream fIn{ "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq" };
+
+ if( !fIn.is_open() )
+ return 0.0;
+
+ std::string strLine;
+ fIn >> strLine;
+ if( strLine.empty() )
+ return 0.0l;
+
+ F64 mhz {};
+ if( !LLStringUtil::convertToF64(strLine, mhz ) )
+ return 0.0;
+
+ mhz = mhz / 1000.0;
+ return mhz;
+ }
+
void get_proc_cpuinfo()
{
std::map< std::string, std::string > cpuinfo;
- LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb");
+ LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, LLFILE_MODE("rb"));
if(cpuinfo_fp)
{
char line[MAX_STRING];
@@ -830,24 +939,17 @@ private:
}
# if LL_X86
-// *NOTE:Mani - eww, macros! srry.
-#define LLPI_SET_INFO_STRING(llpi_id, cpuinfo_id) \
- if (!cpuinfo[cpuinfo_id].empty()) \
- { setInfo(llpi_id, cpuinfo[cpuinfo_id]);}
-
-#define LLPI_SET_INFO_INT(llpi_id, cpuinfo_id) \
- {\
- S32 result; \
- if (!cpuinfo[cpuinfo_id].empty() \
- && LLStringUtil::convertToS32(cpuinfo[cpuinfo_id], result)) \
- { setInfo(llpi_id, result);} \
+ F64 mhzFromSys = getCPUMaxMHZ();
+ F64 mhzFromProc {};
+ if( !LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhzFromProc ) )
+ mhzFromProc = 0.0;
+ if (mhzFromSys > 1.0 && mhzFromSys > mhzFromProc )
+ {
+ setInfo( eFrequency, mhzFromSys );
}
-
- F64 mhz;
- if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz)
- && 200.0 < mhz && mhz < 10000.0)
+ else if ( 200.0 < mhzFromProc && mhzFromProc < 10000.0)
{
- setInfo(eFrequency,(F64)(mhz));
+ setInfo(eFrequency,(F64)(mhzFromProc));
}
LLPI_SET_INFO_STRING(eBrandName, "model name");
@@ -857,7 +959,7 @@ private:
LLPI_SET_INFO_INT(eModel, "model");
- S32 family;
+ S32 family{};
if (!cpuinfo["cpu family"].empty()
&& LLStringUtil::convertToS32(cpuinfo["cpu family"], family))
{
@@ -915,6 +1017,21 @@ private:
setExtension(cpu_feature_names[eSSE4a_Features]);
}
+ if (flags.find(" avx ") != std::string::npos)
+ {
+ setExtension(cpu_feature_names[eAVX_Features]);
+ }
+
+ if (flags.find(" avx2 ") != std::string::npos)
+ {
+ setExtension(cpu_feature_names[eAVX2_Features]);
+ }
+
+ if (flags.find(" avx512f ") != std::string::npos)
+ {
+ setExtension(cpu_feature_names[eAVX512F_Features]);
+ }
+
# endif // LL_X86
}
@@ -923,7 +1040,7 @@ private:
std::ostringstream s;
// *NOTE:Mani - This is for linux only.
- LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb");
+ LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, LLFILE_MODE("rb"));
if(cpuinfo)
{
char line[MAX_STRING];
@@ -979,6 +1096,9 @@ bool LLProcessorInfo::hasSSE3S() const { return mImpl->hasSSE3S(); }
bool LLProcessorInfo::hasSSE41() const { return mImpl->hasSSE41(); }
bool LLProcessorInfo::hasSSE42() const { return mImpl->hasSSE42(); }
bool LLProcessorInfo::hasSSE4a() const { return mImpl->hasSSE4a(); }
+bool LLProcessorInfo::hasAVX() const { return mImpl->hasAVX(); }
+bool LLProcessorInfo::hasAVX2() const { return mImpl->hasAVX2(); }
+bool LLProcessorInfo::hasAVX512F() const { return mImpl->hasAVX512F(); }
bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); }
std::string LLProcessorInfo::getCPUFamilyName() const { return mImpl->getCPUFamilyName(); }
std::string LLProcessorInfo::getCPUBrandName() const { return mImpl->getCPUBrandName(); }