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

Optimize some hotspots #3214

Merged
merged 3 commits into from
Sep 6, 2019
Merged

Conversation

christophsturm
Copy link
Contributor

Don't build huge debug strings unless we have to.

Copy link
Member

@sqrrm sqrrm left a comment

Choose a reason for hiding this comment

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

utACK

... but would be better with braces for the log code blocks

@christophsturm
Copy link
Contributor Author

I did it without braces because the log command is always just one statement, and its already very verbose. do you think i should change it?

@sqrrm
Copy link
Member

sqrrm commented Sep 6, 2019

I have seen a few bugs already due to code blocks without braces. Don't know if java or this project or why, but I now prefer them for all if statements for bisq.

@christophsturm
Copy link
Contributor Author

ok. I'll change it.

Copy link
Contributor

@freimair freimair left a comment

Choose a reason for hiding this comment

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

need to check if the isDebugEnabled() call isn't done by log.debug("{}", a) anyways.

log.debug("We got 2 network_messages received in less than 10 ms. We set the thread to sleep " +
"for 20 ms to avoid getting flooded by our peer. lastReadTimeStamp={}, now={}, elapsed={}",
lastReadTimeStamp, now, elapsed);
if (log.isDebugEnabled())
Copy link
Contributor

Choose a reason for hiding this comment

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

I have been in the believe that this is exactly what log.debug("{}", a) does before the string is assembled?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think as well that the expression is only executed if log level matches. the static string does not has much cost

@@ -724,7 +725,8 @@ public void run() {

NetworkEnvelope networkEnvelope = networkProtoResolver.fromProto(proto);
lastReadTimeStamp = now;
log.debug("<< Received networkEnvelope of type: " + networkEnvelope.getClass().getSimpleName());
if (log.isDebugEnabled())
log.debug("<< Received networkEnvelope of type: " + networkEnvelope.getClass().getSimpleName());

Copy link
Contributor

Choose a reason for hiding this comment

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

I would instead suggest:

Suggested change
log.debug("<< Received networkEnvelope of type: {}", networkEnvelope.getClass().getSimpleName());

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok that will still do the networkEnvelope.getClass().getSimpleName() call but that's probably not expensive.

Copy link
Contributor

Choose a reason for hiding this comment

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

As far I understand it does it only at debug log level

Copy link
Member

Choose a reason for hiding this comment

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

It looks like it will have to do that call to getSimpleName() but not build the string at debug log level. I think that's an acceptable balance so I change my opinion and would go with what @freimair suggests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i already changed it to his suggestion

@christophsturm
Copy link
Contributor Author

@sqrrm @freimair pls review again

@@ -98,7 +98,8 @@

public SettableFuture<Connection> sendMessage(@NotNull NodeAddress peersNodeAddress,
NetworkEnvelope networkEnvelope) {
log.debug("sendMessage: peersNodeAddress=" + peersNodeAddress + "\n\tmessage=" + Utilities.toTruncatedString(networkEnvelope));
if (log.isDebugEnabled())
log.debug("sendMessage: peersNodeAddress=" + peersNodeAddress + "\n\tmessage=" + Utilities.toTruncatedString(networkEnvelope));
Copy link
Contributor

Choose a reason for hiding this comment

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

We should use the {} syntax instead of +

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point but it has no perfomance implications in that case. maybe + is even faster if we already checked for isDebugEnabled?

log.debug("We got 2 network_messages received in less than 10 ms. We set the thread to sleep " +
"for 20 ms to avoid getting flooded by our peer. lastReadTimeStamp={}, now={}, elapsed={}",
lastReadTimeStamp, now, elapsed);
if (log.isDebugEnabled())
Copy link
Contributor

Choose a reason for hiding this comment

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

I think as well that the expression is only executed if log level matches. the static string does not has much cost

@@ -724,7 +725,8 @@ public void run() {

NetworkEnvelope networkEnvelope = networkProtoResolver.fromProto(proto);
lastReadTimeStamp = now;
log.debug("<< Received networkEnvelope of type: " + networkEnvelope.getClass().getSimpleName());
if (log.isDebugEnabled())
log.debug("<< Received networkEnvelope of type: " + networkEnvelope.getClass().getSimpleName());

Copy link
Contributor

Choose a reason for hiding this comment

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

As far I understand it does it only at debug log level

@christophsturm
Copy link
Contributor Author

@chimp1984 i think all your feedback is already implemented in later commits.

Copy link
Member

@sqrrm sqrrm left a comment

Choose a reason for hiding this comment

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

utACK

@sqrrm sqrrm merged commit 118d33a into bisq-network:master Sep 6, 2019
@freimair
Copy link
Contributor

freimair commented Sep 6, 2019

I just played around with numbers a bit and there came a surprising result. But please take these results with a pinch of salt (there might be some caching involved).

  • log.isDebugEnabled() = false
  • I placed a breakpoint in `Connection.java:763'
  • used the [Evaluate]-Tool of IntelliJ to execute:
long start = System.nanoTime();
for(int i = 0; i < 1000; i++)
	log.debug("size=" + size + "object=" + Utilities.toTruncatedString(proto, 100));
System.err.println((System.nanoTime()-start)/1000);
start = System.nanoTime();
for(int i = 0; i < 1000; i++)
	log.debug("size={}; object={}", size, Utilities.toTruncatedString(proto, 100));
System.err.println((System.nanoTime()-start)/1000);
start = System.nanoTime();
for(int i = 0; i < 1000; i++)
   if (log.isDebugEnabled())
       log.debug("size={}; object={}", size, Utilities.toTruncatedString(proto, 100));
System.err.println((System.nanoTime()-start)/1000);

and

long start = System.nanoTime();
for(int i = 0; i < 1000; i++)
    log.debug("size=" + size);
System.err.println((System.nanoTime()-start)/1000);
start = System.nanoTime();
for(int i = 0; i < 1000; i++)
    log.debug("size={}", size);
System.err.println((System.nanoTime()-start)/1000);
start = System.nanoTime();
for(int i = 0; i < 1000; i++)
   if (log.isDebugEnabled())
       log.debug("size={}", size);
System.err.println((System.nanoTime()-start)/1000);

and

long start = System.nanoTime();
for(int i = 0; i < 1000; i++)
    log.debug("classname=" + this.getClass().getSimpleName());
System.err.println((System.nanoTime()-start)/1000);
start = System.nanoTime();
for(int i = 0; i < 1000; i++)
    log.debug("classname={}", this.getClass().getSimpleName());
System.err.println((System.nanoTime()-start)/1000);
start = System.nanoTime();
for(int i = 0; i < 1000; i++)
	if(log.isDebugEnabled())
    	log.debug("classname={}", this.getClass().getSimpleName());
System.err.println((System.nanoTime()-start)/1000);
  • and here comes the somewhat surprising result:

Screenshot from 2019-09-06 14-21-31

What bothers me is that this kind of behavior would render any logging framework useless. Is there something I overlooked?

@sqrrm
Copy link
Member

sqrrm commented Sep 6, 2019

@freimair interesting, I guess Utilities.toTruncatedString is slow and it's worth the check to not run it.

@freimair
Copy link
Contributor

freimair commented Sep 6, 2019

of course. What bothers me is, to be more exact, is that there is no difference whether one uses "+" or "{}".

I recall that at least one logging framework implementation did show a massive performance improvement with using "{}" over "+" back in the days. Apparently not this one...

@sqrrm
Copy link
Member

sqrrm commented Sep 6, 2019

I think there would be a difference if you had more than one concatenated argument, I think it's worse than linear but can't remember where I saw that.

@freimair
Copy link
Contributor

freimair commented Sep 6, 2019

... being the idea of "{}" to only be assembled when the logging priority is actually enabled. In this case it looks like the string is concatenated either way.

@sqrrm
Copy link
Member

sqrrm commented Sep 6, 2019

I stepped through the log code in the debugger and I didn't see it concatenate it when not logging debug.

@christophsturm
Copy link
Contributor Author

I think {} is for objects that have an expensive toString method. the parameters of the log call will always be evaluated, but the toString will only be called when the string is actually assembled.
btw in kotlin logging you can just do log.debug { "a"+ "b"} maybe theres a logging lib for java with a similar syntax.

@christophsturm
Copy link
Contributor Author

if (log.isDebugEnabled()) log.debug("....") is very error prone when you start changing log levels and forget to do it in both places. I have seen it :))

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.

4 participants