-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Can logging macros call code hidden behind a function? #36236
Comments
Yes, this would be great since it could significantly reduce code size and compiler burden. The best practice is for a macro to emit the minimal possible code that can't be done with a function, and put everything else in a function. |
Should this almost word for word be added to the Julia style guide in the docs? |
The logging system is also designed (IIRC) to do as little work as possible in case the log msg is not emitted. |
I think hiding logging behind a function is possible but we need to create a closure to defer the log record creation. |
This is a duplicate of #36174, but happy to continue the discussion here.
Exactly! The original implementation did this, but I changed it in #25922 to use try/catch because there were some worries about creating a lot of closures, and practical inefficiency due to the closure capture boxing problem (see logging bug report #25909). Regardless of those implementation problems I prefer lazy generation of the log information and I think it would improve the logging system as a whole. So I'm definitely open to changing this back to the original version — perhaps with an improved version of the FastClosures "let trick" to avoid #25909. |
For the original implementation which included closures see https://github.com/c42f/julia/blob/1845bdb3ccacfea4e7256b2af3541629eac66536/base/logging.jl#L314 |
@JeffBezanson I know you were originally somewhat against having closures here (#25909 (comment)), but the tradeoff is creating a closure vs emitting rather a lot of code from the macro. We could make it less bad though: detect whether the user code contains any nontrivial expressions; if not emit a standard |
That sounds good. I acknowledge the contradiction: inlining the code is hard on the compiler; moving it to a function is also hard on the compiler. The compiler would like to be left alone to nap, thank you very much 😂 |
I don't think you have a contradiction there. Outlining code for one user is worse on the compiler than using the same code inline. Better is to not have the code, by ensuring duplicated sections are in a function. But, from working on this in the past, we already put the non-duplicated work inside functions, and expose a minimal surface area to the compiler. |
Agreed, having code just causes trouble 😂 Actually I think we could probably delete the try-catch completely from the frontend and push it into the individual logger backends if we make log record computation lazy. I feel like this would be a semantic improvement anyway. So, the plan as I see it:
|
👍 I think this is a nice direction. I think this helps us merging them because the lazy log record can be materialized at the bottom of the logging pipeline (or actually anywhere; though we need to be a bit careful with the fan-out type logging pipeline combinators to avoid materializing records multiple times). This lets us create transducer-like composable logging pipeline (something like JuliaLogging/LoggingExtras.jl#23 (comment)). Making this backward-compatible might be tricky, though. |
Right 👍 Also a single entry point is cleaner if logging ends up going via an effect system. I'm not worried about compatibility at all — I think we just use a new name ( To see whether that all works out it would be nice to combine these ideas into a new Logging2.jl library with a big overhaul of composable log routing machinery and some declarative configuration along the lines of |
Yes, I agree this can/should be done by adding new names. I wasn't sure how difficult it would be but maybe I was over-estimating it. But I guess it's safer to just add the closure-based logging macro implementation without touching the API at all, to ship this within the 1.6 time-frame. The macro could be structured in such a way that it is easy to do the experiment outside |
Yes that's the idea — get the internal rearrangements in and make sure the performance can be acceptable. Another benefit of merging |
Yes! I'm thinking that, too. Minimizing dynamic dispatch and pay it only once sounds like a good strategy. I wonder if it makes the inference of the caller easier (rather than just run-time performance of the callee). |
Yes and if we ensure the entry point doesn't get inlined and also ensure that the return type is always (Edit: the return type of the public API may not be |
I was wondering if we could move the code for logging behind a function. For example, the try/catch in
@warn
causes issues with the code generation in Zygote. Even if that did get fixed in Zygote, the process would have to churn through less code if@warn
was calling a function, and that function was given an adjoint definition that told it to ignore the code in there. So something as some asmacro warn(args...) = _warn(@__MODULE__,args...)
or the like would allow defining hooks on_warn
that fix the issue.@c42f @MikeInnes
The text was updated successfully, but these errors were encountered: