-
Notifications
You must be signed in to change notification settings - Fork 334
Description
Looking at some perf traces today, I stumbled upon the fact that swift-log appears to be failing at its goal of making non-issued logs approximately free. Consider this code:
public func whyThough(_ logger: Logger) {
logger.trace("Hello, world!")
}In an ideal world, in release builds this code would execute almost no instructions when the log level is higher than trace: it would check the log level, and then return.
In practice what it does is:
- Call
swift_beginAccess - Call
outlined init with copy of Logging.LogHandler, which includes calling through the VWT for the LogHandler to execute its copy constructor - Call
swift_project_boxed_opaque_existential_1 - Call
swift_destroy_boxed_opaque_existential_1
This appears to all boil down to the fact that the logLevel is held on the LogHandler, not the Logger, so we have to touch the existential in order to load the log level.
In some cases this may not be excessive, but if anyone has inserted trace level logs in hot code paths the cost can spiral quite badly. We’re seeing it take up to 10% of the CPU time in some of our high packet rate benchmarks.
Now, we can resolve this issue by just deleting the trace logging, but I wanted to ask: do we think swift-log should be this expensive? Are we interested in making it faster? We could make it faster by moving the log level to the Logger, not the LogHandler, but conceptually that could break existing code if they were playing weird tricks, and it could cause things that used to fit safely into existentials to not fit. How do we feel?