include: Merge misc thread runtime support.

This commit is contained in:
Wilson Snyder 2018-05-13 19:30:51 -04:00
parent 2c568603f6
commit fe917ba7f4
5 changed files with 42 additions and 99 deletions

View File

@ -202,7 +202,7 @@ IData VL_RAND32() VL_MT_SAFE {
t_seeded = true;
long seedval;
{
VerilatedLockGuard guard(s_mutex);
VerilatedLockGuard lock(s_mutex);
seedval = lrand48()<<16 ^ lrand48();
if (!seedval) seedval++;
}
@ -1612,7 +1612,7 @@ Verilated::ThreadLocal::~ThreadLocal() {
}
void Verilated::debug(int val) VL_MT_SAFE {
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
s_s.s_debug = val;
if (val) {
#ifdef VL_DEBUG
@ -1623,23 +1623,23 @@ void Verilated::debug(int val) VL_MT_SAFE {
}
}
void Verilated::randReset(int val) VL_MT_SAFE {
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
s_s.s_randReset = val;
}
void Verilated::calcUnusedSigs(bool flag) VL_MT_SAFE {
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
s_s.s_calcUnusedSigs = flag;
}
void Verilated::gotFinish(bool flag) VL_MT_SAFE {
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
s_s.s_gotFinish = flag;
}
void Verilated::assertOn(bool flag) VL_MT_SAFE {
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
s_s.s_assertOn = flag;
}
void Verilated::fatalOnVpiError(bool flag) VL_MT_SAFE {
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
s_s.s_fatalOnVpiError = flag;
}
@ -1661,7 +1661,7 @@ const char* Verilated::catName(const char* n1, const char* n2) VL_MT_SAFE {
}
void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
if (s_flushCb == cb) {} // Ok - don't duplicate
else if (!s_flushCb) { s_flushCb=cb; }
else {
@ -1671,14 +1671,14 @@ void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
}
void Verilated::flushCall() VL_MT_SAFE {
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
if (s_flushCb) (*s_flushCb)();
fflush(stderr);
fflush(stdout);
}
void Verilated::commandArgs(int argc, const char** argv) VL_MT_SAFE {
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
s_args.argc = argc;
s_args.argv = argv;
VerilatedImp::commandArgs(argc,argv);
@ -1716,16 +1716,6 @@ void Verilated::scopesDump() VL_MT_SAFE {
VerilatedImp::scopesDump();
}
void Verilated::numThreads(unsigned threads) VL_MT_SAFE {
VerilatedImp::numThreads(threads);
}
unsigned Verilated::numThreads() VL_MT_SAFE {
return VerilatedImp::numThreads();
}
void Verilated::spawnThreads() VL_MT_SAFE {
VerilatedImp::spawnThreads();
}
const VerilatedScope* Verilated::scopeFind(const char* namep) VL_MT_SAFE {
return VerilatedImp::scopeFind(namep);
}
@ -1948,7 +1938,7 @@ void VerilatedScope::scopeDump() const {
//===========================================================================
// VerilatedOneThreaded:: Methods
#ifdef VL_THREADED
#if defined(VL_THREADED) && defined(VL_DEBUG)
void VerilatedAssertOneThread::fatal_different() VL_MT_SAFE {
VL_FATAL_MT(__FILE__, __LINE__, "", "Routine called that is single threaded, but called from"
" a different thread then the expected constructing thread");

View File

@ -437,17 +437,6 @@ public:
/// releases - contact the authors before production use.
static void scopesDump() VL_MT_SAFE;
/// Set the number of threads to execute on.
/// 0x0 = use all available CPU threads, or 1 if no support compiled in
/// Ignored after spawnThreads() has been called
static void numThreads(unsigned threads) VL_MT_SAFE;
static unsigned numThreads() VL_MT_SAFE;
/// Spawn child threads, using numThreads() as # of threads
/// Verilator calls this automatically on the first eval() call
/// User code may call it earlier if desired
/// Once called the first time, later calls are ignored
static void spawnThreads() VL_MT_SAFE;
public:
// METHODS - INTERNAL USE ONLY (but public due to what uses it)
// Internal: Create a new module name by concatenating two strings

View File

@ -233,12 +233,12 @@ public:
// PUBLIC METHODS
void clear() VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
clearGuts();
}
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
if (matchp && matchp[0]) {
ItemList newlist;
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
@ -254,7 +254,7 @@ public:
}
void zero() VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
(*it)->zero();
}
@ -262,18 +262,18 @@ public:
// We assume there's always call to i/f/p in that order
void inserti (VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
assert(!m_insertp);
m_insertp = itemp;
}
void insertf (const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
m_insertFilenamep = filenamep;
m_insertLineno = lineno;
}
void insertp (const char* ckeyps[MAX_KEYS],
const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
assert(m_insertp);
// First two key/vals are filename
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
@ -328,7 +328,7 @@ public:
void write(const char* filename) VL_EXCLUDES(m_mutex) {
Verilated::quiesce();
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
#ifndef VM_COVERAGE
VL_FATAL_MT("",0,"","%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
#endif

View File

@ -94,7 +94,7 @@ public:
// METHODS
//// Add message to queue (called by producer)
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
VerilatedLockGuard guard(m_mutex);
VerilatedLockGuard lock(m_mutex);
m_queue.insert(msg); // Pass by value to copy the message into queue
++m_depth;
}
@ -199,15 +199,10 @@ class VerilatedImp {
std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors
std::deque<IData> m_fdFree VL_GUARDED_BY(m_fdMutex); ///< List of free descriptors (SLOW - FOPEN/CLOSE only)
// Threads
VerilatedMutex m_threadMutex; ///< Protect m_numThreads, etc
bool m_spawned VL_GUARDED_BY(m_threadMutex); ///< Already called spawnThreads()
unsigned m_numThreads VL_GUARDED_BY(m_threadMutex); ///< Number of threads user requested, 0x0=all cpus
public: // But only for verilated*.cpp
// CONSTRUCTORS
VerilatedImp()
: m_argVecLoaded(false), m_exportNext(0), m_spawned(false), m_numThreads(0) {
: m_argVecLoaded(false), m_exportNext(0) {
m_fdps.resize(3);
m_fdps[0] = stdin;
m_fdps[1] = stdout;
@ -218,7 +213,7 @@ private:
VL_UNCOPYABLE(VerilatedImp);
public:
static void internalsDump() VL_MT_SAFE {
VerilatedLockGuard guard(s_s.m_argMutex);
VerilatedLockGuard lock(s_s.m_argMutex);
VL_PRINTF_MT("internalsDump:\n");
VL_PRINTF_MT(" Argv:");
for (ArgVec::const_iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
@ -234,16 +229,16 @@ public:
// METHODS - arguments
public:
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
VerilatedLockGuard guard(s_s.m_argMutex);
VerilatedLockGuard lock(s_s.m_argMutex);
s_s.m_argVec.clear(); // Always clear
commandArgsAddGuts(argc, argv);
}
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex) {
VerilatedLockGuard guard(s_s.m_argMutex);
VerilatedLockGuard lock(s_s.m_argMutex);
commandArgsAddGuts(argc, argv);
}
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
VerilatedLockGuard guard(s_s.m_argMutex);
VerilatedLockGuard lock(s_s.m_argMutex);
// Note prefixp does not include the leading "+"
size_t len = strlen(prefixp);
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
@ -272,14 +267,14 @@ public:
// There's often many more scopes than userdata's and thus having a ~48byte
// per map overhead * N scopes would take much more space and cache thrashing.
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
VerilatedLockGuard guard(s_s.m_userMapMutex);
VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
if (it != s_s.m_userMap.end()) it->second = userData;
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep,userKey),userData));
}
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
VerilatedLockGuard guard(s_s.m_userMapMutex);
VerilatedLockGuard lock(s_s.m_userMapMutex);
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep,userKey));
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
else return NULL;
@ -288,7 +283,7 @@ private:
/// Symbol table destruction cleans up the entries for each scope.
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope on destruction, so we simply iterate.
VerilatedLockGuard guard(s_s.m_userMapMutex);
VerilatedLockGuard lock(s_s.m_userMapMutex);
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
if (it->first.first == scopep) {
s_s.m_userMap.erase(it++);
@ -298,7 +293,7 @@ private:
}
}
static void userDump() VL_MT_SAFE {
VerilatedLockGuard guard(s_s.m_userMapMutex); // Avoid it changing in middle of dump
VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
bool first = true;
for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; }
@ -311,27 +306,27 @@ public: // But only for verilated*.cpp
// METHODS - scope name
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope at construction
VerilatedLockGuard guard(s_s.m_nameMutex);
VerilatedLockGuard lock(s_s.m_nameMutex);
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
if (it == s_s.m_nameMap.end()) {
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(),scopep));
}
}
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
VerilatedLockGuard guard(s_s.m_nameMutex); // If too slow, can assume this is only VL_MT_SAFE_POSINIT
VerilatedLockGuard lock(s_s.m_nameMutex); // If too slow, can assume this is only VL_MT_SAFE_POSINIT
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
else return NULL;
}
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
// Slow ok - called once/scope at destruction
VerilatedLockGuard guard(s_s.m_nameMutex);
VerilatedLockGuard lock(s_s.m_nameMutex);
userEraseScope(scopep);
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
}
static void scopesDump() VL_MT_SAFE {
VerilatedLockGuard guard(s_s.m_nameMutex);
VerilatedLockGuard lock(s_s.m_nameMutex);
VL_PRINTF_MT(" scopesDump:\n");
for (VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) {
const VerilatedScope* scopep = it->second;
@ -355,7 +350,7 @@ public: // But only for verilated*.cpp
// miss at the cost of a multiply, and all lookups move to slowpath.
static int exportInsert(const char* namep) VL_MT_SAFE {
// Slow ok - called once/function at creation
VerilatedLockGuard guard(s_s.m_exportMutex);
VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::iterator it=s_s.m_exportMap.find(namep);
if (it == s_s.m_exportMap.end()) {
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
@ -365,7 +360,7 @@ public: // But only for verilated*.cpp
}
}
static int exportFind(const char* namep) VL_MT_SAFE {
VerilatedLockGuard guard(s_s.m_exportMutex);
VerilatedLockGuard lock(s_s.m_exportMutex);
ExportNameMap::const_iterator it=s_s.m_exportMap.find(namep);
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
std::string msg = (std::string("%Error: Testbench C called ")+namep
@ -375,14 +370,14 @@ public: // But only for verilated*.cpp
}
static const char* exportName(int funcnum) VL_MT_SAFE {
// Slowpath; find name for given export; errors only so no map to reverse-map it
VerilatedLockGuard guard(s_s.m_exportMutex);
VerilatedLockGuard lock(s_s.m_exportMutex);
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
if (it->second == funcnum) return it->first;
}
return "*UNKNOWN*";
}
static void exportsDump() VL_MT_SAFE {
VerilatedLockGuard guard(s_s.m_exportMutex);
VerilatedLockGuard lock(s_s.m_exportMutex);
bool first = true;
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
@ -397,7 +392,7 @@ public: // But only for verilated*.cpp
static IData fdNew(FILE* fp) VL_MT_SAFE {
if (VL_UNLIKELY(!fp)) return 0;
// Bit 31 indicates it's a descriptor not a MCD
VerilatedLockGuard guard(s_s.m_fdMutex);
VerilatedLockGuard lock(s_s.m_fdMutex);
if (s_s.m_fdFree.empty()) {
// Need to create more space in m_fdps and m_fdFree
size_t start = s_s.m_fdps.size();
@ -410,7 +405,7 @@ public: // But only for verilated*.cpp
}
static void fdDelete(IData fdi) VL_MT_SAFE {
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard guard(s_s.m_fdMutex);
VerilatedLockGuard lock(s_s.m_fdMutex);
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
s_s.m_fdps[idx] = NULL;
@ -418,41 +413,10 @@ public: // But only for verilated*.cpp
}
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
IData idx = VL_MASK_I(31) & fdi;
VerilatedLockGuard guard(s_s.m_fdMutex); // This might get slow, if it does we can cache it
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
return s_s.m_fdps[idx];
}
public: // But only for verilated*.cpp
// METHODS - Threading
static void numThreads(unsigned threads) VL_MT_SAFE {
VerilatedLockGuard guard(s_s.m_threadMutex);
if (!s_s.m_spawned) s_s.m_numThreads = threads;
}
static unsigned numThreads() VL_MT_SAFE {
VerilatedLockGuard guard(s_s.m_threadMutex);
#ifdef VL_THREADED
unsigned threads = s_s.m_numThreads;
if (threads == 0x0) {
threads = std::thread::hardware_concurrency(); // Or 0=unknown, C++11
}
if (threads<1) threads = 1;
return threads;
#else
return 0;
#endif
}
static void spawnThreads() VL_MT_SAFE {
VerilatedLockGuard guard(s_s.m_threadMutex);
if (!s_s.m_spawned) {
// Convert numThreads from 0 to the spawned number
numThreads(numThreads());
s_s.m_spawned = true;
#ifdef VL_THREADED
// THREADED-TODO startup threads
#endif
}
}
};
//======================================================================

View File

@ -61,18 +61,18 @@ private:
static Singleton& singleton() { static Singleton s; return s; }
public:
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
VerilatedLockGuard guard(singleton().s_vcdMutex);
VerilatedLockGuard lock(singleton().s_vcdMutex);
singleton().s_vcdVecp.push_back(vcdp);
}
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
VerilatedLockGuard guard(singleton().s_vcdMutex);
VerilatedLockGuard lock(singleton().s_vcdMutex);
VcdVec::iterator pos = find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
}
static void flush_all() VL_EXCLUDES(singleton().s_vcdMutex) VL_MT_UNSAFE_ONE {
// Thread safety: Although this function is protected by a mutex so perhaps
// in the future we can allow tracing in separate threads, vcdp->flush() assumes call from single thread
VerilatedLockGuard guard(singleton().s_vcdMutex);
VerilatedLockGuard lock(singleton().s_vcdMutex);
for (VcdVec::const_iterator it=singleton().s_vcdVecp.begin(); it!=singleton().s_vcdVecp.end(); ++it) {
VerilatedVcd* vcdp = *it;
vcdp->flush();