Can someone help me in identifying the hot spots in the plugin ? Where should I start to look for possible candidates ?
Can you first try what happens if you disable the ToDo list plugin (yes: ToDo)?
I have tried that, and unfortunately it did not help.
I have tried to measure the code speed on my laptop at work : I have found a few solutions, although it is not perfect.
BUG 1 : loading a workspace is 10 times slower on Win XP than on Win 7 (laptop on WinXP is an Intel Core I7, laptop on Win7 64 is an Intel Core I5)
=> most of the time is spent in the method NativeParser::AddCompilerDirs.
More specifically : it seems to be in these following pieces of code:
// get targets include dirs
for (int i = 0; i < project->GetBuildTargetsCount(); ++i)
{
ProjectBuildTarget* target = project->GetBuildTarget(i);
if (target && target->SupportsCurrentPlatform())
{
if (compiler)
{
// post-processed search dirs (from build scripts)
for (unsigned int ti = 0; ti < compiler->GetCompilerSearchDirs(target).GetCount(); ++ti)
{
wxString out = compiler->GetCompilerSearchDirs(target)[ti];
wxFileName dir(out);
if (NormalizePath(dir, base))
{
parser->AddIncludeDir(dir.GetFullPath());
TRACE(_T("AddCompilerDirs() : Adding compiler target dir to parser: ") + dir.GetFullPath());
}
else
CCLogger::Get()->DebugLog(F(_T("Error normalizing path: '%s' from '%s'"), out.wx_str(), base.wx_str()));
}
}
// apply target vars
// target->GetCustomVars().ApplyVarsToEnvironment();
for (unsigned int ti = 0; ti < target->GetIncludeDirs().GetCount(); ++ti)
{
wxString out = target->GetIncludeDirs()[ti];
// Manager::Get()->GetMacrosManager()->ReplaceMacros(out);
wxFileName dir(out);
if (NormalizePath(dir, base))
{
parser->AddIncludeDir(dir.GetFullPath());
TRACE(_T("AddCompilerDirs() : Adding target dir to parser: ") + dir.GetFullPath());
}
else
CCLogger::Get()->DebugLog(F(_T("Error normalizing path: '%s' from '%s'"), out.wx_str(), base.wx_str()));
}
// get the compiler
wxString CompilerIndex = target->GetCompilerID();
Compiler* tgtCompiler = CompilerFactory::GetCompiler(CompilerIndex);
if (tgtCompiler)
{
Compilers[nCompilers] = tgtCompiler;
++nCompilers;
}
} // if (target)
} // end loop over the targets
// add compiler include dirs
for (int idxCompiler = 0; idxCompiler < nCompilers; ++idxCompiler)
{
const wxArrayString& dirs = (Compilers[idxCompiler])->GetIncludeDirs();
for (unsigned int i = 0; i < dirs.GetCount(); ++i)
{
// CCLogger::Get()->Log(mltDevDebug, "Adding %s", dirs[i].c_str());
wxString out = dirs[i];
Manager::Get()->GetMacrosManager()->ReplaceMacros(out);
wxFileName dir(out);
if (NormalizePath(dir,base))
{
parser->AddIncludeDir(dir.GetFullPath());
TRACE(_T("AddCompilerDirs() : Adding compiler dir to parser: ") + dir.GetFullPath());
}
else
CCLogger::Get()->DebugLog(F(_T("Error normalizing path: '%s' from '%s'"), out.wx_str(), base.wx_str()));
}
// find out which compiler, if gnu, do the special trick
// to find it's internal include paths
// but do only once per C::B session, thus cache for later calls
wxString CompilerID = (Compilers[idxCompiler])->GetID();
if (CompilerID.Contains(_T("gcc")))
AddGCCCompilerDirs(Compilers[idxCompiler], parser);
} // end of while loop over the found compilers
(code for finding the compiler and target include directories, and compute full-path from that).
So I have optimized a bit this method :
1 - cache loop boundaries (no need to call each loop GetCount()). I know it is probably not significant, but just for testing
2 - Optimize ParserBase::AddIncludeDir : there is a call here to wxArrayString::Index, which is linear (O(n)). I have added a HashSet for string (available in wxWidgets)
3 - clean up the code : there is 3 times the same code to do: fetch include dir, do macro expansion, normalize the path, add to include dir list. I have moved this code inside a new method ParserBase::AddIncludeDirFast, and commented out the previous code
4 - there is probably some other optimisations to perform : there is a lot of wxString copy overall.
I attach a patch with :
- the modifications discussed above
- some additional debugging code in NativeParser.cpp and codecompletion.cpp (can be deactivated).
Applying the patch above helped a lot... at first. After 1 hour, the slow behaviour resumed, so there must be another bottleneck somewhere.
BUG 2 : same freezing behaviour, but I can reproduce it at will now. Use case is as follow:
- large workspace, with several projects
- project A is active
- open a file from another project (not from the active project) => freeze for 2 to 6 minutes observed.
Debug logs pointed out to NativeParser::AddCompilerDirs again. The patch above solved this problem as well - for 1 hour...
I am sorry if I could not find out more - after a while, I had to resume what I should have been doing at work : working. I will try again when possible
Regards,
Seb