mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-20 19:14:38 +02:00
8056124: Hotspot should use PICL interface to get cacheline size on SPARC
Using libpicl to get L1 data and L2 cache line sizes Reviewed-by: kvn, roland, morris
This commit is contained in:
parent
35bca0df61
commit
5db7b3a4e1
4 changed files with 149 additions and 53 deletions
|
@ -143,7 +143,7 @@ else
|
|||
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
|
||||
|
|
|
@ -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 @@ void VM_Version::initialize() {
|
|||
}
|
||||
|
||||
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 @@ void VM_Version::initialize() {
|
|||
}
|
||||
|
||||
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 @@ void VM_Version::initialize() {
|
|||
// 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 @@ void VM_Version::initialize() {
|
|||
#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");
|
||||
|
|
|
@ -96,6 +96,9 @@ protected:
|
|||
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 @@ public:
|
|||
|
||||
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() {
|
||||
|
|
|
@ -32,6 +32,136 @@
|
|||
#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 @@ int VM_Version::platform_features(int features) {
|
|||
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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue