-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Only load floating point registers when needed #1981
Conversation
aarzilli
commented
Apr 2, 2020
cee08e1
to
dd595b8
Compare
Looks like I broke arm64, I'll have to look into it. |
2aa9905
to
d2c01be
Compare
En, about
When I do benchmark (previous similar optimizations), the fluctuation is very big every time and the value is inconspicuous. Of course it must be optimized in theory. I just want to konw how to generate reliable data. Maybe remove the maximum, remove the minimum, take the average? |
bdbed27
to
c2a5212
Compare
Fixed it.
I don't get a lot of variance. If you are using 1.14 disable async preemption, that adds a lot of noise, otherwise change the number of iterations in issue1549.go. |
} | ||
|
||
type DwarfRegister struct { | ||
Uint64Val uint64 | ||
Bytes []byte | ||
} | ||
|
||
// NewDwarfRegisters returns a new DwarfRegisters object. | ||
func NewDwarfRegisters(staticBase uint64, regs []*DwarfRegister, byteOrder binary.ByteOrder, pcRegNum, spRegNum, bpRegNum, lrRegNum uint64) *DwarfRegisters { |
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 is just a thin wrapper around initializing the struct. All function args become struct members with no processing done by the function. Maybe we just let the callers initialize the struct themselves?
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 unexported the Regs field so that consumers of DwarfRegisters can't access it directly and have to go through the appropriate methods (that will call loadMoreCallback when needed). Philosophical reasons aside, this also made sure that I converted all accesses to Regs. However now users of DwarfRegisters can't instantiate it because they can't assign to regs
.
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.
Ack, makes perfect sense.
pkg/dwarf/op/regs.go
Outdated
if idx >= uint64(len(regs.Regs)) { | ||
return nil | ||
if idx >= uint64(len(regs.regs)) { | ||
if regs.loadMoreCallback != nil { |
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.
nit: I think this would read better as:
if regs.loadMoreCallback == nil {
return nil
}
regs.loadMoreCallback()
regs.loadMoreCallback = nil
if idx >= uint64(len(regs.regs)) {
return nil
}
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.
Done.
pkg/dwarf/op/regs.go
Outdated
return nil | ||
if idx >= uint64(len(regs.regs)) { | ||
if regs.loadMoreCallback != nil { | ||
regs.loadMoreCallback() |
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 think we should put this into a regs.loadMore
method which can wrap the logic of checking if the callback is not nil and then setting it to nil once it's been called.
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.
Done, see what you think.
} | ||
|
||
// ClearRegisters clears all registers except for PC, SP and BP | ||
func (regs *DwarfRegisters) ClearRegisters() { |
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 think the name should reflect that this is selective in which registers it clears (e.g. ClearGeneralPurposeRegisters
or something). Also, why be selective?
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.
General purpose registers usually refers to rax, rbx, etc... this cleans all of them (including xmm, etc) except for PC, SP and BP. It's like this because the only place we need this is in the function call protocol.
However, you are right, this is pretty weird and ugly and I've thought of a way to do it better.
Changes implementations of proc.Registers interface and the op.DwarfRegisters struct so that floating point registers can be loaded only when they are needed. Removes the floatingPoint parameter from proc.Thread.Registers. This accomplishes three things: 1. it simplifies the proc.Thread.Registers interface 2. it makes it impossible to accidentally create a broken set of saved registers or of op.DwarfRegisters by accidentally calling Registers(false) 3. it improves general performance of Delve by avoiding to load floating point registers as much as possible Floating point registers are loaded under two circumstances: 1. When the Slice method is called with floatingPoint == true 2. When the Copy method is called Benchmark before: BenchmarkConditionalBreakpoints-4 1 4327350142 ns/op Benchmark after: BenchmarkConditionalBreakpoints-4 1 3852642917 ns/op Updates go-delve#1549
Changes implementations of proc.Registers interface and the op.DwarfRegisters struct so that floating point registers can be loaded only when they are needed. Removes the floatingPoint parameter from proc.Thread.Registers. This accomplishes three things: 1. it simplifies the proc.Thread.Registers interface 2. it makes it impossible to accidentally create a broken set of saved registers or of op.DwarfRegisters by accidentally calling Registers(false) 3. it improves general performance of Delve by avoiding to load floating point registers as much as possible Floating point registers are loaded under two circumstances: 1. When the Slice method is called with floatingPoint == true 2. When the Copy method is called Benchmark before: BenchmarkConditionalBreakpoints-4 1 4327350142 ns/op Benchmark after: BenchmarkConditionalBreakpoints-4 1 3852642917 ns/op Updates go-delve#1549
Changes implementations of proc.Registers interface and the op.DwarfRegisters struct so that floating point registers can be loaded only when they are needed. Removes the floatingPoint parameter from proc.Thread.Registers. This accomplishes three things: 1. it simplifies the proc.Thread.Registers interface 2. it makes it impossible to accidentally create a broken set of saved registers or of op.DwarfRegisters by accidentally calling Registers(false) 3. it improves general performance of Delve by avoiding to load floating point registers as much as possible Floating point registers are loaded under two circumstances: 1. When the Slice method is called with floatingPoint == true 2. When the Copy method is called Benchmark before: BenchmarkConditionalBreakpoints-4 1 4327350142 ns/op Benchmark after: BenchmarkConditionalBreakpoints-4 1 3852642917 ns/op Updates go-delve#1549