blob: f24217002897cb3256f29742acc1daaabba5d66d [file] [log] [blame]
duke6e45e102007-12-01 00:00:00 +00001/*
ohair2283b9d2010-05-25 15:58:33 -07002 * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
duke6e45e102007-12-01 00:00:00 +00003 * 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
ohair2283b9d2010-05-25 15:58:33 -07007 * published by the Free Software Foundation. Oracle designates this
duke6e45e102007-12-01 00:00:00 +00008 * particular file as subject to the "Classpath" exception as provided
ohair2283b9d2010-05-25 15:58:33 -07009 * by Oracle in the LICENSE file that accompanied this code.
duke6e45e102007-12-01 00:00:00 +000010 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
ohair2283b9d2010-05-25 15:58:33 -070021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
duke6e45e102007-12-01 00:00:00 +000024 */
25
26#include "ergo.h"
27
28static unsigned long physical_processors(void);
29
30#ifdef __solaris__
31
32/*
33 * A utility method for asking the CPU about itself.
34 * There's a corresponding version of linux-i586
35 * because the compilers are different.
36 */
37static void
38get_cpuid(uint32_t arg,
39 uint32_t* eaxp,
40 uint32_t* ebxp,
41 uint32_t* ecxp,
42 uint32_t* edxp) {
43#ifdef _LP64
44 asm(
45 /* rbx is a callee-saved register */
46 " movq %rbx, %r11 \n"
47 /* rdx and rcx are 3rd and 4th argument registers */
48 " movq %rdx, %r10 \n"
49 " movq %rcx, %r9 \n"
50 " movl %edi, %eax \n"
51 " cpuid \n"
52 " movl %eax, (%rsi)\n"
53 " movl %ebx, (%r10)\n"
54 " movl %ecx, (%r9) \n"
55 " movl %edx, (%r8) \n"
56 /* Restore rbx */
57 " movq %r11, %rbx");
58#else
59 /* EBX is a callee-saved register */
60 asm(" pushl %ebx");
61 /* Need ESI for storing through arguments */
62 asm(" pushl %esi");
63 asm(" movl 8(%ebp), %eax \n"
64 " cpuid \n"
65 " movl 12(%ebp), %esi \n"
66 " movl %eax, (%esi) \n"
67 " movl 16(%ebp), %esi \n"
68 " movl %ebx, (%esi) \n"
69 " movl 20(%ebp), %esi \n"
70 " movl %ecx, (%esi) \n"
71 " movl 24(%ebp), %esi \n"
72 " movl %edx, (%esi) ");
73 /* Restore ESI and EBX */
74 asm(" popl %esi");
75 /* Restore EBX */
76 asm(" popl %ebx");
77#endif /* LP64 */
78}
79
80/* The definition of a server-class machine for solaris-i586/amd64 */
81jboolean
82ServerClassMachineImpl(void) {
83 jboolean result = JNI_FALSE;
84 /* How big is a server class machine? */
85 const unsigned long server_processors = 2UL;
86 const uint64_t server_memory = 2UL * GB;
87 /*
88 * We seem not to get our full complement of memory.
89 * We allow some part (1/8?) of the memory to be "missing",
90 * based on the sizes of DIMMs, and maybe graphics cards.
91 */
92 const uint64_t missing_memory = 256UL * MB;
93 const uint64_t actual_memory = physical_memory();
94
95 /* Is this a server class machine? */
96 if (actual_memory >= (server_memory - missing_memory)) {
97 const unsigned long actual_processors = physical_processors();
98 if (actual_processors >= server_processors) {
99 result = JNI_TRUE;
100 }
101 }
102 JLI_TraceLauncher("solaris_" LIBARCHNAME "_ServerClassMachine: %s\n",
103 (result == JNI_TRUE ? "true" : "false"));
104 return result;
105}
106
107#endif /* __solaris__ */
108
109#ifdef __linux__
110
111/*
112 * A utility method for asking the CPU about itself.
113 * There's a corresponding version of solaris-i586
114 * because the compilers are different.
115 */
116static void
117get_cpuid(uint32_t arg,
118 uint32_t* eaxp,
119 uint32_t* ebxp,
120 uint32_t* ecxp,
121 uint32_t* edxp) {
122#ifdef _LP64
123 __asm__ volatile (/* Instructions */
124 " movl %4, %%eax \n"
125 " cpuid \n"
126 " movl %%eax, (%0)\n"
127 " movl %%ebx, (%1)\n"
128 " movl %%ecx, (%2)\n"
129 " movl %%edx, (%3)\n"
130 : /* Outputs */
131 : /* Inputs */
132 "r" (eaxp),
133 "r" (ebxp),
134 "r" (ecxp),
135 "r" (edxp),
136 "r" (arg)
137 : /* Clobbers */
138 "%rax", "%rbx", "%rcx", "%rdx", "memory"
139 );
140#else /* _LP64 */
141 uint32_t value_of_eax = 0;
142 uint32_t value_of_ebx = 0;
143 uint32_t value_of_ecx = 0;
144 uint32_t value_of_edx = 0;
145 __asm__ volatile (/* Instructions */
146 /* ebx is callee-save, so push it */
147 " pushl %%ebx \n"
148 " movl %4, %%eax \n"
149 " cpuid \n"
150 " movl %%eax, %0 \n"
151 " movl %%ebx, %1 \n"
152 " movl %%ecx, %2 \n"
153 " movl %%edx, %3 \n"
154 /* restore ebx */
155 " popl %%ebx \n"
156
157 : /* Outputs */
158 "=m" (value_of_eax),
159 "=m" (value_of_ebx),
160 "=m" (value_of_ecx),
161 "=m" (value_of_edx)
162 : /* Inputs */
163 "m" (arg)
164 : /* Clobbers */
165 "%eax", "%ecx", "%edx"
166 );
167 *eaxp = value_of_eax;
168 *ebxp = value_of_ebx;
169 *ecxp = value_of_ecx;
170 *edxp = value_of_edx;
171#endif /* _LP64 */
172}
173
174/* The definition of a server-class machine for linux-i586 */
175jboolean
176ServerClassMachineImpl(void) {
177 jboolean result = JNI_FALSE;
178 /* How big is a server class machine? */
179 const unsigned long server_processors = 2UL;
180 const uint64_t server_memory = 2UL * GB;
181 /*
182 * We seem not to get our full complement of memory.
183 * We allow some part (1/8?) of the memory to be "missing",
184 * based on the sizes of DIMMs, and maybe graphics cards.
185 */
186 const uint64_t missing_memory = 256UL * MB;
187 const uint64_t actual_memory = physical_memory();
188
189 /* Is this a server class machine? */
190 if (actual_memory >= (server_memory - missing_memory)) {
191 const unsigned long actual_processors = physical_processors();
192 if (actual_processors >= server_processors) {
193 result = JNI_TRUE;
194 }
195 }
196 JLI_TraceLauncher("linux_" LIBARCHNAME "_ServerClassMachine: %s\n",
197 (result == JNI_TRUE ? "true" : "false"));
198 return result;
199}
200#endif /* __linux__ */
201
202/*
203 * Routines shared by solaris-i586 and linux-i586.
204 */
205
206enum HyperThreadingSupport_enum {
207 hts_supported = 1,
208 hts_too_soon_to_tell = 0,
209 hts_not_supported = -1,
210 hts_not_pentium4 = -2,
211 hts_not_intel = -3
212};
213typedef enum HyperThreadingSupport_enum HyperThreadingSupport;
214
215/* Determine if hyperthreading is supported */
216static HyperThreadingSupport
217hyperthreading_support(void) {
218 HyperThreadingSupport result = hts_too_soon_to_tell;
219 /* Bits 11 through 8 is family processor id */
220# define FAMILY_ID_SHIFT 8
221# define FAMILY_ID_MASK 0xf
222 /* Bits 23 through 20 is extended family processor id */
223# define EXT_FAMILY_ID_SHIFT 20
224# define EXT_FAMILY_ID_MASK 0xf
225 /* Pentium 4 family processor id */
226# define PENTIUM4_FAMILY_ID 0xf
227 /* Bit 28 indicates Hyper-Threading Technology support */
228# define HT_BIT_SHIFT 28
229# define HT_BIT_MASK 1
230 uint32_t vendor_id[3] = { 0U, 0U, 0U };
231 uint32_t value_of_eax = 0U;
232 uint32_t value_of_edx = 0U;
233 uint32_t dummy = 0U;
234
235 /* Yes, this is supposed to be [0], [2], [1] */
236 get_cpuid(0, &dummy, &vendor_id[0], &vendor_id[2], &vendor_id[1]);
237 JLI_TraceLauncher("vendor: %c %c %c %c %c %c %c %c %c %c %c %c \n",
238 ((vendor_id[0] >> 0) & 0xff),
239 ((vendor_id[0] >> 8) & 0xff),
240 ((vendor_id[0] >> 16) & 0xff),
241 ((vendor_id[0] >> 24) & 0xff),
242 ((vendor_id[1] >> 0) & 0xff),
243 ((vendor_id[1] >> 8) & 0xff),
244 ((vendor_id[1] >> 16) & 0xff),
245 ((vendor_id[1] >> 24) & 0xff),
246 ((vendor_id[2] >> 0) & 0xff),
247 ((vendor_id[2] >> 8) & 0xff),
248 ((vendor_id[2] >> 16) & 0xff),
249 ((vendor_id[2] >> 24) & 0xff));
250 get_cpuid(1, &value_of_eax, &dummy, &dummy, &value_of_edx);
251 JLI_TraceLauncher("value_of_eax: 0x%x value_of_edx: 0x%x\n",
252 value_of_eax, value_of_edx);
253 if ((((value_of_eax >> FAMILY_ID_SHIFT) & FAMILY_ID_MASK) == PENTIUM4_FAMILY_ID) ||
254 (((value_of_eax >> EXT_FAMILY_ID_SHIFT) & EXT_FAMILY_ID_MASK) != 0)) {
255 if ((((vendor_id[0] >> 0) & 0xff) == 'G') &&
256 (((vendor_id[0] >> 8) & 0xff) == 'e') &&
257 (((vendor_id[0] >> 16) & 0xff) == 'n') &&
258 (((vendor_id[0] >> 24) & 0xff) == 'u') &&
259 (((vendor_id[1] >> 0) & 0xff) == 'i') &&
260 (((vendor_id[1] >> 8) & 0xff) == 'n') &&
261 (((vendor_id[1] >> 16) & 0xff) == 'e') &&
262 (((vendor_id[1] >> 24) & 0xff) == 'I') &&
263 (((vendor_id[2] >> 0) & 0xff) == 'n') &&
264 (((vendor_id[2] >> 8) & 0xff) == 't') &&
265 (((vendor_id[2] >> 16) & 0xff) == 'e') &&
266 (((vendor_id[2] >> 24) & 0xff) == 'l')) {
267 if (((value_of_edx >> HT_BIT_SHIFT) & HT_BIT_MASK) == HT_BIT_MASK) {
268 JLI_TraceLauncher("Hyperthreading supported\n");
269 result = hts_supported;
270 } else {
271 JLI_TraceLauncher("Hyperthreading not supported\n");
272 result = hts_not_supported;
273 }
274 } else {
275 JLI_TraceLauncher("Not GenuineIntel\n");
276 result = hts_not_intel;
277 }
278 } else {
279 JLI_TraceLauncher("not Pentium 4 or extended\n");
280 result = hts_not_pentium4;
281 }
282 return result;
283}
284
285/* Determine how many logical processors there are per CPU */
286static unsigned int
287logical_processors_per_package(void) {
288 /*
289 * After CPUID with EAX==1, register EBX bits 23 through 16
290 * indicate the number of logical processors per package
291 */
292# define NUM_LOGICAL_SHIFT 16
293# define NUM_LOGICAL_MASK 0xff
294 unsigned int result = 1U;
295 const HyperThreadingSupport hyperthreading = hyperthreading_support();
296
297 if (hyperthreading == hts_supported) {
298 uint32_t value_of_ebx = 0U;
299 uint32_t dummy = 0U;
300
301 get_cpuid(1, &dummy, &value_of_ebx, &dummy, &dummy);
302 result = (value_of_ebx >> NUM_LOGICAL_SHIFT) & NUM_LOGICAL_MASK;
303 JLI_TraceLauncher("logical processors per package: %u\n", result);
304 }
305 return result;
306}
307
308/* Compute the number of physical processors, not logical processors */
309static unsigned long
310physical_processors(void) {
311 const long sys_processors = sysconf(_SC_NPROCESSORS_CONF);
312 unsigned long result = sys_processors;
313
314 JLI_TraceLauncher("sysconf(_SC_NPROCESSORS_CONF): %lu\n", sys_processors);
315 if (sys_processors > 1) {
316 unsigned int logical_processors = logical_processors_per_package();
317 if (logical_processors > 1) {
318 result = (unsigned long) sys_processors / logical_processors;
319 }
320 }
321 JLI_TraceLauncher("physical processors: %lu\n", result);
322 return result;
323}