1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/stat.h>
4 #ifndef WIN32
5 #include <unistd.h>
6 #endif
7
8 #include <string.h>
9 #include "hardware.h"
10
11 #define PLL_FEAT_AVAIL(x,y) (((x) & (y)) == (y))
12 #define PLL_SYS_CPU_DIR_PATH "/sys/devices/system/cpu/"
13
14 //#ifdef _MSC_VER
15 //#define inline __inline
16 //#endif
17
cpuid(unsigned int op,int count,unsigned int * eax,unsigned int * ebx,unsigned int * ecx,unsigned int * edx)18 static __inline void cpuid(unsigned int op, int count,
19 unsigned int *eax, unsigned int *ebx,
20 unsigned int *ecx, unsigned int *edx)
21 {
22 #ifdef WIN32
23 __int32 regs[4];
24 __cpuid((int*)regs, (int)op);
25 *eax = regs[0];
26 *ebx = regs[1];
27 *ecx = regs[2];
28 *edx = regs[3];
29 #else
30 *eax = op;
31 *ecx = count;
32 asm volatile("cpuid"
33 : "=a" (*eax),
34 "=b" (*ebx),
35 "=c" (*ecx),
36 "=d" (*edx)
37
38 : "0" (*eax), "2" (*ecx)
39 : "memory");
40 #endif
41 }
42
43
show_hardware_info(pllHardwareInfo * hw)44 void show_hardware_info(pllHardwareInfo * hw)
45 {
46 printf ("MMX.........: %d\n"
47 "SSE.........: %d\n"
48 "SSE2........: %d\n"
49 "SSE3........: %d\n"
50 "SSSE3.......: %d\n"
51 "FMA.........: %d\n"
52 "SSE4.1......: %d\n"
53 "SSE4.2......: %d\n"
54 "AVX.........: %d\n"
55 "AVX2........: %d\n"
56 "SSE4A.......: %d\n"
57 "FMA4........: %d\n\n"
58 "Core(s).....: %d\n"
59 "CPU Sockets.: %d\n",
60
61 hw->has_mmx, hw->has_sse, hw->has_sse2, hw->has_sse3, hw->has_ssse3,
62 hw->has_fma, hw->has_sse41, hw->has_sse42, hw->has_avx, hw->has_avx2,
63 hw->has_sse4a, hw->has_fma4, hw->cores, hw->cpu_sockets);
64 }
65
pll_probe_cpu(pllHardwareInfo * hw)66 static int pll_probe_cpu (pllHardwareInfo * hw)
67 {
68 struct stat cpustat;
69 char cpu[30];
70 char cpupath[100];
71 int i, id, max_physical_id = -1;
72 char * physical_id_path = "/topology/physical_package_id";
73 FILE * fd;
74
75 /* check whether the sys cpu dir exists */
76 if (stat(PLL_SYS_CPU_DIR_PATH, &cpustat)) return (0);
77
78 /* and also check whether it is a dir */
79 if (!S_ISDIR(cpustat.st_mode)) return (0);
80
81 /* detect number of processors */
82 for (i = 0; ; ++i)
83 {
84 sprintf(cpu, "cpu%d", i);
85 strcpy (cpupath, PLL_SYS_CPU_DIR_PATH);
86 strcat (cpupath, cpu);
87 if (stat(cpupath, &cpustat)) break;
88
89 strcat (cpupath, physical_id_path);
90 if (!stat(cpupath, &cpustat))
91 {
92 fd = fopen (cpupath,"r");
93 fscanf (fd, "%d", &id);
94 /* printf ("Detected processor %d belonging to package %d\n", i, id); */
95 if (id > max_physical_id) max_physical_id = id;
96 fclose (fd);
97 }
98 }
99
100 hw->cores = i;
101 hw->cpu_sockets = max_physical_id + 1;
102
103 return (1);
104 }
105
pll_probe_hardware(pllHardwareInfo * hw)106 static void pll_probe_hardware (pllHardwareInfo * hw)
107 {
108 unsigned int a, b, c, d;
109 c = 0;
110
111 cpuid(0,0,&a,&b,&c,&d);
112 *((unsigned int *)(hw->vendor) ) = b;
113 *((unsigned int *)(hw->vendor + 4)) = d;
114 *((unsigned int *)(hw->vendor + 8)) = c;
115 hw->vendor[12] = 0;
116
117 printf ("%s\n", hw->vendor);
118
119 cpuid(1,0,&a,&b,&c,&d);
120
121 hw->has_mmx = PLL_FEAT_AVAIL(d,PLL_HAS_MMX);
122 hw->has_sse = PLL_FEAT_AVAIL(d,PLL_HAS_SSE);
123 hw->has_sse2 = PLL_FEAT_AVAIL(d,PLL_HAS_SSE2);
124
125 hw->has_sse3 = PLL_FEAT_AVAIL(c,PLL_HAS_SSE3);
126 hw->has_ssse3 = PLL_FEAT_AVAIL(c,PLL_HAS_SSSE3);
127 hw->has_fma = PLL_FEAT_AVAIL(c,PLL_HAS_FMA);
128 hw->has_sse41 = PLL_FEAT_AVAIL(c,PLL_HAS_SSE41);
129 hw->has_sse42 = PLL_FEAT_AVAIL(c,PLL_HAS_SSE42);
130 hw->has_avx = PLL_FEAT_AVAIL(c,PLL_HAS_AVX);
131
132 cpuid(7,0,&a,&b,&c,&d);
133
134 hw->has_avx2 = PLL_FEAT_AVAIL(b,PLL_HAS_AVX2);
135
136 /* TODO: note, here we have to check whether leaf 0x80000001 exists */
137 cpuid(0x80000001,0,&a,&b,&c,&d);
138
139 hw->has_sse4a = PLL_FEAT_AVAIL(c,PLL_HAS_SSE4A);
140 hw->has_fma4 = PLL_FEAT_AVAIL(c,PLL_HAS_FMA4);
141 }
142
pllGetHardwareInfo(pllHardwareInfo * hw)143 int pllGetHardwareInfo (pllHardwareInfo * hw)
144 {
145 pll_probe_hardware (hw);
146 pll_probe_cpu (hw);
147
148 /* TODO: finish failure checks in probe_hardware and probe_cpu */
149 return (1);
150
151 }
152
153 /* TODO: Remove after testing */
154 /*
155 int main (int argc, char * argv[])
156 {
157 pllHardwareInfo hw;
158
159 pll_probe_hardware(&hw);
160 pll_probe_cpu(&hw);
161
162 show_hardware_info(&hw);
163 return (EXIT_SUCCESS);
164 }
165 */
166