Fix ticket #113 (Add support for multi core CPUs and -w parameter to specifify amount of worker threads)

This commit is contained in:
Reijo Tomperi 2009-02-20 19:40:42 +00:00
parent 439b8c4051
commit 61587c42ae
8 changed files with 104 additions and 29 deletions

View File

@ -105,11 +105,12 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
<arg choice="opt"><option>--all</option></arg> <arg choice="opt"><option>--all</option></arg>
<arg choice="opt"><option>--force</option></arg> <arg choice="opt"><option>--force</option></arg>
<arg choice="opt"><option>--help</option></arg> <arg choice="opt"><option>--help</option></arg>
<arg choice="opt"><option>-Idir</option></arg> <arg choice="opt"><option>-I[dir]</option></arg>
<arg choice="opt"><option>--quiet</option></arg> <arg choice="opt"><option>--quiet</option></arg>
<arg choice="opt"><option>--style</option></arg> <arg choice="opt"><option>--style</option></arg>
<arg choice="opt"><option>--unused-functions</option></arg> <arg choice="opt"><option>--unused-functions</option></arg>
<arg choice="opt"><option>--verbose</option></arg> <arg choice="opt"><option>--verbose</option></arg>
<arg choice="opt"><option>-w[workers]</option></arg>
<arg choice="opt"><option>--xml</option></arg> <arg choice="opt"><option>--xml</option></arg>
<arg choice="opt"><option>file or path</option></arg> <arg choice="opt"><option>file or path</option></arg>
<arg choice="plain"><option>...</option></arg> <arg choice="plain"><option>...</option></arg>
@ -153,7 +154,7 @@ default.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><option>-I &lt;dir&gt;</option></term> <term><option>-I [dir]</option></term>
<listitem> <listitem>
<para>Give include path. Give several -I parameters to give several paths. First given path is checked first. If paths are relative to source <para>Give include path. Give several -I parameters to give several paths. First given path is checked first. If paths are relative to source
files, this is not needed.</para> files, this is not needed.</para>
@ -186,6 +187,12 @@ files, this is not needed.</para>
<para>More detailed error reports</para> <para>More detailed error reports</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>-w [workers]</option></term>
<listitem>
<para>Start [workers] threads to do the checking work.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>--xml</option></term> <term><option>--xml</option></term>
<listitem> <listitem>

View File

@ -146,6 +146,39 @@ std::string CppCheck::parseFromArgs(int argc, const char* const argv[])
_includePaths.push_back(path); _includePaths.push_back(path);
} }
// Include paths
else if (strcmp(argv[i], "-w") == 0 ||
strncmp(argv[i], "-w", 2) == 0)
{
std::string numberString;
// "-w 3"
if (strcmp(argv[i], "-w") == 0)
{
++i;
if (i >= argc)
return "cppcheck: argument to '-w' is missing\n";
numberString = argv[i];
}
// "-w3"
else if (strncmp(argv[i], "-w", 2) == 0)
{
numberString = argv[i];
numberString = numberString.substr(2);
}
std::istringstream iss(numberString);
if (!(iss >> _settings._workers))
return "cppcheck: argument to '-w' is not a number\n";
if (_settings._workers > 1000)
{
return "cppcheck: argument for '-w' is allowed to be 1000 at max\n";
}
}
else if (strncmp(argv[i], "-", 1) == 0 || strncmp(argv[i], "--", 2) == 0) else if (strncmp(argv[i], "-", 1) == 0 || strncmp(argv[i], "--", 2) == 0)
{ {
return "cppcheck: error: unrecognized command line option \"" + std::string(argv[i]) + "\"\n"; return "cppcheck: error: unrecognized command line option \"" + std::string(argv[i]) + "\"\n";
@ -184,7 +217,7 @@ std::string CppCheck::parseFromArgs(int argc, const char* const argv[])
" -f, --force Force checking on files that have \"too many\"\n" " -f, --force Force checking on files that have \"too many\"\n"
" configurations\n" " configurations\n"
" -h, --help Print this help\n" " -h, --help Print this help\n"
" -I <dir> Give include path. Give several -I parameters to give\n" " -I [dir] Give include path. Give several -I parameters to give\n"
" several paths. First given path is checked first. If\n" " several paths. First given path is checked first. If\n"
" paths are relative to source files, this is not needed\n" " paths are relative to source files, this is not needed\n"
" -q, --quiet Only print error messages\n" " -q, --quiet Only print error messages\n"
@ -192,6 +225,7 @@ std::string CppCheck::parseFromArgs(int argc, const char* const argv[])
" --unused-functions Check if there are unused functions\n" " --unused-functions Check if there are unused functions\n"
" --vcl Suppress messages about memory leaks when using VCL classes\n" " --vcl Suppress messages about memory leaks when using VCL classes\n"
" -v, --verbose More detailed error reports\n" " -v, --verbose More detailed error reports\n"
" -w [workers] Start [workers] threads to do the checking work.\n"
" --xml Write results in xml to error stream.\n" " --xml Write results in xml to error stream.\n"
"\n" "\n"
"Example usage:\n" "Example usage:\n"

View File

@ -47,11 +47,15 @@ unsigned int CppCheckExecutor::check(int argc, const char* const argv[])
} }
unsigned int returnValue = 0; unsigned int returnValue = 0;
if (1) if (_settings._workers == 1)
{ {
// Single process // Single process
returnValue = cppCheck.check(); returnValue = cppCheck.check();
} }
else if (!ThreadExecutor::isEnabled())
{
std::cout << "No thread support yet implemented for this platform." << std::endl;
}
else else
{ {
// Multiple processes // Multiple processes

View File

@ -31,6 +31,7 @@ Settings::Settings()
_unusedFunctions = false; _unusedFunctions = false;
_security = false; _security = false;
_vcl = false; _vcl = false;
_workers = 1;
} }
Settings::~Settings() Settings::~Settings()

View File

@ -51,6 +51,10 @@ public:
/** Disable warnings for VCL classes */ /** Disable warnings for VCL classes */
bool _vcl; bool _vcl;
/** How many processes/threads should do checking at the same
time. Default is 1. */
unsigned int _workers;
}; };
#endif // SETTINGS_H #endif // SETTINGS_H

View File

@ -19,18 +19,12 @@
#include "threadexecutor.h" #include "threadexecutor.h"
#include "cppcheck.h" #include "cppcheck.h"
#if 0
/**
This implementation is currently for Linux only and disabled with #if 0 until
proper way is invented.
*/
#include <sys/wait.h>
#include <iostream> #include <iostream>
#if defined(__GNUC__) && !defined(__MINGW32__)
#include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#endif
ThreadExecutor::ThreadExecutor(const std::vector<std::string> &filenames, const Settings &settings, ErrorLogger &errorLogger) ThreadExecutor::ThreadExecutor(const std::vector<std::string> &filenames, const Settings &settings, ErrorLogger &errorLogger)
: _filenames(filenames), _settings(settings), _errorLogger(errorLogger), _fileCount(0) : _filenames(filenames), _settings(settings), _errorLogger(errorLogger), _fileCount(0)
@ -43,6 +37,12 @@ ThreadExecutor::~ThreadExecutor()
//dtor //dtor
} }
///////////////////////////////////////////////////////////////////////////////
////// This code is for __GNUC__ only /////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
#if defined(__GNUC__) && !defined(__MINGW32__)
bool ThreadExecutor::handleRead(unsigned int &result) bool ThreadExecutor::handleRead(unsigned int &result)
{ {
char type = 0; char type = 0;
@ -53,7 +53,7 @@ bool ThreadExecutor::handleRead(unsigned int &result)
if (type != '1' && type != '2' && type != '3') if (type != '1' && type != '2' && type != '3')
{ {
std::cerr << "#### ThreadExecutor::handleRead error, type was:" << type << std::endl; std::cerr << "#### You found a bug from cppcheck.\nThreadExecutor::handleRead error, type was:" << type << std::endl;
exit(0); exit(0);
} }
@ -112,7 +112,7 @@ unsigned int ThreadExecutor::check()
for (unsigned int i = 0; i < _filenames.size(); i++) for (unsigned int i = 0; i < _filenames.size(); i++)
{ {
// Keep only wanted amount of child processes running at a time. // Keep only wanted amount of child processes running at a time.
if (childCount >= 2) if (childCount >= _settings._workers)
{ {
while (handleRead(result)) while (handleRead(result))
{ {
@ -187,5 +187,22 @@ void ThreadExecutor::reportStatus(unsigned int /*index*/, unsigned int /*max*/)
} }
#else #else
unsigned int ThreadExecutor::check()
{
return 0;
}
void ThreadExecutor::reportOut(const std::string &/*outmsg*/)
{
}
void ThreadExecutor::reportErr(const ErrorLogger::ErrorMessage &/*msg*/)
{
}
void ThreadExecutor::reportStatus(unsigned int /*index*/, unsigned int /*max*/)
{
}
#endif #endif

View File

@ -31,7 +31,6 @@
*/ */
class ThreadExecutor : public ErrorLogger class ThreadExecutor : public ErrorLogger
{ {
#if 0
public: public:
ThreadExecutor(const std::vector<std::string> &filenames, const Settings &settings, ErrorLogger &_errorLogger); ThreadExecutor(const std::vector<std::string> &filenames, const Settings &settings, ErrorLogger &_errorLogger);
virtual ~ThreadExecutor(); virtual ~ThreadExecutor();
@ -39,28 +38,37 @@ public:
virtual void reportOut(const std::string &outmsg); virtual void reportOut(const std::string &outmsg);
virtual void reportErr(const ErrorLogger::ErrorMessage &msg); virtual void reportErr(const ErrorLogger::ErrorMessage &msg);
virtual void reportStatus(unsigned int index, unsigned int max); virtual void reportStatus(unsigned int index, unsigned int max);
protected:
private:
bool handleRead(unsigned int &result);
void writeToPipe(char type, const std::string &data);
private:
const std::vector<std::string> &_filenames; const std::vector<std::string> &_filenames;
const Settings &_settings; const Settings &_settings;
ErrorLogger &_errorLogger; ErrorLogger &_errorLogger;
int _pipe[2];
unsigned int _fileCount; unsigned int _fileCount;
#if defined(__GNUC__) && !defined(__MINGW32__)
private:
bool handleRead(unsigned int &result);
void writeToPipe(char type, const std::string &data);
int _pipe[2];
public:
/**
* @return true if support for threads exist.
*/
static bool isEnabled()
{
return true;
}
#else #else
public: public:
ThreadExecutor(const std::vector<std::string> &filenames, const Settings &settings, ErrorLogger &_errorLogger) {}; /**
virtual ~ThreadExecutor() {}; * @return true if support for threads exist.
unsigned int check() */
static bool isEnabled()
{ {
return 0; return false;
} }
virtual void reportOut(const std::string &outmsg) {}
virtual void reportErr(const ErrorLogger::ErrorMessage &msg) {}
virtual void reportStatus(unsigned int index, unsigned int max) {}
#endif #endif
}; };
#endif // THREADEXECUTOR_H #endif // THREADEXECUTOR_H

View File

@ -181,7 +181,7 @@ int main()
fout << " std::string toXML() const;\n"; fout << " std::string toXML() const;\n";
fout << " std::string toText() const;\n"; fout << " std::string toText() const;\n";
fout << " std::string serialize() const;\n"; fout << " std::string serialize() const;\n";
fout << " bool deserialize( const std::string &data );\n"; fout << " bool deserialize(const std::string &data);\n";
fout << " private:\n"; fout << " private:\n";
fout << " std::list<FileLocation> _callStack;\n"; fout << " std::list<FileLocation> _callStack;\n";
fout << " std::string _severity;\n"; fout << " std::string _severity;\n";