Multi-process parsing initial support
Signed-off-by: Alain <alainmarcel@yahoo.com>
diff --git a/.travis.yml b/.travis.yml
index 865cd7d..e4c319f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -37,4 +37,5 @@
- make release
- sudo make install
- make test_install
+ - make test
diff --git a/Makefile b/Makefile
index 9341abb..f5e2649 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@
mkdir -p dist;
cd build; cmake ../ -DCMAKE_BUILD_TYPE=Release
$(MAKE) -C build
- cd build; ../tests/regression.tcl mt=0 show_diff
+
debug:
mkdir -p dbuild/tests;
mkdir -p dbuild/dist;
@@ -14,10 +14,9 @@
cd dbuild; cmake ../ -DCMAKE_BUILD_TYPE=Debug
$(MAKE) -C dbuild
-
test:
mkdir -p build/tests;
- cd build; ../tests/regression.tcl mt=0
+ cd build; ../tests/regression.tcl mt=0 show_diff
clean:
rm -rf dist;
diff --git a/README.md b/README.md
index 0462eac..a96121b 100644
--- a/README.md
+++ b/README.md
@@ -122,6 +122,8 @@
* A simple example of creating a new error message and generating errors can be found here: [`python_listener.py`](src/API/python_listener.py)
+ * A simple example for design-level data model exploration can be found here: [`myscriptPerDesign.py`](tests/UnitPython/myscriptPerDesign.py)
+
* The complete Python API is described in the following files: [`SLAPI.h`](src/API/SLAPI.h) [`vobjecttypes`](src/API/vobjecttypes.py)
* Waivers can be installed in slwaivers.py files in the execution directory or install directory /usr/local/lib/surelog/python
diff --git a/src/Cache/Cache.cpp b/src/Cache/Cache.cpp
index 0b3fb5f..34d0d89 100644
--- a/src/Cache/Cache.cpp
+++ b/src/Cache/Cache.cpp
@@ -67,7 +67,7 @@
std::string cacheFileName) {
/* Schema version */
if (schemaVersion != header->m_flb_version()->c_str()) {
- return false;
+ return false;
}
/* Tool version */
@@ -87,11 +87,16 @@
time_t ct = get_mtime(cacheFileName.c_str());
std::string fileName = header->m_file()->c_str();
time_t ft = get_mtime(fileName.c_str());
- if (ft == -1) return false;
- if (ct == -1) return false;
- if (ct < ft) return false;
+ if (ft == -1) {
+ return false;
+ }
+ if (ct == -1) {
+ return false;
+ }
+ if (ct < ft) {
+ return false;
+ }
}
-
return true;
}
diff --git a/src/Cache/ParseCache.cpp b/src/Cache/ParseCache.cpp
index e76f71e..26b97d0 100644
--- a/src/Cache/ParseCache.cpp
+++ b/src/Cache/ParseCache.cpp
@@ -177,7 +177,9 @@
bool ParseCache::checkCacheIsValid_(std::string cacheFileName) {
uint8_t* buffer_pointer = openFlatBuffers(cacheFileName);
- if (buffer_pointer == NULL) return false;
+ if (buffer_pointer == NULL) {
+ return false;
+ }
if (!PARSECACHE::ParseCacheBufferHasIdentifier(buffer_pointer)) {
delete[] buffer_pointer;
return false;
diff --git a/src/CommandLine/CommandLineParser.cpp b/src/CommandLine/CommandLineParser.cpp
index a507994..87dd533 100644
--- a/src/CommandLine/CommandLineParser.cpp
+++ b/src/CommandLine/CommandLineParser.cpp
@@ -27,6 +27,8 @@
#include <sstream>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/param.h>
+#include <unistd.h>
#include "CommandLine/CommandLineParser.h"
#include "Utils/StringUtils.h"
#include "Utils/FileUtils.h"
@@ -108,6 +110,7 @@
" if \"max\" is given, the program will use one "
"thread",
" per core on the host",
+ " -mp <mb_max_process> 0 up to 512 max processes, 0 or 1 being single process",
" -split <line number> Split files or modules larger than specified line "
"number for multi thread compilation",
" -timescale=<timescale> Specifies the overall timescale",
@@ -230,6 +233,7 @@
m_help(false),
m_cacheAllowed(true),
m_nbMaxTreads(0),
+ m_nbMaxProcesses(0),
m_fullCompileDir(0),
m_cacheDirId(0),
m_note(true),
@@ -359,6 +363,7 @@
int CommandLineParser::parseCommandLine(int argc, const char** argv) {
std::string exe_name = argv[0];
+ m_exePath = exe_name;
std::string exe_path = FileUtils::getPathName(exe_name);
m_precompiledDirId = m_symbolTable->registerSymbol(exe_path + "pkg/");
if (!FileUtils::fileExists(exe_path + "pkg/")) {
@@ -522,7 +527,8 @@
}
i++;
m_nbLinesForFileSplitting = atoi(all_arguments[i].c_str());
- } else if (all_arguments[i] == "-mt") {
+ } else if (all_arguments[i] == "-mt" || all_arguments[i] == "-mp") {
+ bool mt = (all_arguments[i] == "-mt");
if (i == all_arguments.size() - 1) {
Location loc(getSymbolTable()->registerSymbol(all_arguments[i]));
Error err(ErrorDefinition::CMD_MT_MISSING_LEVEL, loc);
@@ -551,13 +557,21 @@
maxMT = (concurentThreadsSupported / 2);
}
- if (maxMT == 0)
- m_nbMaxTreads = maxMT;
- else {
- m_nbMaxTreads = maxMT;
- if (m_nbMaxTreads < 2) m_nbMaxTreads = 2;
+ if (maxMT == 0) {
+ if (mt)
+ m_nbMaxTreads = maxMT;
+ else
+ m_nbMaxProcesses = maxMT;
+ } else {
+ if (mt) {
+ m_nbMaxTreads = maxMT;
+ if (m_nbMaxTreads < 2) m_nbMaxTreads = 2;
+ } else {
+ m_nbMaxProcesses = maxMT;
+ if (m_nbMaxProcesses < 2) m_nbMaxProcesses = 2;
+ }
Location loc(
- getSymbolTable()->registerSymbol(std::to_string(m_nbMaxTreads)));
+ getSymbolTable()->registerSymbol(std::to_string(maxMT)));
Error err(ErrorDefinition::CMD_NUMBER_THREADS, loc);
m_errors->addError(err);
}
@@ -685,6 +699,16 @@
m_parse = true;
m_compile = true;
m_elaborate = true;
+ } else if (all_arguments[i] == "-parseonly") {
+ m_writePpOutput = true;
+ m_parse = true;
+ m_compile = false;
+ m_elaborate = false;
+ m_parseOnly = true;
+ int ret = chdir("..");
+ if (ret < 0) {
+ std::cout << "Could not change directory to ../\n" << std::endl;
+ }
} else if (all_arguments[i] == "-nocomp") {
m_compile = false;
m_elaborate = false;
diff --git a/src/CommandLine/CommandLineParser.h b/src/CommandLine/CommandLineParser.h
index 6253976..e18729f 100644
--- a/src/CommandLine/CommandLineParser.h
+++ b/src/CommandLine/CommandLineParser.h
@@ -59,7 +59,7 @@
return m_defineList;
}
bool fileunit() { return m_fileunit; } // File or all compilation semantic
-
+ void setFileUnit() { m_fileunit = true; }
/* PP Output file/dir options */
SymbolId writePpOutputFileId() { return m_writePpOutputFileId; }
SymbolId getOutputDir() { return m_outputDir; }
@@ -72,21 +72,28 @@
SymbolId getLogFileId() { return m_logFileId; }
SymbolId getDefaultLogFileId() { return m_defaultLogFileId; }
bool writePpOutput() { return m_writePpOutput; }
+ void setwritePpOutput(bool value) { m_writePpOutput = value; }
bool cacheAllowed() { return m_cacheAllowed; }
+ void setCacheAllowed(bool val) { m_cacheAllowed = val; }
bool lineOffsetsAsComments() { return m_lineOffsetsAsComments; }
SymbolId getCacheDir() { return m_cacheDirId; }
SymbolId getPrecompiledDir() { return m_precompiledDirId; }
bool usePPOutoutFileLocation() { return m_ppOutputFileLocation; }
/* PP Output content generation options */
bool filterFileLine() { return m_filterFileLine; }
+ void setFilterFileLine(bool val) { m_filterFileLine = val; }
bool filterSimpleDirectives() { return m_filterSimpleDirectives; }
bool filterProtectedRegions() { return m_filterProtectedRegions; }
bool filterComments() { return m_filterComments; }
bool filterInfo() { return !m_info; }
bool filterNote() { return !m_note; }
bool filterWarning() { return !m_warning; }
+ void setFilterInfo() { m_info = false; }
+ void setFilterNote() { m_note = false; }
+ void setFilterWarning() { m_warning = false; }
/* Debug/traces options */
bool muteStdout() { return m_muteStdout; }
+ void setMuteStdout() { m_muteStdout = true; }
bool verbose() { return m_verbose; }
bool profile() { return m_profile; }
int getDebugLevel() { return m_debugLevel; }
@@ -100,8 +107,13 @@
static std::string getVersionNumber() { return m_versionNumber; }
/* Core functions options */
bool parse() { return m_parse; }
+ bool parseOnly() { return m_parseOnly; }
bool compile() { return m_compile; }
bool elaborate() { return m_elaborate; }
+ void setParse(bool val) { m_parse = val; }
+ void setParseOnly(bool val) { m_parseOnly = val; }
+ void setCompile(bool val) { m_compile = val; }
+ void setElaborate(bool val) { m_elaborate = val; }
bool pythonListener() { return m_pythonListener && m_pythonAllowed; }
bool pythonAllowed() { return m_pythonAllowed; }
void noPython() { m_pythonAllowed = false; }
@@ -116,6 +128,9 @@
ErrorContainer* getErrorContainer() { return m_errors; }
SymbolTable* getSymbolTable() { return m_symbolTable; }
unsigned short int getNbMaxTreads() { return m_nbMaxTreads; }
+ unsigned short int getNbMaxProcesses() { return m_nbMaxProcesses; }
+ void setNbMaxTreads(unsigned short int max) { m_nbMaxTreads = max; }
+ void setNbMaxProcesses(unsigned short int max) { m_nbMaxProcesses = max; }
unsigned int getNbLinesForFileSpliting() { return m_nbLinesForFileSplitting; }
bool useTbb() { return m_useTbb; }
std::string getTimeScale() { return m_timescale; }
@@ -123,6 +138,7 @@
const std::string currentDateTime();
bool parseBuiltIn();
std::string getBuiltInPath() { return m_builtinPath; }
+ std::string getExePath() { return m_exePath; }
private:
bool plus_arguments_(const std::string& s);
void processArgs_(std::vector<std::string>& args,
@@ -162,12 +178,14 @@
bool m_filterProtectedRegions;
bool m_filterComments;
bool m_parse;
+ bool m_parseOnly;
bool m_compile;
bool m_elaborate;
bool m_diff_comp_mode;
bool m_help;
bool m_cacheAllowed;
unsigned short int m_nbMaxTreads;
+ unsigned short int m_nbMaxProcesses;
SymbolId m_compileUnitDirectory;
SymbolId m_compileAllDirectory;
SymbolId m_outputDir;
@@ -200,6 +218,7 @@
bool m_ppOutputFileLocation;
bool m_logFileSpecified;
std::string m_builtinPath;
+ std::string m_exePath;
};
}; // namespace SURELOG
diff --git a/src/ErrorReporting/ErrorContainer.cpp b/src/ErrorReporting/ErrorContainer.cpp
index 56423f8..da63beb 100644
--- a/src/ErrorReporting/ErrorContainer.cpp
+++ b/src/ErrorReporting/ErrorContainer.cpp
@@ -44,15 +44,20 @@
/* Do nothing here */
}
+#include <unistd.h>
+#include <stdio.h>
+
void ErrorContainer::init() {
if (ErrorDefinition::init()) {
const std::string& logFileName =
m_clp->getSymbolTable()->getSymbol(m_clp->getLogFileId());
std::ofstream ofs;
ofs.open(logFileName, std::fstream::out);
+ char cwd[1024];
+ getcwd(cwd, sizeof(cwd));
if (!ofs.good()) {
std::cerr << "[FATAL:LG0001] Cannot create log file \"" << logFileName
- << "\"" << std::endl;
+ << "\"" << "dir: " << cwd << std::endl;
return;
}
ofs.close();
diff --git a/src/SourceCompile/CompileSourceFile.cpp b/src/SourceCompile/CompileSourceFile.cpp
index c1e45a0..5b1aa52 100644
--- a/src/SourceCompile/CompileSourceFile.cpp
+++ b/src/SourceCompile/CompileSourceFile.cpp
@@ -251,10 +251,14 @@
}
bool CompileSourceFile::postPreprocess_() {
+ SymbolTable* symbolTable = getCompiler()->getSymbolTable();
+ if (m_commandLineParser->parseOnly()) {
+ m_ppResultFileId = m_symbolTable->registerSymbol(symbolTable->getSymbol(m_fileId));
+ return true;
+ }
std::string m_pp_result = m_pp->getPreProcessedFileContent();
if (m_commandLineParser->writePpOutput() ||
(m_commandLineParser->writePpOutputFileId() != 0)) {
- SymbolTable* symbolTable = getCompiler()->getSymbolTable();
const std::string& directory =
symbolTable->getSymbol(m_commandLineParser->getFullCompileDir());
std::string fileName = symbolTable->getSymbol(m_fileId);
diff --git a/src/SourceCompile/Compiler.cpp b/src/SourceCompile/Compiler.cpp
index b47783e..a40b864 100644
--- a/src/SourceCompile/Compiler.cpp
+++ b/src/SourceCompile/Compiler.cpp
@@ -21,7 +21,7 @@
* Created on March 4, 2017, 5:16 PM
*/
#include <stdint.h>
-
+#include <cstdlib>
#include "CommandLine/CommandLineParser.h"
#include "ErrorReporting/ErrorContainer.h"
#include "SourceCompile/SymbolTable.h"
@@ -256,7 +256,82 @@
return true;
}
-
+bool Compiler::createMultiProcess_() {
+ unsigned int nbProcesses = m_commandLineParser->getNbMaxProcesses();
+ if (nbProcesses == 0)
+ return true;
+ // Create CMakeLists.txt
+ if (m_commandLineParser->writePpOutput() ||
+ (m_commandLineParser->writePpOutputFileId() != 0)) {
+ SymbolTable* symbolTable = getSymbolTable();
+ const std::string& directory =
+ symbolTable->getSymbol(m_commandLineParser->getFullCompileDir());
+ std::ofstream ofs;
+ std::string fileList = directory + "/CMakeLists.txt";
+ ofs.open(fileList);
+ if (ofs.good()) {
+ ofs << "cmake_minimum_required (VERSION 3.0)" << std::endl;
+ ofs << "# Auto generated by Surelog" << std::endl;
+ unsigned int size = m_compilers.size();
+ std::string full_exe_path = m_commandLineParser->getExePath();
+ full_exe_path = FileUtils::getFullPath(full_exe_path);
+ full_exe_path = StringUtils::eliminateRelativePath(full_exe_path);
+ std::string fileUnit = "";
+ if (m_commandLineParser->fileunit())
+ fileUnit = " -fileunit ";
+ int modulo = 0;
+ if (size > nbProcesses) {
+ modulo = size / (nbProcesses);
+ if (modulo == 0)
+ modulo = 1;
+ }
+ int index = 0;
+ std::string fileList;
+ for (unsigned int i = 0; i < size; i++) {
+ std::string fileName = m_compilers[i]->getSymbolTable()->getSymbol(
+ m_compilers[i]->getPpOutputFileId());
+ if (strstr(fileName.c_str(), "builtin.sv")) continue;
+ index++;
+ fileList += " " + fileName;
+ if ((index == modulo) || (i == size -1)) {
+ std::string targetname = std::to_string(i) + "_" + FileUtils::fileName(fileName);
+ ofs <<"add_custom_command(OUTPUT " << targetname << std::endl;
+ ofs <<" COMMAND " << full_exe_path << fileUnit <<
+ " -parseonly -mt 0 -mp 0 -nostdout -nobuiltin -l "
+ << directory + targetname + ".log" << " " << fileList << std::endl;
+ ofs << ")" << std::endl;
+ fileList = "";
+ index = 0;
+ }
+ }
+ ofs << "add_custom_target(Parse ALL DEPENDS" << std::endl;
+ index = 0;
+ for (unsigned int i = 0; i < size; i++) {
+ std::string fileName = m_compilers[i]->getSymbolTable()->getSymbol(
+ m_compilers[i]->getPpOutputFileId());
+ if (strstr(fileName.c_str(), "builtin.sv")) continue;
+ index++;
+ if ((index == modulo) || (i == size -1)) {
+ ofs << std::to_string(i) << "_" << FileUtils::fileName(fileName) << std::endl;
+ index = 0;
+ }
+ }
+ ofs << ")" << std::endl;
+ ofs << std::flush;
+ ofs.close();
+ std::string command = "cd " + directory + ";" + "cmake .; make -j " + std::to_string(nbProcesses);
+ std::cout << "Running: " << command << std::endl << std::flush;
+ int result = system(command.c_str());
+ std::cout << "cmake result: " << result << std::endl;
+ } else {
+ std::cout << "Could not create CMakeLists.txt: " << fileList << std::endl;
+ }
+ }
+
+
+ return true;
+}
+
bool Compiler::parseinit_() {
Precompiled* prec = Precompiled::getSingleton();
// Single out the large files.
@@ -290,11 +365,14 @@
nbThreads = 0;
}
int effectiveNbThreads = 0;
- if (nbThreads > 4)
- effectiveNbThreads = (int)(log(((float)nbThreads + 1.0) / 4.0) * 10.0);
- else
- effectiveNbThreads = nbThreads;
-
+ if (m_commandLineParser->getNbMaxProcesses()) {
+ effectiveNbThreads = m_commandLineParser->getNbMaxProcesses();
+ } else {
+ if (nbThreads > 4)
+ effectiveNbThreads = (int)(log(((float)nbThreads + 1.0) / 4.0) * 10.0);
+ else
+ effectiveNbThreads = nbThreads;
+ }
AnalyzeFile* fileAnalyzer = new AnalyzeFile(
m_commandLineParser, m_design, fileName, origFile, effectiveNbThreads);
fileAnalyzer->analyze();
@@ -596,19 +674,23 @@
profile += msg;
tmr.reset();
}
- createFileList_();
+
// Parse
bool parserInitialized = false;
if (m_commandLineParser->parse() || m_commandLineParser->pythonListener() ||
m_commandLineParser->pythonEvalScriptPerFile() ||
m_commandLineParser->pythonEvalScript()) {
parseinit_();
+ createFileList_();
+ createMultiProcess_();
parserInitialized = true;
if (!compileFileSet_(CompileSourceFile::Parse, true, m_compilers))
return false; // Small files and large file chunks
if (!compileFileSet_(CompileSourceFile::Parse, true,
m_compilersParentFiles))
return false; // Recombine chunks
+ } else {
+ createFileList_();
}
if (m_commandLineParser->profile()) {
diff --git a/src/SourceCompile/Compiler.h b/src/SourceCompile/Compiler.h
index 3e3cbd8..175f7dd 100644
--- a/src/SourceCompile/Compiler.h
+++ b/src/SourceCompile/Compiler.h
@@ -75,6 +75,7 @@
bool ppinit_();
bool createFileList_();
+ bool createMultiProcess_();
bool parseinit_();
bool pythoninit_();
bool compileFileSet_(CompileSourceFile::Action action, bool allowMultithread,
diff --git a/src/SourceCompile/PreprocessFile.cpp b/src/SourceCompile/PreprocessFile.cpp
index 2b1ab9d..163898a 100644
--- a/src/SourceCompile/PreprocessFile.cpp
+++ b/src/SourceCompile/PreprocessFile.cpp
@@ -279,6 +279,8 @@
}
bool PreprocessFile::preprocess() {
+ if (getCompileSourceFile()->getCommandLineParser()->parseOnly())
+ return true;
Timer tmr;
PPCache cache(this);
if (cache.restore()) {
@@ -1068,6 +1070,8 @@
}
void PreprocessFile::saveCache() {
+ if (getCompileSourceFile()->getCommandLineParser()->parseOnly())
+ return;
if (m_macroBody == "") {
if (!m_usingCachedVersion) {
PPCache cache(this);
diff --git a/src/Utils/FileUtils.cpp b/src/Utils/FileUtils.cpp
index dc4310f..530e044 100644
--- a/src/Utils/FileUtils.cpp
+++ b/src/Utils/FileUtils.cpp
@@ -313,3 +313,12 @@
}
return "FAILED_TO_LOAD_CONTENT";
}
+
+std::string FileUtils::fileName(std::string str) {
+ char c = '/';
+ auto it1 = std::find_if(str.rbegin(), str.rend(),
+ [c](char ch) { return (ch == c); });
+ if (it1 != str.rend())
+ str.erase(str.begin(), it1.base());
+ return str;
+}
\ No newline at end of file
diff --git a/src/Utils/FileUtils.h b/src/Utils/FileUtils.h
index ce65776..c34f643 100644
--- a/src/Utils/FileUtils.h
+++ b/src/Utils/FileUtils.h
@@ -37,6 +37,7 @@
static int mkDir(const char* path);
static std::string getFullPath(const std::string path);
static std::string getPathName(const std::string path);
+ static std::string fileName(std::string str);
static unsigned long fileSize(const std::string name);
static std::vector<SymbolId> collectFiles(const std::string dirPath,
const std::string extension,
diff --git a/src/Utils/StringUtils.cpp b/src/Utils/StringUtils.cpp
index 69f9ede..d0cfbe6 100644
--- a/src/Utils/StringUtils.cpp
+++ b/src/Utils/StringUtils.cpp
@@ -267,13 +267,12 @@
}
std::string StringUtils::leaf(std::string str) {
- std::string result;
char c = '.';
auto it1 = std::find_if(str.rbegin(), str.rend(),
[c](char ch) { return (ch == c); });
- if (it1 != str.rend()) str.erase(str.begin(), it1.base());
+ if (it1 != str.rend())
+ str.erase(str.begin(), it1.base());
return str;
- return result;
}
std::string& StringUtils::getRootFileName(std::string& str) {
diff --git a/src/main.cpp b/src/main.cpp
index 1f8f794..28b8c20 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -37,6 +37,7 @@
SURELOG::ErrorContainer* errors = new SURELOG::ErrorContainer (symbolTable);
SURELOG::CommandLineParser* clp = new SURELOG::CommandLineParser (errors, symbolTable, diff_comp_mode, fileunit);
success = clp->parseCommandLine (argc, argv);
+ bool parseOnly = clp->parseOnly();
errors->printMessages (clp->muteStdout ());
if (success && (!clp->help()))
{
@@ -75,7 +76,10 @@
delete errors;
if ((!noFatalErrors) || (!success))
codedReturn |= 1;
- return codedReturn;
+ if (parseOnly)
+ return 0;
+ else
+ return codedReturn;
}
int