comparison src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp @ 22962:2ac41ee91b06

8062591: SPARC PICL causes significantly longer startup times Summary: Optimize traversals of the PICL tree Reviewed-by: kvn
author iveresov
date Fri, 10 Apr 2015 15:24:50 -0700
parents c49cd31b6da6
children f79d8e8caecb
comparison
equal deleted inserted replaced
22959:421863f11ad7 22962:2ac41ee91b06
32 #include <kstat.h> 32 #include <kstat.h>
33 #include <picl.h> 33 #include <picl.h>
34 #include <dlfcn.h> 34 #include <dlfcn.h>
35 #include <link.h> 35 #include <link.h>
36 36
37 extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result); 37 extern "C" static int PICL_visit_cpu_helper(picl_nodehdl_t nodeh, void *result);
38 extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result);
39 38
40 // Functions from the library we need (signatures should match those in picl.h) 39 // Functions from the library we need (signatures should match those in picl.h)
41 extern "C" { 40 extern "C" {
42 typedef int (*picl_initialize_func_t)(void); 41 typedef int (*picl_initialize_func_t)(void);
43 typedef int (*picl_shutdown_func_t)(void); 42 typedef int (*picl_shutdown_func_t)(void);
126 bool is_initial() { return _state == INITIAL; } 125 bool is_initial() { return _state == INITIAL; }
127 bool is_assigned() { return _state == ASSIGNED; } 126 bool is_assigned() { return _state == ASSIGNED; }
128 bool is_inconsistent() { return _state == INCONSISTENT; } 127 bool is_inconsistent() { return _state == INCONSISTENT; }
129 void set_inconsistent() { _state = INCONSISTENT; } 128 void set_inconsistent() { _state = INCONSISTENT; }
130 129
131 static int visit(picl_nodehdl_t nodeh, const char* name, void *arg) { 130 void visit(picl_nodehdl_t nodeh, const char* name) {
132 UniqueValueVisitor *state = static_cast<UniqueValueVisitor*>(arg); 131 assert(!is_inconsistent(), "Precondition");
133 PICL* picl = state->_picl;
134 assert(!state->is_inconsistent(), "Precondition");
135 int curr; 132 int curr;
136 if (picl->get_int_property(nodeh, name, &curr) == PICL_SUCCESS) { 133 if (_picl->get_int_property(nodeh, name, &curr) == PICL_SUCCESS) {
137 if (!state->is_assigned()) { // first iteration 134 if (!is_assigned()) { // first iteration
138 state->set_value(curr); 135 set_value(curr);
139 } else if (curr != state->value()) { // following iterations 136 } else if (curr != value()) { // following iterations
140 state->set_inconsistent(); 137 set_inconsistent();
141 } 138 }
142 } 139 }
143 if (state->is_inconsistent()) { 140 }
141 };
142
143 class CPUVisitor {
144 UniqueValueVisitor _l1_visitor;
145 UniqueValueVisitor _l2_visitor;
146 int _limit; // number of times visit() can be run
147 public:
148 CPUVisitor(PICL *picl, int limit) : _l1_visitor(picl), _l2_visitor(picl), _limit(limit) {}
149 static int visit(picl_nodehdl_t nodeh, void *arg) {
150 CPUVisitor *cpu_visitor = static_cast<CPUVisitor*>(arg);
151 UniqueValueVisitor* l1_visitor = cpu_visitor->l1_visitor();
152 UniqueValueVisitor* l2_visitor = cpu_visitor->l2_visitor();
153 if (!l1_visitor->is_inconsistent()) {
154 l1_visitor->visit(nodeh, "l1-dcache-line-size");
155 }
156 if (!l2_visitor->is_inconsistent()) {
157 l2_visitor->visit(nodeh, "l2-cache-line-size");
158 }
159
160 if (l1_visitor->is_inconsistent() && l2_visitor->is_inconsistent()) {
144 return PICL_WALK_TERMINATE; 161 return PICL_WALK_TERMINATE;
145 } 162 }
163 cpu_visitor->_limit--;
164 if (cpu_visitor->_limit <= 0) {
165 return PICL_WALK_TERMINATE;
166 }
146 return PICL_WALK_CONTINUE; 167 return PICL_WALK_CONTINUE;
147 } 168 }
169 UniqueValueVisitor* l1_visitor() { return &_l1_visitor; }
170 UniqueValueVisitor* l2_visitor() { return &_l2_visitor; }
148 }; 171 };
149
150 int _L1_data_cache_line_size; 172 int _L1_data_cache_line_size;
151 int _L2_cache_line_size; 173 int _L2_cache_line_size;
152 public: 174 public:
153 static int get_l1_data_cache_line_size(picl_nodehdl_t nodeh, void *state) { 175 static int visit_cpu(picl_nodehdl_t nodeh, void *state) {
154 return UniqueValueVisitor::visit(nodeh, "l1-dcache-line-size", state); 176 return CPUVisitor::visit(nodeh, state);
155 } 177 }
156 static int get_l2_cache_line_size(picl_nodehdl_t nodeh, void *state) { 178
157 return UniqueValueVisitor::visit(nodeh, "l2-cache-line-size", state); 179 PICL(bool is_fujitsu) : _L1_data_cache_line_size(0), _L2_cache_line_size(0), _dl_handle(NULL) {
158 }
159
160 PICL() : _L1_data_cache_line_size(0), _L2_cache_line_size(0), _dl_handle(NULL) {
161 if (!open_library()) { 180 if (!open_library()) {
162 return; 181 return;
163 } 182 }
164 if (_picl_initialize() == PICL_SUCCESS) { 183 if (_picl_initialize() == PICL_SUCCESS) {
165 picl_nodehdl_t rooth; 184 picl_nodehdl_t rooth;
166 if (_picl_get_root(&rooth) == PICL_SUCCESS) { 185 if (_picl_get_root(&rooth) == PICL_SUCCESS) {
167 UniqueValueVisitor L1_state(this); 186 const char* cpu_class = "cpu";
168 // Visit all "cpu" class instances 187 // If it's a Fujitsu machine, it's a "core"
169 _picl_walk_tree_by_class(rooth, "cpu", &L1_state, PICL_get_l1_data_cache_line_size_helper); 188 if (is_fujitsu) {
170 if (L1_state.is_initial()) { // Still initial, iteration found no values 189 cpu_class = "core";
171 // Try walk all "core" class instances, it might be a Fujitsu machine 190 }
172 _picl_walk_tree_by_class(rooth, "core", &L1_state, PICL_get_l1_data_cache_line_size_helper); 191 CPUVisitor cpu_visitor(this, os::processor_count());
173 } 192 _picl_walk_tree_by_class(rooth, cpu_class, &cpu_visitor, PICL_visit_cpu_helper);
174 if (L1_state.is_assigned()) { // Is there a value? 193 if (cpu_visitor.l1_visitor()->is_assigned()) { // Is there a value?
175 _L1_data_cache_line_size = L1_state.value(); 194 _L1_data_cache_line_size = cpu_visitor.l1_visitor()->value();
176 } 195 }
177 196 if (cpu_visitor.l2_visitor()->is_assigned()) {
178 UniqueValueVisitor L2_state(this); 197 _L2_cache_line_size = cpu_visitor.l2_visitor()->value();
179 _picl_walk_tree_by_class(rooth, "cpu", &L2_state, PICL_get_l2_cache_line_size_helper);
180 if (L2_state.is_initial()) {
181 _picl_walk_tree_by_class(rooth, "core", &L2_state, PICL_get_l2_cache_line_size_helper);
182 }
183 if (L2_state.is_assigned()) {
184 _L2_cache_line_size = L2_state.value();
185 } 198 }
186 } 199 }
187 _picl_shutdown(); 200 _picl_shutdown();
188 } 201 }
189 close_library(); 202 close_library();
191 204
192 unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; } 205 unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; }
193 unsigned int L2_cache_line_size() const { return _L2_cache_line_size; } 206 unsigned int L2_cache_line_size() const { return _L2_cache_line_size; }
194 }; 207 };
195 208
196 extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) { 209
197 return PICL::get_l1_data_cache_line_size(nodeh, result); 210 extern "C" static int PICL_visit_cpu_helper(picl_nodehdl_t nodeh, void *result) {
198 } 211 return PICL::visit_cpu(nodeh, result);
199 extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) {
200 return PICL::get_l2_cache_line_size(nodeh, result);
201 } 212 }
202 213
203 template<typename FuncType> 214 template<typename FuncType>
204 bool PICL::bind(FuncType& func, const char* name) { 215 bool PICL::bind(FuncType& func, const char* name) {
205 func = reinterpret_cast<FuncType>(dlsym(_dl_handle, name)); 216 func = reinterpret_cast<FuncType>(dlsym(_dl_handle, name));
468 "unknown cpu info (changed kstat interface?)"); 479 "unknown cpu info (changed kstat interface?)");
469 kstat_close(kc); 480 kstat_close(kc);
470 } 481 }
471 482
472 // Figure out cache line sizes using PICL 483 // Figure out cache line sizes using PICL
473 PICL picl; 484 PICL picl((features & sparc64_family_m) != 0);
474 _L2_cache_line_size = picl.L2_cache_line_size(); 485 _L2_cache_line_size = picl.L2_cache_line_size();
475 486
476 return features; 487 return features;
477 } 488 }