-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Redis profiling experiment #442
Conversation
func (n NetString) UnsafeString() string { | ||
bh := (*reflect.SliceHeader)(unsafe.Pointer(&n)) | ||
sh := reflect.StringHeader{Data: bh.Data, Len: bh.Len} | ||
return *(*string)(unsafe.Pointer(&sh)) |
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.
Go performs a copy when converting from []byte
to string
to guarantee that the contents of the string
can not be changed by mutating the []byte
since the contract in Go is that strings are immutable.
This seems like a good optimization to use when you know for sure that the returned string is not going to be retained (where immutability guarantees might be required). The method should get updated to document when and how to safely use it.
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.
Not sure we want to get ourselves in the Unsafe territory. How much do we win in terms of performance? Perhaps we can find another way to avoid the copy by refactoring at an upper layer.
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.
Not keen about unsafe territory either. That's why introduced NetString over unsafe copying all []byte into string. Purpose of this method is to be used with map lookups (map keys can not be []byte, but must be string) in cases of compiler not optimizing []byte into string conversion. Optimized version in disassembly contains runtime.slicebytetostringtmp, unoptimized with copy will be runtime.slicebytetostring).
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.
Not required anymore. Rather remove it.
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.
Did you intend to remove the method before merging?
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.
oh, I thought I removed it. Will be removed.
I like the |
yep, also like to have -httpprof. you can run packetbeat with '-httpprof :6060' to have to locally on port 6060 ;) |
added some very simple/small benchmarks for redis parser only (does not take the removed allocations for removal of redundant transaction object into account): old parser (using string):
new parser (using NetString):
Allocations and runtime are reduced (some allocations are due to test setup). |
4206e37
to
32c7ea6
Compare
LGTM! Do you want to cleanup history before merging? |
Also a line in the Changelog about the Redis parser being faster would be good. |
let me cleanup first |
cleaned up history + guarded all debug statements. New benchmark results:
|
|
||
func init() { | ||
memprofile = flag.String("memprofile", "", "Write memory profile to this file") | ||
cpuprofile = flag.String("cpuprofile", "", "Write cpu profile to file") | ||
httpprof = flag.String("httpprof", "", "Start pprof http server") |
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 option needs added to the docs.
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
That's incredible. Great work, Steffen! |
- added commandline flag '-httpprof' to start HTTP pprof endpoint for doing some live profiling of beat services (heap profiling, cpu profiling) - add streambuf.AppendWithCapLimits which guarantees newly allocated buffers have at least configured capacity in case the buffer must grow when appending new content (excert more control on buffer sizing) => not used, as number of objects allocated was minor in contrast to other object types. Plus bad policy can increase overal memory usage dramatically due to pointers back into original slice - add common.NetString basically being []byte. Difference to []byte is, this type implements the encoding.TextMarhsaller interface. NetString objects will be handled by JSON encoder like normal strings, thusly no allocation and copy is required when extracting strings from parsed messages. NetString being []byte will directly point into original message buffer. NetString also provides UnsafeString to cast a NetString into a string without allocation + copy => Using NetString over string reduce allocations + copy operations + less object to be GCed - remove some unwanted allocation in async publisher client - redis 'optimizations': - replace all string types with common.NetString to reduce allocations - pre-allocate command buffer holding command + 4 arguments by default - remove some more allocations + copies by 'low-level code' - remove transaction object type (not required anymore due to correlation supporting piping), but generate event type directly from correlated messages => reduces allocation once more + removes computation of unused fields
@urso As @travis-ci seems to be broken at the moment I suggest to rely on our Jenkins build. |
Did play with golang pprof tool today + redis pcap files. This PR hugely reduces number of objects allocated by redis-module itself. When replaying redis traffic only object allocations are mostly dominated by the json encoder (the output worker directly calls console outputer doing json encoding):
TODO: some benchmarking on redis module to check if allocations really make a big difference.
changes
added commandline flag '-httpprof' to start HTTP pprof endpoint for doing
some live profiling of beat services (heap profiling, cpu profiling)
add streambuf.AppendWithCapLimits which guarantees newly allocated
buffers have at least configured capacity in case the buffer
must grow when appending new content (excert more control on buffer sizing)
=> not used, as number of objects allocated was minor in contrast to
other object types. Plus bad policy can increase overal memory usage
dramatically due to pointers back into original slice
add common.NetString basically being []byte. Difference to []byte is, this
type implements the encoding.TextMarhsaller interface. NetString objects
will be handled by JSON encoder like normal strings, thusly no allocation
and copy is required when extracting strings from parsed messages.
NetString being []byte will directly point into original message buffer.
NetString also provides UnsafeString to cast a NetString into a string
without allocation + copy
=> Using NetString over string reduce allocations + copy operations +
less object to be GCed
remove some unwanted allocation in async publisher client
redis 'optimizations':
supporting piping), but generate event type directly from correlated
messages => reduces allocation once more + removes computation of unused
fields