Add CPU auto-detecting feature.

This commit is contained in:
Zhang Xianyi 2015-04-21 14:26:39 -05:00
parent 70731aa312
commit 5008870893
4 changed files with 315 additions and 0 deletions

View File

@ -15,10 +15,15 @@ set (OpenVML_FUNC_PREFIX "")
set (OpenVML_FUNC_SUFFIX "")
option(BUILD_SINGLE_THREAD "Only build the single thread" ON)
option(AUTO_DETECT_CPU "Auto detect CPU architecture." ON)
option(BUILD_OpenVML_TEST "Build Test" ON)
#####################################################
if(AUTO_DETECT_CPU)
include(${PROJECT_SOURCE_DIR}/cmake/auto_detect_cpu.cmake)
endif()
if (NOT OpenVML_ARCH)
set (OpenVML_ARCH "generic")
endif(NOT OpenVML_ARCH)

37
cmake/arch_detect.c Normal file
View File

@ -0,0 +1,37 @@
/* * Copyright (c) 2014, 2015 Zhang Xianyi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
int main()
{
#if defined(__x86_64__) || defined(__amd64__)
printf("x86_64");
return 0;
#endif
//default
printf("generic");
return 0;
}

View File

@ -0,0 +1,30 @@
set (OpenVML_ARCH "generic")
set (OpenVML_CPU_CORENAME "generic")
try_run(arch_detect_result arch_detect_compile_result
${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/arch_detect.c
RUN_OUTPUT_VARIABLE arch_detect_output
)
if(arch_detect_compile_result)
if(arch_detect_result EQUAL 0)
set (OpenVML_ARCH ${arch_detect_output})
endif()
endif()
#For x86_64
if(OpenVML_ARCH STREQUAL "x86_64")
try_run(cpu_detect_result cpu_detect_compile_result
${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/cmake/cpuid_x86.c
RUN_OUTPUT_VARIABLE cpu_detect_output
)
endif()
if(cpu_detect_compile_result)
if(cpu_detect_result EQUAL 0)
set (OpenVML_CPU_CORENAME ${cpu_detect_output})
endif()
endif()
message(STATUS "Detect Arch:" ${OpenVML_ARCH} "\tCPU:" ${OpenVML_CPU_CORENAME})

243
cmake/cpuid_x86.c Normal file
View File

@ -0,0 +1,243 @@
/* * Copyright (c) 2014, 2015 Zhang Xianyi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#define VENDOR_UNKNOWN 0
#define VENDOR_INTEL 1
#define VENDOR_AMD 2
#define CPUNAME_GENERIC 0
#define CPUNAME_SANDYBRIDGE 1
#define CPUNAME_HASWELL 2
//temp set to generic
#define CPUNAME_BULLDOZER 0
#define CPUNAME_PILEDRIVER 0
static char *cpuname[] = {
"generic",
"sandybridge",
"haswell",
};
#define BITMASK(a, b, c) ((((a) >> (b)) & (c)))
static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx){
#if defined(__i386__) && defined(__PIC__)
__asm__ __volatile__
("mov %%ebx, %%edi;"
"cpuid;"
"xchgl %%ebx, %%edi;"
: "=a" (*eax), "=D" (*ebx), "=c" (*ecx), "=d" (*edx) : "a" (op) : "cc");
#else
__asm__ __volatile__
("cpuid": "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) : "a" (op) : "cc");
#endif
}
static inline int have_cpuid(void){
int eax, ebx, ecx, edx;
cpuid(0, &eax, &ebx, &ecx, &edx);
return eax;
}
int get_vendor(void){
int eax, ebx, ecx, edx;
char vendor[13];
cpuid(0, &eax, &ebx, &ecx, &edx);
*(int *)(&vendor[0]) = ebx;
*(int *)(&vendor[4]) = edx;
*(int *)(&vendor[8]) = ecx;
vendor[12] = (char)0;
if (!strcmp(vendor, "GenuineIntel")) return VENDOR_INTEL;
if (!strcmp(vendor, "AuthenticAMD")) return VENDOR_AMD;
if ((eax == 0) || ((eax & 0x500) != 0)) return VENDOR_INTEL;
return VENDOR_UNKNOWN;
}
static inline void xgetbv(int op, int * eax, int * edx){
//Use binary code for xgetbv
__asm__ __volatile__
(".byte 0x0f, 0x01, 0xd0": "=a" (*eax), "=d" (*edx) : "c" (op) : "cc");
}
int support_avx(){
int eax, ebx, ecx, edx;
int ret=0;
cpuid(1, &eax, &ebx, &ecx, &edx);
if ((ecx & (1 << 28)) != 0 && (ecx & (1 << 27)) != 0 && (ecx & (1 << 26)) != 0){
xgetbv(0, &eax, &edx);
if((eax & 6) == 6){
ret=1; //OS support AVX
}
}
return ret;
}
int cpu_detect()
{
int eax, ebx, ecx, edx;
int vendor, family, extend_family, model, extend_model;
if (!have_cpuid()) return CPUNAME_GENERIC;
vendor=get_vendor();
cpuid(1, &eax, &ebx, &ecx, &edx);
extend_family = BITMASK(eax, 20, 0xff);
extend_model=BITMASK(eax, 16, 0x0f);
family=BITMASK(eax, 8, 0x0f);
model=BITMASK(eax, 4, 0x0f);
if (vendor == VENDOR_INTEL){
switch (family) {
case 0x6:
switch (extend_model) {
case 2:
switch (model) {
case 10:
case 13:
if(support_avx()) {
return CPUNAME_SANDYBRIDGE;
}else{
return CPUNAME_GENERIC; //OS doesn't support AVX
}
}
break;
case 3:
switch (model) {
case 10:
case 14:
//Ivy Bridge
if(support_avx()) {
return CPUNAME_SANDYBRIDGE;
}else{
return CPUNAME_GENERIC; //OS doesn't support AVX
}
case 12:
case 15:
//Haswell.
if(support_avx()) {
return CPUNAME_HASWELL;
}else{
return CPUNAME_GENERIC; //OS doesn't support AVX
}
case 13:
//broadwell
if(support_avx()) {
return CPUNAME_HASWELL;
}else{
return CPUNAME_GENERIC; //OS doesn't support AVX
}
}
break;
case 4:
switch (model) {
case 5:
case 6:
//Haswell.
if(support_avx()) {
return CPUNAME_HASWELL;
}else{
return CPUNAME_GENERIC; //OS doesn't support AVX
}
case 7:
case 15:
//broadwell
if(support_avx()) {
return CPUNAME_HASWELL;
}else{
return CPUNAME_GENERIC; //OS doesn't support AVX
}
}
break;
case 5:
switch (model) {
case 6:
//broadwell
if(support_avx()) {
return CPUNAME_HASWELL;
}else{
return CPUNAME_GENERIC; //OS doesn't support AVX
}
}
break;
}
break;
}
}else if (vendor == VENDOR_AMD){
switch (family) {
case 0xf:
switch (extend_family) {
case 6:
switch (model) {
case 1:
if(support_avx())
return CPUNAME_BULLDOZER;
else
return CPUNAME_GENERIC; //OS don't support AVX.
case 2:
if(support_avx())
return CPUNAME_PILEDRIVER;
else
return CPUNAME_GENERIC; //OS don't support AVX.
case 0:
//Steamroller. Temp use Piledriver.
if(support_avx())
return CPUNAME_PILEDRIVER;
else
return CPUNAME_GENERIC; //OS don't support AVX.
}
}
break;
}
}
return CPUNAME_GENERIC;
}
int main()
{
int cpuname_id;
cpuname_id=cpu_detect();
printf("%s", cpuname[cpuname_id]);
return 0;
}