On 19-03-2012 16:42, Matthew Toseland wrote:
No it doesn't. We need to be able to filter *by class name*, not just globally. 
I agree that in theory the if(logMINOR) is optional if the message is static 
though; I guess the JVM is fast enough that this won't cost us any cycles?

However, the minimum form of the boilerplate code is only:

static {
        volatile boolean logMINOR;
        volatile boolean logDEBUG;
        Logger.registerClass(Blah.class);
}
Fred source tree (@master) contains 1012 *.java files. Even if conservatively assuming that only 50% of those classes contain this snippet, and that they all use this minimal form, we have 2530 LoC for boilerplate code alone. Plus, 3379 hits to either logMINOR or logDEBUG.

That's a lot of code and memory use just to decide if a message is to be logged or not. (Yes, speed. See below)

Hmm, maybe. Something like s[n]printf even - log("request %u rejected by %o", 
requestID, peer) ??? Might be clearer code? Lot of work to change it though - and 
fractionally lower runtime performance than the if(). Unfortunately java doesn't have 
macros - but even if it did we'd like to be able to turn it on at runtime.
I was thinking in something along the lines of Python's print() - if the message is to be logged:

Logger.info("This: ", this, ", and that: ", this.that)

is completely equivalent to:

Logger.info("This: " + this + ", and that: " + this.that)

If the message is discarded, the overhead is a function call + cost of filtering (most likely a simple table lookup and two int comparisons in the worst case).

If you'd like a strict comparison between the overhead of using an if, against the overhead of a function call, I ran three simple test cases:

- Call an empty function;
- Test a boolean and then call an empty function, with the boolean set to either true or false.

The test case was inside a for loop, repeating for about 2 billion times. The test was run thrice, with only milliseconds of difference between runs. More importantly, JIT was disabled through -Xint.

Function call: ~31 seconds
Test + call: ~33 seconds
Failed test: ~23 seconds

So yes, in my machine, using an if saves 7 seconds over 2 billion best case tests. That's ~3,26 nanoseconds saved per test - an insignificant microptimization.

If JIT is enabled, it could be argued that it's easier for the JVM to perform optimizations based on a single boolean, than on multiple volatile booleans.

PrintWriter (System.err) busy-loops. :( It is probably possible to get the 
underlying OutputStream though.
Will take a look at it.

Yes. There is no reason to have each and every thread wait on disk I/O (whether 
this is cached or not), and furthermore this will lead to locking/concurrency 
problems. We get best performance by writing off thread, and we can then have 
that thread dump excess log messages if it can't keep up, avoiding blocking; or 
if something has to block, it's that thread and no other; and it can also 
handle log rotation cleanly. And even more importantly, we can keep lock 
contention to an absolute minimum, so other threads logging data create a 
byte[] and then lock only to add it to a queue (and delete surplus from the 
other end if necessary), which takes insignificant time.

All of this stuff is in FileLoggerHook.java.
Synchronization is the reason every thread should wait. If the log is always flushed and fred crashes, you know exactly where the last good checkpoint was before the crash. If the log is buffered (or asynchronous), the thread may be miles ahead from the last message written to disk, and suddenly you have no idea where to look for the bug. Shotgun debugging indeed.

Granted, if you want to generate lots of traces and debug data, it is desirable to churn out data at the highest rate possible. Possibly a configuration variable? Something like 'logger.mode = safe' (sync + flush) and 'logger.mode = unsafe' (async + buffered)?

Now, I'd wager the cost of maintaining a cache of log messages far surpass the cost of generating them in the first place except for very costly messages regenerated sparingly (or not at all). I haven't seen the current implementation, so there might exist some trick I'm failing to grasp.

I beg to differ. This shouldn't happen in normal use anyway. It's a message to 
devs doing shotgun debugging that they need a narrower filter (or faster 
disks!). We do indicate when stuff has been dropped.
Indication is no substitute for missing data. Speed doesn't really matter if you lose that critical message.

Would that be solved by renaming?
Since most people are used to DEBUG and INFO levels, their use becomes apparent.

Both. When doing shotgun debugging a dev needs to be able to search by class 
name, this is why we log(this, ...), and even more importantly they need to be 
able to identify which classes to log properly.
Right, but wouldn't the use of call stack + reflection be cleaner for the caller? Yes, performance impact. I will measure this later, if it's even possible.

For the per-class filtering, I think a HashTable<String, Severity> populated at init should solve the problem cleanly:

if severity < min_severity or if caller class is in table and severity < table_severity
    return
do_log

Performance hit should be negligible.

Currently this is handled in FileLoggerHook like everything else. Whatever 
happens will need to be closely linked to the code that actually does the 
writing for several reasons:
1. We need to do size-based rotation sometimes, especially with heavy log 
settings.
2. On Windows, we cannot rename a file until we have closed it.
3. It's easier to ensure that everything goes to one log or another if we just 
have the thread doing the writing close it and then open another one.
Figured as much. Inside Logger it is.

You can get it from Node IIRC? Not sure offhand. But have a look at the current 
code, in FileLoggerHook.java. No doubt it can be tidied up but it does at least 
meet all our requirements.
Will take a look. The format will possibly be: '[<uptime>] <thread_id> <severity> <class> <message>'. I might put the message on the next line with a bit of indentation if this format turns out to be too ugly.
_______________________________________________
Devl mailing list
[email protected]
https://emu.freenetproject.org/cgi-bin/mailman/listinfo/devl

Reply via email to