logic: multithreaded parsing

* modified the TaskParseCxx to be able to run multiple times in parallel
* made FileRegister threadsafe and changed a lot of its mechanisms
* added TaskGroupParallel that runs all children in parallel
* added TaskParseWrapper that acts as a decorator to execute some code before and after parsing.
* implemented task setup in project with 4 parsing threads
* removed SimpleTask as it was only used as interface for the LambdaTask
This commit is contained in:
malte_langkabel
2016-05-13 13:23:54 +02:00
parent 245cafdc7b
commit c61efbbcde
27 changed files with 535 additions and 317 deletions
+1
View File
@@ -2,6 +2,7 @@ add_files(
APP_FILES APP_FILES
data/parser/cxx/TaskParseCxx.cpp data/parser/cxx/TaskParseCxx.cpp
data/parser/cxx/TaskParseWrapper.cpp
utility/commandline/CommandLineParser.cpp utility/commandline/CommandLineParser.cpp
utility/commandline/CommandLineParser.h utility/commandline/CommandLineParser.h
+30 -68
View File
@@ -11,25 +11,6 @@
#include "utility/messaging/type/MessageStatus.h" #include "utility/messaging/type/MessageStatus.h"
#include "utility/utility.h" #include "utility/utility.h"
TaskParseCxx::TaskParseCxx(
PersistentStorage* storage,
const FileManager* fileManager,
const Parser::Arguments& arguments,
const std::vector<FilePath>& files
)
: m_storage(storage)
, m_arguments(arguments)
, m_files(files)
, m_isCDB(false)
{
if (arguments.compilationDatabasePath.exists())
{
m_isCDB = true;
}
m_parserClient = std::make_shared<ParserClientImpl>();
m_parser = std::make_shared<CxxParser>(m_parserClient.get(), fileManager);
}
std::vector<FilePath> TaskParseCxx::getSourceFilesFromCDB(const FilePath& compilationDatabasePath) std::vector<FilePath> TaskParseCxx::getSourceFilesFromCDB(const FilePath& compilationDatabasePath)
{ {
std::string error; std::string error;
@@ -45,52 +26,46 @@ std::vector<FilePath> TaskParseCxx::getSourceFilesFromCDB(const FilePath& compil
return filePaths; return filePaths;
} }
TaskParseCxx::TaskParseCxx(
PersistentStorage* storage,
std::shared_ptr<std::mutex> storageMutex,
std::shared_ptr<FileRegister> fileRegister,
const Parser::Arguments& arguments
)
: m_storage(storage)
, m_storageMutex(storageMutex)
, m_arguments(arguments)
, m_isCDB(false)
{
if (arguments.compilationDatabasePath.exists())
{
m_isCDB = true;
}
m_parserClient = std::make_shared<ParserClientImpl>(); // todo: create one parserclient per file
m_parser = std::make_shared<CxxParser>(m_parserClient.get(), fileRegister);
}
void TaskParseCxx::enter() void TaskParseCxx::enter()
{ {
m_start = utility::durationStart();
if (m_isCDB) if (m_isCDB)
{ {
std::string error; std::string error;
m_cdb = std::shared_ptr<clang::tooling::JSONCompilationDatabase> m_cdb = std::shared_ptr<clang::tooling::JSONCompilationDatabase>
(clang::tooling::JSONCompilationDatabase::loadFromFile(m_arguments.compilationDatabasePath.str(), error)); (clang::tooling::JSONCompilationDatabase::loadFromFile(m_arguments.compilationDatabasePath.str(), error));
m_parser->setupParsingCDB(m_files, m_arguments); m_parser->setupParsingCDB(m_arguments);
} }
else else
{ {
m_parser->setupParsing(m_files, m_arguments); m_parser->setupParsing(m_arguments);
} }
for (const FilePath& path : m_parser->getFileRegister()->getUnparsedSourceFilePaths())
{
m_sourcePaths.push_back(path.absolute());
}
m_storage->startParsing();
} }
Task::TaskState TaskParseCxx::update() Task::TaskState TaskParseCxx::update()
{ {
FilePath sourcePath;
bool isSource = false;
FileRegister* fileRegister = m_parser->getFileRegister(); FileRegister* fileRegister = m_parser->getFileRegister();
if (m_sourcePaths.size()) FilePath sourcePath = fileRegister->consumeSourceFile();
{
sourcePath = m_sourcePaths.front();
m_sourcePaths.pop_front();
isSource = true;
}
else if (!m_isCDB)
{
std::vector<FilePath> unparsedHeaders = fileRegister->getUnparsedIncludeFilePaths();
if (unparsedHeaders.size())
{
sourcePath = unparsedHeaders[0];
}
}
if (sourcePath.empty()) if (sourcePath.empty())
{ {
@@ -99,16 +74,15 @@ Task::TaskState TaskParseCxx::update()
std::stringstream ss; std::stringstream ss;
ss << "analyzing files (ESC to quit): ["; ss << "analyzing files (ESC to quit): [";
ss << (m_isCDB ? fileRegister->getParsedSourceFilesCount() : fileRegister->getParsedFilesCount()) + 1 << "/"; ss << fileRegister->getParsedSourceFilesCount() << "/";
ss << (m_isCDB ? fileRegister->getSourceFilesCount() : fileRegister->getFilesCount()) << "] "; ss << fileRegister->getSourceFilesCount() << "] ";
ss << sourcePath.str(); ss << sourcePath.str();
MessageStatus(ss.str(), false, true).dispatch(); MessageStatus(ss.str(), false, true).dispatch();
std::shared_ptr<IntermediateStorage> intermediateStorage = std::make_shared<IntermediateStorage>(); std::shared_ptr<IntermediateStorage> intermediateStorage = std::make_shared<IntermediateStorage>();
m_parserClient->setStorage(intermediateStorage); m_parserClient->setStorage(intermediateStorage);
m_parserClient->startParsingFile(sourcePath); m_parserClient->startParsingFile();
if (m_isCDB) if (m_isCDB)
{ {
@@ -123,37 +97,25 @@ Task::TaskState TaskParseCxx::update()
m_parser->runTool(std::vector<std::string>(1, sourcePath.str())); m_parser->runTool(std::vector<std::string>(1, sourcePath.str()));
} }
m_parserClient->finishParsingFile(sourcePath); m_parserClient->finishParsingFile();
m_parserClient->resetStorage(); m_parserClient->resetStorage();
m_storage->inject(intermediateStorage.get());
if (isSource)
{ {
fileRegister->markSourceFileParsed(sourcePath.str()); std::lock_guard<std::mutex> lock(*(m_storageMutex.get()));
m_storage->inject(intermediateStorage.get());
} }
fileRegister->markThreadFilesParsed();
return Task::STATE_RUNNING; return Task::STATE_RUNNING;
} }
void TaskParseCxx::exit() void TaskParseCxx::exit()
{ {
MessageStatus("building search index", false, true).dispatch();
m_storage->finishParsing();
FileRegister* fileRegister = m_parser->getFileRegister();
MessageFinishedParsing(
(m_isCDB ? fileRegister->getParsedSourceFilesCount() : fileRegister->getParsedFilesCount()),
(m_isCDB ? fileRegister->getSourceFilesCount() : fileRegister->getFilesCount()),
utility::duration(m_start)
).dispatch();
} }
void TaskParseCxx::interrupt() void TaskParseCxx::interrupt()
{ {
MessageStatus("analyzing files interrupted", false, true).dispatch();
} }
void TaskParseCxx::revert() void TaskParseCxx::revert()
@@ -0,0 +1,57 @@
#include "data/parser/cxx/TaskParseWrapper.h"
#include "data/PersistentStorage.h"
#include "utility/file/FileRegister.h"
#include "utility/messaging/type/MessageFinishedParsing.h"
#include "utility/messaging/type/MessageStatus.h"
#include "utility/utility.h"
TaskParseWrapper::TaskParseWrapper(
std::shared_ptr<Task> child,
PersistentStorage* storage,
std::shared_ptr<FileRegister> fileRegister
)
: m_child(child)
, m_storage(storage)
, m_fileRegister(fileRegister)
{
}
void TaskParseWrapper::enter()
{
m_start = utility::durationStart();
m_storage->startParsing();
m_child->enter();
}
Task::TaskState TaskParseWrapper::update()
{
return m_child->update();
}
void TaskParseWrapper::exit()
{
m_child->exit();
MessageStatus("building search index", false, true).dispatch();
m_storage->finishParsing();
MessageFinishedParsing(
m_fileRegister->getParsedSourceFilesCount(),
m_fileRegister->getSourceFilesCount(),
utility::duration(m_start)
).dispatch();
}
void TaskParseWrapper::interrupt()
{
MessageStatus("analyzing files interrupted", false, true).dispatch();
m_child->interrupt();
}
void TaskParseWrapper::revert()
{
m_child->revert();
}
+3 -2
View File
@@ -124,6 +124,7 @@ add_files(
data/name/NameHierarchy.h data/name/NameHierarchy.h
data/parser/cxx/TaskParseCxx.h data/parser/cxx/TaskParseCxx.h
data/parser/cxx/TaskParseWrapper.h
data/parser/ParseLocation.cpp data/parser/ParseLocation.cpp
data/parser/ParseLocation.h data/parser/ParseLocation.h
@@ -274,12 +275,12 @@ add_files(
utility/scheduling/LambdaTask.cpp utility/scheduling/LambdaTask.cpp
utility/scheduling/LambdaTask.h utility/scheduling/LambdaTask.h
utility/scheduling/SimpleTask.cpp
utility/scheduling/SimpleTask.h
utility/scheduling/Task.cpp utility/scheduling/Task.cpp
utility/scheduling/Task.h utility/scheduling/Task.h
utility/scheduling/TaskGroup.cpp utility/scheduling/TaskGroup.cpp
utility/scheduling/TaskGroup.h utility/scheduling/TaskGroup.h
utility/scheduling/TaskGroupParallel.cpp
utility/scheduling/TaskGroupParallel.h
utility/scheduling/TaskGroupSequential.cpp utility/scheduling/TaskGroupSequential.cpp
utility/scheduling/TaskGroupSequential.h utility/scheduling/TaskGroupSequential.h
utility/scheduling/TaskScheduler.cpp utility/scheduling/TaskScheduler.cpp
+33 -14
View File
@@ -1,20 +1,23 @@
#include "Project.h" #include "Project.h"
#include "utility/file/FileSystem.h"
#include "utility/logging/logging.h"
#include "utility/messaging/type/MessageFinishedParsing.h"
#include "utility/scheduling/TaskGroupSequential.h"
#include "utility/utility.h"
#include "utility/Version.h"
#include "data/access/StorageAccessProxy.h" #include "data/access/StorageAccessProxy.h"
#include "data/graph/Token.h" #include "data/graph/Token.h"
#include "data/parser/cxx/TaskParseCxx.h" #include "data/parser/cxx/TaskParseCxx.h"
#include "data/parser/cxx/TaskParseWrapper.h"
#include "data/PersistentStorage.h" #include "data/PersistentStorage.h"
#include "data/TaskCleanStorage.h" #include "data/TaskCleanStorage.h"
#include "settings/ApplicationSettings.h" #include "settings/ApplicationSettings.h"
#include "settings/ProjectSettings.h" #include "settings/ProjectSettings.h"
#include "utility/file/FileRegister.h"
#include "utility/file/FileSystem.h"
#include "utility/logging/logging.h"
#include "utility/messaging/type/MessageFinishedParsing.h"
#include "utility/scheduling/TaskGroupSequential.h"
#include "utility/scheduling/TaskGroupParallel.h"
#include "utility/utility.h"
#include "utility/Version.h"
std::shared_ptr<Project> Project::create(StorageAccessProxy* storageAccessProxy) std::shared_ptr<Project> Project::create(StorageAccessProxy* storageAccessProxy)
{ {
std::shared_ptr<Project> ptr(new Project(storageAccessProxy)); std::shared_ptr<Project> ptr(new Project(storageAccessProxy));
@@ -149,26 +152,42 @@ void Project::parseCode()
utility::append(updatedFilePaths, m_storage->getDependingFilePaths(updatedFilePaths)); utility::append(updatedFilePaths, m_storage->getDependingFilePaths(updatedFilePaths));
utility::append(updatedFilePaths, m_storage->getDependingFilePaths(removedFilePaths)); utility::append(updatedFilePaths, m_storage->getDependingFilePaths(removedFilePaths));
std::shared_ptr<TaskGroupSequential> taskGroup = std::make_shared<TaskGroupSequential>(); std::shared_ptr<TaskGroupSequential> taskSequential = std::make_shared<TaskGroupSequential>();
std::vector<FilePath> filesToClean; std::vector<FilePath> filesToClean;
filesToClean.insert(filesToClean.end(), removedFilePaths.begin(), removedFilePaths.end()); filesToClean.insert(filesToClean.end(), removedFilePaths.begin(), removedFilePaths.end());
filesToClean.insert(filesToClean.end(), updatedFilePaths.begin(), updatedFilePaths.end()); filesToClean.insert(filesToClean.end(), updatedFilePaths.begin(), updatedFilePaths.end());
taskGroup->addTask(std::make_shared<TaskCleanStorage>(m_storage.get(), filesToClean)); taskSequential->addTask(std::make_shared<TaskCleanStorage>(m_storage.get(), filesToClean));
std::vector<FilePath> filesToParse; std::vector<FilePath> filesToParse;
filesToParse.insert(filesToParse.end(), addedFilePaths.begin(), addedFilePaths.end()); filesToParse.insert(filesToParse.end(), addedFilePaths.begin(), addedFilePaths.end());
filesToParse.insert(filesToParse.end(), updatedFilePaths.begin(), updatedFilePaths.end()); filesToParse.insert(filesToParse.end(), updatedFilePaths.begin(), updatedFilePaths.end());
taskGroup->addTask(std::make_shared<TaskParseCxx>( std::shared_ptr<FileRegister> fileRegister = std::make_shared<FileRegister>(&m_fileManager);
fileRegister->setFilePaths(filesToParse);
std::shared_ptr<TaskGroupParallel> taskParallel = std::make_shared<TaskGroupParallel>();
taskSequential->addTask(std::make_shared<TaskParseWrapper>(
taskParallel,
m_storage.get(), m_storage.get(),
&m_fileManager, fileRegister
getParserArguments(),
filesToParse
)); ));
Task::dispatch(taskGroup); std::shared_ptr<std::mutex> storageMutex = std::make_shared<std::mutex>();
for (int i = 0; i < 4; i++)
{
taskParallel->addTask(std::make_shared<TaskParseCxx>(
m_storage.get(),
storageMutex,
fileRegister,
getParserArguments()
));
}
Task::dispatch(taskSequential);
m_state = PROJECT_LOADED; m_state = PROJECT_LOADED;
} }
+2 -2
View File
@@ -39,8 +39,8 @@ public:
ParserClient(); ParserClient();
virtual ~ParserClient(); virtual ~ParserClient();
virtual void startParsingFile(const FilePath& filePath) = 0; virtual void startParsingFile() = 0;
virtual void finishParsingFile(const FilePath& filePath) = 0; virtual void finishParsingFile() = 0;
virtual void onError(const ParseLocation& location, const std::string& message, bool fatal) = 0; virtual void onError(const ParseLocation& location, const std::string& message, bool fatal) = 0;
+3 -3
View File
@@ -25,12 +25,12 @@ void ParserClientImpl::resetStorage()
m_storage.reset(); m_storage.reset();
} }
void ParserClientImpl::startParsingFile(const FilePath& filePath) void ParserClientImpl::startParsingFile()
{ {
m_nodeIdsToMemberEdgeIds.clear(); m_nodeIdsToMemberEdgeIds.clear(); // remove this when one parserclient is created per file
} }
void ParserClientImpl::finishParsingFile(const FilePath& filePath) void ParserClientImpl::finishParsingFile()
{ {
} }
+2 -2
View File
@@ -18,8 +18,8 @@ public:
void setStorage(std::shared_ptr<IntermediateStorage> storage); void setStorage(std::shared_ptr<IntermediateStorage> storage);
void resetStorage(); void resetStorage();
virtual void startParsingFile(const FilePath& filePath); virtual void startParsingFile();
virtual void finishParsingFile(const FilePath& filePath); virtual void finishParsingFile();
virtual void onError(const ParseLocation& location, const std::string& message, bool fatal); virtual void onError(const ParseLocation& location, const std::string& message, bool fatal);
+8 -11
View File
@@ -2,6 +2,7 @@
#define TASK_PARSE_CXX_H #define TASK_PARSE_CXX_H
#include <memory> #include <memory>
#include <mutex>
#include <deque> #include <deque>
#include "data/parser/Parser.h" #include "data/parser/Parser.h"
@@ -10,7 +11,7 @@
#include "utility/TimePoint.h" #include "utility/TimePoint.h"
class PersistentStorage; class PersistentStorage;
class FileManager; class FileRegister;
class CxxParser; class CxxParser;
namespace clang namespace clang
@@ -25,15 +26,15 @@ class TaskParseCxx
: public Task : public Task
{ {
public: public:
static std::vector<FilePath> getSourceFilesFromCDB(const FilePath& compilationDatabasePath);
TaskParseCxx( TaskParseCxx(
PersistentStorage* storage, PersistentStorage* storage,
const FileManager* fileManager, std::shared_ptr<std::mutex> storageMutex,
const Parser::Arguments& arguments, std::shared_ptr<FileRegister> fileRegister,
const std::vector<FilePath>& files const Parser::Arguments& arguments
); );
static std::vector<FilePath> getSourceFilesFromCDB(const FilePath& compilationDatabasePath);
virtual void enter(); virtual void enter();
virtual TaskState update(); virtual TaskState update();
virtual void exit(); virtual void exit();
@@ -43,14 +44,10 @@ public:
private: private:
PersistentStorage* m_storage; PersistentStorage* m_storage;
std::shared_ptr<std::mutex> m_storageMutex;
std::shared_ptr<CxxParser> m_parser; std::shared_ptr<CxxParser> m_parser;
std::shared_ptr<ParserClientImpl> m_parserClient; std::shared_ptr<ParserClientImpl> m_parserClient;
const Parser::Arguments m_arguments; const Parser::Arguments m_arguments;
const std::vector<FilePath> m_files;
std::deque<FilePath> m_sourcePaths;
TimePoint m_start;
bool m_isCDB; bool m_isCDB;
std::shared_ptr<clang::tooling::JSONCompilationDatabase> m_cdb; std::shared_ptr<clang::tooling::JSONCompilationDatabase> m_cdb;
@@ -0,0 +1,41 @@
#ifndef TASK_PARSE_WRAPPER_H
#define TASK_PARSE_WRAPPER_H
#include <memory>
#include "data/parser/Parser.h"
#include "data/parser/ParserClientImpl.h"
#include "utility/scheduling/Task.h"
#include "utility/TimePoint.h"
class PersistentStorage;
class FileRegister;
class CxxParser;
class TaskParseWrapper
: public Task
{
public:
TaskParseWrapper(
std::shared_ptr<Task> child,
PersistentStorage* storage,
std::shared_ptr<FileRegister> fileRegister
);
virtual void enter();
virtual TaskState update();
virtual void exit();
virtual void interrupt();
virtual void revert();
private:
std::shared_ptr<Task> m_child;
PersistentStorage* m_storage;
std::shared_ptr<FileRegister> m_fileRegister;
TimePoint m_start;
};
#endif // TASK_PARSE_WRAPPER_H
+138 -97
View File
@@ -8,13 +8,11 @@ FileRegister::FileRegister(const FileManager* fileManager)
{ {
} }
const FileManager* FileRegister::getFileManager() const
{
return m_fileManager;
}
void FileRegister::setFilePaths(const std::vector<FilePath>& filePaths) void FileRegister::setFilePaths(const std::vector<FilePath>& filePaths)
{ {
std::lock_guard<std::mutex> sourceFileLock(m_sourceFileMutex);
std::lock_guard<std::mutex> includeFileLock(m_includeFileMutex);
m_sourceFilePaths.clear(); m_sourceFilePaths.clear();
m_includeFilePaths.clear(); m_includeFilePaths.clear();
@@ -33,96 +31,18 @@ void FileRegister::setFilePaths(const std::vector<FilePath>& filePaths)
} }
} }
const FileManager* FileRegister::getFileManager() const
{
return m_fileManager;
}
std::vector<FilePath> FileRegister::getUnparsedSourceFilePaths() const std::vector<FilePath> FileRegister::getUnparsedSourceFilePaths() const
{ {
return getUnparsedFilePaths(m_sourceFilePaths); std::lock_guard<std::mutex> lock(m_sourceFileMutex);
}
std::vector<FilePath> FileRegister::getUnparsedIncludeFilePaths() const
{
return getUnparsedFilePaths(m_includeFilePaths);
}
bool FileRegister::fileIsParsed(const FilePath& filePath) const
{
std::map<FilePath, ParseState>::const_iterator it = m_includeFilePaths.find(filePath);
if (it != m_includeFilePaths.end())
{
return it->second == STATE_PARSED;
}
it = m_sourceFilePaths.find(filePath);
if (it != m_sourceFilePaths.end())
{
return it->second == STATE_PARSED;
}
return true;
}
bool FileRegister::includeFileIsParsing(const FilePath& filePath) const
{
std::map<FilePath, ParseState>::const_iterator it = m_includeFilePaths.find(filePath);
if (it == m_includeFilePaths.end())
{
return false;
}
return it->second == STATE_PARSING;
}
bool FileRegister::includeFileIsParsed(const FilePath& filePath) const
{
std::map<FilePath, ParseState>::const_iterator it = m_includeFilePaths.find(filePath);
if (it == m_includeFilePaths.end())
{
return false;
}
return it->second == STATE_PARSED;
}
void FileRegister::markSourceFileParsed(const std::string& filePath)
{
std::map<FilePath, ParseState>::iterator it = m_sourceFilePaths.find(FilePath(filePath));
if (it == m_sourceFilePaths.end())
{
return;
}
it->second = STATE_PARSED;
}
void FileRegister::markIncludeFileParsing(const std::string& filePath)
{
std::map<FilePath, ParseState>::iterator it = m_includeFilePaths.find(FilePath(filePath));
if (it == m_includeFilePaths.end())
{
return;
}
if (it->second != STATE_PARSED)
{
it->second = STATE_PARSING;
}
}
void FileRegister::markParsingIncludeFilesParsed()
{
for (auto& p : m_includeFilePaths)
{
if (p.second == STATE_PARSING)
{
p.second = STATE_PARSED;
}
}
}
std::vector<FilePath> FileRegister::getUnparsedFilePaths(const std::map<FilePath, ParseState> filePaths) const
{
std::vector<FilePath> files; std::vector<FilePath> files;
for (std::pair<FilePath, ParseState>&& p : filePaths) for (std::pair<FilePath, ParseState>&& p : m_sourceFilePaths)
{ {
if (p.second == STATE_UNPARSED) if (p.second == STATE_UNPARSED)
{ {
@@ -133,21 +53,142 @@ std::vector<FilePath> FileRegister::getUnparsedFilePaths(const std::map<FilePath
return files; return files;
} }
size_t FileRegister::getFilesCount() const bool FileRegister::fileIsParsed(const FilePath& filePath) const
{ {
return m_sourceFilePaths.size() + m_includeFilePaths.size(); return sourceFileIsParsed(filePath) || includeFileIsParsed(filePath);
}
bool FileRegister::sourceFileIsParsed(const FilePath& filePath) const
{
{
std::lock_guard<std::mutex> lock(m_sourceFileMutex);
std::map<FilePath, ParseState>::const_iterator it = m_sourceFilePaths.find(filePath);
if (it == m_sourceFilePaths.end())
{
return false;
}
if (it->second == STATE_UNPARSED)
{
return false;
}
else if (it->second == STATE_PARSED)
{
return true;
}
}
{
std::lock_guard<std::mutex> lock(m_threadFileMutex);
std::map<std::thread::id, std::set<FilePath>>::const_iterator it2 = m_threadParsingFiles.find(std::this_thread::get_id());
if (it2 != m_threadParsingFiles.end())
{
if (it2->second.find(filePath) != it2->second.end())
{
return false;
}
}
return true;
}
}
bool FileRegister::includeFileIsParsed(const FilePath& filePath) const
{
{
std::lock_guard<std::mutex> lock(m_includeFileMutex);
std::map<FilePath, ParseState>::const_iterator it = m_includeFilePaths.find(filePath);
if (it == m_includeFilePaths.end())
{
return false;
}
if (it->second == STATE_UNPARSED)
{
return false;
}
else if (it->second == STATE_PARSED)
{
return true;
}
}
{
std::lock_guard<std::mutex> lock(m_threadFileMutex);
std::map<std::thread::id, std::set<FilePath>>::const_iterator it2 = m_threadParsingFiles.find(std::this_thread::get_id());
if (it2 != m_threadParsingFiles.end())
{
if (it2->second.find(filePath) != it2->second.end())
{
return false;
}
}
return true;
}
}
FilePath FileRegister::consumeSourceFile()
{
std::lock_guard<std::mutex> lock(m_sourceFileMutex);
for (std::map<FilePath, ParseState>::iterator it = m_sourceFilePaths.begin(); it != m_sourceFilePaths.end(); it++)
{
if (it->second == STATE_UNPARSED)
{
it->second = STATE_PARSING;
m_threadParsingFiles[std::this_thread::get_id()].insert(it->first);
return it->first;
}
}
return FilePath();
}
void FileRegister::markIncludeFileParsing(const FilePath& filePath)
{
std::lock_guard<std::mutex> lock(m_includeFileMutex);
std::map<FilePath, ParseState>::iterator it = m_includeFilePaths.find(filePath);
if (it != m_includeFilePaths.end())
{
if (it->second == STATE_UNPARSED)
{
it->second = STATE_PARSING;
m_threadParsingFiles[std::this_thread::get_id()].insert(it->first);
}
}
}
void FileRegister::markThreadFilesParsed()
{
std::lock_guard<std::mutex> sourceFileLock(m_sourceFileMutex);
std::lock_guard<std::mutex> includeFileLock(m_includeFileMutex);
std::lock_guard<std::mutex> threadFileLock(m_threadFileMutex);
for (std::set<FilePath>::iterator it = m_threadParsingFiles[std::this_thread::get_id()].begin(); it != m_threadParsingFiles[std::this_thread::get_id()].end(); it++)
{
std::map<FilePath, ParseState>::iterator it2;
it2 = m_sourceFilePaths.find(*it);
if (it2 != m_sourceFilePaths.end())
{
it2->second = STATE_PARSED;
continue;
}
it2 = m_includeFilePaths.find(*it);
if (it2 != m_includeFilePaths.end())
{
it2->second = STATE_PARSED;
}
}
m_threadParsingFiles[std::this_thread::get_id()].clear();
} }
size_t FileRegister::getSourceFilesCount() const size_t FileRegister::getSourceFilesCount() const
{ {
std::lock_guard<std::mutex> lock(m_sourceFileMutex);
return m_sourceFilePaths.size(); return m_sourceFilePaths.size();
} }
size_t FileRegister::getParsedFilesCount() const
{
return getFilesCount() - getUnparsedSourceFilePaths().size() - getUnparsedIncludeFilePaths().size();
}
size_t FileRegister::getParsedSourceFilesCount() const size_t FileRegister::getParsedSourceFilesCount() const
{ {
return getSourceFilesCount() - getUnparsedSourceFilePaths().size(); return getSourceFilesCount() - getUnparsedSourceFilePaths().size();
+16 -12
View File
@@ -2,7 +2,10 @@
#define FILE_REGISTER_H #define FILE_REGISTER_H
#include <map> #include <map>
#include <mutex>
#include <set>
#include <string> #include <string>
#include <thread>
#include <vector> #include <vector>
#include "utility/file/FilePath.h" #include "utility/file/FilePath.h"
@@ -14,25 +17,22 @@ class FileRegister
public: public:
explicit FileRegister(const FileManager* fileManager); explicit FileRegister(const FileManager* fileManager);
const FileManager* getFileManager() const;
void setFilePaths(const std::vector<FilePath>& filePaths); void setFilePaths(const std::vector<FilePath>& filePaths);
const FileManager* getFileManager() const;
std::vector<FilePath> getUnparsedSourceFilePaths() const; std::vector<FilePath> getUnparsedSourceFilePaths() const;
std::vector<FilePath> getUnparsedIncludeFilePaths() const;
bool fileIsParsed(const FilePath& filePath) const; bool fileIsParsed(const FilePath& filePath) const;
bool includeFileIsParsing(const FilePath& filePath) const;
bool includeFileIsParsed(const FilePath& filePath) const; bool includeFileIsParsed(const FilePath& filePath) const;
bool sourceFileIsParsed(const FilePath& filePath) const;
void markSourceFileParsed(const std::string& filePath); FilePath consumeSourceFile();
void markIncludeFileParsing(const std::string& filePath);
void markParsingIncludeFilesParsed(); void markIncludeFileParsing(const FilePath& filePath);
void markThreadFilesParsed();
size_t getFilesCount() const;
size_t getSourceFilesCount() const; size_t getSourceFilesCount() const;
size_t getParsedFilesCount() const;
size_t getParsedSourceFilesCount() const; size_t getParsedSourceFilesCount() const;
private: private:
@@ -43,12 +43,16 @@ private:
STATE_PARSED STATE_PARSED
}; };
std::vector<FilePath> getUnparsedFilePaths(const std::map<FilePath, ParseState> filePaths) const;
const FileManager* m_fileManager; const FileManager* m_fileManager;
std::map<FilePath, ParseState> m_sourceFilePaths; std::map<FilePath, ParseState> m_sourceFilePaths;
std::map<FilePath, ParseState> m_includeFilePaths; std::map<FilePath, ParseState> m_includeFilePaths;
std::map<std::thread::id, std::set<FilePath>> m_threadParsingFiles;
mutable std::mutex m_sourceFileMutex;
mutable std::mutex m_includeFileMutex;
mutable std::mutex m_threadFileMutex;
}; };
#endif // FILE_REGISTER_H #endif // FILE_REGISTER_H
+19 -1
View File
@@ -9,7 +9,25 @@ LambdaTask::~LambdaTask()
{ {
} }
void LambdaTask::perform() void LambdaTask::enter()
{
}
Task::TaskState LambdaTask::update()
{ {
m_func(); m_func();
return Task::STATE_FINISHED;
}
void LambdaTask::exit()
{
}
void LambdaTask::interrupt()
{
}
void LambdaTask::revert()
{
} }
+8 -3
View File
@@ -3,16 +3,21 @@
#include <functional> #include <functional>
#include "utility/scheduling/SimpleTask.h" #include "utility/scheduling/Task.h"
class LambdaTask class LambdaTask
: public SimpleTask : public Task
{ {
public: public:
LambdaTask(std::function<void()> func); LambdaTask(std::function<void()> func);
virtual ~LambdaTask(); virtual ~LambdaTask();
virtual void perform(); virtual void enter();
virtual TaskState update();
virtual void exit();
virtual void interrupt();
virtual void revert();
private: private:
std::function<void()> m_func; std::function<void()> m_func;
-28
View File
@@ -1,28 +0,0 @@
#include "utility/scheduling/SimpleTask.h"
void SimpleTask::enter()
{
}
Task::TaskState SimpleTask::update()
{
perform();
return Task::STATE_FINISHED;
}
void SimpleTask::exit()
{
}
void SimpleTask::interrupt()
{
}
void SimpleTask::revert()
{
}
-20
View File
@@ -1,20 +0,0 @@
#ifndef SIMPLE_TASK_H
#define SIMPLE_TASK_H
#include "utility/scheduling/Task.h"
class SimpleTask
: public Task
{
public:
virtual void enter();
virtual TaskState update();
virtual void exit();
virtual void interrupt();
virtual void revert();
virtual void perform() = 0;
};
#endif // SIMPLE_TASK_H
@@ -0,0 +1,75 @@
#include "utility/scheduling/TaskGroupParallel.h"
#include <thread>
TaskGroupParallel::TaskGroupParallel()
{
}
TaskGroupParallel::~TaskGroupParallel()
{
}
void TaskGroupParallel::enter()
{
m_interrupt = false;
m_running = false;
m_activeTaskCount = 0;
}
Task::TaskState TaskGroupParallel::update()
{
if (!m_running)
{
for (size_t i = 0; i < m_tasks.size(); i++)
{
std::thread(&TaskGroupParallel::processTask, this, m_tasks[i]).detach();
std::lock_guard<std::mutex> lock(m_activeTaskCountMutex);
m_activeTaskCount++;
}
m_running = true;
}
int activeTaskCount = 0;
{
std::lock_guard<std::mutex> lock(m_activeTaskCountMutex);
activeTaskCount = m_activeTaskCount;
}
if (activeTaskCount == 0)
{
return (m_interrupt ? STATE_CANCELED : STATE_FINISHED);
}
return Task::STATE_RUNNING;
}
void TaskGroupParallel::exit()
{
}
void TaskGroupParallel::interrupt()
{
m_interrupt = true;
}
void TaskGroupParallel::revert()
{
m_interrupt = true;
}
void TaskGroupParallel::processTask(std::shared_ptr<Task> task)
{
Task::TaskState state = Task::STATE_NEW;
while (state != Task::STATE_FINISHED && state != Task::STATE_CANCELED)
{
state = task->process(m_interrupt);
}
{
std::lock_guard<std::mutex> lock(m_activeTaskCountMutex);
m_activeTaskCount--; // not safe! if exception hits this thread before this point the count is not decremented.
}
}
@@ -0,0 +1,30 @@
#ifndef TASK_GROUP_PARALLEL_H
#define TASK_GROUP_PARALLEL_H
#include "utility/scheduling/TaskGroup.h"
#include <mutex>
class TaskGroupParallel
: public TaskGroup
{
public:
TaskGroupParallel();
virtual ~TaskGroupParallel();
virtual void enter();
virtual TaskState update();
virtual void exit();
virtual void interrupt();
virtual void revert();
private:
void processTask(std::shared_ptr<Task> task);
volatile bool m_interrupt;
bool m_running;
volatile int m_activeTaskCount;
std::mutex m_activeTaskCountMutex;
};
#endif // TASK_GROUP_PARALLEL_H
@@ -29,8 +29,3 @@ bool ASTAction::BeginSourceFileAction(clang::CompilerInstance& compiler, llvm::S
preprocessor.addCommentHandler(&m_commentHandler); preprocessor.addCommentHandler(&m_commentHandler);
return true; return true;
} }
void ASTAction::EndSourceFileAction()
{
m_fileRegister->markParsingIncludeFilesParsed();
}
@@ -18,7 +18,6 @@ protected:
virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance& compiler, llvm::StringRef inFile); virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance& compiler, llvm::StringRef inFile);
virtual bool BeginSourceFileAction(clang::CompilerInstance& compiler, llvm::StringRef filePath); virtual bool BeginSourceFileAction(clang::CompilerInstance& compiler, llvm::StringRef filePath);
virtual void EndSourceFileAction();
private: private:
ParserClient* m_client; ParserClient* m_client;
@@ -1503,7 +1503,7 @@ bool ASTVisitor::isLocatedInUnparsedProjectFile(clang::SourceLocation loc)
{ {
std::string fileName = fileEntry->getName(); std::string fileName = fileEntry->getName();
FilePath filePath = FilePath(fileName).canonical(); FilePath filePath = FilePath(fileName).canonical();
ret = m_fileRegister->includeFileIsParsing(filePath.str()); ret = m_fileRegister->includeFileIsParsed(filePath.str());
} }
} }
m_inUnparsedProjectFileMap[fileId] = ret; m_inUnparsedProjectFileMap[fileId] = ret;
+9 -19
View File
@@ -2,7 +2,6 @@
#include "clang/Tooling/Tooling.h" #include "clang/Tooling/Tooling.h"
#include "utility/file/FileManager.h"
#include "utility/file/FileRegister.h" #include "utility/file/FileRegister.h"
#include "utility/logging/logging.h" #include "utility/logging/logging.h"
#include "utility/text/TextAccess.h" #include "utility/text/TextAccess.h"
@@ -53,9 +52,9 @@ namespace
} }
CxxParser::CxxParser(ParserClient* client, const FileManager* fileManager) CxxParser::CxxParser(ParserClient* client, std::shared_ptr<FileRegister> fileRegister)
: Parser(client) : Parser(client)
, m_fileRegister(std::make_shared<FileRegister>(fileManager)) , m_fileRegister(fileRegister)
{ {
} }
@@ -65,29 +64,22 @@ CxxParser::~CxxParser()
void CxxParser::parseFiles(const std::vector<FilePath>& filePaths, const Arguments& arguments) void CxxParser::parseFiles(const std::vector<FilePath>& filePaths, const Arguments& arguments)
{ {
setupParsing(filePaths, arguments); m_fileRegister->setFilePaths(filePaths);
setupParsing(arguments);
std::vector<std::string> sourcePaths; std::vector<std::string> sourcePaths;
for (const FilePath& path : m_fileRegister->getUnparsedSourceFilePaths()) for (const FilePath& path : m_fileRegister->getUnparsedSourceFilePaths()) // filter headers
{ {
sourcePaths.push_back(path.absolute().str()); sourcePaths.push_back(path.absolute().str());
} }
runTool(sourcePaths); runTool(sourcePaths);
std::vector<FilePath> unparsedHeaders = m_fileRegister->getUnparsedIncludeFilePaths();
for (const FilePath& path : unparsedHeaders)
{
if (!m_fileRegister->includeFileIsParsed(path))
{
runTool(std::vector<std::string>(1, path.str()));
}
}
} }
void CxxParser::parseFile(const FilePath& filePath, std::shared_ptr<TextAccess> textAccess, const Arguments& arguments) void CxxParser::parseFile(const FilePath& filePath, std::shared_ptr<TextAccess> textAccess, const Arguments& arguments)
{ {
setupParsing(std::vector<FilePath>(1, filePath), arguments); m_fileRegister->setFilePaths(std::vector<FilePath>(1, filePath));
setupParsing(arguments);
std::vector<std::string> args = getCommandlineArguments(arguments); std::vector<std::string> args = getCommandlineArguments(arguments);
std::shared_ptr<CxxDiagnosticConsumer> diagnostics = getDiagnostics(arguments); std::shared_ptr<CxxDiagnosticConsumer> diagnostics = getDiagnostics(arguments);
@@ -190,16 +182,14 @@ std::shared_ptr<CxxDiagnosticConsumer> CxxParser::getDiagnostics(const Arguments
llvm::errs(), &*options, m_client, m_fileRegister->getFileManager(), arguments.logErrors); llvm::errs(), &*options, m_client, m_fileRegister->getFileManager(), arguments.logErrors);
} }
void CxxParser::setupParsing(const std::vector<FilePath>& filePaths, const Arguments& arguments) void CxxParser::setupParsing(const Arguments& arguments)
{ {
m_fileRegister->setFilePaths(filePaths);
m_compilationDatabase = getCompilationDatabase(arguments); m_compilationDatabase = getCompilationDatabase(arguments);
m_diagnostics = getDiagnostics(arguments); m_diagnostics = getDiagnostics(arguments);
} }
void CxxParser::setupParsingCDB(const std::vector<FilePath>& filePaths, const Arguments& arguments) void CxxParser::setupParsingCDB(const Arguments& arguments)
{ {
m_fileRegister->setFilePaths(filePaths);
m_diagnostics = getDiagnostics(arguments); m_diagnostics = getDiagnostics(arguments);
} }
+4 -4
View File
@@ -5,14 +5,14 @@
#include "data/parser/Parser.h" #include "data/parser/Parser.h"
class CxxDiagnosticConsumer; class CxxDiagnosticConsumer;
class FileManager; class FileRegister;
class FileRegister; class FileRegister;
class TaskParseCxx; class TaskParseCxx;
class CxxParser: public Parser class CxxParser: public Parser
{ {
public: public:
CxxParser(ParserClient* client, const FileManager* fileManager); CxxParser(ParserClient* client, std::shared_ptr<FileRegister> fileRegister);
~CxxParser(); ~CxxParser();
// ParserClient implementation // ParserClient implementation
@@ -27,8 +27,8 @@ private:
std::shared_ptr<CxxDiagnosticConsumer> getDiagnostics(const Arguments& arguments) const; std::shared_ptr<CxxDiagnosticConsumer> getDiagnostics(const Arguments& arguments) const;
// Accessed by TaskParseCxx // Accessed by TaskParseCxx
void setupParsing(const std::vector<FilePath>& filePaths, const Arguments& arguments); void setupParsing(const Arguments& arguments);
void setupParsingCDB(const std::vector<FilePath>& filePaths, const Arguments& arguments); void setupParsingCDB(const Arguments& arguments);
void runTool(const std::vector<std::string>& files); void runTool(const std::vector<std::string>& files);
void runTool(clang::tooling::CompileCommand command, const Arguments& arguments); void runTool(clang::tooling::CompileCommand command, const Arguments& arguments);
+6 -12
View File
@@ -2779,8 +2779,9 @@ public:
void test_cxx_parser_parses_multiple_files() void test_cxx_parser_parses_multiple_files()
{ {
TestFileManager fm; TestFileManager fm;
std::shared_ptr<FileRegister> fr = std::make_shared<FileRegister>(&fm);
TestParserClient client; TestParserClient client;
CxxParser parser(&client, &fm); CxxParser parser(&client, fr);
std::vector<FilePath> filePaths; std::vector<FilePath> filePaths;
filePaths.push_back(FilePath("data/CxxParserTestSuite/header.h")); filePaths.push_back(FilePath("data/CxxParserTestSuite/header.h"));
@@ -2866,19 +2867,11 @@ private:
class TestParserClient: public ParserClient class TestParserClient: public ParserClient
{ {
public: public:
virtual void startParsing() virtual void startParsingFile()
{ {
} }
virtual void finishParsing() virtual void finishParsingFile()
{
}
virtual void startParsingFile(const FilePath& filePath)
{
}
virtual void finishParsingFile(const FilePath& filePath)
{ {
} }
@@ -3109,8 +3102,9 @@ private:
m_args.languageStandard = "1z"; m_args.languageStandard = "1z";
TestFileManager fm; TestFileManager fm;
std::shared_ptr<FileRegister> fr = std::make_shared<FileRegister>(&fm);
std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>(); std::shared_ptr<TestParserClient> client = std::make_shared<TestParserClient>();
CxxParser parser(client.get(), &fm); CxxParser parser(client.get(), fr);
parser.parseFile("input.cc", TextAccess::createFromString(code), m_args); parser.parseFile("input.cc", TextAccess::createFromString(code), m_args);
return client; return client;
} }
+1
View File
@@ -2,6 +2,7 @@ add_files(
TRIAL_FILES TRIAL_FILES
data/parser/cxx/TaskParseCxx.cpp data/parser/cxx/TaskParseCxx.cpp
data/parser/cxx/TaskParseWrapper.cpp
isTrial.cpp isTrial.cpp
main.cpp main.cpp
+3 -12
View File
@@ -1,16 +1,11 @@
#include "data/parser/cxx/TaskParseCxx.h" #include "data/parser/cxx/TaskParseCxx.h"
#include "data/PersistentStorage.h"
#include "utility/messaging/type/MessageFinishedParsing.h"
TaskParseCxx::TaskParseCxx( TaskParseCxx::TaskParseCxx(
PersistentStorage* storage, PersistentStorage* storage,
const FileManager* fileManager, std::shared_ptr<std::mutex> storageMutex,
const Parser::Arguments& arguments, std::shared_ptr<FileRegister> fileRegister,
const std::vector<FilePath>& files const Parser::Arguments& arguments
) )
: m_storage(storage)
, m_arguments(arguments)
{ {
} }
@@ -21,7 +16,6 @@ std::vector<FilePath> TaskParseCxx::getSourceFilesFromCDB(const FilePath& compil
void TaskParseCxx::enter() void TaskParseCxx::enter()
{ {
m_storage->startParsing();
} }
Task::TaskState TaskParseCxx::update() Task::TaskState TaskParseCxx::update()
@@ -31,9 +25,6 @@ Task::TaskState TaskParseCxx::update()
void TaskParseCxx::exit() void TaskParseCxx::exit()
{ {
m_storage->finishParsing();
MessageFinishedParsing(0, 0, 0).dispatch();
} }
void TaskParseCxx::interrupt() void TaskParseCxx::interrupt()
@@ -0,0 +1,45 @@
#include "data/parser/cxx/TaskParseWrapper.h"
#include "data/PersistentStorage.h"
#include "utility/messaging/type/MessageFinishedParsing.h"
TaskParseWrapper::TaskParseWrapper(
std::shared_ptr<Task> child,
PersistentStorage* storage,
std::shared_ptr<FileRegister> fileRegister
)
: m_child(child)
, m_storage(storage)
{
}
void TaskParseWrapper::enter()
{
m_storage->startParsing();
m_child->enter();
}
Task::TaskState TaskParseWrapper::update()
{
return m_child->update();
}
void TaskParseWrapper::exit()
{
m_child->exit();
m_storage->finishParsing();
MessageFinishedParsing(0, 0, 0).dispatch();
}
void TaskParseWrapper::interrupt()
{
m_child->interrupt();
}
void TaskParseWrapper::revert()
{
m_child->revert();
}