-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Fix threadsafe issue of GetLogger / GetCurrentClassLogger (+improve performance) #1310
Fix threadsafe issue of GetLogger / GetCurrentClassLogger (+improve performance) #1310
Conversation
@@ -92,17 +94,21 @@ internal void PrecalculateStackTraceUsage() | |||
|
|||
// find all objects which may need stack trace | |||
// and determine maximum | |||
foreach (var item in ObjectGraphScanner.FindReachableObjects<IUsesStackTrace>(this)) | |||
// only the target can have IUsesStackTrace | |||
if (Target != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't you need to recurse NextInChain as well? In case those LayoutRenderers require stacktraces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK that isn't needed. This call is invoked for every targerwithchain. But please correct me if I missed something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From what I can see it's definitely needed: The root of the chain is used here to determine which kind of stacktrace is needed, then the chain itself is processed later in a loop.
The PrecalculateStackTraceUsage is also only called for the root of the chain, so only the StackTraceUsage of the root is valid.
I noticed this PR after investigating an initialization performance issue when using ~150 loggers with 6 logging rules (on NLog 4.2.3). PrecalculateStackTraceUsage would end up calling the ObjectGraphScanner quite often, and we all know Reflection isn't fast. Disabling it reduced app startup from 8 sec to 1 sec, but that's by no means a solution. Doing the scanning during Initialize is definitely an improvement. Allowing GetAllLayouts to do lazyloading is a bit risky, coz that potentially conflicts with another thread calling GetLogger. I assume there aren't any guarantees that the user calls ReconfigExistingLoggers after configuring, right? Isn't it ridiculous the amount of work done to determine what kind of stacktrace is needed... |
Well getting stacktrace costs a lot at runtime. But there is also a thread-safe issue here which I try to solve without many locks. Can you test the performance after I get this working? |
Current coverage is
|
…ndReachableObjects by replacing objectscanner and let SimpleLayout implement IUsesStackTrace
8398327
to
1471656
Compare
All PRs are succeeding so tested at least 12 times (6 PRs) |
…aceUsage Fix threadsafe issue of GetLogger / GetCurrentClassLogger (+improve performance)
Performance is good, same 1 s startup time as when I disabled it entirely. However, you still need to process Also, |
Missed indeed your 2nd comment. Will check now. Thanks! |
Can you elaborate on that? Thanks! |
FindAllLayouts uses ObjectGraphScanner, which checks all properties on the Target and it's hierarchy. When it finds a Layout instance it adds it to the resultset but it also it dives into the properties of the Layout and it's children (LayoutRenderers for example). So it scans more objects that strictly required. |
another try for #1262
Fix PrecalculateStackTraceUsage for threadsafe issues in objectscaner.FindReachableObjects