-
-
Notifications
You must be signed in to change notification settings - Fork 439
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix temperature readings on Intel CPUs with heterogeneous core design #1269
base: main
Are you sure you want to change the base?
Conversation
@@ -261,6 +261,43 @@ void LibSensors_getCPUTemperatures(CPUData* cpus, unsigned int existingCPUs, uns | |||
goto out; | |||
} | |||
|
|||
/* Read sysfs to get HT/SMT cores and correctly distribute the temperature values */ | |||
if (coreTempCount < activeCPUs) { | |||
double oldData[existingCPUs + 1]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable length array is not recommended in C.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid VLA. Although they are part of C99 (which htop targets), there are later language versions that make them optional. Also, having dynamically sized data on the stack is an accident waiting to happen, from a security PoV. Thus: No VLAs!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for a late response, but isn't this also a VLA?
Line 146 in 477c20b
double data[existingCPUs + 1]; |
That's where I got this from.
I don't mind changing it though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The LibSensors code is not the cleanest in some places … ;-)
That said, I did some cleanup in #1273.
int dataCell = 1; | ||
for (unsigned int i = 0; i < existingCPUs; i++) { | ||
char path[100]; | ||
sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", i); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have xSnprintf
function in htop codebase. Please use that instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also if you are iterating over several items in a common parent directory, it might be worth using things like opendir
and openat
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code should best be split in a way that the gathered topology information can be re-used for frequency and temperatures alike.
Also, please take better care of defense-in-depth precautions to avoid security related issues.
memcpy(oldData, data, sizeof(oldData)); | ||
|
||
int dataCell = 1; | ||
for (unsigned int i = 0; i < existingCPUs; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use size_t
for things that represent the number of items/counts of things.
int dataCell = 1; | ||
for (unsigned int i = 0; i < existingCPUs; i++) { | ||
char path[100]; | ||
sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", i); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also if you are iterating over several items in a common parent directory, it might be worth using things like opendir
and openat
.
for (unsigned int i = 0; i < existingCPUs; i++) { | ||
char path[100]; | ||
sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", i); | ||
FILE* file = fopen(path, "r"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fopen
APIs are usually avoided due to their overhead and performance impact. As mentioned above, use opendir
and openat
(cf. wrappers in XUtils.h
) instead.
char contents[10]; | ||
fgets(contents, 10, file); | ||
fclose(file); | ||
|
||
int start, end; | ||
int rangeNums = sscanf(contents, "%d-%d", &start, &end); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This buffer is too short for the potential values that could be returned by the kernel. Should be at least 24 bytes (2x 10 bytes for int32_t
plus 2 bytes for -
and \n
, plus one final \0
terminator.
int start, end; | ||
int rangeNums = sscanf(contents, "%d-%d", &start, &end); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer fixed width integer types and suffixes defined in inttypes.h
.
int rangeNums = sscanf(contents, "%d-%d", &start, &end); | ||
|
||
if (rangeNums == 1) { | ||
data[i+1] = oldData[dataCell]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent use of indexing source. When just one value given, this should equal to running the below code for just the start index, which is not the case at all.
dataCell++; | ||
} else if (rangeNums == 2) { | ||
for (int j = start; j <= end; j++) { | ||
data[j+1] = oldData[dataCell]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unchecked buffer overflow from untrusted/unsanitized input.
fgets(contents, 10, file); | ||
fclose(file); | ||
|
||
int start, end; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use some sane initialization, even though sscanf
will potentially assign those variables.
Hmm, this does not give the expected results for me. Actually it show the temperature for one core less than before. |
@dawidpotocki Do you mind updating this PR and incorporate the comments from the different reviews? TIA. @eworm-de Mind to provide some dump to reproduce this? |
Hmm, #1352 addresses the same issue. Does it make sense to focus on this topic in just one PR? |
Whichever fixes the open issues first … I do not have a particular preference right now … |
Ok. So what info to provide from my system? This is from
|
@BenBE I was going to update it ages ago, but stuff happened and forgot about this a bit. I will not have time to work on this until at least July. |
No worries. Take the time you need. There were quite a few comments that probably will need a bit of work to address properly. In any case: If you need help or if you have questions feel free to ask. |
Fixes #1048
I don't really know C, so it is what it is.
This code probably should be changed to also handle CPUs that use
,
instead of
-
in sysfs. Could probably then replace the code that justblindly copies the temperatures of the first half to the second half.
Screenshots
Before
After
Example sysfs output of a Raptor Lake CPU (i7-13700K)
P-cores
E-cores