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

inefficient use of loggers #1680

Closed
stephengold opened this issue Nov 24, 2021 · 10 comments · Fixed by #1682
Closed

inefficient use of loggers #1680

stephengold opened this issue Nov 24, 2021 · 10 comments · Fixed by #1682
Assignees
Milestone

Comments

@stephengold
Copy link
Member

Issue #1672 drew my attention to inefficient use of loggers in JMonkeyEngine. A quick scan found dozens of instances that can probably be improved. A common anti-pattern is code that constructs a log message using string concatenation, as in GltfUtilities:

                logger.log(Level.WARNING, "Unsupported Vertex Buffer type " + attribute);

Most of these should be refactored.

@pspeed42
Copy link
Contributor

WARNING is a bad example because it is almost always enabled and so the check is redundant.

Whatever crappy-JUL's version of INFO is... that's sort of on the fence. Finer than that should either be gated or use the pattern version. (I prefer gating in general if a conversion is being done because that pattern idiom has an argument limit before it's no better than concatenating a string.)

vxel pushed a commit to vxel/jmonkeyengine that referenced this issue Nov 24, 2021
@vxel
Copy link
Contributor

vxel commented Nov 24, 2021

Indeed, I've spotted the same issue in a couple of classes in jme3-core. I did not check in other libs.
Not all FINE loggers are problematic though, e.g. those used only during initialization.

Additionnally, I wonder if it is worth the effort to gate logger statements that use multiple parameters, such as :
logger.log(Level.FINE, "{0} {1}", new Object[]{myobject1, myobject2})
Since this statement implies the creation of an object array, I also added a gate, but not systematically.

I'm preparing a PR fot this. Before submit it, you may take a look and tell me what you think.

@tonihele
Copy link
Contributor

tonihele commented Nov 24, 2021 via email

@vxel
Copy link
Contributor

vxel commented Nov 24, 2021

No, this statement does not use the supplier. I'm pretty sure the performance penalty of the array creation is present, even if the logger is not enabled, because the parameter is evaluated before calling the log method.

It is true that we can use a supplier instead of a gate for log statements like this :
logger.log(Level.FINE, "My log : {0}", () -> myMethod())
This does not seem to be a common practice in jme3, so I use a gate for now.

@stephengold
Copy link
Member Author

I'm preparing a PR fot this. Before submit it, you may take a look and tell me what you think.

I'm glad to know you're working on this, and I look forward to seeing your changes.

However, I'll do that after you submit the PR, not before.

@stephengold stephengold added this to the v3.5.0 milestone Nov 24, 2021
@pspeed42
Copy link
Contributor

re: logger.log(Level.FINE, "{0} {1}", new Object[]{myobject1, myobject2})

Yeah, that should be gated also. (Some logging APIs supply several multi-arg methods to avoid a var-args but JUL, even in its labyrinth of poopy and confusing APIs, chose not to do this.)

I still fail to understand why a line like that is better than logger.log(Level.FIND, myobject1 + " " + myobject2) but that may be personal style.

@pspeed42
Copy link
Contributor

Also, strictly speaking, if object creation is what we try to avoid then:
logger.log(Level.FINE, "My log : {0}", () -> myMethod())

...is no better because it will instantiate a lambda object every time, even if logging will be suppressed for FINE.

@vxel
Copy link
Contributor

vxel commented Nov 25, 2021

re: logger.log(Level.FINE, "{0} {1}", new Object[]{myobject1, myobject2})
I still fail to understand why a line like that is better than logger.log(Level.FINE, myobject1 + " " + myobject2) but that may be personal style.

The 1st statement requires the cost of an array creation. The 2nd statement requires two invocations of myobject1.toString(), myobject2.toString, plus the overall string concatenation, even if the level is suppressed. This certainly more expensive, even if the toString() implementations of the objects are trivial.

Also, strictly speaking, if object creation is what we try to avoid then:
logger.log(Level.FINE, "My log : {0}", () -> myMethod())
...is no better because it will instantiate a lambda object every time, even if logging will be suppressed for FINE.

Regarding the use of lambdas, my understanding is that lambdas without parameters are compiled once (at runtime) and reused (according to the talk of Brian Goetz about this : http://youtu.be/C_QbkGU_lqY?t=36m25s).

The example is then equivalent to :

private static final Supplier<String> MY_LAMBDA = () -> myMethod();
...
logger.log(Level.FINE, "My log : {0}", MY_LAMBDA);

which costs less than using a gate (not counting the unique compilation overhead).

Anyway, I wouldn't use lambda to preserve coherence among the code base, and because the logging API limits to 1 the number of supplier parameters we can pass.

@tonihele
Copy link
Contributor

Anyway, I wouldn't use lambda to preserve coherence among the code base, and because the logging API limits to 1 the number of supplier parameters we can pass.

One is enough right?

logger.log(Level.FINE, () -> myobject1 + " " + myobject2)

@vxel
Copy link
Contributor

vxel commented Nov 25, 2021

Oh yes it is.

Btw, I now understand the point of @pspeed42 regarding the personal style. If the statement is already gated, then the difference between

logger.log(Level.FINE, "{0} {1}", new Object[]{myobject1, myobject2})
and
logger.log(Level.FINE, myobject1 + " " + myobject2)

is mostly aesthetic.

vxel pushed a commit to vxel/jmonkeyengine that referenced this issue Nov 25, 2021
vxel pushed a commit to vxel/jmonkeyengine that referenced this issue Nov 25, 2021
vxel pushed a commit to vxel/jmonkeyengine that referenced this issue Nov 25, 2021
vxel pushed a commit to vxel/jmonkeyengine that referenced this issue Nov 26, 2021
@stephengold stephengold linked a pull request Nov 26, 2021 that will close this issue
stephengold added a commit that referenced this issue Nov 30, 2021
* #1680 jme3-core inefficient use of loggers

* #1680 All modules : Gate FINE loggers when required for perf reasons

* #1680 All modules : Gate INFO loggers when required for perf reasons

* #1680 All modules : Gate INFO loggers when required for perf reasons

* #1680 Reverts the "not worthwhile" changes

* revert changes that added complexity to init/cleanup code

* whitespace

Co-authored-by: Cédric de Launois <>
Co-authored-by: Stephen Gold <sgold@sonic.net>
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 a pull request may close this issue.

4 participants