8249675: x86: frequency extraction from cpu brand string is incomplete

Reviewed-by: egahlin, dholmes
This commit is contained in:
Markus Grönlund 2020-10-23 09:04:03 +00:00
parent e52156d730
commit 63ce304ea4
2 changed files with 38 additions and 44 deletions

@ -256,7 +256,7 @@ const size_t VM_Version_Ext::CPU_EBS_MAX_LENGTH = (3 * 4 * 4 + 1);
const size_t VM_Version_Ext::CPU_TYPE_DESC_BUF_SIZE = 256;
const size_t VM_Version_Ext::CPU_DETAILED_DESC_BUF_SIZE = 4096;
char* VM_Version_Ext::_cpu_brand_string = NULL;
jlong VM_Version_Ext::_max_qualified_cpu_frequency = 0;
int64_t VM_Version_Ext::_max_qualified_cpu_frequency = 0;
int VM_Version_Ext::_no_of_threads = 0;
int VM_Version_Ext::_no_of_cores = 0;
@ -644,56 +644,50 @@ const char* VM_Version_Ext::cpu_description(void) {
}
/**
* See Intel Application note 485 (chapter 10) for details
* on frequency extraction from cpu brand string.
* http://www.intel.com/content/dam/www/public/us/en/documents/application-notes/processor-identification-cpuid-instruction-note.pdf
* For information about extracting the frequency from the cpu brand string, please see:
*
* Intel Processor Identification and the CPUID Instruction
* Application Note 485
* May 2012
*
* The return value is the frequency in Hz.
*/
jlong VM_Version_Ext::max_qualified_cpu_freq_from_brand_string(void) {
// get brand string
int64_t VM_Version_Ext::max_qualified_cpu_freq_from_brand_string(void) {
const char* const brand_string = cpu_brand_string();
if (brand_string == NULL) {
return 0;
}
const u8 MEGA = 1000000;
u8 multiplier = 0;
jlong frequency = 0;
// the frequency information in the cpu brand string
// is given in either of two formats "x.xxyHz" or "xxxxyHz",
// where y=M,G,T and x is digits
const char* Hz_location = strchr(brand_string, 'H');
if (Hz_location != NULL) {
if (*(Hz_location + 1) == 'z') {
// switch on y in "yHz"
switch(*(Hz_location - 1)) {
case 'M' :
// Set multiplier to frequency is in Hz
multiplier = MEGA;
break;
case 'G' :
multiplier = MEGA * 1000;
break;
case 'T' :
multiplier = MEGA * 1000 * 1000;
break;
const int64_t MEGA = 1000000;
int64_t multiplier = 0;
int64_t frequency = 0;
uint8_t idx = 0;
// The brand string buffer is at most 48 bytes.
// -2 is to prevent buffer overrun when looking for y in yHz, as z is +2 from y.
for (; idx < 48-2; ++idx) {
// Format is either "x.xxyHz" or "xxxxyHz", where y=M, G, T and x are digits.
// Search brand string for "yHz" where y is M, G, or T.
if (brand_string[idx+1] == 'H' && brand_string[idx+2] == 'z') {
if (brand_string[idx] == 'M') {
multiplier = MEGA;
} else if (brand_string[idx] == 'G') {
multiplier = MEGA * 1000;
} else if (brand_string[idx] == 'T') {
multiplier = MEGA * MEGA;
}
break;
}
}
if (multiplier > 0) {
// compute frequency (in Hz) from brand string
if (*(Hz_location - 4) == '.') { // if format is "x.xx"
frequency = (jlong)(*(Hz_location - 5) - '0') * (multiplier);
frequency += (jlong)(*(Hz_location - 3) - '0') * (multiplier / 10);
frequency += (jlong)(*(Hz_location - 2) - '0') * (multiplier / 100);
// Compute freqency (in Hz) from brand string.
if (brand_string[idx-3] == '.') { // if format is "x.xx"
frequency = (brand_string[idx-4] - '0') * multiplier;
frequency += (brand_string[idx-2] - '0') * multiplier / 10;
frequency += (brand_string[idx-1] - '0') * multiplier / 100;
} else { // format is "xxxx"
frequency = (jlong)(*(Hz_location - 5) - '0') * 1000;
frequency += (jlong)(*(Hz_location - 4) - '0') * 100;
frequency += (jlong)(*(Hz_location - 3) - '0') * 10;
frequency += (jlong)(*(Hz_location - 2) - '0');
frequency = (brand_string[idx-4] - '0') * 1000;
frequency += (brand_string[idx-3] - '0') * 100;
frequency += (brand_string[idx-2] - '0') * 10;
frequency += (brand_string[idx-1] - '0');
frequency *= multiplier;
}
}
@ -701,7 +695,7 @@ jlong VM_Version_Ext::max_qualified_cpu_freq_from_brand_string(void) {
}
jlong VM_Version_Ext::maximum_qualified_cpu_frequency(void) {
int64_t VM_Version_Ext::maximum_qualified_cpu_frequency(void) {
if (_max_qualified_cpu_frequency == 0) {
_max_qualified_cpu_frequency = max_qualified_cpu_freq_from_brand_string();
}

@ -55,7 +55,7 @@ class VM_Version_Ext : public VM_Version {
static int _no_of_cores;
static int _no_of_packages;
static char* _cpu_brand_string;
static jlong _max_qualified_cpu_frequency;
static int64_t _max_qualified_cpu_frequency;
static const char* cpu_family_description(void);
static const char* cpu_model_description(void);
@ -72,7 +72,7 @@ class VM_Version_Ext : public VM_Version {
// Returns bytes written excluding termninating null byte.
static size_t cpu_write_support_string(char* const buf, size_t buf_len);
static void resolve_cpu_information_details(void);
static jlong max_qualified_cpu_freq_from_brand_string(void);
static int64_t max_qualified_cpu_freq_from_brand_string(void);
public:
// Offsets for cpuid asm stub brand string
@ -93,7 +93,7 @@ class VM_Version_Ext : public VM_Version {
static int number_of_cores(void);
static int number_of_sockets(void);
static jlong maximum_qualified_cpu_frequency(void);
static int64_t maximum_qualified_cpu_frequency(void);
static bool supports_tscinv_ext(void);