Mon, 08 Sep 2014 18:11:37 -0700
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.1 --- a/make/solaris/makefiles/vm.make Mon Sep 08 23:01:01 2014 +0000 1.2 +++ b/make/solaris/makefiles/vm.make Mon Sep 08 18:11:37 2014 -0700 1.3 @@ -141,7 +141,7 @@ 1.4 LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle 1.5 endif # sparcWorks 1.6 1.7 -LIBS += -lkstat 1.8 +LIBS += -lkstat -lpicl 1.9 1.10 # By default, link the *.o into the library, not the executable. 1.11 LINK_INTO$(LINK_INTO) = LIBJVM
2.1 --- a/src/cpu/sparc/vm/vm_version_sparc.cpp Mon Sep 08 23:01:01 2014 +0000 2.2 +++ b/src/cpu/sparc/vm/vm_version_sparc.cpp Mon Sep 08 18:11:37 2014 -0700 2.3 @@ -37,6 +37,7 @@ 2.4 2.5 int VM_Version::_features = VM_Version::unknown_m; 2.6 const char* VM_Version::_features_str = ""; 2.7 +unsigned int VM_Version::_L2_cache_line_size = 0; 2.8 2.9 void VM_Version::initialize() { 2.10 _features = determine_features(); 2.11 @@ -197,7 +198,7 @@ 2.12 } 2.13 2.14 assert(BlockZeroingLowLimit > 0, "invalid value"); 2.15 - if (has_block_zeroing()) { 2.16 + if (has_block_zeroing() && cache_line_size > 0) { 2.17 if (FLAG_IS_DEFAULT(UseBlockZeroing)) { 2.18 FLAG_SET_DEFAULT(UseBlockZeroing, true); 2.19 } 2.20 @@ -207,7 +208,7 @@ 2.21 } 2.22 2.23 assert(BlockCopyLowLimit > 0, "invalid value"); 2.24 - if (has_block_zeroing()) { // has_blk_init() && is_T4(): core's local L2 cache 2.25 + if (has_block_zeroing() && cache_line_size > 0) { // has_blk_init() && is_T4(): core's local L2 cache 2.26 if (FLAG_IS_DEFAULT(UseBlockCopy)) { 2.27 FLAG_SET_DEFAULT(UseBlockCopy, true); 2.28 } 2.29 @@ -362,6 +363,7 @@ 2.30 2.31 #ifndef PRODUCT 2.32 if (PrintMiscellaneous && Verbose) { 2.33 + tty->print_cr("L2 cache line size: %u", L2_cache_line_size()); 2.34 tty->print("Allocation"); 2.35 if (AllocatePrefetchStyle <= 0) { 2.36 tty->print_cr(": no prefetching");
3.1 --- a/src/cpu/sparc/vm/vm_version_sparc.hpp Mon Sep 08 23:01:01 2014 +0000 3.2 +++ b/src/cpu/sparc/vm/vm_version_sparc.hpp Mon Sep 08 18:11:37 2014 -0700 3.3 @@ -96,6 +96,9 @@ 3.4 static int _features; 3.5 static const char* _features_str; 3.6 3.7 + static unsigned int _L2_cache_line_size; 3.8 + static unsigned int L2_cache_line_size() { return _L2_cache_line_size; } 3.9 + 3.10 static void print_features(); 3.11 static int determine_features(); 3.12 static int platform_features(int features); 3.13 @@ -167,9 +170,8 @@ 3.14 3.15 static const char* cpu_features() { return _features_str; } 3.16 3.17 - static intx prefetch_data_size() { 3.18 - return is_T4() && !is_T7() ? 32 : 64; // default prefetch block size on sparc 3.19 - } 3.20 + // default prefetch block size on sparc 3.21 + static intx prefetch_data_size() { return L2_cache_line_size(); } 3.22 3.23 // Prefetch 3.24 static intx prefetch_copy_interval_in_bytes() {
4.1 --- a/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Mon Sep 08 23:01:01 2014 +0000 4.2 +++ b/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Mon Sep 08 18:11:37 2014 -0700 4.3 @@ -26,10 +26,140 @@ 4.4 #include "runtime/os.hpp" 4.5 #include "vm_version_sparc.hpp" 4.6 4.7 -# include <sys/auxv.h> 4.8 -# include <sys/auxv_SPARC.h> 4.9 -# include <sys/systeminfo.h> 4.10 -# include <kstat.h> 4.11 +#include <sys/auxv.h> 4.12 +#include <sys/auxv_SPARC.h> 4.13 +#include <sys/systeminfo.h> 4.14 +#include <kstat.h> 4.15 +#include <picl.h> 4.16 + 4.17 +extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result); 4.18 +extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result); 4.19 + 4.20 +class PICL { 4.21 + // Get a value of the integer property. The value in the tree can be either 32 or 64 bit 4.22 + // depending on the platform. The result is converted to int. 4.23 + static int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) { 4.24 + picl_propinfo_t pinfo; 4.25 + picl_prophdl_t proph; 4.26 + if (picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS || 4.27 + picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) { 4.28 + return PICL_FAILURE; 4.29 + } 4.30 + 4.31 + if (pinfo.type != PICL_PTYPE_INT && pinfo.type != PICL_PTYPE_UNSIGNED_INT) { 4.32 + assert(false, "Invalid property type"); 4.33 + return PICL_FAILURE; 4.34 + } 4.35 + if (pinfo.size == sizeof(int64_t)) { 4.36 + int64_t val; 4.37 + if (picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) { 4.38 + return PICL_FAILURE; 4.39 + } 4.40 + *result = static_cast<int>(val); 4.41 + } else if (pinfo.size == sizeof(int32_t)) { 4.42 + int32_t val; 4.43 + if (picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) { 4.44 + return PICL_FAILURE; 4.45 + } 4.46 + *result = static_cast<int>(val); 4.47 + } else { 4.48 + assert(false, "Unexpected integer property size"); 4.49 + return PICL_FAILURE; 4.50 + } 4.51 + return PICL_SUCCESS; 4.52 + } 4.53 + 4.54 + // Visitor and a state machine that visits integer properties and verifies that the 4.55 + // values are the same. Stores the unique value observed. 4.56 + class UniqueValueVisitor { 4.57 + enum { 4.58 + INITIAL, // Start state, no assignments happened 4.59 + ASSIGNED, // Assigned a value 4.60 + INCONSISTENT // Inconsistent value seen 4.61 + } _state; 4.62 + int _value; 4.63 + public: 4.64 + UniqueValueVisitor() : _state(INITIAL) { } 4.65 + int value() { 4.66 + assert(_state == ASSIGNED, "Precondition"); 4.67 + return _value; 4.68 + } 4.69 + void set_value(int value) { 4.70 + assert(_state == INITIAL, "Precondition"); 4.71 + _value = value; 4.72 + _state = ASSIGNED; 4.73 + } 4.74 + bool is_initial() { return _state == INITIAL; } 4.75 + bool is_assigned() { return _state == ASSIGNED; } 4.76 + bool is_inconsistent() { return _state == INCONSISTENT; } 4.77 + void set_inconsistent() { _state = INCONSISTENT; } 4.78 + 4.79 + static int visit(picl_nodehdl_t nodeh, const char* name, void *arg) { 4.80 + UniqueValueVisitor *state = static_cast<UniqueValueVisitor*>(arg); 4.81 + assert(!state->is_inconsistent(), "Precondition"); 4.82 + int curr; 4.83 + if (PICL::get_int_property(nodeh, name, &curr) == PICL_SUCCESS) { 4.84 + if (!state->is_assigned()) { // first iteration 4.85 + state->set_value(curr); 4.86 + } else if (curr != state->value()) { // following iterations 4.87 + state->set_inconsistent(); 4.88 + } 4.89 + } 4.90 + if (state->is_inconsistent()) { 4.91 + return PICL_WALK_TERMINATE; 4.92 + } 4.93 + return PICL_WALK_CONTINUE; 4.94 + } 4.95 + }; 4.96 + 4.97 + int _L1_data_cache_line_size; 4.98 + int _L2_cache_line_size; 4.99 +public: 4.100 + static int get_l1_data_cache_line_size(picl_nodehdl_t nodeh, void *state) { 4.101 + return UniqueValueVisitor::visit(nodeh, "l1-dcache-line-size", state); 4.102 + } 4.103 + static int get_l2_cache_line_size(picl_nodehdl_t nodeh, void *state) { 4.104 + return UniqueValueVisitor::visit(nodeh, "l2-cache-line-size", state); 4.105 + } 4.106 + 4.107 + PICL() : _L1_data_cache_line_size(0), _L2_cache_line_size(0) { 4.108 + if (picl_initialize() == PICL_SUCCESS) { 4.109 + picl_nodehdl_t rooth; 4.110 + if (picl_get_root(&rooth) == PICL_SUCCESS) { 4.111 + UniqueValueVisitor L1_state; 4.112 + // Visit all "cpu" class instances 4.113 + picl_walk_tree_by_class(rooth, "cpu", &L1_state, PICL_get_l1_data_cache_line_size_helper); 4.114 + if (L1_state.is_initial()) { // Still initial, iteration found no values 4.115 + // Try walk all "core" class instances, it might be a Fujitsu machine 4.116 + picl_walk_tree_by_class(rooth, "core", &L1_state, PICL_get_l1_data_cache_line_size_helper); 4.117 + } 4.118 + if (L1_state.is_assigned()) { // Is there a value? 4.119 + _L1_data_cache_line_size = L1_state.value(); 4.120 + } 4.121 + 4.122 + UniqueValueVisitor L2_state; 4.123 + picl_walk_tree_by_class(rooth, "cpu", &L2_state, PICL_get_l2_cache_line_size_helper); 4.124 + if (L2_state.is_initial()) { 4.125 + picl_walk_tree_by_class(rooth, "core", &L2_state, PICL_get_l2_cache_line_size_helper); 4.126 + } 4.127 + if (L2_state.is_assigned()) { 4.128 + _L2_cache_line_size = L2_state.value(); 4.129 + } 4.130 + } 4.131 + picl_shutdown(); 4.132 + } 4.133 + } 4.134 + 4.135 + unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; } 4.136 + unsigned int L2_cache_line_size() const { return _L2_cache_line_size; } 4.137 +}; 4.138 + 4.139 +extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) { 4.140 + return PICL::get_l1_data_cache_line_size(nodeh, result); 4.141 +} 4.142 +extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) { 4.143 + return PICL::get_l2_cache_line_size(nodeh, result); 4.144 +} 4.145 4.146 // We need to keep these here as long as we have to build on Solaris 4.147 // versions before 10. 4.148 @@ -263,5 +393,9 @@ 4.149 kstat_close(kc); 4.150 } 4.151 4.152 + // Figure out cache line sizes using PICL 4.153 + PICL picl; 4.154 + _L2_cache_line_size = picl.L2_cache_line_size(); 4.155 + 4.156 return features; 4.157 }