-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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 num cpu #1518
Fix num cpu #1518
Conversation
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.
Interesting, thanks, it seems mostly reasonable.
Please sign off your commits with git commit -s --amend
. Also, it would be good to add an [ENHANCEMENT]
entry to the changelog.
50e67a7
to
c6a436b
Compare
`runtime.NumCPU()` returns the number of CPUs that the process can run on. This number does not necessarily correlate to CPU ids if the affinity mask of the process is set. This change maintains the current behavior as default, but also allows the user to specify a range of CPUids to use instead. The CPU id is stored as the value of a map keyed on the profiler object's address. Signed-off-by: Joe Damato <[email protected]>
c6a436b
to
b17a872
Compare
Thanks for the review @SuperQ. Made some changes as you've suggested. Let me know how this looks. |
This is a nice config option! |
Signed-off-by: Joe Damato <[email protected]>
f0bb354
to
27381c4
Compare
I think this addresses your feedback @discordianfish and @SuperQ. Was wondering if there might be anyone who would be interested in testing this just to double check that this is working for them? cc @hodgesds |
Signed-off-by: Joe Damato <[email protected]>
c772e25
to
341322e
Compare
collector/perf_linux.go
Outdated
for cpu, profiler := range c.perfSwProfilers { | ||
cpuStr := fmt.Sprintf("%d", cpu) | ||
for _, profiler := range c.perfSwProfilers { | ||
cpuid := c.swProfilerCpuMap[&profiler] |
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.
So, I'm new to go and this appears to be a bug.
&profiler
here refers to the address of the profiler
object itself and not the address of the perf.SoftwareProfiler
that was inserted into c.swProfilerCpuMap
.
This leads to the incorrect CPU id being retrieved. I'm not really sure how to deal with this as I know basically 0 golang (sorry). Would love any suggestions you folks have on the best way to fix this.
Signed-off-by: Joe Damato <[email protected]>
57bc58c
to
573cf02
Compare
I don't really know anything about golang but this commit I just pushed: 573cf02 I think fixes the address of the object issue I mentioned here: #1518 (comment) |
perfSwProfilers map[int]perf.SoftwareProfiler | ||
perfCacheProfilers map[int]perf.CacheProfiler | ||
desc map[string]*prometheus.Desc | ||
hwProfilerCpuMap map[*perf.HardwareProfiler]int |
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.
I wouldn't expect to keep a map of pointers to interfaces. For example NewSoftwareProfiler
returns an interface that can be used directly.
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.
yea but I think you need them otherwise you can't generate a map of pointers to CPU ids.
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.
confirmed that this change (pointers to interfaces) works correctly, as the address pointed to can be used as a key for the CPU ID map. the code without this change does not work as mentioned here: #1518 (comment)
I think keeping this is correct -- I am using this in a lab setting and am getting the expected results now.
It might be nice to make the flag match the |
That sounds like a lot of work. Happy to turn that over to anyone else who'd like to jump in on this, though. |
Signed-off-by: Joe Damato <[email protected]>
cf393a4
to
b813bf1
Compare
I think this roughly does what you want, let me know your thoughts. |
I left a few comments on the code over there. As mentioned above, I'm not a golang programmer so I'm probably not a good person to ask for a code review 😅 FWIW I am using the code I wrote in this branch in a lab setting and it is working as expected (as mentioned here: #1518 (comment)). In my use case: I run It's worth noting that any use of |
I see the bug now, here's a small example that shows it's because a interface isn't assignable, the index expression isn't valid by taking the address of the interface it works. I think this is fine then, would you mind porting over the flag parsing code so that strides work properly as well? |
Thanks for the detailed explanation. Sure, I can copy over your flag parsing code shortly. |
FWIW, worth noting that using the code I wrote in this branch the HardwareProfiler which gathers |
What are you observing?
Note that configuration for those events also includes some defaults that are pretty opinionated. For more configuration and moved much of that functionality into |
On kernel 4.19 with a sandybridge CPU issuing For example, on my system However, running This leads me to believe that either I'm not sure if this bug is related to my code or something else. EDIT : I should note that some CPUs seem to have correct values, but others have values which never seem to change from |
I've tested your branch on two kernels (4.14.78 and 5.2.5) on a E3-1505M v5 and Ryzen 2600 processors and both seem to be working as expected. Do you have access to any other architectures for testing? |
It appears to work on kernel 4.9 on this machine, but not on kernel 4.19. Could be some weird kernel regression. Any chance you could test on 4.19? |
I run custom kernels for everything so my config will likely be different. Can you post the output of:
|
|
I've tested this on a few machines with a similar config and it seems to be working as expected. I think this is good to go, however you may want to do some more digging ( |
kingpin "gopkg.in/alecthomas/kingpin.v2" | ||
"runtime" | ||
"strconv" | ||
"strings" |
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.
Normally we group all the built-in imports at the top, can you re-format these using goimports
?
go get golang.org/x/tools/cmd/goimports
goimports -w ./collector/perf_linux.go
|
||
ncpus, err = strconv.Atoi(cpuRange[1]) | ||
if err != nil { | ||
ncpus = runtime.NumCPU() - 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.
I don't think we should fallback to the default when a user provided a non-integer. This should fail instead.
cacheProfilerCpuMap: map[*perf.CacheProfiler]int{}, | ||
} | ||
|
||
start := 0 |
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 a var block here:
var (
start = 0
ncpus = 0
..
)
// Use -1 to profile all processes on the CPU, see: | ||
// man perf_event_open | ||
collector.perfHwProfilers[i] = perf.NewHardwareProfiler(-1, i) | ||
if err := collector.perfHwProfilers[i].Start(); err != nil { | ||
p := perf.NewHardwareProfiler(-1, 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.
Let's rename the p's here:
- ph = hardware profiler
- ps = software profiler
- pc = cache profiler
return collector, err | ||
} else { |
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.
No need for the else here, if err != nil it returns anyway.
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.
(same below)
Should we close this in favor of #1561? |
Superseded by #1561. |
runtime.NumCPU()
returns the number of CPUs that the process can runon. This number does not necessarily correlate to CPU ids if the
affinity mask of the process is set.
This change maintains the current behavior as default, but also allows
the user to specify a range of CPUids to use instead.
The CPU id is stored as the value of a map keyed on the profiler
object's address.