rev 56859 : 8233787: Break cycle in vm_version* includes
Reviewed-by:
1 /*
2 * Copyright (c) 2006, 2018, 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 */
24
25 #include "logging/log.hpp"
26 #include "precompiled.hpp"
27 #include "runtime/os.hpp"
28 #include "vm_version_sparc.hpp"
29
30
31 #define CPUINFO_LINE_SIZE 1024
32
33
34 class CPUinfo {
35 public:
36 CPUinfo(const char* field) : _string(NULL) {
37
38 char line[CPUINFO_LINE_SIZE];
39 FILE* fp = fopen("/proc/cpuinfo", "r");
40
41 if (fp != NULL) {
42 while (fgets(line, sizeof(line), fp) != NULL) {
43 assert(strlen(line) < sizeof(line) - 1,
44 "buffer too small (%d)", CPUINFO_LINE_SIZE);
45
46 const char* vstr = match_field(line, field);
47
48 if (vstr != NULL) {
49 // We have a matching line and a valid starting point to the value of
50 // the field, copy the string for keeps.
51 _string = strdup(vstr);
52 break;
53 }
54 }
55 fclose(fp);
56 }
57 }
58
59 ~CPUinfo() { free((void*)_string); }
60
61 const char* value() const { return _string; }
62
63 bool valid() const { return _string != NULL; }
64
65 bool match(const char* s) const {
66 return valid() ? strcmp(_string, s) == 0 : false;
67 }
68
69 private:
70 const char* _string;
71
72 const char* match_field(char line[CPUINFO_LINE_SIZE], const char* field);
73 const char* match_alo(const char* text, const char* exp);
74 const char* match_seq(const char* text, const char* seq);
75 };
76
77 /* Given a line of text read from /proc/cpuinfo, determine if the property header
78 * matches the field specified, according to the following regexp: "<field>"\W+:\W+
79 *
80 * If we have a matching expression, return a pointer to the first character after
81 * the matching pattern, i.e. the "value", otherwise return NULL.
82 */
83 const char* CPUinfo::match_field(char line[CPUINFO_LINE_SIZE], const char* field) {
84 return match_alo(match_seq(match_alo(match_seq(line, field), "\t "), ":"), "\t ");
85 }
86
87 /* Match a sequence of at-least-one character in the string expression (exp) to
88 * the text input.
89 */
90 const char* CPUinfo::match_alo(const char* text, const char* exp) {
91 if (text == NULL) return NULL;
92
93 const char* chp;
94
95 for (chp = &text[0]; *chp != '\0'; chp++) {
96 if (strchr(exp, *chp) == NULL) break;
97 }
98
99 return text < chp ? chp : NULL;
100 }
101
102 /* Match an exact sequence of characters as specified by the string expression
103 * (seq) to the text input.
104 */
105 const char* CPUinfo::match_seq(const char* text, const char* seq) {
106 if (text == NULL) return NULL;
107
108 while (*seq != '\0') {
109 if (*seq != *text++) break; else seq++;
110 }
111
112 return *seq == '\0' ? text : NULL;
113 }
114
115
116 typedef struct {
117 const uint32_t hash;
118 bool seen;
119 const char* const name;
120 const uint64_t mask;
121 } FeatureEntry;
122
123
124 static uint64_t parse_features(FeatureEntry feature_tbl[], const char input[]);
125
126
127 void VM_Version::platform_features() {
128
129 // Some of the features reported via "cpucaps", such as; 'flush', 'stbar',
130 // 'swap', 'muldiv', 'ultra3', 'blkinit', 'n2', 'mul32', 'div32', 'fsmuld'
131 // and 'v8plus', are either SPARC V8, supported by all HW or simply nonsense
132 // (the 'ultra3' "property").
133 //
134 // Entries marked as 'NYI' are not yet supported via "cpucaps" but are
135 // expected to have the names used in the table below (these are SPARC M7
136 // features or more recent).
137 //
138 // NOTE: Table sorted on lookup/hash ID.
139
140 static FeatureEntry s_feature_tbl[] = {
141 { 0x006f, false, "v9", ISA_v9_msk }, // Mandatory
142 { 0x00a6, false, "md5", ISA_md5_msk },
143 { 0x00ce, false, "adi", ISA_adi_msk }, // NYI
144 { 0x00d7, false, "ima", ISA_ima_msk },
145 { 0x00d9, false, "aes", ISA_aes_msk },
146 { 0x00db, false, "hpc", ISA_hpc_msk },
147 { 0x00dc, false, "des", ISA_des_msk },
148 { 0x00ed, false, "sha1", ISA_sha1_msk },
149 { 0x00f2, false, "vis", ISA_vis1_msk },
150 { 0x0104, false, "vis2", ISA_vis2_msk },
151 { 0x0105, false, "vis3", ISA_vis3_msk },
152 { 0x0114, false, "sha512", ISA_sha512_msk },
153 { 0x0119, false, "sha256", ISA_sha256_msk },
154 { 0x011a, false, "fmaf", ISA_fmaf_msk },
155 { 0x0132, false, "popc", ISA_popc_msk },
156 { 0x0140, false, "crc32c", ISA_crc32c_msk },
157 { 0x0147, false, "vis3b", ISA_vis3b_msk }, // NYI
158 { 0x017e, false, "pause", ISA_pause_msk },
159 { 0x0182, false, "mwait", ISA_mwait_msk }, // NYI
160 { 0x018b, false, "mpmul", ISA_mpmul_msk },
161 { 0x018e, false, "sparc5", ISA_sparc5_msk }, // NYI
162 { 0x01a9, false, "cbcond", ISA_cbcond_msk },
163 { 0x01c3, false, "vamask", ISA_vamask_msk }, // NYI
164 { 0x01ca, false, "kasumi", ISA_kasumi_msk },
165 { 0x01e3, false, "xmpmul", ISA_xmpmul_msk }, // NYI
166 { 0x022c, false, "montmul", ISA_mont_msk },
167 { 0x0234, false, "montsqr", ISA_mont_msk },
168 { 0x0238, false, "camellia", ISA_camellia_msk },
169 { 0x024a, false, "ASIBlkInit", ISA_blk_init_msk },
170 { 0x0284, false, "xmontmul", ISA_xmont_msk }, // NYI
171 { 0x02e6, false, "pause_nsec", ISA_pause_nsec_msk }, // NYI
172
173 { 0x0000, false, NULL, 0 }
174 };
175
176 CPUinfo caps("cpucaps"); // Read "cpucaps" from /proc/cpuinfo.
177
178 assert(caps.valid(), "must be");
179
180 _features = parse_features(s_feature_tbl, caps.value());
181
182 assert(has_v9(), "must be"); // Basic SPARC-V9 required (V8 not supported).
183
184 CPUinfo type("type");
185
186 bool is_sun4v = type.match("sun4v"); // All Oracle SPARC + Fujitsu Athena+
187 bool is_sun4u = type.match("sun4u"); // All other Fujitsu
188
189 uint64_t synthetic = 0;
190
191 if (is_sun4v) {
192 // Indirect and direct branches are equally fast.
193 synthetic = CPU_fast_ind_br_msk;
194 // Fast IDIV, BIS and LD available on Niagara Plus.
195 if (has_vis2()) {
196 synthetic |= (CPU_fast_idiv_msk | CPU_fast_ld_msk);
197 // ...on Core C4 however, we prefer not to use BIS.
198 if (!has_sparc5()) {
199 synthetic |= CPU_fast_bis_msk;
200 }
201 }
202 // Niagara Core C3 supports fast RDPC and block zeroing.
203 if (has_ima()) {
204 synthetic |= (CPU_fast_rdpc_msk | CPU_blk_zeroing_msk);
205 }
206 // Niagara Core C3 and C4 have slow CMOVE.
207 if (!has_ima()) {
208 synthetic |= CPU_fast_cmove_msk;
209 }
210 } else if (is_sun4u) {
211 // SPARC64 only have fast IDIV and RDPC.
212 synthetic |= (CPU_fast_idiv_msk | CPU_fast_rdpc_msk);
213 } else {
214 log_info(os, cpu)("Unable to derive CPU features: %s", type.value());
215 }
216
217 _features += synthetic; // Including CPU derived/synthetic features.
218 }
219
220
221 ////////////////////////////////////////////////////////////////////////////////
222
223 static uint32_t uhash32(const char name[]);
224
225 static void update_table(FeatureEntry feature_tbl[], uint32_t hv,
226 const char* ch1p,
227 const char* endp);
228
229 /* Given a feature table, parse the input text holding the string value of
230 * 'cpucaps' as reported by '/proc/cpuinfo', in order to complete the table
231 * with information on each admissible feature (whether present or not).
232 *
233 * Return the composite bit-mask representing the features found.
234 */
235 static uint64_t parse_features(FeatureEntry feature_tbl[], const char input[]) {
236 log_info(os, cpu)("Parse CPU features: %s\n", input);
237
238 #ifdef ASSERT
239 // Verify that hash value entries in the table are unique and ordered.
240
241 uint32_t prev = 0;
242
243 for (uint k = 0; feature_tbl[k].name != NULL; k++) {
244 feature_tbl[k].seen = false;
245
246 assert(feature_tbl[k].hash == uhash32(feature_tbl[k].name),
247 "feature '%s' has mismatching hash 0x%08x (expected 0x%08x).\n",
248 feature_tbl[k].name,
249 feature_tbl[k].hash,
250 uhash32(feature_tbl[k].name));
251
252 assert(prev < feature_tbl[k].hash,
253 "feature '%s' has invalid hash 0x%08x (previous is 0x%08x).\n",
254 feature_tbl[k].name,
255 feature_tbl[k].hash,
256 prev);
257
258 prev = feature_tbl[k].hash;
259 }
260 #endif
261 // Identify features from the input, consisting of a string with features
262 // separated by commas (or whitespace), e.g. "flush,muldiv,v9,mul32,div32,
263 // v8plus,popc,vis".
264
265 uint32_t hv = 0;
266 const char* ch1p = &input[0];
267 uint i = 0;
268
269 do {
270 char ch = input[i];
271
272 if (isalnum(ch) || ch == '_') {
273 hv += (ch - 32u);
274 }
275 else if (isspace(ch) || ch == ',' || ch == '\0') { // end-of-token
276 if (ch1p < &input[i]) {
277 update_table(feature_tbl, hv, ch1p, &input[i]);
278 }
279 ch1p = &input[i + 1]; hv = 0;
280 } else {
281 // Handle non-accepted input robustly.
282 log_info(os, cpu)("Bad token in feature string: '%c' (0x%02x).\n", ch, ch);
283 ch1p = &input[i + 1]; hv = 0;
284 }
285 }
286 while (input[i++] != '\0');
287
288 // Compute actual bit-mask representation.
289
290 uint64_t mask = 0;
291
292 for (uint k = 0; feature_tbl[k].name != NULL; k++) {
293 mask |= feature_tbl[k].seen ? feature_tbl[k].mask : 0;
294 }
295
296 return mask;
297 }
298
299 static uint32_t uhash32(const char name[]) {
300 uint32_t hv = 0;
301
302 for (uint i = 0; name[i] != '\0'; i++) {
303 hv += (name[i] - 32u);
304 }
305
306 return hv;
307 }
308
309 static bool verify_match(const char name[], const char* ch1p, const char* endp);
310
311 static void update_table(FeatureEntry feature_tbl[], uint32_t hv, const char* ch1p, const char* endp) {
312 assert(ch1p < endp, "at least one character");
313
314 // Look for a hash value in the table. Since this table is a small one (and
315 // is expected to stay small), we use a simple linear search (iff the table
316 // grows large, we may consider to adopt a binary ditto, or a perfect hash).
317
318 for (uint k = 0; feature_tbl[k].name != NULL; k++) {
319 uint32_t hash = feature_tbl[k].hash;
320
321 if (hash < hv) continue;
322
323 if (hash == hv) {
324 const char* name = feature_tbl[k].name;
325
326 if (verify_match(name, ch1p, endp)) {
327 feature_tbl[k].seen = true;
328 break;
329 }
330 }
331
332 // Either a non-matching feature (when hash == hv) or hash > hv. In either
333 // case we break out of the loop and terminate the search (note that the
334 // table is assumed to be uniquely sorted on the hash).
335
336 break;
337 }
338 }
339
340 static bool verify_match(const char name[], const char* ch1p, const char* endp) {
341 size_t len = strlen(name);
342
343 if (len != static_cast<size_t>(endp - ch1p)) {
344 return false;
345 }
346
347 for (uint i = 0; ch1p + i < endp; i++) {
348 if (name[i] != ch1p[i]) return false;
349 }
350
351 return true;
352 }
--- EOF ---