StringTemplates deferred evaluation
Brian Goetz
brian.goetz at oracle.com
Sun Mar 17 19:45:29 UTC 2024
It depends on how you measure "don't care anything". Even this, which
is pretty fast, still creates an object with a list containing {
hugeObject, expensiveObject }. This is pretty cheap but not necessarily
free. (It may be free if the debug() call gets inlined.)
I think for 9x% of the cases, this is entirely cheap enough; for those
cases where it is not, the old fussy technique of
if (isDebugLogging)
logger.debug(...)
will recapture the rest.
On 3/17/2024 3:41 PM, Anatoly Kupriyanov wrote:
> I guess it is not fair to think about it in terms of premature
> optimization. I am trying to look at it from a logging-framework
> developer point of view. As a library developer I should give the
> smallest overhead possible. So library users could safely do
> LOGGER.debug("Some thing={}, another={}", hugeObject, expensiveObject);
> and don't care about anything at all as debug is usually disabled. So
> the debug statement could be used even in a tight computation loop
> without worries. In other words, logger devs could not assume anything
> about how their framework would be used, but they will fight for the
> easiest to use api with the fastest performance.
> The idea is that the trace is usually disabled and an app could
> chew-up gigs of data, but while debugging/investigating, the trace
> could be temporarily enabled and expected to degrade performance.
>
>
> On Sun, 17 Mar 2024 at 17:36, David Alayachew
> <davidalayachew at gmail.com> wrote:
>
> Thank you for the code example. That helps clarify your desired
> behaviour.
>
> Ok, if your intent is to have absolutely no garbage collection
> whatsoever, then yes, my solution does not guarantee that. How
> much the JIT will help or optimize, I cannot say.
>
> That said, a String is a "blessed type" in Java. It has a handful
> of optimizations that are specific to it and it alone. I am
> actually expecting that StringTemplates will receive at least a
> small taste of this sort of optimization.
>
> Furthermore, the cost of creating a StringTemplate is rarely, if
> ever, the expensive part of the operation. In fact, I am certain
> it is trivial, if not optimized away like you were asking.
>
> I won't presume to call this premature optimization -- perhaps
> your application needs require it. But if so, I would first wait
> and see (or better yet, calculate!) the performance metrics of
> these StringTemplates. If they fail to meet your performance
> needs, then communicate your performance needs to this mailing
> list, with a hard example (and ideally metrics!) in tow.
>
> On Sun, Mar 17, 2024 at 1:07 PM Anatoly Kupriyanov
> <kan.izh at gmail.com> wrote:
>
> Classically (how it was done a decade or so ago) the logger
> method would look like:
> void debug(String template, Object arg1, Object arg2) {
> if(!enabled) return;
> writeLog(interpolate(template, arg1.toString(), arg2.toString()));
> }
>
> That allows that if enabled==false, then it will be zero-gc,
> guaranteed.
> It even used a lot of overrides with zero args, one arg, two
> args to avoid ...-ellipsis array allocation. E.g. see
> https://www.slf4j.org/api/org/slf4j/Logger.html
>
> There is a C# hacky approach the String Interpolation Handler
> (
> https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/interpolated-string-handler
> ) to use struct (allocated on stack) and magical isEnabled
> flags to cover logging effectively.
>
> I don't see how it would be possible to use the StringTemplate
> to achieve the similar effectiveness, unless there are some
> good and reliable optimizations in JIT to avoid allocations.
>
> On Sun, 17 Mar 2024 at 16:41, David Alayachew
> <davidalayachew at gmail.com> wrote:
>
> The cost would be no different than evaluating a
> StringTemplate lazily. Utlimately, log.debug(blah) is
> still a method call, and therefore, some object is going
> into the method. Whether we evaluate the StringTemplate
> lazily or the Supplier<StringTemplate> lazily is largely
> the same thing.
>
> Or am I misunderstanding you?
>
> On Sun, Mar 17, 2024 at 12:28 PM Anatoly Kupriyanov
> <kan.izh at gmail.com> wrote:
>
> But the "() ->" thing is still a runtime object to be
> allocated on the heap... or is the JIT smart enough to
> always optimize it out?
>
> On Sun, 17 Mar 2024 at 16:17, David Alayachew
> <davidalayachew at gmail.com> wrote:
>
> I feel like that would be on the logging libraries
> to provide, not so much the language.
>
> Let's say that your problem (as I understand it)
> is like this.
>
> log.debug("metrics =
> \{this.expensiveComputationThatNormallyWouldntRunUnlessYouActivateDebug()}");
>
> Sounds to me like the solution is this instead.
>
> log.debug(() -> "metrics =
> \{this.expensiveComputationThatNormallyWouldntRunUnlessYouActivateDebug()}")
>
> So, your logging library just needs to add a new
> overload for a Supplier<StringTemplate>, and then
> this problem is solved entirely outside of the
> language. Log4J and friends are pretty good about
> keeping up with new additions, so it should not
> take long.
>
> I know it's a little less convenient, but doing it
> this way helps keep out complexity from the
> feature, and only introduces it where necessary
> (and it's only necessary at use-site).
>
> Would this meet your needs?
>
> On Sun, Mar 17, 2024 at 11:15 AM Justin Spindler
> <justin.spindler at gmail.com> wrote:
>
> I was toying around with the second preview of
> StringTemplates and I had a question regarding
> their design. I was wondering if it had been
> considered for the embedded expressions to be
> evaluated lazily?
>
> One of the first use cases that came to mind
> when I was exploring StringTemplates is
> logging. That is an extremely common case
> where we want to produce a form of
> interpolated value, and the current syntax
> generally has the same concerns that a
> formatted string would, in that the inputs are
> removed from where they are defined within the
> message format. However, if the log message is
> below the log level threshold you generally
> don't want to incur the cost of building the
> message, including evaluating those embedded
> expressions. Log libraries typically offer a
> mechanism to defer evaluation via Suppliers,
> but that feels like it would be a challenge to
> use within StringTemplate.
>
> C# is an example of a language that offers
> this functionality via FormattableString,
> which gives a method the ability to choose
> whether or not to interpret the template or
> evaluate the expressions. That allows logging
> below threshold to be more or less a no-op.
>
>
>
>
> --
> WBR, Anatoly.
>
>
>
> --
> WBR, Anatoly.
>
>
>
> --
> WBR, Anatoly.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20240317/1f3f2f2a/attachment-0001.htm>
More information about the amber-dev
mailing list