src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp

Mon, 08 Sep 2014 18:11:37 -0700

author
iveresov
date
Mon, 08 Sep 2014 18:11:37 -0700
changeset 7135
d635fd1ac81c
parent 7027
b20a35eae442
child 7296
c49cd31b6da6
permissions
-rw-r--r--

8056124: Hotspot should use PICL interface to get cacheline size on SPARC
Summary: Using libpicl to get L1 data and L2 cache line sizes
Reviewed-by: kvn, roland, morris

     1 /*
     2  * Copyright (c) 2006, 2014, 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.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  *
    23  */
    25 #include "precompiled.hpp"
    26 #include "runtime/os.hpp"
    27 #include "vm_version_sparc.hpp"
    29 #include <sys/auxv.h>
    30 #include <sys/auxv_SPARC.h>
    31 #include <sys/systeminfo.h>
    32 #include <kstat.h>
    33 #include <picl.h>
    35 extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result);
    36 extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result);
    38 class PICL {
    39   // Get a value of the integer property. The value in the tree can be either 32 or 64 bit
    40   // depending on the platform. The result is converted to int.
    41   static int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) {
    42     picl_propinfo_t pinfo;
    43     picl_prophdl_t proph;
    44     if (picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS ||
    45         picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) {
    46       return PICL_FAILURE;
    47     }
    49     if (pinfo.type != PICL_PTYPE_INT && pinfo.type != PICL_PTYPE_UNSIGNED_INT) {
    50       assert(false, "Invalid property type");
    51       return PICL_FAILURE;
    52     }
    53     if (pinfo.size == sizeof(int64_t)) {
    54       int64_t val;
    55       if (picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) {
    56         return PICL_FAILURE;
    57       }
    58       *result = static_cast<int>(val);
    59     } else if (pinfo.size == sizeof(int32_t)) {
    60       int32_t val;
    61       if (picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) {
    62         return PICL_FAILURE;
    63       }
    64       *result = static_cast<int>(val);
    65     } else {
    66       assert(false, "Unexpected integer property size");
    67       return PICL_FAILURE;
    68     }
    69     return PICL_SUCCESS;
    70   }
    72   // Visitor and a state machine that visits integer properties and verifies that the
    73   // values are the same. Stores the unique value observed.
    74   class UniqueValueVisitor {
    75     enum {
    76       INITIAL,        // Start state, no assignments happened
    77       ASSIGNED,       // Assigned a value
    78       INCONSISTENT    // Inconsistent value seen
    79     } _state;
    80     int _value;
    81   public:
    82     UniqueValueVisitor() : _state(INITIAL) { }
    83     int value() {
    84       assert(_state == ASSIGNED, "Precondition");
    85       return _value;
    86     }
    87     void set_value(int value) {
    88       assert(_state == INITIAL, "Precondition");
    89       _value = value;
    90       _state = ASSIGNED;
    91     }
    92     bool is_initial()       { return _state == INITIAL;      }
    93     bool is_assigned()      { return _state == ASSIGNED;     }
    94     bool is_inconsistent()  { return _state == INCONSISTENT; }
    95     void set_inconsistent() { _state = INCONSISTENT;         }
    97     static int visit(picl_nodehdl_t nodeh, const char* name, void *arg) {
    98       UniqueValueVisitor *state = static_cast<UniqueValueVisitor*>(arg);
    99       assert(!state->is_inconsistent(), "Precondition");
   100       int curr;
   101       if (PICL::get_int_property(nodeh, name, &curr) == PICL_SUCCESS) {
   102         if (!state->is_assigned()) { // first iteration
   103           state->set_value(curr);
   104         } else if (curr != state->value()) { // following iterations
   105           state->set_inconsistent();
   106         }
   107       }
   108       if (state->is_inconsistent()) {
   109         return PICL_WALK_TERMINATE;
   110       }
   111       return PICL_WALK_CONTINUE;
   112     }
   113   };
   115   int _L1_data_cache_line_size;
   116   int _L2_cache_line_size;
   117 public:
   118   static int get_l1_data_cache_line_size(picl_nodehdl_t nodeh, void *state) {
   119     return UniqueValueVisitor::visit(nodeh, "l1-dcache-line-size", state);
   120   }
   121   static int get_l2_cache_line_size(picl_nodehdl_t nodeh, void *state) {
   122     return UniqueValueVisitor::visit(nodeh, "l2-cache-line-size", state);
   123   }
   125   PICL() : _L1_data_cache_line_size(0), _L2_cache_line_size(0) {
   126     if (picl_initialize() == PICL_SUCCESS) {
   127       picl_nodehdl_t rooth;
   128       if (picl_get_root(&rooth) == PICL_SUCCESS) {
   129         UniqueValueVisitor L1_state;
   130         // Visit all "cpu" class instances
   131         picl_walk_tree_by_class(rooth, "cpu", &L1_state, PICL_get_l1_data_cache_line_size_helper);
   132         if (L1_state.is_initial()) { // Still initial, iteration found no values
   133           // Try walk all "core" class instances, it might be a Fujitsu machine
   134           picl_walk_tree_by_class(rooth, "core", &L1_state, PICL_get_l1_data_cache_line_size_helper);
   135         }
   136         if (L1_state.is_assigned()) { // Is there a value?
   137           _L1_data_cache_line_size = L1_state.value();
   138         }
   140         UniqueValueVisitor L2_state;
   141         picl_walk_tree_by_class(rooth, "cpu", &L2_state, PICL_get_l2_cache_line_size_helper);
   142         if (L2_state.is_initial()) {
   143           picl_walk_tree_by_class(rooth, "core", &L2_state, PICL_get_l2_cache_line_size_helper);
   144         }
   145         if (L2_state.is_assigned()) {
   146           _L2_cache_line_size = L2_state.value();
   147         }
   148       }
   149       picl_shutdown();
   150     }
   151   }
   153   unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; }
   154   unsigned int L2_cache_line_size() const      { return _L2_cache_line_size;      }
   155 };
   157 extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) {
   158   return PICL::get_l1_data_cache_line_size(nodeh, result);
   159 }
   160 extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) {
   161   return PICL::get_l2_cache_line_size(nodeh, result);
   162 }
   164 // We need to keep these here as long as we have to build on Solaris
   165 // versions before 10.
   166 #ifndef SI_ARCHITECTURE_32
   167 #define SI_ARCHITECTURE_32      516     /* basic 32-bit SI_ARCHITECTURE */
   168 #endif
   170 #ifndef SI_ARCHITECTURE_64
   171 #define SI_ARCHITECTURE_64      517     /* basic 64-bit SI_ARCHITECTURE */
   172 #endif
   174 static void do_sysinfo(int si, const char* string, int* features, int mask) {
   175   char   tmp;
   176   size_t bufsize = sysinfo(si, &tmp, 1);
   178   // All SI defines used below must be supported.
   179   guarantee(bufsize != -1, "must be supported");
   181   char* buf = (char*) malloc(bufsize);
   183   if (buf == NULL)
   184     return;
   186   if (sysinfo(si, buf, bufsize) == bufsize) {
   187     // Compare the string.
   188     if (strcmp(buf, string) == 0) {
   189       *features |= mask;
   190     }
   191   }
   193   free(buf);
   194 }
   196 int VM_Version::platform_features(int features) {
   197   // getisax(2), SI_ARCHITECTURE_32, and SI_ARCHITECTURE_64 are
   198   // supported on Solaris 10 and later.
   199   if (os::Solaris::supports_getisax()) {
   201     // Check 32-bit architecture.
   202     do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m);
   204     // Check 64-bit architecture.
   205     do_sysinfo(SI_ARCHITECTURE_64, "sparcv9", &features, generic_v9_m);
   207     // Extract valid instruction set extensions.
   208     uint_t avs[2];
   209     uint_t avn = os::Solaris::getisax(avs, 2);
   210     assert(avn <= 2, "should return two or less av's");
   211     uint_t av = avs[0];
   213 #ifndef PRODUCT
   214     if (PrintMiscellaneous && Verbose) {
   215       tty->print("getisax(2) returned: " PTR32_FORMAT, av);
   216       if (avn > 1) {
   217         tty->print(", " PTR32_FORMAT, avs[1]);
   218       }
   219       tty->cr();
   220     }
   221 #endif
   223     if (av & AV_SPARC_MUL32)  features |= hardware_mul32_m;
   224     if (av & AV_SPARC_DIV32)  features |= hardware_div32_m;
   225     if (av & AV_SPARC_FSMULD) features |= hardware_fsmuld_m;
   226     if (av & AV_SPARC_V8PLUS) features |= v9_instructions_m;
   227     if (av & AV_SPARC_POPC)   features |= hardware_popc_m;
   228     if (av & AV_SPARC_VIS)    features |= vis1_instructions_m;
   229     if (av & AV_SPARC_VIS2)   features |= vis2_instructions_m;
   230     if (avn > 1) {
   231       uint_t av2 = avs[1];
   232 #ifndef AV2_SPARC_SPARC5
   233 #define AV2_SPARC_SPARC5 0x00000008 /* The 29 new fp and sub instructions */
   234 #endif
   235       if (av2 & AV2_SPARC_SPARC5)       features |= sparc5_instructions_m;
   236     }
   238     // Next values are not defined before Solaris 10
   239     // but Solaris 8 is used for jdk6 update builds.
   240 #ifndef AV_SPARC_ASI_BLK_INIT
   241 #define AV_SPARC_ASI_BLK_INIT 0x0080  /* ASI_BLK_INIT_xxx ASI */
   242 #endif
   243     if (av & AV_SPARC_ASI_BLK_INIT) features |= blk_init_instructions_m;
   245 #ifndef AV_SPARC_FMAF
   246 #define AV_SPARC_FMAF 0x0100        /* Fused Multiply-Add */
   247 #endif
   248     if (av & AV_SPARC_FMAF)         features |= fmaf_instructions_m;
   250 #ifndef AV_SPARC_FMAU
   251 #define    AV_SPARC_FMAU    0x0200  /* Unfused Multiply-Add */
   252 #endif
   253     if (av & AV_SPARC_FMAU)         features |= fmau_instructions_m;
   255 #ifndef AV_SPARC_VIS3
   256 #define    AV_SPARC_VIS3    0x0400  /* VIS3 instruction set extensions */
   257 #endif
   258     if (av & AV_SPARC_VIS3)         features |= vis3_instructions_m;
   260 #ifndef AV_SPARC_CBCOND
   261 #define AV_SPARC_CBCOND 0x10000000  /* compare and branch instrs supported */
   262 #endif
   263     if (av & AV_SPARC_CBCOND)       features |= cbcond_instructions_m;
   265 #ifndef AV_SPARC_AES
   266 #define AV_SPARC_AES 0x00020000  /* aes instrs supported */
   267 #endif
   268     if (av & AV_SPARC_AES)       features |= aes_instructions_m;
   270 #ifndef AV_SPARC_SHA1
   271 #define AV_SPARC_SHA1   0x00400000  /* sha1 instruction supported */
   272 #endif
   273     if (av & AV_SPARC_SHA1)         features |= sha1_instruction_m;
   275 #ifndef AV_SPARC_SHA256
   276 #define AV_SPARC_SHA256 0x00800000  /* sha256 instruction supported */
   277 #endif
   278     if (av & AV_SPARC_SHA256)       features |= sha256_instruction_m;
   280 #ifndef AV_SPARC_SHA512
   281 #define AV_SPARC_SHA512 0x01000000  /* sha512 instruction supported */
   282 #endif
   283     if (av & AV_SPARC_SHA512)       features |= sha512_instruction_m;
   285   } else {
   286     // getisax(2) failed, use the old legacy code.
   287 #ifndef PRODUCT
   288     if (PrintMiscellaneous && Verbose)
   289       tty->print_cr("getisax(2) is not supported.");
   290 #endif
   292     char   tmp;
   293     size_t bufsize = sysinfo(SI_ISALIST, &tmp, 1);
   294     char*  buf     = (char*) malloc(bufsize);
   296     if (buf != NULL) {
   297       if (sysinfo(SI_ISALIST, buf, bufsize) == bufsize) {
   298         // Figure out what kind of sparc we have
   299         char *sparc_string = strstr(buf, "sparc");
   300         if (sparc_string != NULL) {              features |= v8_instructions_m;
   301           if (sparc_string[5] == 'v') {
   302             if (sparc_string[6] == '8') {
   303               if (sparc_string[7] == '-') {      features |= hardware_mul32_m;
   304                                                  features |= hardware_div32_m;
   305               } else if (sparc_string[7] == 'p') features |= generic_v9_m;
   306               else                               features |= generic_v8_m;
   307             } else if (sparc_string[6] == '9')   features |= generic_v9_m;
   308           }
   309         }
   311         // Check for visualization instructions
   312         char *vis = strstr(buf, "vis");
   313         if (vis != NULL) {                       features |= vis1_instructions_m;
   314           if (vis[3] == '2')                     features |= vis2_instructions_m;
   315         }
   316       }
   317       free(buf);
   318     }
   319   }
   321   // Determine the machine type.
   322   do_sysinfo(SI_MACHINE, "sun4v", &features, sun4v_m);
   324   {
   325     // Using kstat to determine the machine type.
   326     kstat_ctl_t* kc = kstat_open();
   327     kstat_t* ksp = kstat_lookup(kc, (char*)"cpu_info", -1, NULL);
   328     const char* implementation = "UNKNOWN";
   329     if (ksp != NULL) {
   330       if (kstat_read(kc, ksp, NULL) != -1 && ksp->ks_data != NULL) {
   331         kstat_named_t* knm = (kstat_named_t *)ksp->ks_data;
   332         for (int i = 0; i < ksp->ks_ndata; i++) {
   333           if (strcmp((const char*)&(knm[i].name),"implementation") == 0) {
   334 #ifndef KSTAT_DATA_STRING
   335 #define KSTAT_DATA_STRING   9
   336 #endif
   337             if (knm[i].data_type == KSTAT_DATA_CHAR) {
   338               // VM is running on Solaris 8 which does not have value.str.
   339               implementation = &(knm[i].value.c[0]);
   340             } else if (knm[i].data_type == KSTAT_DATA_STRING) {
   341               // VM is running on Solaris 10.
   342 #ifndef KSTAT_NAMED_STR_PTR
   343               // Solaris 8 was used to build VM, define the structure it misses.
   344               struct str_t {
   345                 union {
   346                   char *ptr;     /* NULL-term string */
   347                   char __pad[8]; /* 64-bit padding */
   348                 } addr;
   349                 uint32_t len;    /* # bytes for strlen + '\0' */
   350               };
   351 #define KSTAT_NAMED_STR_PTR(knptr) (( (str_t*)&((knptr)->value) )->addr.ptr)
   352 #endif
   353               implementation = KSTAT_NAMED_STR_PTR(&knm[i]);
   354             }
   355 #ifndef PRODUCT
   356             if (PrintMiscellaneous && Verbose) {
   357               tty->print_cr("cpu_info.implementation: %s", implementation);
   358             }
   359 #endif
   360             // Convert to UPPER case before compare.
   361             char* impl = strdup(implementation);
   363             for (int i = 0; impl[i] != 0; i++)
   364               impl[i] = (char)toupper((uint)impl[i]);
   365             if (strstr(impl, "SPARC64") != NULL) {
   366               features |= sparc64_family_m;
   367             } else if (strstr(impl, "SPARC-M") != NULL) {
   368               // M-series SPARC is based on T-series.
   369               features |= (M_family_m | T_family_m);
   370             } else if (strstr(impl, "SPARC-T") != NULL) {
   371               features |= T_family_m;
   372               if (strstr(impl, "SPARC-T1") != NULL) {
   373                 features |= T1_model_m;
   374               }
   375             } else {
   376               if (strstr(impl, "SPARC") == NULL) {
   377 #ifndef PRODUCT
   378                 // kstat on Solaris 8 virtual machines (branded zones)
   379                 // returns "(unsupported)" implementation.
   380                 warning("kstat cpu_info implementation = '%s', should contain SPARC", impl);
   381 #endif
   382                 implementation = "SPARC";
   383               }
   384             }
   385             free((void*)impl);
   386             break;
   387           }
   388         } // for(
   389       }
   390     }
   391     assert(strcmp(implementation, "UNKNOWN") != 0,
   392            "unknown cpu info (changed kstat interface?)");
   393     kstat_close(kc);
   394   }
   396   // Figure out cache line sizes using PICL
   397   PICL picl;
   398   _L2_cache_line_size      = picl.L2_cache_line_size();
   400   return features;
   401 }

mercurial