summaryrefslogtreecommitdiffstats
path: root/xbmc/platform/freebsd/CPUInfoFreebsd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/platform/freebsd/CPUInfoFreebsd.cpp')
-rw-r--r--xbmc/platform/freebsd/CPUInfoFreebsd.cpp268
1 files changed, 268 insertions, 0 deletions
diff --git a/xbmc/platform/freebsd/CPUInfoFreebsd.cpp b/xbmc/platform/freebsd/CPUInfoFreebsd.cpp
new file mode 100644
index 0000000..5128a72
--- /dev/null
+++ b/xbmc/platform/freebsd/CPUInfoFreebsd.cpp
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "CPUInfoFreebsd.h"
+
+#include "utils/Temperature.h"
+#include "utils/log.h"
+
+#include <array>
+#include <vector>
+
+// clang-format off
+/* sys/types.h must be included early, esp. before sysy/systl.h, otherwise:
+ /usr/include/sys/sysctl.h:1117:25: error: unknown type name 'u_int' */
+
+#include <sys/types.h>
+// clang-format on
+
+#if defined(__i386__) || defined(__x86_64__)
+#include <cpuid.h>
+#elif __has_include(<sys/auxv.h>)
+#include <sys/auxv.h>
+#endif
+
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+
+namespace
+{
+
+struct CpuData
+{
+public:
+ std::size_t GetActiveTime() const { return state[CP_USER] + state[CP_NICE] + state[CP_SYS]; }
+
+ std::size_t GetIdleTime() const { return state[CP_INTR] + state[CP_IDLE]; }
+
+ std::size_t GetTotalTime() const { return GetActiveTime() + GetIdleTime(); }
+
+ std::size_t state[CPUSTATES];
+};
+
+} // namespace
+
+std::shared_ptr<CCPUInfo> CCPUInfo::GetCPUInfo()
+{
+ return std::make_shared<CCPUInfoFreebsd>();
+}
+
+CCPUInfoFreebsd::CCPUInfoFreebsd()
+{
+ int count = 0;
+ size_t countLength = sizeof(count);
+ if (sysctlbyname("hw.ncpu", &count, &countLength, nullptr, 0) == 0)
+ m_cpuCount = count;
+ else
+ m_cpuCount = 1;
+
+ std::array<char, 512> cpuModel;
+ size_t length = cpuModel.size();
+ if (sysctlbyname("hw.model", cpuModel.data(), &length, nullptr, 0) == 0)
+ m_cpuModel = cpuModel.data();
+
+ for (int i = 0; i < m_cpuCount; i++)
+ {
+ CoreInfo core;
+ core.m_id = i;
+ m_cores.emplace_back(core);
+ }
+#if defined(__i386__) || defined(__x86_64__)
+ uint32_t eax, ebx, ecx, edx;
+
+ m_cpuVendor.clear();
+
+ if (__get_cpuid(CPUID_INFOTYPE_MANUFACTURER, &eax, &ebx, &ecx, &edx))
+ {
+ m_cpuVendor.append(reinterpret_cast<const char*>(&ebx), 4);
+ m_cpuVendor.append(reinterpret_cast<const char*>(&edx), 4);
+ m_cpuVendor.append(reinterpret_cast<const char*>(&ecx), 4);
+ }
+
+ if (__get_cpuid(CPUID_INFOTYPE_EXTENDED_IMPLEMENTED, &eax, &ebx, &ecx, &edx))
+ {
+ if (eax >= CPUID_INFOTYPE_PROCESSOR_3)
+ {
+ m_cpuModel.clear();
+
+ if (__get_cpuid(CPUID_INFOTYPE_PROCESSOR_1, &eax, &ebx, &ecx, &edx))
+ {
+ m_cpuModel.append(reinterpret_cast<const char*>(&eax), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&ebx), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&ecx), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&edx), 4);
+ }
+
+ if (__get_cpuid(CPUID_INFOTYPE_PROCESSOR_2, &eax, &ebx, &ecx, &edx))
+ {
+ m_cpuModel.append(reinterpret_cast<const char*>(&eax), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&ebx), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&ecx), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&edx), 4);
+ }
+
+ if (__get_cpuid(CPUID_INFOTYPE_PROCESSOR_3, &eax, &ebx, &ecx, &edx))
+ {
+ m_cpuModel.append(reinterpret_cast<const char*>(&eax), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&ebx), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&ecx), 4);
+ m_cpuModel.append(reinterpret_cast<const char*>(&edx), 4);
+ }
+ }
+ }
+
+ m_cpuModel = m_cpuModel.substr(0, m_cpuModel.find(char(0))); // remove extra null terminations
+
+ if (__get_cpuid(CPUID_INFOTYPE_STANDARD, &eax, &eax, &ecx, &edx))
+ {
+ if (edx & CPUID_00000001_EDX_MMX)
+ m_cpuFeatures |= CPU_FEATURE_MMX;
+
+ // Set MMX2 when SSE is present as SSE is a superset of MMX2 and Intel doesn't set the MMX2 cap
+ if (edx & CPUID_00000001_EDX_SSE)
+ m_cpuFeatures |= (CPU_FEATURE_SSE | CPU_FEATURE_MMX2);
+
+ if (edx & CPUID_00000001_EDX_SSE2)
+ m_cpuFeatures |= CPU_FEATURE_SSE2;
+
+ if (ecx & CPUID_00000001_ECX_SSE3)
+ m_cpuFeatures |= CPU_FEATURE_SSE3;
+
+ if (ecx & CPUID_00000001_ECX_SSSE3)
+ m_cpuFeatures |= CPU_FEATURE_SSSE3;
+
+ if (ecx & CPUID_00000001_ECX_SSE4)
+ m_cpuFeatures |= CPU_FEATURE_SSE4;
+
+ if (ecx & CPUID_00000001_ECX_SSE42)
+ m_cpuFeatures |= CPU_FEATURE_SSE42;
+ }
+
+ if (__get_cpuid(CPUID_INFOTYPE_EXTENDED_IMPLEMENTED, &eax, &eax, &ecx, &edx))
+ {
+ if (eax >= CPUID_INFOTYPE_EXTENDED)
+ {
+ if (edx & CPUID_80000001_EDX_MMX)
+ m_cpuFeatures |= CPU_FEATURE_MMX;
+
+ if (edx & CPUID_80000001_EDX_MMX2)
+ m_cpuFeatures |= CPU_FEATURE_MMX2;
+
+ if (edx & CPUID_80000001_EDX_3DNOW)
+ m_cpuFeatures |= CPU_FEATURE_3DNOW;
+
+ if (edx & CPUID_80000001_EDX_3DNOWEXT)
+ m_cpuFeatures |= CPU_FEATURE_3DNOWEXT;
+ }
+ }
+#endif
+
+#if defined(HAS_NEON)
+#if defined(__ARM_NEON)
+ m_cpuFeatures |= CPU_FEATURE_NEON;
+#elif __has_include(<sys/auxv.h>)
+ unsigned long hwcap = 0;
+ elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
+ if (hwcap & HWCAP_NEON)
+ m_cpuFeatures |= CPU_FEATURE_NEON;
+#endif
+#endif
+}
+
+int CCPUInfoFreebsd::GetUsedPercentage()
+{
+ if (!m_nextUsedReadTime.IsTimePast())
+ return m_lastUsedPercentage;
+
+ size_t len = sizeof(long);
+
+ if (sysctlbyname("kern.cp_times", nullptr, &len, nullptr, 0) != 0)
+ return false;
+
+ std::vector<long> cptimes(len);
+ size_t cptimesLength = cptimes.size();
+ if (sysctlbyname("kern.cp_times", cptimes.data(), &cptimesLength, nullptr, 0) != 0)
+ return false;
+
+ size_t activeTime{0};
+ size_t idleTime{0};
+ size_t totalTime{0};
+
+ std::vector<CpuData> cpuData;
+
+ for (int i = 0; i < m_cpuCount; i++)
+ {
+ CpuData info;
+
+ for (size_t state = 0; state < CPUSTATES; state++)
+ {
+ info.state[state] = cptimes[i * CPUSTATES + state];
+ }
+
+ activeTime += info.GetActiveTime();
+ idleTime += info.GetIdleTime();
+ totalTime += info.GetTotalTime();
+
+ cpuData.emplace_back(info);
+ }
+
+ activeTime -= m_activeTime;
+ idleTime -= m_idleTime;
+ totalTime -= m_totalTime;
+
+ m_activeTime += activeTime;
+ m_idleTime += idleTime;
+ m_totalTime += totalTime;
+
+ m_lastUsedPercentage = activeTime * 100.0f / totalTime;
+ m_nextUsedReadTime.Set(MINIMUM_TIME_BETWEEN_READS);
+
+ for (size_t core = 0; core < cpuData.size(); core++)
+ {
+ auto activeTime = cpuData[core].GetActiveTime() - m_cores[core].m_activeTime;
+ auto idleTime = cpuData[core].GetIdleTime() - m_cores[core].m_idleTime;
+ auto totalTime = cpuData[core].GetTotalTime() - m_cores[core].m_totalTime;
+
+ m_cores[core].m_usagePercent = activeTime * 100.0 / totalTime;
+
+ m_cores[core].m_activeTime += activeTime;
+ m_cores[core].m_idleTime += idleTime;
+ m_cores[core].m_totalTime += totalTime;
+ }
+
+ return static_cast<int>(m_lastUsedPercentage);
+}
+
+float CCPUInfoFreebsd::GetCPUFrequency()
+{
+ int hz = 0;
+ size_t len = sizeof(hz);
+ if (sysctlbyname("dev.cpu.0.freq", &hz, &len, nullptr, 0) != 0)
+ hz = 0;
+
+ return static_cast<float>(hz);
+}
+
+
+bool CCPUInfoFreebsd::GetTemperature(CTemperature& temperature)
+{
+ if (CheckUserTemperatureCommand(temperature))
+ return true;
+
+ int value;
+ size_t len = sizeof(value);
+
+ /* Temperature is in Kelvin * 10 */
+ if (sysctlbyname("dev.cpu.0.temperature", &value, &len, nullptr, 0) != 0)
+ return false;
+
+ temperature = CTemperature::CreateFromKelvin(static_cast<double>(value) / 10.0);
+ temperature.SetValid(true);
+
+ return true;
+}