-
Notifications
You must be signed in to change notification settings - Fork 24
perf: human log sink performance bump via reduction of allocs/total allocated memory #220
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
Conversation
Signed-off-by: Callum Styan <callumstyan@gmail.com>
Signed-off-by: Callum Styan <callumstyan@gmail.com>
…e the optimized version should return an error Signed-off-by: Callum Styan <callumstyan@gmail.com>
Pull Request Test Coverage Report for Build bb87268ba9bc796f570dc37547e5f0281129ddf5-PR-220Details
💛 - Coveralls |
Signed-off-by: Callum Styan <callumstyan@gmail.com>
Signed-off-by: Callum Styan <callumstyan@gmail.com>
…ne very specific case that should never happen if we're actually going to OOM via logging it would panic Signed-off-by: Callum Styan <callumstyan@gmail.com>
… files for new test cases Signed-off-by: Callum Styan <callumstyan@gmail.com>
Signed-off-by: Callum Styan <callumstyan@gmail.com>
| level := ent.Level.String() | ||
| level = strings.ToLower(level) | ||
| if len(level) > 4 { | ||
| level = level[:4] | ||
| } | ||
| level = "[" + level + "]" |
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.
wow this old code was kinda dumb in comparison.
| func bracketedLevel(l slog.Level) string { | ||
| switch l { | ||
| case slog.LevelDebug: | ||
| return "[debu]" | ||
| case slog.LevelInfo: | ||
| return "[info]" | ||
| case slog.LevelWarn: | ||
| return "[warn]" | ||
| case slog.LevelError: | ||
| return "[erro]" | ||
| case slog.LevelCritical: | ||
| return "[crit]" | ||
| case slog.LevelFatal: | ||
| return "[fata]" | ||
| default: | ||
| return "[unkn]" | ||
| } | ||
| } |
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.
👍
Signed-off-by: Callum Styan <callumstyan@gmail.com>
…only saves ~1 byte per op) Signed-off-by: Callum Styan <callumstyan@gmail.com>
dannykopping
left a comment
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.
Awesome result 💪
Only nits
internal/entryhuman/entry.go
Outdated
| case int: | ||
| var a [20]byte | ||
| _, err := w.Write(strconv.AppendInt(a[:0], int64(x), 10)) | ||
| return true, err | ||
| case int8: | ||
| var a [20]byte | ||
| _, err := w.Write(strconv.AppendInt(a[:0], int64(x), 10)) | ||
| return true, err | ||
| case int16: | ||
| var a [20]byte | ||
| _, err := w.Write(strconv.AppendInt(a[:0], int64(x), 10)) | ||
| return true, err | ||
| case int32: | ||
| var a [20]byte | ||
| _, err := w.Write(strconv.AppendInt(a[:0], int64(x), 10)) | ||
| return true, err |
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: DRY
| case int: | |
| var a [20]byte | |
| _, err := w.Write(strconv.AppendInt(a[:0], int64(x), 10)) | |
| return true, err | |
| case int8: | |
| var a [20]byte | |
| _, err := w.Write(strconv.AppendInt(a[:0], int64(x), 10)) | |
| return true, err | |
| case int16: | |
| var a [20]byte | |
| _, err := w.Write(strconv.AppendInt(a[:0], int64(x), 10)) | |
| return true, err | |
| case int32: | |
| var a [20]byte | |
| _, err := w.Write(strconv.AppendInt(a[:0], int64(x), 10)) | |
| return true, err | |
| case int, int8, int16, int32: | |
| var a [20]byte | |
| _, err := w.Write(strconv.AppendInt(a[:0], int64(x), 10)) | |
| return true, err |
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.
unfortunately we can't do it quite like this, the compiler still treats each type as distinct even if they're all in the same case like this, which means we'd either have to type assert OR reflect within the case itself
we can at least move the byte slice declaration, write call, and return, into reusable writeSignedInt and writeUnsignedInt functions
Signed-off-by: Callum Styan <callumstyan@gmail.com>
I was poking around in profiling data for our dogfood instance and I noticed that over a 24h period debug logging through the human readable log sink was producing 10-12% of our memory allocation. Garbage collection is only ~7.5% of our CPU time, but hopefully this has a nice reduction for allocs/memory allocated and small reduction for GC related CPU usage.
Benchmark data:
Note that the existing benchmark didn't cover many use cases, so the changes are not as obvious there:
Current alloc space:

Current alloc object:

Alloc objects path:

Alloc space path:

GC CPU time:
