BURTON Mark
Builds for 1 pipeline passed in 6 minutes 20 seconds

Second attempt at determinism, seems to work

... ... @@ -26,10 +26,9 @@
* In addition, as a special exception, the copyright holders, GreenSocs
* Ltd, give you permission to combine GreenSocs code with free software
* programs or libraries that are released under the GNU LGPL, under the
* OSCI license, under the OCP TLM Kit Research License Agreement or
* under the OVP evaluation license.You may copy and distribute such a
* system following the terms of the GNU GPL and the licenses of the
* other code concerned.
* OSCI license, under the OCP TLM Kit Research License Agreement.
* You may copy and distribute such a system following the terms of the
* GNU GPL and the licenses of the other code concerned.
*
* Note that people who make modified versions of GreenSocs code are not
* obligated to grant this special exception for their modified versions;
... ... @@ -70,6 +69,8 @@ typedef struct s_source_entry {
syncSource *source;
sc_time end_time;
sc_time quantum;
bool locked;
bool decoupled;
} source_entry;
class centralSyncPolicy : sc_core::sc_module {
... ... @@ -90,6 +91,7 @@ private:
sem_i canLock;
int locksToDo;
async_event checkWindowEvent;
bool have_d_mutex;
/* It is always safe to call this method from anywhere in the SystemC thread */
void takeLockMethod() {
... ... @@ -102,7 +104,7 @@ private:
}
public:
spin_mutex d_mutex;
fifo_mutex d_mutex;
void releaseLock() {
canLock.post();
... ... @@ -141,7 +143,11 @@ public:
pthread_mutex_init(&cnd_mutex, NULL);
pthread_cond_init(&cnd, NULL);
if (deterministic) d_mutex.lock();
have_d_mutex=false;
if (deterministic) {
d_mutex.lock();
have_d_mutex=true;
}
}
void start_of_simulation() {
... ... @@ -155,7 +161,11 @@ public:
~centralSyncPolicy() {
/* release other models */
d_mutex.unlock();
if (have_d_mutex) {
d_mutex.unlock();
have_d_mutex=false;
}
/*
* Take the lock before you exit, will force others out of the critical region
* (preventing segfault on exit)
... ... @@ -163,18 +173,35 @@ public:
mutex.lock();
}
void setWindow(sc_core::sc_time t, source_entry *source, bool decoupled)
void initWindow(sc_core::sc_time t, source_entry *source, bool decoupled)
{
pthread_mutex_lock(&cnd_mutex);
source->end_time = t;
update_window();
pthread_mutex_unlock(&cnd_mutex);
source->decoupled=decoupled;
}
void setWindow(sc_core::sc_time t, source_entry *source)
{
pthread_mutex_lock(&cnd_mutex);
source->end_time = t;
update_window();
if (decoupled) {
if (source->decoupled) {
pthread_mutex_unlock(&cnd_mutex);
return; // do not attempt to sync this source.
}
if (deterministic) {
if (t > (backWindow + source->quantum)) {
if (source->locked) {
source->locked = false;
d_mutex.unlock();
}
}
}
/* wait if we're ahead the backWindow plus a quantum */
while (t > (backWindow + source->quantum)) {
// mutex.lock();
... ... @@ -191,6 +218,13 @@ public:
}
}
pthread_mutex_unlock(&cnd_mutex);
if (deterministic) {
if (!source->locked) {
d_mutex.lock();
source->locked=true;
}
}
}
source_entry *registerSource(syncSource *source, uint64_t quantum) {
... ... @@ -200,6 +234,7 @@ public:
entry->source = source;
entry->end_time = SC_ZERO_TIME;
entry->quantum = sc_time(quantum, SC_NS);
entry->locked=false;
mutex.unlock();
return entry;
}
... ... @@ -213,7 +248,11 @@ public:
*/
void checkWindow()
{
if (deterministic) d_mutex.unlock();
// We may have been woken up to do somethign on behalf of a Qemu.
if (have_d_mutex) {
d_mutex.unlock();
have_d_mutex=false;
}
pthread_mutex_lock(&cnd_mutex);
if (sc_is_back_window) {
... ... @@ -234,12 +273,20 @@ public:
// mechanism - presumably re-using the same cnd_mutex etc....
if (sc_time_stamp() < sc_front_window) {
checkWindowEvent.notify(sc_front_window - sc_time_stamp());
if (deterministic) d_mutex.lock();
if (deterministic) {
if (d_mutex.trylock()) {
/* otherwise a sync source has it, and we will be called again */
checkWindowEvent.notify(sc_front_window - sc_time_stamp());
have_d_mutex=true;
}
} else {
checkWindowEvent.notify(sc_front_window - sc_time_stamp());
}
} else {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 1;
ts.tv_sec += 5;
/* Ensure there are no pending token requests. */
takeLockMethod();
... ... @@ -250,11 +297,17 @@ public:
sem_post(&(canLock()));
mutex.unlock();
/* we rely on checkWindowEvent being notified at the end of the transaction */
} else if (errno == ETIMEDOUT) {
/* } else if (errno == ETIMEDOUT) {
checkWindowEvent.notify();
if (deterministic) d_mutex.lock();
if (deterministic) {
d_mutex.lock();
have_d_mutex=true;
}*/
// we get woken up because we have to do something.... (on
// behalf of e.g. a Qemu...
} else {
SC_REPORT_ERROR("greenthreads", "sem_timedwait failed in checkWindow()");
SC_REPORT_ERROR("greenthreads", "Timeout or sem_timedwait failed in checkWindow()");
}
}
}
... ... @@ -307,34 +360,23 @@ protected:
class syncSource {
source_entry *handle;
pthread_t sc_thread;
bool decoupled;
bool locked;
public:
/*
* This class must be instanciated from SystemC (and in the SystemC thread)
*/
syncSource(uint64_t quantum, bool _decoupled = false) : decoupled(_decoupled) {
syncSource(uint64_t quantum, bool _decoupled = false) {
sc_thread = pthread_self();
handle = centralSyncPolicy::share.registerSource(this, quantum);
centralSyncPolicy::share.setWindow(SC_ZERO_TIME, handle, decoupled);
locked = false;
centralSyncPolicy::share.initWindow(SC_ZERO_TIME, handle, _decoupled);
}
void syncAt(sc_core::sc_time t) {
if (pthread_equal(pthread_self(), sc_thread)) {
return;
}
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;
}
centralSyncPolicy::share.setWindow(t, handle);
}
};
... ...
... ... @@ -100,6 +100,52 @@ public:
}
};
/** Convenience timed cond implementation */
class fifo_mutex {
pthread_cond_t cnd;
pthread_mutex_t mutex;
unsigned long head, tail;
public:
fifo_mutex() {
head=0;
tail=0;
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cnd, NULL);
}
bool trylock()
{
bool r=false;
pthread_mutex_lock(&mutex);
if (tail == head) {
tail++;
r=true;
}
pthread_mutex_unlock(&mutex);
return r;
}
void lock()
{
unsigned long me;
pthread_mutex_lock(&mutex);
me = tail++;
while (me != head) {
pthread_cond_wait(&cnd, &mutex);
}
pthread_mutex_unlock(&mutex);
}
void unlock()
{
pthread_mutex_lock(&mutex);
head++;
pthread_cond_broadcast(&cnd);
pthread_mutex_unlock(&mutex);
}
};
}
}
... ...