jdk/src/java.base/unix/native/libjli/ergo_i586.c
changeset 42001 b91683ebc1ba
parent 42000 8b7412f7eecd
parent 41988 ead9c72b9635
child 42002 3ee4e7827413
equal deleted inserted replaced
42000:8b7412f7eecd 42001:b91683ebc1ba
     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 #include "ergo.h"
       
    27 
       
    28 static unsigned long physical_processors(void);
       
    29 
       
    30 #ifdef __solaris__
       
    31 
       
    32 /*
       
    33  * A utility method for asking the CPU about itself.
       
    34  * There's a corresponding version of linux-i586
       
    35  * because the compilers are different.
       
    36  */
       
    37 static void
       
    38 get_cpuid(uint32_t arg,
       
    39           uint32_t* eaxp,
       
    40           uint32_t* ebxp,
       
    41           uint32_t* ecxp,
       
    42           uint32_t* edxp) {
       
    43 #ifdef _LP64
       
    44   asm(
       
    45   /* rbx is a callee-saved register */
       
    46       " movq    %rbx, %r11  \n"
       
    47   /* rdx and rcx are 3rd and 4th argument registers */
       
    48       " movq    %rdx, %r10  \n"
       
    49       " movq    %rcx, %r9   \n"
       
    50       " movl    %edi, %eax  \n"
       
    51       " cpuid               \n"
       
    52       " movl    %eax, (%rsi)\n"
       
    53       " movl    %ebx, (%r10)\n"
       
    54       " movl    %ecx, (%r9) \n"
       
    55       " movl    %edx, (%r8) \n"
       
    56   /* Restore rbx */
       
    57       " movq    %r11, %rbx");
       
    58 #else
       
    59   /* EBX is a callee-saved register */
       
    60   asm(" pushl   %ebx");
       
    61   /* Need ESI for storing through arguments */
       
    62   asm(" pushl   %esi");
       
    63   asm(" movl    8(%ebp), %eax   \n"
       
    64       " cpuid                   \n"
       
    65       " movl    12(%ebp), %esi  \n"
       
    66       " movl    %eax, (%esi)    \n"
       
    67       " movl    16(%ebp), %esi  \n"
       
    68       " movl    %ebx, (%esi)    \n"
       
    69       " movl    20(%ebp), %esi  \n"
       
    70       " movl    %ecx, (%esi)    \n"
       
    71       " movl    24(%ebp), %esi  \n"
       
    72       " movl    %edx, (%esi)      ");
       
    73   /* Restore ESI and EBX */
       
    74   asm(" popl    %esi");
       
    75   /* Restore EBX */
       
    76   asm(" popl    %ebx");
       
    77 #endif /* LP64 */
       
    78 }
       
    79 
       
    80 /* The definition of a server-class machine for solaris-i586/amd64 */
       
    81 jboolean
       
    82 ServerClassMachineImpl(void) {
       
    83   jboolean            result            = JNI_FALSE;
       
    84   /* How big is a server class machine? */
       
    85   const unsigned long server_processors = 2UL;
       
    86   const uint64_t      server_memory     = 2UL * GB;
       
    87   /*
       
    88    * We seem not to get our full complement of memory.
       
    89    *     We allow some part (1/8?) of the memory to be "missing",
       
    90    *     based on the sizes of DIMMs, and maybe graphics cards.
       
    91    */
       
    92   const uint64_t      missing_memory    = 256UL * MB;
       
    93   const uint64_t      actual_memory     = physical_memory();
       
    94 
       
    95   /* Is this a server class machine? */
       
    96   if (actual_memory >= (server_memory - missing_memory)) {
       
    97     const unsigned long actual_processors = physical_processors();
       
    98     if (actual_processors >= server_processors) {
       
    99       result = JNI_TRUE;
       
   100     }
       
   101   }
       
   102   JLI_TraceLauncher("solaris_" LIBARCHNAME "_ServerClassMachine: %s\n",
       
   103            (result == JNI_TRUE ? "true" : "false"));
       
   104   return result;
       
   105 }
       
   106 
       
   107 #endif /* __solaris__ */
       
   108 
       
   109 #ifdef __linux__
       
   110 
       
   111 /*
       
   112  * A utility method for asking the CPU about itself.
       
   113  * There's a corresponding version of solaris-i586
       
   114  * because the compilers are different.
       
   115  */
       
   116 static void
       
   117 get_cpuid(uint32_t arg,
       
   118           uint32_t* eaxp,
       
   119           uint32_t* ebxp,
       
   120           uint32_t* ecxp,
       
   121           uint32_t* edxp) {
       
   122 #ifdef _LP64
       
   123   __asm__ volatile (/* Instructions */
       
   124                     "   movl    %4, %%eax  \n"
       
   125                     "   cpuid              \n"
       
   126                     "   movl    %%eax, (%0)\n"
       
   127                     "   movl    %%ebx, (%1)\n"
       
   128                     "   movl    %%ecx, (%2)\n"
       
   129                     "   movl    %%edx, (%3)\n"
       
   130                     : /* Outputs */
       
   131                     : /* Inputs */
       
   132                     "r" (eaxp),
       
   133                     "r" (ebxp),
       
   134                     "r" (ecxp),
       
   135                     "r" (edxp),
       
   136                     "r" (arg)
       
   137                     : /* Clobbers */
       
   138                     "%rax", "%rbx", "%rcx", "%rdx", "memory"
       
   139                     );
       
   140 #else /* _LP64 */
       
   141   uint32_t value_of_eax = 0;
       
   142   uint32_t value_of_ebx = 0;
       
   143   uint32_t value_of_ecx = 0;
       
   144   uint32_t value_of_edx = 0;
       
   145   __asm__ volatile (/* Instructions */
       
   146                         /* ebx is callee-save, so push it */
       
   147                     "   pushl   %%ebx      \n"
       
   148                     "   movl    %4, %%eax  \n"
       
   149                     "   cpuid              \n"
       
   150                     "   movl    %%eax, %0  \n"
       
   151                     "   movl    %%ebx, %1  \n"
       
   152                     "   movl    %%ecx, %2  \n"
       
   153                     "   movl    %%edx, %3  \n"
       
   154                         /* restore ebx */
       
   155                     "   popl    %%ebx      \n"
       
   156 
       
   157                     : /* Outputs */
       
   158                     "=m" (value_of_eax),
       
   159                     "=m" (value_of_ebx),
       
   160                     "=m" (value_of_ecx),
       
   161                     "=m" (value_of_edx)
       
   162                     : /* Inputs */
       
   163                     "m" (arg)
       
   164                     : /* Clobbers */
       
   165                     "%eax", "%ecx", "%edx"
       
   166                     );
       
   167   *eaxp = value_of_eax;
       
   168   *ebxp = value_of_ebx;
       
   169   *ecxp = value_of_ecx;
       
   170   *edxp = value_of_edx;
       
   171 #endif /* _LP64 */
       
   172 }
       
   173 
       
   174 /* The definition of a server-class machine for linux-i586 */
       
   175 jboolean
       
   176 ServerClassMachineImpl(void) {
       
   177   jboolean            result            = JNI_FALSE;
       
   178   /* How big is a server class machine? */
       
   179   const unsigned long server_processors = 2UL;
       
   180   const uint64_t      server_memory     = 2UL * GB;
       
   181   /*
       
   182    * We seem not to get our full complement of memory.
       
   183    *     We allow some part (1/8?) of the memory to be "missing",
       
   184    *     based on the sizes of DIMMs, and maybe graphics cards.
       
   185    */
       
   186   const uint64_t      missing_memory    = 256UL * MB;
       
   187   const uint64_t      actual_memory     = physical_memory();
       
   188 
       
   189   /* Is this a server class machine? */
       
   190   if (actual_memory >= (server_memory - missing_memory)) {
       
   191     const unsigned long actual_processors = physical_processors();
       
   192     if (actual_processors >= server_processors) {
       
   193       result = JNI_TRUE;
       
   194     }
       
   195   }
       
   196   JLI_TraceLauncher("linux_" LIBARCHNAME "_ServerClassMachine: %s\n",
       
   197            (result == JNI_TRUE ? "true" : "false"));
       
   198   return result;
       
   199 }
       
   200 #endif /* __linux__ */
       
   201 
       
   202 /*
       
   203  * Routines shared by solaris-i586 and linux-i586.
       
   204  */
       
   205 
       
   206 enum HyperThreadingSupport_enum {
       
   207   hts_supported        =  1,
       
   208   hts_too_soon_to_tell =  0,
       
   209   hts_not_supported    = -1,
       
   210   hts_not_pentium4     = -2,
       
   211   hts_not_intel        = -3
       
   212 };
       
   213 typedef enum HyperThreadingSupport_enum HyperThreadingSupport;
       
   214 
       
   215 /* Determine if hyperthreading is supported */
       
   216 static HyperThreadingSupport
       
   217 hyperthreading_support(void) {
       
   218   HyperThreadingSupport result = hts_too_soon_to_tell;
       
   219   /* Bits 11 through 8 is family processor id */
       
   220 # define FAMILY_ID_SHIFT 8
       
   221 # define FAMILY_ID_MASK 0xf
       
   222   /* Bits 23 through 20 is extended family processor id */
       
   223 # define EXT_FAMILY_ID_SHIFT 20
       
   224 # define EXT_FAMILY_ID_MASK 0xf
       
   225   /* Pentium 4 family processor id */
       
   226 # define PENTIUM4_FAMILY_ID 0xf
       
   227   /* Bit 28 indicates Hyper-Threading Technology support */
       
   228 # define HT_BIT_SHIFT 28
       
   229 # define HT_BIT_MASK 1
       
   230   uint32_t vendor_id[3] = { 0U, 0U, 0U };
       
   231   uint32_t value_of_eax = 0U;
       
   232   uint32_t value_of_edx = 0U;
       
   233   uint32_t dummy        = 0U;
       
   234 
       
   235   /* Yes, this is supposed to be [0], [2], [1] */
       
   236   get_cpuid(0, &dummy, &vendor_id[0], &vendor_id[2], &vendor_id[1]);
       
   237   JLI_TraceLauncher("vendor: %c %c %c %c %c %c %c %c %c %c %c %c \n",
       
   238            ((vendor_id[0] >>  0) & 0xff),
       
   239            ((vendor_id[0] >>  8) & 0xff),
       
   240            ((vendor_id[0] >> 16) & 0xff),
       
   241            ((vendor_id[0] >> 24) & 0xff),
       
   242            ((vendor_id[1] >>  0) & 0xff),
       
   243            ((vendor_id[1] >>  8) & 0xff),
       
   244            ((vendor_id[1] >> 16) & 0xff),
       
   245            ((vendor_id[1] >> 24) & 0xff),
       
   246            ((vendor_id[2] >>  0) & 0xff),
       
   247            ((vendor_id[2] >>  8) & 0xff),
       
   248            ((vendor_id[2] >> 16) & 0xff),
       
   249            ((vendor_id[2] >> 24) & 0xff));
       
   250   get_cpuid(1, &value_of_eax, &dummy, &dummy, &value_of_edx);
       
   251   JLI_TraceLauncher("value_of_eax: 0x%x  value_of_edx: 0x%x\n",
       
   252            value_of_eax, value_of_edx);
       
   253   if ((((value_of_eax >> FAMILY_ID_SHIFT) & FAMILY_ID_MASK) == PENTIUM4_FAMILY_ID) ||
       
   254       (((value_of_eax >> EXT_FAMILY_ID_SHIFT) & EXT_FAMILY_ID_MASK) != 0)) {
       
   255     if ((((vendor_id[0] >>  0) & 0xff) == 'G') &&
       
   256         (((vendor_id[0] >>  8) & 0xff) == 'e') &&
       
   257         (((vendor_id[0] >> 16) & 0xff) == 'n') &&
       
   258         (((vendor_id[0] >> 24) & 0xff) == 'u') &&
       
   259         (((vendor_id[1] >>  0) & 0xff) == 'i') &&
       
   260         (((vendor_id[1] >>  8) & 0xff) == 'n') &&
       
   261         (((vendor_id[1] >> 16) & 0xff) == 'e') &&
       
   262         (((vendor_id[1] >> 24) & 0xff) == 'I') &&
       
   263         (((vendor_id[2] >>  0) & 0xff) == 'n') &&
       
   264         (((vendor_id[2] >>  8) & 0xff) == 't') &&
       
   265         (((vendor_id[2] >> 16) & 0xff) == 'e') &&
       
   266         (((vendor_id[2] >> 24) & 0xff) == 'l')) {
       
   267       if (((value_of_edx >> HT_BIT_SHIFT) & HT_BIT_MASK) == HT_BIT_MASK) {
       
   268         JLI_TraceLauncher("Hyperthreading supported\n");
       
   269         result = hts_supported;
       
   270       } else {
       
   271         JLI_TraceLauncher("Hyperthreading not supported\n");
       
   272         result = hts_not_supported;
       
   273       }
       
   274     } else {
       
   275       JLI_TraceLauncher("Not GenuineIntel\n");
       
   276       result = hts_not_intel;
       
   277     }
       
   278   } else {
       
   279     JLI_TraceLauncher("not Pentium 4 or extended\n");
       
   280     result = hts_not_pentium4;
       
   281   }
       
   282   return result;
       
   283 }
       
   284 
       
   285 /* Determine how many logical processors there are per CPU */
       
   286 static unsigned int
       
   287 logical_processors_per_package(void) {
       
   288   /*
       
   289    * After CPUID with EAX==1, register EBX bits 23 through 16
       
   290    * indicate the number of logical processors per package
       
   291    */
       
   292 # define NUM_LOGICAL_SHIFT 16
       
   293 # define NUM_LOGICAL_MASK 0xff
       
   294   unsigned int result                        = 1U;
       
   295   const HyperThreadingSupport hyperthreading = hyperthreading_support();
       
   296 
       
   297   if (hyperthreading == hts_supported) {
       
   298     uint32_t value_of_ebx = 0U;
       
   299     uint32_t dummy        = 0U;
       
   300 
       
   301     get_cpuid(1, &dummy, &value_of_ebx, &dummy, &dummy);
       
   302     result = (value_of_ebx >> NUM_LOGICAL_SHIFT) & NUM_LOGICAL_MASK;
       
   303     JLI_TraceLauncher("logical processors per package: %u\n", result);
       
   304   }
       
   305   return result;
       
   306 }
       
   307 
       
   308 /* Compute the number of physical processors, not logical processors */
       
   309 static unsigned long
       
   310 physical_processors(void) {
       
   311   const long sys_processors = sysconf(_SC_NPROCESSORS_CONF);
       
   312   unsigned long result      = sys_processors;
       
   313 
       
   314   JLI_TraceLauncher("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors);
       
   315   if (sys_processors > 1) {
       
   316     unsigned int logical_processors = logical_processors_per_package();
       
   317     if (logical_processors > 1) {
       
   318       result = (unsigned long) sys_processors / logical_processors;
       
   319     }
       
   320   }
       
   321   JLI_TraceLauncher("physical processors: %lu\n", result);
       
   322   return result;
       
   323 }