Fujitsu Sparc64 acceleration and general fixes for non-x86 builds
[alexxy/gromacs.git] / src / gmxlib / gmx_cpuid.c
index 402af15f41d64d1070f057d9d2b8fa36919976ef..c17e8097185289fa00c0ab9ccd96aa6f85ebf725 100644 (file)
  * in a single file, but to avoid repeated ifdefs we set the overall architecture here.
  */
 #if defined (__i386__) || defined (__x86_64__) || defined (_M_IX86) || defined (_M_X64)
+/* OK, it is x86, but can we execute cpuid? */
+#if defined(GMX_X86_GCC_INLINE_ASM) || ( defined(_MSC_VER) && ( (_MSC_VER > 1500) || (_MSC_VER==1500 & _MSC_FULL_VER >= 150030729)))
 #    define GMX_CPUID_X86
 #endif
+#endif
 
 /* Global constant character strings corresponding to our enumerated types */
 const char *
@@ -74,7 +77,9 @@ gmx_cpuid_vendor_string[GMX_CPUID_NVENDORS] =
     "CannotDetect",
     "Unknown",
     "GenuineIntel",
-    "AuthenticAMD"
+    "AuthenticAMD",
+    "Fujitsu",
+    "IBM"
 };
 
 const char *
@@ -125,7 +130,8 @@ gmx_cpuid_acceleration_string[GMX_CPUID_NACCELERATIONS] =
     "SSE2",
     "SSE4.1",
     "AVX_128_FMA",
-    "AVX_256"
+    "AVX_256",
+    "Sparc64 HPC-ACE"
 };
 
 /* Max length of brand string */
@@ -223,6 +229,10 @@ enum gmx_cpuid_acceleration
 static const
 enum gmx_cpuid_acceleration
     compiled_acc = GMX_CPUID_ACCELERATION_X86_SSE2;
+#elif defined GMX_CPU_ACCELERATION_SPARC64_HPC_ACE
+static const
+enum gmx_cpuid_acceleration
+    compiled_acc = GMX_CPUID_ACCELERATION_SPARC64_HPC_ACE;
 #else
 static const
 enum gmx_cpuid_acceleration
@@ -696,6 +706,48 @@ cpuid_check_intel_x86(gmx_cpuid_t                cpuid)
 
 
 
+
+static void
+chomp_substring_before_colon(const char *in, char *s, int maxlength)
+{
+    char *p;
+    strncpy(s,in,maxlength);
+    p = strchr(s,':');
+    if(p!=NULL)
+    {
+        *p='\0';
+        while(isspace(*(--p)) && (p>=s))
+        {
+            *p='\0';
+        }
+    }
+    else
+    {
+        *s='\0';
+    }
+}
+
+static void
+chomp_substring_after_colon(const char *in, char *s, int maxlength)
+{
+    char *p;
+    if( (p = strchr(in,':'))!=NULL)
+    {
+        p++;
+        while(isspace(*p)) p++;
+        strncpy(s,p,maxlength);
+        p = s+strlen(s);
+        while(isspace(*(--p)) && (p>=s))
+        {
+            *p='\0';
+        }
+    }
+    else
+    {
+        *s='\0';
+    }
+}
+
 /* Try to find the vendor of the current CPU, so we know what specific
  * detection routine to call.
  */
@@ -706,6 +758,8 @@ cpuid_check_vendor(void)
     /* Register data used on x86 */
     unsigned int               eax, ebx, ecx, edx;
     char                       vendorstring[13];
+    FILE *                     fp;
+    char                       buffer[255],buffer2[255];
 
     /* Set default first */
     vendor = GMX_CPUID_VENDOR_UNKNOWN;
@@ -726,6 +780,29 @@ cpuid_check_vendor(void)
             vendor = i;
         }
     }
+#elif defined(__linux__) || defined(__linux)
+    /* General Linux. Try to get CPU vendor from /proc/cpuinfo */
+    if( (fp = fopen("/proc/cpuinfo","r")) != NULL)
+    {
+        while( (vendor == GMX_CPUID_VENDOR_UNKNOWN) && (fgets(buffer,sizeof(buffer),fp) != NULL))
+        {
+            chomp_substring_before_colon(buffer,buffer2,sizeof(buffer2));
+            /* Intel/AMD use "vendor_id", IBM "vendor". Fujitsu "manufacture". Add others if you have them! */
+            if( !strcmp(buffer2,"vendor_id") || !strcmp(buffer2,"vendor") || !strcmp(buffer2,"manufacture") )
+            {
+                chomp_substring_after_colon(buffer,buffer2,sizeof(buffer2));
+                for(i=GMX_CPUID_VENDOR_UNKNOWN; i<GMX_CPUID_NVENDORS; i++)
+                {
+                    /* Be liberal and accept if we find the vendor anywhere in string */
+                    if(strstr(buffer2,gmx_cpuid_vendor_string[i]))
+                    {
+                        vendor = i;
+                    }
+                }
+            }
+        }
+    }
+    fclose(fp);
 #else
     vendor = GMX_CPUID_VENDOR_UNKNOWN;
 #endif
@@ -794,6 +871,9 @@ gmx_cpuid_init               (gmx_cpuid_t *              pcpuid)
 {
     gmx_cpuid_t cpuid;
     int         i;
+    FILE *      fp;
+    char        buffer[255],buffer2[255];
+    int         found_brand;
 
     cpuid = malloc(sizeof(*cpuid));
 
@@ -803,6 +883,7 @@ gmx_cpuid_init               (gmx_cpuid_t *              pcpuid)
     {
         cpuid->feature[i] = 0;
     }
+
     cpuid->have_cpu_topology   = 0;
     cpuid->nproc               = 0;
     cpuid->npackages           = 0;
@@ -826,20 +907,37 @@ gmx_cpuid_init               (gmx_cpuid_t *              pcpuid)
             break;
 #endif
         default:
-            /* Could not find vendor */
-            strncpy(cpuid->brand, "Unknown CPU brand", GMX_CPUID_BRAND_MAXLEN);
+            /* Default value */
+            strncpy(cpuid->brand,"Unknown CPU brand",GMX_CPUID_BRAND_MAXLEN);
+#if defined(__linux__) || defined(__linux)
+            /* General Linux. Try to get CPU type from /proc/cpuinfo */
+            if( (fp = fopen("/proc/cpuinfo","r")) != NULL)
+            {
+                found_brand = 0;
+                while( (found_brand==0) && (fgets(buffer,sizeof(buffer),fp) !=NULL))
+                {
+                    chomp_substring_before_colon(buffer,buffer2,sizeof(buffer2));
+                    /* Intel uses "model name", Fujitsu and IBM "cpu". */
+                    if( !strcmp(buffer2,"model name") || !strcmp(buffer2,"cpu"))
+                    {
+                        chomp_substring_after_colon(buffer,cpuid->brand,GMX_CPUID_BRAND_MAXLEN);
+                        found_brand = 1;
+                    }
+                }
+            }
+            fclose(fp);
+#endif
             cpuid->family         = 0;
             cpuid->model          = 0;
             cpuid->stepping       = 0;
-
-            for (i = 0; i < GMX_CPUID_NFEATURES; i++)
+            
+            for(i=0; i<GMX_CPUID_NFEATURES; i++)
             {
-                cpuid->feature[i] = 0;
+                cpuid->feature[i]=0;
             }
             cpuid->feature[GMX_CPUID_FEATURE_CANNOTDETECT] = 1;
             break;
     }
-
     return 0;
 }
 
@@ -950,7 +1048,13 @@ gmx_cpuid_acceleration_suggest  (gmx_cpuid_t                 cpuid)
             tmpacc = GMX_CPUID_ACCELERATION_X86_SSE2;
         }
     }
-
+    else if(gmx_cpuid_vendor(cpuid)==GMX_CPUID_VENDOR_FUJITSU)
+    {
+        if(strstr(gmx_cpuid_brand(cpuid),"SPARC64"))
+        {
+            tmpacc = GMX_CPUID_ACCELERATION_SPARC64_HPC_ACE;
+        }
+    }
     return tmpacc;
 }
 
@@ -1001,7 +1105,6 @@ gmx_cpuid_acceleration_check(gmx_cpuid_t   cpuid,
 }
 
 
-
 #ifdef GMX_CPUID_STANDALONE
 /* Stand-alone program to enable queries of CPU features from Cmake.
  * Note that you need to check inline ASM capabilities before compiling and set