1 /*
   2  * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #if defined(__solaris__) || defined(__linux__)
  27 
  28 #include "ergo.h"
  29 
  30 static unsigned long physical_processors(void);
  31 
  32 #ifdef __solaris__
  33 
  34 /*
  35  * A utility method for asking the CPU about itself.
  36  * There's a corresponding version of linux-i586
  37  * because the compilers are different.
  38  */
  39 static void
  40 get_cpuid(uint32_t arg,
  41           uint32_t* eaxp,
  42           uint32_t* ebxp,
  43           uint32_t* ecxp,
  44           uint32_t* edxp) {
  45 #ifdef _LP64
  46   asm(
  47   /* rbx is a callee-saved register */
  48       " movq    %rbx, %r11  \n"
  49   /* rdx and rcx are 3rd and 4th argument registers */
  50       " movq    %rdx, %r10  \n"
  51       " movq    %rcx, %r9   \n"
  52       " movl    %edi, %eax  \n"
  53       " cpuid               \n"
  54       " movl    %eax, (%rsi)\n"
  55       " movl    %ebx, (%r10)\n"
  56       " movl    %ecx, (%r9) \n"
  57       " movl    %edx, (%r8) \n"
  58   /* Restore rbx */
  59       " movq    %r11, %rbx");
  60 #else
  61   /* EBX is a callee-saved register */
  62   asm(" pushl   %ebx");
  63   /* Need ESI for storing through arguments */
  64   asm(" pushl   %esi");
  65   asm(" movl    8(%ebp), %eax   \n"
  66       " cpuid                   \n"
  67       " movl    12(%ebp), %esi  \n"
  68       " movl    %eax, (%esi)    \n"
  69       " movl    16(%ebp), %esi  \n"
  70       " movl    %ebx, (%esi)    \n"
  71       " movl    20(%ebp), %esi  \n"
  72       " movl    %ecx, (%esi)    \n"
  73       " movl    24(%ebp), %esi  \n"
  74       " movl    %edx, (%esi)      ");
  75   /* Restore ESI and EBX */
  76   asm(" popl    %esi");
  77   /* Restore EBX */
  78   asm(" popl    %ebx");
  79 #endif /* LP64 */
  80 }
  81 
  82 /* The definition of a server-class machine for solaris-i586/amd64 */
  83 jboolean
  84 ServerClassMachineImpl(void) {
  85   jboolean            result            = JNI_FALSE;
  86   /* How big is a server class machine? */
  87   const unsigned long server_processors = 2UL;
  88   const uint64_t      server_memory     = 2UL * GB;
  89   /*
  90    * We seem not to get our full complement of memory.
  91    *     We allow some part (1/8?) of the memory to be "missing",
  92    *     based on the sizes of DIMMs, and maybe graphics cards.
  93    */
  94   const uint64_t      missing_memory    = 256UL * MB;
  95   const uint64_t      actual_memory     = physical_memory();
  96 
  97   /* Is this a server class machine? */
  98   if (actual_memory >= (server_memory - missing_memory)) {
  99     const unsigned long actual_processors = physical_processors();
 100     if (actual_processors >= server_processors) {
 101       result = JNI_TRUE;
 102     }
 103   }
 104   JLI_TraceLauncher("solaris_" LIBARCHNAME "_ServerClassMachine: %s\n",
 105            (result == JNI_TRUE ? "true" : "false"));
 106   return result;
 107 }
 108 
 109 #endif /* __solaris__ */
 110 
 111 #ifdef __linux__
 112 
 113 /*
 114  * A utility method for asking the CPU about itself.
 115  * There's a corresponding version of solaris-i586
 116  * because the compilers are different.
 117  */
 118 static void
 119 get_cpuid(uint32_t arg,
 120           uint32_t* eaxp,
 121           uint32_t* ebxp,
 122           uint32_t* ecxp,
 123           uint32_t* edxp) {
 124 #ifdef _LP64
 125   __asm__ volatile (/* Instructions */
 126                     "   movl    %4, %%eax  \n"
 127                     "   cpuid              \n"
 128                     "   movl    %%eax, (%0)\n"
 129                     "   movl    %%ebx, (%1)\n"
 130                     "   movl    %%ecx, (%2)\n"
 131                     "   movl    %%edx, (%3)\n"
 132                     : /* Outputs */
 133                     : /* Inputs */
 134                     "r" (eaxp),
 135                     "r" (ebxp),
 136                     "r" (ecxp),
 137                     "r" (edxp),
 138                     "r" (arg)
 139                     : /* Clobbers */
 140                     "%rax", "%rbx", "%rcx", "%rdx", "memory"
 141                     );
 142 #else /* _LP64 */
 143   uint32_t value_of_eax = 0;
 144   uint32_t value_of_ebx = 0;
 145   uint32_t value_of_ecx = 0;
 146   uint32_t value_of_edx = 0;
 147   __asm__ volatile (/* Instructions */
 148                         /* ebx is callee-save, so push it */
 149                     "   pushl   %%ebx      \n"
 150                     "   movl    %4, %%eax  \n"
 151                     "   cpuid              \n"
 152                     "   movl    %%eax, %0  \n"
 153                     "   movl    %%ebx, %1  \n"
 154                     "   movl    %%ecx, %2  \n"
 155                     "   movl    %%edx, %3  \n"
 156                         /* restore ebx */
 157                     "   popl    %%ebx      \n"
 158 
 159                     : /* Outputs */
 160                     "=m" (value_of_eax),
 161                     "=m" (value_of_ebx),
 162                     "=m" (value_of_ecx),
 163                     "=m" (value_of_edx)
 164                     : /* Inputs */
 165                     "m" (arg)
 166                     : /* Clobbers */
 167                     "%eax", "%ecx", "%edx"
 168                     );
 169   *eaxp = value_of_eax;
 170   *ebxp = value_of_ebx;
 171   *ecxp = value_of_ecx;
 172   *edxp = value_of_edx;
 173 #endif /* _LP64 */
 174 }
 175 
 176 /* The definition of a server-class machine for linux-i586 */
 177 jboolean
 178 ServerClassMachineImpl(void) {
 179   jboolean            result            = JNI_FALSE;
 180   /* How big is a server class machine? */
 181   const unsigned long server_processors = 2UL;
 182   const uint64_t      server_memory     = 2UL * GB;
 183   /*
 184    * We seem not to get our full complement of memory.
 185    *     We allow some part (1/8?) of the memory to be "missing",
 186    *     based on the sizes of DIMMs, and maybe graphics cards.
 187    */
 188   const uint64_t      missing_memory    = 256UL * MB;
 189   const uint64_t      actual_memory     = physical_memory();
 190 
 191   /* Is this a server class machine? */
 192   if (actual_memory >= (server_memory - missing_memory)) {
 193     const unsigned long actual_processors = physical_processors();
 194     if (actual_processors >= server_processors) {
 195       result = JNI_TRUE;
 196     }
 197   }
 198   JLI_TraceLauncher("linux_" LIBARCHNAME "_ServerClassMachine: %s\n",
 199            (result == JNI_TRUE ? "true" : "false"));
 200   return result;
 201 }
 202 #endif /* __linux__ */
 203 
 204 /*
 205  * Routines shared by solaris-i586 and linux-i586.
 206  */
 207 
 208 enum HyperThreadingSupport_enum {
 209   hts_supported        =  1,
 210   hts_too_soon_to_tell =  0,
 211   hts_not_supported    = -1,
 212   hts_not_pentium4     = -2,
 213   hts_not_intel        = -3
 214 };
 215 typedef enum HyperThreadingSupport_enum HyperThreadingSupport;
 216 
 217 /* Determine if hyperthreading is supported */
 218 static HyperThreadingSupport
 219 hyperthreading_support(void) {
 220   HyperThreadingSupport result = hts_too_soon_to_tell;
 221   /* Bits 11 through 8 is family processor id */
 222 # define FAMILY_ID_SHIFT 8
 223 # define FAMILY_ID_MASK 0xf
 224   /* Bits 23 through 20 is extended family processor id */
 225 # define EXT_FAMILY_ID_SHIFT 20
 226 # define EXT_FAMILY_ID_MASK 0xf
 227   /* Pentium 4 family processor id */
 228 # define PENTIUM4_FAMILY_ID 0xf
 229   /* Bit 28 indicates Hyper-Threading Technology support */
 230 # define HT_BIT_SHIFT 28
 231 # define HT_BIT_MASK 1
 232   uint32_t vendor_id[3] = { 0U, 0U, 0U };
 233   uint32_t value_of_eax = 0U;
 234   uint32_t value_of_edx = 0U;
 235   uint32_t dummy        = 0U;
 236 
 237   /* Yes, this is supposed to be [0], [2], [1] */
 238   get_cpuid(0, &dummy, &vendor_id[0], &vendor_id[2], &vendor_id[1]);
 239   JLI_TraceLauncher("vendor: %c %c %c %c %c %c %c %c %c %c %c %c \n",
 240            ((vendor_id[0] >>  0) & 0xff),
 241            ((vendor_id[0] >>  8) & 0xff),
 242            ((vendor_id[0] >> 16) & 0xff),
 243            ((vendor_id[0] >> 24) & 0xff),
 244            ((vendor_id[1] >>  0) & 0xff),
 245            ((vendor_id[1] >>  8) & 0xff),
 246            ((vendor_id[1] >> 16) & 0xff),
 247            ((vendor_id[1] >> 24) & 0xff),
 248            ((vendor_id[2] >>  0) & 0xff),
 249            ((vendor_id[2] >>  8) & 0xff),
 250            ((vendor_id[2] >> 16) & 0xff),
 251            ((vendor_id[2] >> 24) & 0xff));
 252   get_cpuid(1, &value_of_eax, &dummy, &dummy, &value_of_edx);
 253   JLI_TraceLauncher("value_of_eax: 0x%x  value_of_edx: 0x%x\n",
 254            value_of_eax, value_of_edx);
 255   if ((((value_of_eax >> FAMILY_ID_SHIFT) & FAMILY_ID_MASK) == PENTIUM4_FAMILY_ID) ||
 256       (((value_of_eax >> EXT_FAMILY_ID_SHIFT) & EXT_FAMILY_ID_MASK) != 0)) {
 257     if ((((vendor_id[0] >>  0) & 0xff) == 'G') &&
 258         (((vendor_id[0] >>  8) & 0xff) == 'e') &&
 259         (((vendor_id[0] >> 16) & 0xff) == 'n') &&
 260         (((vendor_id[0] >> 24) & 0xff) == 'u') &&
 261         (((vendor_id[1] >>  0) & 0xff) == 'i') &&
 262         (((vendor_id[1] >>  8) & 0xff) == 'n') &&
 263         (((vendor_id[1] >> 16) & 0xff) == 'e') &&
 264         (((vendor_id[1] >> 24) & 0xff) == 'I') &&
 265         (((vendor_id[2] >>  0) & 0xff) == 'n') &&
 266         (((vendor_id[2] >>  8) & 0xff) == 't') &&
 267         (((vendor_id[2] >> 16) & 0xff) == 'e') &&
 268         (((vendor_id[2] >> 24) & 0xff) == 'l')) {
 269       if (((value_of_edx >> HT_BIT_SHIFT) & HT_BIT_MASK) == HT_BIT_MASK) {
 270         JLI_TraceLauncher("Hyperthreading supported\n");
 271         result = hts_supported;
 272       } else {
 273         JLI_TraceLauncher("Hyperthreading not supported\n");
 274         result = hts_not_supported;
 275       }
 276     } else {
 277       JLI_TraceLauncher("Not GenuineIntel\n");
 278       result = hts_not_intel;
 279     }
 280   } else {
 281     JLI_TraceLauncher("not Pentium 4 or extended\n");
 282     result = hts_not_pentium4;
 283   }
 284   return result;
 285 }
 286 
 287 /* Determine how many logical processors there are per CPU */
 288 static unsigned int
 289 logical_processors_per_package(void) {
 290   /*
 291    * After CPUID with EAX==1, register EBX bits 23 through 16
 292    * indicate the number of logical processors per package
 293    */
 294 # define NUM_LOGICAL_SHIFT 16
 295 # define NUM_LOGICAL_MASK 0xff
 296   unsigned int result                        = 1U;
 297   const HyperThreadingSupport hyperthreading = hyperthreading_support();
 298 
 299   if (hyperthreading == hts_supported) {
 300     uint32_t value_of_ebx = 0U;
 301     uint32_t dummy        = 0U;
 302 
 303     get_cpuid(1, &dummy, &value_of_ebx, &dummy, &dummy);
 304     result = (value_of_ebx >> NUM_LOGICAL_SHIFT) & NUM_LOGICAL_MASK;
 305     JLI_TraceLauncher("logical processors per package: %u\n", result);
 306   }
 307   return result;
 308 }
 309 
 310 /* Compute the number of physical processors, not logical processors */
 311 static unsigned long
 312 physical_processors(void) {
 313   const long sys_processors = sysconf(_SC_NPROCESSORS_CONF);
 314   unsigned long result      = sys_processors;
 315 
 316   JLI_TraceLauncher("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors);
 317   if (sys_processors > 1) {
 318     unsigned int logical_processors = logical_processors_per_package();
 319     if (logical_processors > 1) {
 320       result = (unsigned long) sys_processors / logical_processors;
 321     }
 322   }
 323   JLI_TraceLauncher("physical processors: %lu\n", result);
 324   return result;
 325 }
 326 
 327 #endif // __solaris__ || __linux__