/***************************************************************************
* EventQueue.cpp *
* ------------------- *
* copyright : (C) 2009 by Jesus Garrido and Richard Carrillo *
* email : jgarrido@atc.ugr.es *
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "../../include/simulation/EventQueue.h"
#include "../../include/simulation/Event.h"
#include "../../include/spike/Neuron.h"
#include "../../include/spike/InputSpike.h"
#include "../../include/openmp/openmp.h"
EventQueue::EventQueue(int numberOfQueues) : NumberOfQueues(numberOfQueues){
//Queues for each OpenMP thread that manage a queue.
NumberOfElements=new unsigned int[NumberOfQueues]();
AllocatedSize=new unsigned int[NumberOfQueues]();
Events=(EventForQueue **)new EventForQueue *[NumberOfQueues];
for(int i=0; i<NumberOfQueues; i++){
// Allocate memory for a MIN_SIZE sized array
this->Events[i] = (EventForQueue *) new EventForQueue [MIN_SIZE];
this->AllocatedSize[i] = MIN_SIZE;
// The first element in the array is discard
NumberOfElements[i] = 1;
}
//Queue for events that require synchronization between OpenMP threads.
EventsWithSynchronization=(EventForQueue *) new EventForQueue [MIN_SIZE];
NumberOfElementsWithSynchronization=1;
AllocatedSizeWithSynchronization=MIN_SIZE;
//Memory for buffers
AllocatedBuffers=(int**)new int * [NumberOfQueues];
SizeBuffers=(int**)new int * [NumberOfQueues];
Buffers=(Event ****)new Event ***[NumberOfQueues];
for(int i=0; i<NumberOfQueues; i++){
AllocatedBuffers[i]=(int*)new int [NumberOfQueues];
SizeBuffers[i]=(int*)new int [NumberOfQueues]();
Buffers[i]=(Event ***)new Event **[NumberOfQueues];
for(int j=0; j<NumberOfQueues; j++){
AllocatedBuffers[i][j]=MIN_SIZE;
Buffers[i][j]=(Event **) new Event * [MIN_SIZE];
}
}
}
EventQueue::~EventQueue(){
for(int j=0; j<NumberOfQueues; j++){
for (unsigned int i=1; i<this->NumberOfElements[j]; ++i){
delete (this->Events[j]+i)->EventPtr;
}
delete this->Events[j];
}
delete this->Events;
delete NumberOfElements;
delete AllocatedSize;
delete EventsWithSynchronization;
//Memory for buffers
for(int i=0; i<NumberOfQueues; i++){
for(int j=0; j<NumberOfQueues; j++){
for(int k=0; k<this->SizeBuffers[i][j]; k++){
delete Buffers[i][j][k];
}
delete [] Buffers[i][j];
}
delete [] Buffers[i];
delete [] SizeBuffers[i];
delete [] AllocatedBuffers[i];
}
delete [] Buffers;
delete [] SizeBuffers;
delete [] AllocatedBuffers;
}
void EventQueue::SwapEvents(int index, unsigned int c1, unsigned int c2){
EventForQueue exchange;
exchange=*(this->Events[index]+c2);
*(this->Events[index]+c2)=*(this->Events[index]+c1);
*(this->Events[index]+c1)=exchange;
}
void EventQueue::Resize(int index, unsigned int NewSize){
EventForQueue * Temp = this->Events[index];
// Allocate the new array
this->Events[index] = (EventForQueue *) new EventForQueue [NewSize];
this->AllocatedSize[index] = NewSize;
// Copy all the elements from the original array
for (unsigned int i = 0; i<this->NumberOfElements[index]; ++i){
*(this->Events[index]+i) = *(Temp+i);
}
// Release old memory
delete [] Temp;
}
void EventQueue::InsertEvent(Event * event){
int index=omp_get_thread_num();
if (this->NumberOfElements[index] == this->AllocatedSize[index]){
this->Resize(index, this->AllocatedSize[index]*RESIZE_FACTOR);
}
(this->Events[index]+this->NumberOfElements[index])->EventPtr = event;
(this->Events[index]+this->NumberOfElements[index])->Time = event->GetTime();
this->NumberOfElements[index]++;
for(unsigned int c=this->Size(index);c>1 && (((this->Events[index]+c/2)->Time > (this->Events[index]+c)->Time) ||(((this->Events[index]+c/2)->Time == (this->Events[index]+c)->Time) && ((this->Events[index]+c/2)->EventPtr->ProcessingPriority() < (this->Events[index]+c)->EventPtr->ProcessingPriority()) )); c/=2){
SwapEvents(index,c, c/2);
}
return;
}
void EventQueue::InsertEvent(int index, Event * event){
if (this->NumberOfElements[index] == this->AllocatedSize[index]){
this->Resize(index, this->AllocatedSize[index]*RESIZE_FACTOR);
}
(this->Events[index]+this->NumberOfElements[index])->EventPtr = event;
(this->Events[index]+this->NumberOfElements[index])->Time = event->GetTime();
this->NumberOfElements[index]++;
for(unsigned int c=this->Size(index);c>1 && (((this->Events[index]+c/2)->Time > (this->Events[index]+c)->Time) ||(((this->Events[index]+c/2)->Time == (this->Events[index]+c)->Time) && ((this->Events[index]+c/2)->EventPtr->ProcessingPriority() < (this->Events[index]+c)->EventPtr->ProcessingPriority()) )); c/=2){
SwapEvents(index,c, c/2);
}
return;
}
unsigned int EventQueue::Size(int index) const{
return this->NumberOfElements[index]-1;
}
Event * EventQueue::RemoveEvent(int index){
unsigned int c,p;
Event * first = 0;
if(this->NumberOfElements[index]>2){
first=(this->Events[index]+1)->EventPtr;
*(this->Events[index]+1)=*(this->Events[index]+this->Size(index));
this->NumberOfElements[index]--;
if (this->NumberOfElements[index]>MIN_SIZE && this->NumberOfElements[index]<this->AllocatedSize[index]/(RESIZE_FACTOR*2)){
this->Resize(index, this->AllocatedSize[index]/RESIZE_FACTOR);
}
p=1;
for(c=p*2;c<this->Size(index);p=c,c=p*2){
if(((this->Events[index]+c)->Time > (this->Events[index]+c+1)->Time) || (((this->Events[index]+c)->Time == (this->Events[index]+c+1)->Time) && ((this->Events[index]+c)->EventPtr->ProcessingPriority() < (this->Events[index]+c+1)->EventPtr->ProcessingPriority())))
c++;
if(((this->Events[index]+c)->Time < (this->Events[index]+p)->Time) || (((this->Events[index]+c)->Time == (this->Events[index]+p)->Time) && ((this->Events[index]+c)->EventPtr->ProcessingPriority() > (this->Events[index]+p)->EventPtr->ProcessingPriority()) ))
SwapEvents(index,p, c);
else
break;
}
if(c==this->Size(index) && (((this->Events[index]+c)->Time < (this->Events[index]+p)->Time) || (((this->Events[index]+c)->Time == (this->Events[index]+p)->Time) && ((this->Events[index]+c)->EventPtr->ProcessingPriority() > (this->Events[index]+p)->EventPtr->ProcessingPriority()))))
SwapEvents(index,p, c);
} else if (this->NumberOfElements[index]==2){
first = (this->Events[index]+1)->EventPtr;
this->NumberOfElements[index]--;
}
return(first);
}
double EventQueue::FirstEventTime(int index) const{
double ti;
if(this->NumberOfElements[index]>1)
ti=(this->Events[index]+1)->Time;
else
ti=-1.0;
return(ti);
}
void EventQueue::RemoveSpikes(int index){
unsigned int OldNumberOfElements=this->NumberOfElements[index];
Event * TmpEvent;
this->NumberOfElements[index]=1; // Initially resize occupied size of the heap so that all the events are out
// Reinsert in the heap only the events which are spikes
for (unsigned int i = 1; i<OldNumberOfElements; ++i){
TmpEvent=(this->Events[index]+i)->EventPtr;
if(!TmpEvent->IsSpike()){
InsertEvent(index, TmpEvent);
}else{
delete TmpEvent;
}
}
}
void EventQueue::InsertInputSpikeEvent(double time, Neuron * neuron){
InputSpike * newEvent=new InputSpike(time, neuron);
InsertEvent(neuron->get_OpenMP_queue_index(), newEvent);
}
void EventQueue::SwapEventsWithSynchronization(unsigned int c1, unsigned int c2){
EventForQueue exchange;
exchange=*(this->EventsWithSynchronization+c2);
*(this->EventsWithSynchronization+c2)=*(this->EventsWithSynchronization+c1);
*(this->EventsWithSynchronization+c1)=exchange;
}
void EventQueue::ResizeWithSynchronization(unsigned int NewSize){
EventForQueue * Temp = this->EventsWithSynchronization;
// Allocate the new array
this->EventsWithSynchronization = (EventForQueue *) new EventForQueue [NewSize];
this->AllocatedSizeWithSynchronization = NewSize;
// Copy all the elements from the original array
for (unsigned int i = 0; i<this->NumberOfElementsWithSynchronization; ++i){
*(this->EventsWithSynchronization+i) = *(Temp+i);
}
// Release old memory
delete [] Temp;
}
void EventQueue::InsertEventWithSynchronization(Event * event){
if (this->NumberOfElementsWithSynchronization == this->AllocatedSizeWithSynchronization){
this->ResizeWithSynchronization(this->AllocatedSizeWithSynchronization*RESIZE_FACTOR);
}
(this->EventsWithSynchronization+this->NumberOfElementsWithSynchronization)->EventPtr = event;
(this->EventsWithSynchronization+this->NumberOfElementsWithSynchronization)->Time = event->GetTime();
this->NumberOfElementsWithSynchronization++;
for(unsigned int c=this->SizeWithSynchronization();c>1 && (((this->EventsWithSynchronization+c/2)->Time > (this->EventsWithSynchronization+c)->Time) ||(((this->EventsWithSynchronization+c/2)->Time == (this->EventsWithSynchronization+c)->Time) && ((this->EventsWithSynchronization+c/2)->EventPtr->ProcessingPriority() < (this->EventsWithSynchronization+c)->EventPtr->ProcessingPriority()) )); c/=2){
SwapEventsWithSynchronization(c, c/2);
}
return;
}
unsigned int EventQueue::SizeWithSynchronization() const{
return this->NumberOfElementsWithSynchronization-1;
}
Event * EventQueue::RemoveEventWithSynchronization(){
unsigned int c,p;
Event * first = 0;
if(this->NumberOfElementsWithSynchronization>2){
first=(this->EventsWithSynchronization+1)->EventPtr;
*(this->EventsWithSynchronization+1)=*(this->EventsWithSynchronization+this->SizeWithSynchronization());
this->NumberOfElementsWithSynchronization--;
if (this->NumberOfElementsWithSynchronization>MIN_SIZE && this->NumberOfElementsWithSynchronization<this->AllocatedSizeWithSynchronization/(RESIZE_FACTOR*2)){
this->ResizeWithSynchronization(this->AllocatedSizeWithSynchronization/RESIZE_FACTOR);
}
p=1;
for(c=p*2;c<this->SizeWithSynchronization();p=c,c=p*2){
if(((this->EventsWithSynchronization+c)->Time > (this->EventsWithSynchronization+c+1)->Time) || (((this->EventsWithSynchronization+c)->Time == (this->EventsWithSynchronization+c+1)->Time) && ((this->EventsWithSynchronization+c)->EventPtr->ProcessingPriority() < (this->EventsWithSynchronization+c+1)->EventPtr->ProcessingPriority())))
c++;
if(((this->EventsWithSynchronization+c)->Time < (this->EventsWithSynchronization+p)->Time) || (((this->EventsWithSynchronization+c)->Time == (this->EventsWithSynchronization+p)->Time) && ((this->EventsWithSynchronization+c)->EventPtr->ProcessingPriority() > (this->EventsWithSynchronization+p)->EventPtr->ProcessingPriority()) ))
SwapEventsWithSynchronization(p, c);
else
break;
}
if(c==this->SizeWithSynchronization() && (((this->EventsWithSynchronization+c)->Time < (this->EventsWithSynchronization+p)->Time) || (((this->EventsWithSynchronization+c)->Time == (this->EventsWithSynchronization+p)->Time) && ((this->EventsWithSynchronization+c)->EventPtr->ProcessingPriority() > (this->EventsWithSynchronization+p)->EventPtr->ProcessingPriority()))))
SwapEventsWithSynchronization(p, c);
} else if (this->NumberOfElementsWithSynchronization==2){
first = (this->EventsWithSynchronization+1)->EventPtr;
this->NumberOfElementsWithSynchronization--;
}
return(first);
}
double EventQueue::FirstEventTimeWithSynchronization() const{
double ti;
if(this->NumberOfElementsWithSynchronization>1)
ti=(this->EventsWithSynchronization+1)->Time;
else
ti=-1.0;
return(ti);
}
void EventQueue::InsertEventInBuffer(int index1, int index2, Event * NewEvent){
if((this->SizeBuffers[index1][index2])==this->AllocatedBuffers[index1][index2]){
ResizeBuffer(index1, index2);
}
this->Buffers[index1][index2][this->SizeBuffers[index1][index2]]=NewEvent;
this->IncrementSizeBuffer(index1, index2);
}
void EventQueue::InsertBufferInQueue(int index){
for(int i=0; i<NumberOfQueues; i++){
for(int j=0; j<this->SizeBuffers[i][index]; j++){
this->InsertEvent(index,this->Buffers[i][index][j]);
}
this->ResetSizeBuffer(i,index);
}
}
void EventQueue::ResetBuffer(int index){
for(int i=0; i<NumberOfQueues; i++){
for(int j=0; j<this->SizeBuffers[i][index]; j++){
delete this->Buffers[i][index][j];
}
this->ResetSizeBuffer(i,index);
}
}
void EventQueue::ResizeBuffer(int index1, int index2){
Event ** aux=this->Buffers[index1][index2];
this->Buffers[index1][index2]=(Event **)new Event * [this->AllocatedBuffers[index1][index2]*RESIZE_FACTOR];
for(int i=0; i<this->AllocatedBuffers[index1][index2]; i++){
Buffers[index1][index2][i]=aux[i];
}
delete [] aux;
this->AllocatedBuffers[index1][index2]*=RESIZE_FACTOR;
}
int EventQueue::GetAllocatedBuffer(int index1, int index2){
return this->AllocatedBuffers[index1][index2];
}
int EventQueue::GetSizeBuffer( int index1, int index2){
return this->SizeBuffers[index1][index2];
}
void EventQueue::IncrementSizeBuffer(int index1, int index2){
this->SizeBuffers[index1][index2]++;
}
void EventQueue::ResetSizeBuffer(int index1, int index2){
this->SizeBuffers[index1][index2]=0;
}