Skip to content
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

slog: faster and easier on the memory #8

Closed
wants to merge 15 commits into from

Conversation

holiman
Copy link

@holiman holiman commented Nov 7, 2023

These changes improves the performance of the non-coloured terminal formatting, quite a lot.

ok      github.com/ethereum/go-ethereum/log     17.305s
[user@work go-ethereum]$ benchstat slog.before slog.after 
name               old time/op    new time/op    delta
GloggerTerminal-8    9.46µs ± 8%    6.07µs ±20%  -35.85%  (p=0.000 n=10+10)

name               old alloc/op   new alloc/op   delta
GloggerTerminal-8    1.96kB ± 0%    0.23kB ± 0%  -88.47%  (p=0.000 n=10+10)

name               old allocs/op  new allocs/op  delta
GloggerTerminal-8      33.0 ± 0%       5.0 ± 0%  -84.85%  (p=0.000 n=10+10)

I tried to somewhat organize the commits, but the it might still be a bit chaotic. Some core insights:

  • The function terminalHandler.Handl uses a mutex, and writes all output immediately to 'upstream'. Thus, it can reuse a scratch-buffer every time.
  • This buffer can be propagated internally, making all the internal formatters either write directly to it,
  • OR, make use of the tmp := buf.AvailableBuffer() in some cases, where a byte buffer "extra capacity" can be temporarily used.
  • The slog package uses Attr by value. It makes sense to minimize operating on them, since iterating / collecting into a new slice, iterating again etc causes copy-on-heap. Better to operate on them only once.
  • If we want to do padding, it's better to copy from a constant space-buffer than to invoke bytes.Repeat every single time.

I haven't merged it directly into the slog PR, maybe we should get that fixed and merged first? We can do either way, putting it up here for some feeback.

log/handler.go Outdated
}
case *uint256.Int:
if v == nil {
attr.Value = slog.AnyValue("<nil>")
} else {
attr.Value = slog.AnyValue(formatLogfmtUint256(v))
attr.Value = slog.AnyValue(appendU256(nil, v))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String it

log/format.go Show resolved Hide resolved
@holiman
Copy link
Author

holiman commented Nov 14, 2023

Rebased on latest, also improved some.

$ benchstat slog.before slog.after4 
name               old time/op    new time/op    delta
GloggerTerminal-8    9.10µs ± 9%    4.86µs ±14%  -46.55%  (p=0.000 n=10+10)

name               old alloc/op   new alloc/op   delta
GloggerTerminal-8    1.89kB ± 0%    0.18kB ± 0%  -90.57%  (p=0.000 n=10+10)

name               old allocs/op  new allocs/op  delta
GloggerTerminal-8      30.0 ± 0%       4.0 ± 0%  -86.67%  (p=0.000 n=10+10)

(still, let's merge the original one first)

key := escapeString(attr.Key)
rawVal := attr.Value.Any()
val := FormatLogfmtValue(rawVal, true)
tmp := buf.AvailableBuffer()
Copy link
Owner

@jwasinger jwasinger Nov 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bytes.AvailableBuffer was introduced in go1.21 . for now, can we make use of a separate temporary buffer, clearing it on each call to appendEscapeString?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Something temporary yes, lemme think about it...

karalabe and others added 15 commits November 27, 2023 16:20
…28584)

This change exposes more information from sync module internally
This changes removes the package 'light', which is currently unused.
…aintests) (ethereum#28504)

There were several problems related to dumping state. 

- If a preimage was missing, even if we had set the `OnlyWithAddresses` to `false`, to export them anyway, the way the mapping was constructed (using `common.Address` as key) made the entries get lost anyway. Concerns both state- and blockchain tests. 
- Blockchain test execution was not configured to store preimages.

This changes makes it so that the block test executor takes a callback, just like the state test executor already does. This callback can be used to examine the post-execution state, e.g. to aid debugging of test failures.
This change fixes two type-inconsistencies in the JS tracer:

- In most places we return byte arrays as a `Uint8Array` to the tracer. However it seems we missed doing the conversion for `ctx` fields which are passed to the tracer during `result`. They are passed as simple arrays. I think Uint8Arrays are more suitable and we should change this inconsistency. Note: this will be a breaking-change. But I believe the effect is small. If we look at our tracers we see that these fields (`ctx.from`, `ctx.to`, etc.) are used in 2 ways. Passed to `toHex` which takes both array or buffer. Or the length was measured which is the same for both types.
- The `slice` taking in `int, int` params versus `memory.slice` taking `int64, int64` params. I suggest changing `slice` types to `int64`. This should have no effect almost in any case.
…ations (ethereum#28618)

* eth/gasestimator: early exit for plain transfer and error allowance

* core, eth/gasestimator: hard guess at a possible required gas

* internal/ethapi: update estimation tests with the error ratio

* eth/gasestimator: I hate you linter

* graphql: fix gas estimation test

---------

Co-authored-by: Oren <orenyomtov@users.noreply.github.com>
This PR replaces Geth's logger package (a fork of [log15](https://github.com/inconshreveable/log15)) with an implementation using slog, a logging library included as part of the Go standard library as of Go1.21.

Main changes are as follows:
* removes any log handlers that were unused in the Geth codebase.
* Json, logfmt, and terminal formatters are now slog handlers.
* Verbosity level constants are changed to match slog constant values.  Internal translation is done to make this opaque to the user and backwards compatible with existing `--verbosity` and `--vmodule` options.
* `--log.backtraceat` and `--log.debug` are removed.

The external-facing API is largely the same as the existing Geth logger.  Logger method signatures remain unchanged.

A small semantic difference is that a `Handler` can only be set once per `Logger` and not changed dynamically.  This just means that a new logger must be instantiated every time the handler of the root logger is changed.

----
For users of the `go-ethereum/log` module. If you were using this module for your own project, you will need to change the initialization. If you previously did 
```golang
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
```
You now instead need to do 
```golang
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true)))
```
See more about reasoning here: ethereum#28558 (comment)
- implement custom time writer,
- better padding with spaces
- better use of spaces
- log: more efficient handling of slog.Value
- log: utilize scratch-buffer in terminal handler
- log: use scratch-space for value formatting
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants