-
Notifications
You must be signed in to change notification settings - Fork 939
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
Logging restructure #1127
Logging restructure #1127
Conversation
…ith other cinder interfaces.
…or for the logger stack.
The logic I was using to tally time / log was incorrect. I was doing:
Which is incorrect because the timers were running in a concurrent manner. If I switch to using the max time any of the loggers took, things are a bit more reasonable:
Produces these results: Main branch (localized locks, not thread safe)
This branch (lock in write(), thread safe)
|
//! Returns a vector of all current loggers | ||
std::vector<Logger *> getAllLoggers(); | ||
//! Returns the mutex used for thread safe loggers. Also used when adding or resetting new loggers. | ||
std::vector<LoggerT*> getLoggers(); |
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.
Since we're switching to LoggerRef's before, might as well return a std::vector<LoggerRef>
here too (can be done with std::dynamic_pointer_cast<LoggerT>()
in impl).
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.
I struggled with that a little bit. I really wanted to return a std::vector<shared_ptr<LoggerT>>
, but returning a shared_ptr of a different template is problematic.
Part of me thought it was strange to return std::vector<LoggerRef>
since you requested LoggerT
, but I think it's more consistent than the raw pointers, and makes more sense given the rest of the interface.
I'll make that change.
Thanks for the review!
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.
Despite my suggestion above to return vector (wasn't thinking to deeply), what if we did it like this? That way if the type of logger you're requesting has special parameters you have the right type in the vector and can act on them directly, without needing to type cast again.
If this is agreeable, then I'll go ahead and merge the PR along with that change.
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.
Got it, I didn't fully understand the workings of std::dynamic_pointer_cast<LoggerT>()
when you first mentioned it. This is definitely the ideal solution.
Other than above comment, looks good to me. Thanks for getting through all of this! |
Related to #1107
Tasks completed in this rewrite
Performance
The good news is we now prevent a crash when adding and removing loggers from threads. I confirmed the crash exists in the main branch, and confirmed the crash is fixed in this PR.
The bad news is that, in order to stop this crash, we had to move the lock mutex to the lowest level write() routine. This really starts to show when you are logging from multiple threads.
For tests below, each thread logged 1 million times to a single log file.
Main branch (localized locks, not thread safe)
This branch (lock in write(), thread safe)
This is, of course, probably worse case since my test case has multiple threads logging from within loops. I think we'll be able to improve this considerably when we can introduce shared_locks into the code base.