[beast: 17/20] SFI: add and use cpu_info() from Rapicorn
- From: Tim Janik <timj src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [beast: 17/20] SFI: add and use cpu_info() from Rapicorn
- Date: Sun, 24 Sep 2017 00:21:04 +0000 (UTC)
commit 2ea2fef6b25c0e24a37ce9da5231f55ce0ae6ed8
Author: Tim Janik <timj gnu org>
Date: Sun Sep 17 15:19:49 2017 +0200
SFI: add and use cpu_info() from Rapicorn
Import is based on Rapicorn commit id:
bf228016cba3f6d252ee2cc38e1ed32607f37bf0
Signed-off-by: Tim Janik <timj gnu org>
sfi/bcore.hh | 1 -
sfi/platform.cc | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
sfi/platform.hh | 1 +
3 files changed, 286 insertions(+), 1 deletions(-)
---
diff --git a/sfi/bcore.hh b/sfi/bcore.hh
index 697e3bc..05fd2db 100644
--- a/sfi/bcore.hh
+++ b/sfi/bcore.hh
@@ -31,7 +31,6 @@ using Rapicorn::url_show;
using Rapicorn::void_t;
using Rapicorn::Blob;
using Rapicorn::Res;
-using Rapicorn::cpu_info;
// == Diagnostics ==
template<class... Args> String string_format (const char *format, const Args &...args)
BSE_PRINTF (1, 0);
diff --git a/sfi/platform.cc b/sfi/platform.cc
index e65a9c0..423cfe9 100644
--- a/sfi/platform.cc
+++ b/sfi/platform.cc
@@ -3,6 +3,7 @@
#include "path.hh"
#include <unistd.h>
#include <cstring>
+#include <setjmp.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <execinfo.h> // _EXECINFO_H
@@ -16,6 +17,290 @@
namespace Bse {
+// == cpu_info ==
+// figure architecture name from compiler
+static const char*
+get_arch_name (void)
+{
+#if defined __alpha__
+ return "Alpha";
+#elif defined __frv__
+ return "frv";
+#elif defined __s390__
+ return "s390";
+#elif defined __m32c__
+ return "m32c";
+#elif defined sparc
+ return "Sparc";
+#elif defined __m32r__
+ return "m32r";
+#elif defined __x86_64__ || defined __amd64__
+ return "AMD64";
+#elif defined __ia64__
+ return "Intel Itanium";
+#elif defined __m68k__
+ return "mc68000";
+#elif defined __powerpc__ || defined PPC || defined powerpc || defined __PPC__
+ return "PPC";
+#elif defined __arc__
+ return "arc";
+#elif defined __arm__
+ return "Arm";
+#elif defined __mips__ || defined mips
+ return "Mips";
+#elif defined __tune_i686__ || defined __i686__
+ return "i686";
+#elif defined __tune_i586__ || defined __i586__
+ return "i586";
+#elif defined __tune_i486__ || defined __i486__
+ return "i486";
+#elif defined i386 || defined __i386__
+ return "i386";
+#else
+ return "unknown-arch";
+#warning platform.cc needs updating for this processor type
+#endif
+}
+
+/// Acquire information about the runtime architecture and CPU type.
+struct CPUInfo {
+ // architecture name
+ const char *machine;
+ // CPU Vendor ID
+ char cpu_vendor[13];
+ // CPU features on X86
+ uint x86_fpu : 1, x86_ssesys : 1, x86_tsc : 1, x86_htt : 1;
+ uint x86_mmx : 1, x86_mmxext : 1, x86_3dnow : 1, x86_3dnowext : 1;
+ uint x86_sse : 1, x86_sse2 : 1, x86_sse3 : 1, x86_ssse3 : 1;
+ uint x86_cx16 : 1, x86_sse4_1 : 1, x86_sse4_2 : 1, x86_rdrand : 1;
+};
+
+static jmp_buf cpu_info_jmp_buf;
+
+static void RAPICORN_NORETURN
+cpu_info_sigill_handler (int dummy)
+{
+ longjmp (cpu_info_jmp_buf, 1);
+}
+
+#if defined __i386__
+# define x86_has_cpuid() ({ \
+ unsigned int __eax, __ecx; \
+ __asm__ __volatile__ \
+ ( \
+ /* copy EFLAGS into eax and ecx */ \
+ "pushf ; pop %0 ; mov %0, %1 \n\t" \
+ /* toggle the ID bit and store back to EFLAGS */ \
+ "xor $0x200000, %0 ; push %0 ; popf \n\t" \
+ /* read back EFLAGS with possibly modified ID bit */ \
+ "pushf ; pop %0 \n\t" \
+ : "=a" (__eax), "=c" (__ecx) \
+ : /* no inputs */ \
+ : "cc" \
+ ); \
+ bool __result = (__eax ^ __ecx) & 0x00200000; \
+ __result; \
+})
+/* save EBX around CPUID, because gcc doesn't like it to be clobbered with -fPIC */
+# define x86_cpuid(input, eax, ebx, ecx, edx) \
+ __asm__ __volatile__ ( \
+ /* save ebx in esi */ \
+ "mov %%ebx, %%esi \n\t" \
+ /* get CPUID with eax=input */ \
+ "cpuid \n\t" \
+ /* swap ebx and esi */ \
+ "xchg %%ebx, %%esi" \
+ : "=a" (eax), "=S" (ebx), \
+ "=c" (ecx), "=d" (edx) \
+ : "0" (input) \
+ : "cc")
+#elif defined __x86_64__ || defined __amd64__
+/* CPUID is always present on AMD64, see:
+ * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/24594.pdf
+ * "AMD64 Architecture Programmer's Manual Volume 3",
+ * "Appendix D: Instruction Subsets and CPUID Feature Sets"
+ */
+# define x86_has_cpuid() (1)
+/* save EBX around CPUID, because gcc doesn't like it to be clobbered with -fPIC */
+# define x86_cpuid(input, eax, ebx, ecx, edx) \
+ __asm__ __volatile__ ( \
+ /* save ebx in esi */ \
+ "mov %%rbx, %%rsi \n\t" \
+ /* get CPUID with eax=input */ \
+ "cpuid \n\t" \
+ /* swap ebx and esi */ \
+ "xchg %%rbx, %%rsi" \
+ : "=a" (eax), "=S" (ebx), \
+ "=c" (ecx), "=d" (edx) \
+ : "0" (input) \
+ : "cc")
+#else
+# define x86_has_cpuid() (false)
+# define x86_cpuid(input, eax, ebx, ecx, edx) do {} while (0)
+#endif
+
+static bool
+get_x86_cpu_features (CPUInfo *ci)
+{
+ memset (ci, 0, sizeof (*ci));
+ /* check if the CPUID instruction is supported */
+ if (!x86_has_cpuid ())
+ return false;
+
+ /* query intel CPUID range */
+ unsigned int eax, ebx, ecx, edx;
+ x86_cpuid (0, eax, ebx, ecx, edx);
+ unsigned int v_ebx = ebx, v_ecx = ecx, v_edx = edx;
+ char *vendor = ci->cpu_vendor;
+ *((unsigned int*) &vendor[0]) = ebx;
+ *((unsigned int*) &vendor[4]) = edx;
+ *((unsigned int*) &vendor[8]) = ecx;
+ vendor[12] = 0;
+ if (eax >= 1) /* may query version and feature information */
+ {
+ x86_cpuid (1, eax, ebx, ecx, edx);
+ if (ecx & (1 << 0))
+ ci->x86_sse3 = true;
+ if (ecx & (1 << 9))
+ ci->x86_ssse3 = true;
+ if (ecx & (1 << 13))
+ ci->x86_cx16 = true;
+ if (ecx & (1 << 19))
+ ci->x86_sse4_1 = true;
+ if (ecx & (1 << 20))
+ ci->x86_sse4_2 = true;
+ if (ecx & (1 << 30))
+ ci->x86_rdrand = true;
+ if (edx & (1 << 0))
+ ci->x86_fpu = true;
+ if (edx & (1 << 4))
+ ci->x86_tsc = true;
+ if (edx & (1 << 23))
+ ci->x86_mmx = true;
+ if (edx & (1 << 25))
+ {
+ ci->x86_sse = true;
+ ci->x86_mmxext = true;
+ }
+ if (edx & (1 << 26))
+ ci->x86_sse2 = true;
+ if (edx & (1 << 28))
+ ci->x86_htt = true;
+ /*
http://www.intel.com/content/www/us/en/processors/processor-identification-cpuid-instruction-note.html
+ * "Intel Processor Identification and the CPUID Instruction"
+ */
+ }
+
+ /* query extended CPUID range */
+ x86_cpuid (0x80000000, eax, ebx, ecx, edx);
+ if (eax >= 0x80000001 && /* may query extended feature information */
+ v_ebx == 0x68747541 && /* AuthenticAMD */
+ v_ecx == 0x444d4163 && v_edx == 0x69746e65)
+ {
+ x86_cpuid (0x80000001, eax, ebx, ecx, edx);
+ if (edx & (1 << 31))
+ ci->x86_3dnow = true;
+ if (edx & (1 << 22))
+ ci->x86_mmxext = true;
+ if (edx & (1 << 30))
+ ci->x86_3dnowext = true;
+ /* www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf
+ * "AMD CPUID Specification"
+ */
+ }
+
+ /* check system support for SSE */
+ if (ci->x86_sse)
+ {
+ struct sigaction action, old_action;
+ action.sa_handler = cpu_info_sigill_handler;
+ sigemptyset (&action.sa_mask);
+ action.sa_flags = SA_NOMASK;
+ sigaction (SIGILL, &action, &old_action);
+ if (setjmp (cpu_info_jmp_buf) == 0)
+ {
+#if defined __i386__ || defined __x86_64__ || defined __amd64__
+ unsigned int mxcsr;
+ __asm__ __volatile__ ("stmxcsr %0 ; sfence ; emms" : "=m" (mxcsr));
+ /* executed SIMD instructions without exception */
+ ci->x86_ssesys = true;
+#endif // x86
+ }
+ else
+ {
+ /* signal handler jumped here */
+ // g_printerr ("caught SIGILL\n");
+ }
+ sigaction (SIGILL, &old_action, NULL);
+ }
+
+ return true;
+}
+
+/** The returned string contains: number of online CPUs, a string
+ * describing the CPU architecture, the vendor and finally
+ * a number of flag words describing CPU features plus a trailing space.
+ * This allows checks for CPU features via a simple string search for
+ * " FEATURE ".
+ * @return Example: "4 AMD64 GenuineIntel FPU TSC HTT CMPXCHG16B MMX MMXEXT SSESYS SSE SSE2 SSE3 SSSE3
SSE4.1 SSE4.2 "
+ */
+String
+cpu_info()
+{
+ static String cpu_info_string = []() {
+ CPUInfo cpu_info = { 0, };
+ if (!get_x86_cpu_features (&cpu_info))
+ strcat (cpu_info.cpu_vendor, "Unknown");
+ cpu_info.machine = get_arch_name();
+ String info;
+ // cores
+ info += string_format ("%d", sysconf (_SC_NPROCESSORS_ONLN));
+ // architecture
+ info += String (" ") + cpu_info.machine;
+ // vendor
+ info += String (" ") + cpu_info.cpu_vendor;
+ // processor flags
+ if (cpu_info.x86_fpu)
+ info += " FPU";
+ if (cpu_info.x86_tsc)
+ info += " TSC";
+ if (cpu_info.x86_htt)
+ info += " HTT";
+ if (cpu_info.x86_cx16)
+ info += " CMPXCHG16B";
+ // MMX flags
+ if (cpu_info.x86_mmx)
+ info += " MMX";
+ if (cpu_info.x86_mmxext)
+ info += " MMXEXT";
+ // SSE flags
+ if (cpu_info.x86_ssesys)
+ info += " SSESYS";
+ if (cpu_info.x86_sse)
+ info += " SSE";
+ if (cpu_info.x86_sse2)
+ info += " SSE2";
+ if (cpu_info.x86_sse3)
+ info += " SSE3";
+ if (cpu_info.x86_ssse3)
+ info += " SSSE3";
+ if (cpu_info.x86_sse4_1)
+ info += " SSE4.1";
+ if (cpu_info.x86_sse4_2)
+ info += " SSE4.2";
+ if (cpu_info.x86_rdrand)
+ info += " rdrand";
+ // 3DNOW flags
+ if (cpu_info.x86_3dnow)
+ info += " 3DNOW";
+ if (cpu_info.x86_3dnowext)
+ info += " 3DNOWEXT";
+ info += " ";
+ return String (info.c_str());
+ }();
+ return cpu_info_string;
+}
+
// == Timestamps ==
static clockid_t monotonic_clockid = CLOCK_REALTIME;
static uint64 monotonic_start = 0;
diff --git a/sfi/platform.hh b/sfi/platform.hh
index bbc2aca..4910d50 100644
--- a/sfi/platform.hh
+++ b/sfi/platform.hh
@@ -23,6 +23,7 @@ void application_name_init (String desktopname); ///< Set the application
String program_cwd (); ///< The current working directory during startup.
std::string executable_name (); ///< Retrieve the name part of executable_path().
std::string executable_path (); ///< Retrieve the path to the currently running
executable.
+std::string cpu_info (); ///< Retrieve string identifying the runtime CPU
type.
// == Thread Status ==
/// Acquire information about a task (process or thread) at runtime.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]