BURTON Mark
Builds for 1 pipeline failed in 5 minutes 50 seconds

WIP adding a first attempt at a deterministic thing

(plus many comments)
... ... @@ -55,26 +55,28 @@
#include <time.h>
#include <tlm_utils/tlm_quantumkeeper.h>
#include "greencontrol/config.h"
#include "greenthreads/util.h"
#include "greenthreads/async_event.h"
#define COUT if (0) cout << pthread_self() << ":"
#define COUT if (1) cout << pthread_self() << ":"
namespace gs {
namespace gt {
typedef enum {parallel, qemu_decoupled, systemc_behind, determanistic} sync_mode;
class centralSyncPolicy : sc_core::sc_module {
public:
static centralSyncPolicy share;
gs::gs_param<bool> deterministic;
gs::gs_param<bool> sc_behind_mode;
private:
std::list<sc_core::sc_time> endTimes;
spin_mutex mutex;
timed_cond ahead;
sc_core::sc_time backWindow;
sc_core::sc_time frontWindow;
sc_core::sc_time backSourceWindow;
bool sc_is_back_window;
sem_i canLock;
int locksToDo;
... ... @@ -91,6 +93,7 @@ private:
}
public:
spin_mutex d_mutex;
void releaseLock() {
canLock.post();
... ... @@ -112,9 +115,12 @@ public:
}
SC_CTOR(centralSyncPolicy)
: endTimes(), mutex()
: deterministic("deterministic",false)
, sc_behind_mode("sc_behind",true)
, endTimes(), mutex()
, backWindow(SC_ZERO_TIME), frontWindow(SC_ZERO_TIME), sc_is_back_window(false)
, canLock(0), locksToDo(0)
, d_mutex()
{
/* Prevent sc_stop posting an invisible event (causing us to hang) */
sc_core::sc_set_stop_mode(SC_STOP_IMMEDIATE);
... ... @@ -122,6 +128,8 @@ public:
SC_METHOD(checkWindow);
sensitive << checkWindowEvent;
dont_initialize();
if (deterministic) d_mutex.lock();
}
void start_of_simulation() {
... ... @@ -141,25 +149,30 @@ public:
mutex.lock();
}
void setWindow(sc_core::sc_time t, sc_core::sc_time *entryRef, sync_mode mode)
void setWindow(sc_core::sc_time t, sc_core::sc_time *entryRef, bool decoupled)
{
*entryRef = t;
// pthread_mutex_lock(&mutex);
update_window();
if (decoupled) return; // do not attempt to sync this source.
/* wait if we're ahead the backWindow plus a quantum */
sc_core::sc_time quantum = tlm_utils::tlm_quantumkeeper::get_global_quantum();
while (mode!=qemu_decoupled && (t > backWindow + quantum)) {
sc_core::sc_time quantum = /* get the local quantum */tlm_utils::tlm_quantumkeeper::get_global_quantum();
while (t > (backWindow + quantum)) {
// mutex.lock();
// COUT << "ahead wait sc_time:"<<sc_time_stamp()<< " our time:"<<t<< " backWindow:"<<backWindow<<" bwin+q "<<(backWindow + quantum)<<"bool:"<<(t > (backWindow + quantum))<<"\n";
// mutex.unlock();
// int p = pthread_cond_timedwait(&cnd, &mutex, &ts);
if (ahead.wait()) {
COUT << "Timeout reached\n";
break;
SC_REPORT_ERROR("greenthreads", "Deadlock timeout reached");
break;
}
}
}
sc_core::sc_time getBackWindow() { return backWindow; }
sc_core::sc_time getFrontWindow() { return frontWindow; }
// make this a list of sync_source - not 'times'
sc_core::sc_time *registerLockable() {
mutex.lock();
endTimes.push_back(SC_ZERO_TIME);
... ... @@ -177,12 +190,16 @@ public:
*/
void checkWindow()
{
if (deterministic) d_mutex.unlock();
if (sc_is_back_window) {
update_window();
}
sc_core::sc_time sc_front_window=(sc_behind_mode)?backSourceWindow:frontWindow;
// or backWindow+quantum
if (sc_time_stamp() < frontWindow) {
checkWindowEvent.notify(frontWindow - sc_time_stamp());
if (sc_time_stamp() < sc_front_window) {
checkWindowEvent.notify(sc_front_window - sc_time_stamp());
} else {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
... ... @@ -197,10 +214,13 @@ public:
sem_post(&(canLock()));
mutex.unlock();
/* we rely on checkWindowEvent being notified at the end of the transaction */
} else {
} else if (errno == ETIMEDOUT) {
checkWindowEvent.notify();
} else {
SC_REPORT_ERROR("greenthreads", "sem_timedwait failed in checkWindow()");
}
}
if (deterministic) d_mutex.lock();
}
protected:
... ... @@ -211,7 +231,9 @@ protected:
sc_core::sc_time front = sc_ts;
bool changed = false;
/* Update all Windows by iterating over all sources */
mutex.lock();
sc_core::sc_time min_back=*endTimes.begin();
for (std::list<sc_core::sc_time>::iterator i = endTimes.begin(); i != endTimes.end(); ++i) {
if (*i < back) {
back = *i;
... ... @@ -219,8 +241,9 @@ protected:
else if (*i > front) {
front = *i;
}
if (*i < min_back) min_back=*i;
}
if (back != backWindow) {
if (backWindow != back) {
changed = true;
backWindow = back;
}
... ... @@ -228,44 +251,53 @@ protected:
changed = true;
frontWindow = front;
}
if (backSourceWindow != min_back) {
changed = true;
backSourceWindow = min_back;
}
sc_is_back_window = (sc_ts == backWindow);
mutex.unlock();
/* If the windows changed, wake-up pending threads */
if (changed) {
ahead.release();
kickLock();
ahead.release(); // kick sources
kickLock(); // kick systemc
}
}
};
class syncSource {
sc_core::sc_time *handle;
sc_core::sc_time back_window;
pthread_t owner_thread;
sync_mode mode;
pthread_t sc_thread;
bool decoupled;
bool locked;
public:
syncSource(sync_mode _mode = parallel) : mode(_mode) {
owner_thread = pthread_self();
/*
* This class must be instanciated from SystemC (and in the SystemC thread)
*/
// register the quantum here....
syncSource(bool _decoupled = false) : decoupled(_decoupled) {
sc_thread = pthread_self();
handle = centralSyncPolicy::share.registerLockable();
back_window = SC_ZERO_TIME;
centralSyncPolicy::share.setWindow(back_window, handle, mode);
centralSyncPolicy::share.setWindow(SC_ZERO_TIME, handle, decoupled);
locked=false;
}
void syncAt(sc_core::sc_time t) {
if (pthread_equal(pthread_self(), owner_thread)) {
if (pthread_equal(pthread_self(), sc_thread)) {
return;
}
if (t > back_window) {
back_window = t;
if (mode==qemu_decoupled) {
back_window = sc_time_stamp();
}
/* setWindow could lock if WE have got ahead (SystemC is behind) */
centralSyncPolicy::share.setWindow(back_window, handle, mode);
if (locked) {
locked=false;
centralSyncPolicy::share.d_mutex.unlock();
}
COUT << "SyncAt sc_time:"<<sc_time_stamp()<< " sync time:"<<t<<"\n";
centralSyncPolicy::share.setWindow(t, handle, decoupled);
if (centralSyncPolicy::share.deterministic) {
centralSyncPolicy::share.d_mutex.lock();
locked=true;
}
}
};
... ...
/* temporarily for legacy */
#ifndef GS_GT_THREAD_SAFE_EVENT_H
#define GS_GT_THREAD_SAFE_EVENT_H
#include "greenthreads/greenthreads.h"
namespace gs {
namespace gt {
typedef async_event event_async;
}
}
#endif
... ... @@ -86,7 +86,7 @@ public:
bool wait() {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 1; // Wait 1 second
ts.tv_sec += 5; // Wait 1 second
pthread_mutex_lock(&mutex);
int p = pthread_cond_timedwait(&cnd, &mutex, &ts);
pthread_mutex_unlock(&mutex);
... ...