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
--- a/hotspot/make/solaris/makefiles/vm.make Fri Sep 05 16:07:22 2014 +0200
+++ b/hotspot/make/solaris/makefiles/vm.make Fri Sep 05 11:23:47 2014 -0700
@@ -143,7 +143,7 @@
LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle
endif # sparcWorks
-LIBS += -lkstat
+LIBS += -lkstat -lpicl
# By default, link the *.o into the library, not the executable.
LINK_INTO$(LINK_INTO) = LIBJVM
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Fri Sep 05 16:07:22 2014 +0200
+++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Fri Sep 05 11:23:47 2014 -0700
@@ -32,6 +32,7 @@
int VM_Version::_features = VM_Version::unknown_m;
const char* VM_Version::_features_str = "";
+unsigned int VM_Version::_L2_cache_line_size = 0;
void VM_Version::initialize() {
_features = determine_features();
@@ -192,7 +193,7 @@
}
assert(BlockZeroingLowLimit > 0, "invalid value");
- if (has_block_zeroing()) {
+ if (has_block_zeroing() && cache_line_size > 0) {
if (FLAG_IS_DEFAULT(UseBlockZeroing)) {
FLAG_SET_DEFAULT(UseBlockZeroing, true);
}
@@ -202,7 +203,7 @@
}
assert(BlockCopyLowLimit > 0, "invalid value");
- if (has_block_zeroing()) { // has_blk_init() && is_T4(): core's local L2 cache
+ if (has_block_zeroing() && cache_line_size > 0) { // has_blk_init() && is_T4(): core's local L2 cache
if (FLAG_IS_DEFAULT(UseBlockCopy)) {
FLAG_SET_DEFAULT(UseBlockCopy, true);
}
@@ -252,49 +253,6 @@
// buf is started with ", " or is empty
_features_str = os::strdup(strlen(buf) > 2 ? buf + 2 : buf);
- // There are three 64-bit SPARC families that do not overlap, e.g.,
- // both is_ultra3() and is_sparc64() cannot be true at the same time.
- // Within these families, there can be more than one chip, e.g.,
- // is_T4() and is_T7() machines are also is_niagara().
- if (is_ultra3()) {
- assert(_L1_data_cache_line_size == 0, "overlap with Ultra3 family");
- // Ref: UltraSPARC III Cu Processor
- _L1_data_cache_line_size = 64;
- }
- if (is_niagara()) {
- assert(_L1_data_cache_line_size == 0, "overlap with niagara family");
- // All Niagara's are sun4v's, but not all sun4v's are Niagaras, e.g.,
- // Fujitsu SPARC64 is sun4v, but we don't want it in this block.
- //
- // Ref: UltraSPARC T1 Supplement to the UltraSPARC Architecture 2005
- // Appendix F.1.3.1 Cacheable Accesses
- // -> 16-byte L1 cache line size
- //
- // Ref: UltraSPARC T2: A Highly-Threaded, Power-Efficient, SPARC SOC
- // Section III: SPARC Processor Core
- // -> 16-byte L1 cache line size
- //
- // Ref: Oracle's SPARC T4-1, SPARC T4-2, SPARC T4-4, and SPARC T4-1B Server Architecture
- // Section SPARC T4 Processor Cache Architecture
- // -> 32-byte L1 cache line size (no longer see that info on this ref)
- //
- // XXX - still need a T7 reference here
- //
- if (is_T7()) { // T7 or newer
- _L1_data_cache_line_size = 64;
- } else if (is_T4()) { // T4 or newer (until T7)
- _L1_data_cache_line_size = 32;
- } else { // T1 or newer (until T4)
- _L1_data_cache_line_size = 16;
- }
- }
- if (is_sparc64()) {
- guarantee(_L1_data_cache_line_size == 0, "overlap with SPARC64 family");
- // Ref: Fujitsu SPARC64 VII Processor
- // Section 4 Cache System
- _L1_data_cache_line_size = 64;
- }
-
// UseVIS is set to the smallest of what hardware supports and what
// the command line requires. I.e., you cannot set UseVIS to 3 on
// older UltraSparc which do not support it.
@@ -401,6 +359,7 @@
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose) {
tty->print_cr("L1 data cache line size: %u", L1_data_cache_line_size());
+ tty->print_cr("L2 cache line size: %u", L2_cache_line_size());
tty->print("Allocation");
if (AllocatePrefetchStyle <= 0) {
tty->print_cr(": no prefetching");
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Fri Sep 05 16:07:22 2014 +0200
+++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Fri Sep 05 11:23:47 2014 -0700
@@ -96,6 +96,9 @@
static int _features;
static const char* _features_str;
+ static unsigned int _L2_cache_line_size;
+ static unsigned int L2_cache_line_size() { return _L2_cache_line_size; }
+
static void print_features();
static int determine_features();
static int platform_features(int features);
@@ -167,9 +170,8 @@
static const char* cpu_features() { return _features_str; }
- static intx prefetch_data_size() {
- return is_T4() && !is_T7() ? 32 : 64; // default prefetch block size on sparc
- }
+ // default prefetch block size on sparc
+ static intx prefetch_data_size() { return L2_cache_line_size(); }
// Prefetch
static intx prefetch_copy_interval_in_bytes() {
--- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Fri Sep 05 16:07:22 2014 +0200
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Fri Sep 05 11:23:47 2014 -0700
@@ -28,10 +28,140 @@
#include "runtime/os.hpp"
#include "vm_version_sparc.hpp"
-# include <sys/auxv.h>
-# include <sys/auxv_SPARC.h>
-# include <sys/systeminfo.h>
-# include <kstat.h>
+#include <sys/auxv.h>
+#include <sys/auxv_SPARC.h>
+#include <sys/systeminfo.h>
+#include <kstat.h>
+#include <picl.h>
+
+extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result);
+extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result);
+
+class PICL {
+ // Get a value of the integer property. The value in the tree can be either 32 or 64 bit
+ // depending on the platform. The result is converted to int.
+ static int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) {
+ picl_propinfo_t pinfo;
+ picl_prophdl_t proph;
+ if (picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS ||
+ picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) {
+ return PICL_FAILURE;
+ }
+
+ if (pinfo.type != PICL_PTYPE_INT && pinfo.type != PICL_PTYPE_UNSIGNED_INT) {
+ assert(false, "Invalid property type");
+ return PICL_FAILURE;
+ }
+ if (pinfo.size == sizeof(int64_t)) {
+ int64_t val;
+ if (picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) {
+ return PICL_FAILURE;
+ }
+ *result = static_cast<int>(val);
+ } else if (pinfo.size == sizeof(int32_t)) {
+ int32_t val;
+ if (picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) {
+ return PICL_FAILURE;
+ }
+ *result = static_cast<int>(val);
+ } else {
+ assert(false, "Unexpected integer property size");
+ return PICL_FAILURE;
+ }
+ return PICL_SUCCESS;
+ }
+
+ // Visitor and a state machine that visits integer properties and verifies that the
+ // values are the same. Stores the unique value observed.
+ class UniqueValueVisitor {
+ enum {
+ INITIAL, // Start state, no assignments happened
+ ASSIGNED, // Assigned a value
+ INCONSISTENT // Inconsistent value seen
+ } _state;
+ int _value;
+ public:
+ UniqueValueVisitor() : _state(INITIAL) { }
+ int value() {
+ assert(_state == ASSIGNED, "Precondition");
+ return _value;
+ }
+ void set_value(int value) {
+ assert(_state == INITIAL, "Precondition");
+ _value = value;
+ _state = ASSIGNED;
+ }
+ bool is_initial() { return _state == INITIAL; }
+ bool is_assigned() { return _state == ASSIGNED; }
+ bool is_inconsistent() { return _state == INCONSISTENT; }
+ void set_inconsistent() { _state = INCONSISTENT; }
+
+ static int visit(picl_nodehdl_t nodeh, const char* name, void *arg) {
+ UniqueValueVisitor *state = static_cast<UniqueValueVisitor*>(arg);
+ assert(!state->is_inconsistent(), "Precondition");
+ int curr;
+ if (PICL::get_int_property(nodeh, name, &curr) == PICL_SUCCESS) {
+ if (!state->is_assigned()) { // first iteration
+ state->set_value(curr);
+ } else if (curr != state->value()) { // following iterations
+ state->set_inconsistent();
+ }
+ }
+ if (state->is_inconsistent()) {
+ return PICL_WALK_TERMINATE;
+ }
+ return PICL_WALK_CONTINUE;
+ }
+ };
+
+ int _L1_data_cache_line_size;
+ int _L2_cache_line_size;
+public:
+ static int get_l1_data_cache_line_size(picl_nodehdl_t nodeh, void *state) {
+ return UniqueValueVisitor::visit(nodeh, "l1-dcache-line-size", state);
+ }
+ static int get_l2_cache_line_size(picl_nodehdl_t nodeh, void *state) {
+ return UniqueValueVisitor::visit(nodeh, "l2-cache-line-size", state);
+ }
+
+ PICL() : _L1_data_cache_line_size(0), _L2_cache_line_size(0) {
+ if (picl_initialize() == PICL_SUCCESS) {
+ picl_nodehdl_t rooth;
+ if (picl_get_root(&rooth) == PICL_SUCCESS) {
+ UniqueValueVisitor L1_state;
+ // Visit all "cpu" class instances
+ picl_walk_tree_by_class(rooth, "cpu", &L1_state, PICL_get_l1_data_cache_line_size_helper);
+ if (L1_state.is_initial()) { // Still initial, iteration found no values
+ // Try walk all "core" class instances, it might be a Fujitsu machine
+ picl_walk_tree_by_class(rooth, "core", &L1_state, PICL_get_l1_data_cache_line_size_helper);
+ }
+ if (L1_state.is_assigned()) { // Is there a value?
+ _L1_data_cache_line_size = L1_state.value();
+ }
+
+ UniqueValueVisitor L2_state;
+ picl_walk_tree_by_class(rooth, "cpu", &L2_state, PICL_get_l2_cache_line_size_helper);
+ if (L2_state.is_initial()) {
+ picl_walk_tree_by_class(rooth, "core", &L2_state, PICL_get_l2_cache_line_size_helper);
+ }
+ if (L2_state.is_assigned()) {
+ _L2_cache_line_size = L2_state.value();
+ }
+ }
+ picl_shutdown();
+ }
+ }
+
+ unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; }
+ unsigned int L2_cache_line_size() const { return _L2_cache_line_size; }
+};
+
+extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) {
+ return PICL::get_l1_data_cache_line_size(nodeh, result);
+}
+extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) {
+ return PICL::get_l2_cache_line_size(nodeh, result);
+}
// We need to keep these here as long as we have to build on Solaris
// versions before 10.
@@ -211,5 +341,10 @@
kstat_close(kc);
}
+ // Figure out cache line sizes using PICL
+ PICL picl;
+ _L1_data_cache_line_size = picl.L1_data_cache_line_size();
+ _L2_cache_line_size = picl.L2_cache_line_size();
+
return features;
}