-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
EnableLogCleaner() interface is not thread safe? #753
Comments
Could you please point out the exact location where the problem occurs? |
When one thread is logging to file, it will call the function meanwhile other thread try to change the so may be it lead to undefined behaviour? I am just in doubt of this. May be I am wrong. Thanks for response. |
Is it possible that you mean a race condition and not undefined behavior? The former can occur because cc @aesophor |
Yes. It must not leads to undefined behavior because |
I'm not sure what are you asking. Just because a boolean is not atomic it will not immediately cause undefined behavior. Also, undefined behavior is generally not prescribed by a library but by the language standard. |
OK. If the |
Quoting from @sergiud:
@kimi20071025 We understand the possible race condition you've mentioned. Are you working on something that can trigger this race condition and is intolerable? IMO, if we want to eliminate race condition completely, just making In this case, is there a better option other than a mutex? |
What I am worried about is not race condition but data race. Glog library try to clean overdue logs every time when logging. I think it may cost much performance If LogCleaner is opened all the time. So Once a day, I enable log cleaner ( When a thread is logging, it will finally call Meanwhile, other thread calls So what I worried is the condition may cause data race . |
I had to actually look this up. But it seems that concurrent reading/writing of/to a variable is indeed undefined behavior in C++. However, at this point I would rather claim that your use case is not supported in the sense that you should not be calling
How did you determine the performance penalty, or is this only a guess? If it's the latter, you should measure quantitatively first and let us know how strong the performance degradation is if the cleaner has been enabled. This is something worth improving. |
About the log cleaner performance, I shared the same opnion with issue #702 . Much performance cost when enable log clean. And I also read the benchmark #761 , could @aesophor help to make other benchmark comparing the logging performance between enable log clean with disable log clean? If there is much performance penalty comparing by disable log clean. It means the LogCleaner can not be enabled all the time. |
Upon each call to |
Platform
Test code#include "glog/logging.h"
#include <unistd.h>
#include <chrono>
#include <iostream>
using namespace std;
using namespace chrono;
int main(int argc, char *argv[])
{
google::InitGoogleLogging("");
FLAGS_logbufsecs = 0;
FLAGS_max_log_size = 100;
google::SetLogDestination(google::GLOG_ERROR, "/tmp/glog/ERROR_");
google::SetLogDestination(google::GLOG_WARNING, "");
google::SetLogDestination(google::GLOG_INFO, "");
FLAGS_colorlogtostderr = false;
FLAGS_alsologtostderr = false;
google::SetStderrLogging(google::GLOG_FATAL);
google::EnableLogCleaner(1);
auto enableLogCleanStart = system_clock::now();
for (uint16_t i = 0; i < 50000; i++)
{
LOG(ERROR)<<"glog error";
}
auto enableLogCleanEnd = system_clock::now();
std::chrono::duration<double, std::milli> enableLogCleanDuration = enableLogCleanEnd - enableLogCleanStart;
cout<<"cost: "<<enableLogCleanDuration.count()<<" ms when enable log clean"<<endl;
google::DisableLogCleaner();
auto disableLogCleanStart = system_clock::now();
for (uint16_t i = 0; i < 50000; i++)
{
LOG(ERROR)<<"glog error";
}
auto disableLogCleanEnd = system_clock::now();
std::chrono::duration<double, std::milli> disableLogCleanDuration = disableLogCleanEnd - disableLogCleanStart;
cout<<"cost: "<<disableLogCleanDuration.count()<<" ms when disable log clean"<<endl;
return 0;
}
Resultcost: 518.541 ms when enable log clean
cost: 225.845 ms when disable log clean conclusionWhen there are 1 file in log directories and log cleaner is opened, the log performance will decrease 230% comparing with log cleaner is closed. |
I believe that the overhead (518.541 ms) is because:
If your application needs to write so frequently but it's performance critical at the same time, then you can use another thread to occasionally perform cleanup. You are also welcome to submit a PR and improve it. |
A possible optimization strategy: use |
This is what I already do, But the date race of |
I read the functions of
EnableLogCleaner
,DisableLogCleaner
andLogCleaner::enabled()
.I find the private member
enabled_
ofLogCleaner
is not lock guard.Once one thread call
EnableLogCleaner
,and other thread is logging, It may lead to undefined behaviour?The text was updated successfully, but these errors were encountered: