/********************************************************************** ** calQ.c ** ** These routines implement a Calander Queue data structure for ** maintaining a priority queue in a shared memory multiprocessor ** system. **********************************************************************/ #include #include #include #include #include #include "calQ.h" /* ** GLOBAL DEFINES */ #define MAXBUCKETS (512 * 1024) /* max 512K buckets in calendar */ /* ** GLOBAL VARIABLES */ bucketEntry *bfreelist; /* a head pointer to a free list of buckets */ int calInitialized = FALSE; /* has calendar been initialized? */ bucketEntry * bucketArray[MAXBUCKETS]; /* array of buckets */ bucketEntry ** calendar; /* ptr to base bucket of calendar */ int calFirstSubscript; /* bucketArray index of calendar base */ int calNBuckets; /* current calendar size in buckets */ int calBucketWidth; /* width of each bucket in time units */ int calQSize; /* total number of entries in queue */ int calLastBucket; /* bucket from which last event dequeued */ double calBucketTop; /* priority at top of current bucket */ int calBotThreshold; /* max queue size before shrink calendar */ int calTopThreshold; /* max queue size before expanding calendar */ double lastPriority; /* priority of last event */ double lastBucketTop; /* value of BucketTop when last event dequeued */ double TotQsch = 0,TotSumQsch = 0; double TotBsch = 0,TotSumBsch = 0; int NeedNewWidth; int WhenCalResize; int rescnt=0; //int MAAECR=0,MAADCR=0,MAAECcnt=0,MAADCcnt=0; //double MAAEC[10],MAADC[10]; /* ** LOCAL ROUTINES */ void calInit(int,int,int,double); void calResize(int); double bucketNewWidth(); void localEnqueue(bucketEntry *); void GetStats(); bucketEntry *localDequeue(); /* */ /* ** EXPORTED ROUTINES */ /********************************************************************** */ void enqueue(double timeStamp,int cid,struct event* eventStruct) /* ** enqueue the specified eventStruct, using the timeStamp as its ** priority. no restrictions are placed on the eventStruct, other ** than that it should be allocated from a shared memory segment ** if events are to be accessed by multiple processes. **********************************************************************/ { unsigned long int virtualBucket; /* bucket index if calendar were infinite */ int actualBucket; /* bucket index for actual calendar */ bucketEntry * newBucketEntry; /* bucketEntry for new record */ bucketEntry * curBucketEntry; /* used to traverse entries in bucket */ bucketEntry * prevBucketEntry; /* used to traverse entries in bucket */ int SCnt=0; /* ** throw away the event if it's in the past ** NOTE: should actually return some indication that event ** was in the past and thrown away */ if (timeStamp < lastPriority) { /*fatal("Enqueue Error");*/ return; } /* ** calculate which bucket to insert the event into */ virtualBucket = (unsigned long int)(timeStamp / calBucketWidth); actualBucket = (int)(virtualBucket % calNBuckets); /* ** allocate a new bucketEntry and fill in info fields */ BALLOC(newBucketEntry); newBucketEntry->p.priority = timeStamp; newBucketEntry->p.cid = cid; newBucketEntry->event = eventStruct; /* ** insert the newBucketEntry in the bucket */ if (!calendar[actualBucket]) { calendar[actualBucket] = newBucketEntry; newBucketEntry->next = (bucketEntry *)NULL; } else { prevBucketEntry = (bucketEntry *)NULL; curBucketEntry = calendar[actualBucket]; while (curBucketEntry && (curBucketEntry->p.priority <= newBucketEntry->p.priority)) { if (curBucketEntry->p.priority == newBucketEntry->p.priority) if (curBucketEntry->p.cid > newBucketEntry->p.cid) break; prevBucketEntry = curBucketEntry; curBucketEntry = curBucketEntry->next; SCnt++; } if (!prevBucketEntry) calendar[actualBucket] = newBucketEntry; else prevBucketEntry->next = newBucketEntry; newBucketEntry->next = curBucketEntry; } /* ** increment queue size and expand calendar if necessary */ calQSize++; if (calQSize > calTopThreshold) calResize(2 * calNBuckets); TotQsch++; TotSumQsch += SCnt; /* ** release the calendar lock */ return; } /* */ /********************************************************************** */ struct event *dequeue() /* ** dequeue the highest priority event (smallest timeStamp), and return ** a pointer to it's associated eventStruct. **********************************************************************/ { bucketEntry * returnBucketEntry; /* ptr to event to dequeue */ event * returnEvent; /* ptr to event to return */ int i; /* loop index */ int directSearchInitialized; /* has direct search been initialized */ double directSearchPriority; /* highest priority event found in ** direct search */ int directSearchBucket; /* bucket of highest priority found ** in direct search */ unsigned long int warpBuckets; /* number of buckets warped during ** direct search */ int SCnt=0; /* ** make sure there is at least one event queued */ if (calQSize == 0) { return((struct event *)NULL); } /* ** starting from the bucket where the last event was retrieved, ** search for the next event in this year */ for (i = calLastBucket; ; ) { /* ** check the head element of the current bucket (if it exists) */ if ((calendar[i] != (bucketEntry *)NULL) && ((calendar[i])->p.priority < calBucketTop)) { /* ** next event has been found ** remove it from the queue */ returnBucketEntry = calendar[i]; returnEvent = returnBucketEntry->event; calendar[i] = returnBucketEntry->next; /* ** update position in calendar */ calLastBucket = i; lastPriority = returnBucketEntry->p.priority; lastBucketTop = calBucketTop; calQSize--; BFREE(returnBucketEntry); /* ** reduce calendar size if its shrunk below threshold */ if (calQSize < calBotThreshold) calResize(calNBuckets / 2); TotBsch++; TotSumBsch += SCnt; return(returnEvent); } else { /* ** advance (circularly) to the next bucket in the calendar */ i++; if (i == calNBuckets) i = 0; calBucketTop += calBucketWidth; SCnt++; /* ** if we've cycled a complete year without finding ** an event, then break out and go to direct search */ if (i == calLastBucket) break; } } /* ** perform direct search through a whole year */ directSearchInitialized = FALSE; for (i = 0; i < calNBuckets; i++) { if (calendar[i]) { if (!directSearchInitialized) { directSearchPriority = (calendar[i])->p.priority; directSearchBucket = i; directSearchInitialized = TRUE; } else if ((calendar[i])->p.priority < directSearchPriority) { directSearchPriority = (calendar[i])->p.priority; directSearchBucket = i; } } } /* ** dequeue the event found */ returnBucketEntry = calendar[directSearchBucket]; returnEvent = returnBucketEntry->event; calendar[directSearchBucket] = returnBucketEntry->next; /* ** update position in calendar */ warpBuckets = (unsigned long int)(directSearchPriority / calBucketWidth) - (unsigned long int)(lastPriority / calBucketWidth); calBucketTop = lastBucketTop + (double)warpBuckets * calBucketWidth; lastBucketTop = calBucketTop; calLastBucket = directSearchBucket; lastPriority = directSearchPriority; calQSize--; BFREE(returnBucketEntry); /* ** reduce calendar size if its shrunk below threshold */ if (calQSize < calBotThreshold) calResize(calNBuckets / 2); TotBsch++; TotSumBsch += SCnt; /* if (NeedNewWidth) { if (WhenCalResize) WhenCalResize--; else { NeedNewWidth = 0; calResize(calNBuckets); } } ** unlock the calendar and return the dequeued event */ return(returnEvent); } /* */ /********************************************************************** ** Local Routines **********************************************************************/ /********************************************************************** */ void calInit(int bucketArrayBase,int numBuckets,int bucketWidth,double startPriority) /* ** Initialize all of the global state variables related to changing ** the calendar size. **********************************************************************/ { unsigned long int virtualBucket; /* bucket index if calendar were infinite */ int i; /* loop index */ /* ** set position and size of new calendar */ calFirstSubscript = bucketArrayBase; calendar = &(bucketArray[bucketArrayBase]); calBucketWidth = bucketWidth; calNBuckets = numBuckets; /* ** initialize the buckets to be empty */ if(numBuckets > (MAXBUCKETS / 2)) cout<<"fatal error"<= 0; i--) { if (calOld[i]) { curBucketEntry = calOld[i]; while (curBucketEntry) { nextBucketEntry = curBucketEntry->next; localEnqueue(curBucketEntry); curBucketEntry = nextBucketEntry; } } } ++rescnt; } /* */ /********************************************************************** */ double bucketNewWidth() /* ** calculate the width to use for buckets **********************************************************************/ { int numSamples; /* number of queue elements to sample */ int localCalLastBucket; /* local copy of calLastBucket */ double localCalBucketTop; /* local copy of calBucketTop */ double localLastPriority; /* local copy of lastPriority */ double localLastBucketTop; /* local copy of lastBucketTop */ #define MAXSAMPLES (25) bucketEntry * sampleArray[MAXSAMPLES]; /* dequeued events to sample */ double priorities[MAXSAMPLES]; /* priorities from sampled events */ double cumSeparation; /* cumulative separations between events */ double avgSeparation; /* average separation between events */ double twiceAvgSeparation; /* twice the calculated avg separation */ int numSeparations; /* number of separations less than twice avg */ double curSeparation; /* separation between current event pair */ int i; /* loop index */ /* ** decide how many samples to use in calculation of bucketWidth */ if (calQSize < 2) return((double)1.0); if (calQSize <= 5) numSamples = calQSize; else numSamples = 5 + calQSize / 10; if (numSamples > 25) numSamples = 25; /* ** save state info */ localCalLastBucket = calLastBucket; localCalBucketTop = calBucketTop; localLastPriority = lastPriority; localLastBucketTop = lastBucketTop; /* ** dequeue the specified number of events */ for (i = 0; i < numSamples; i++) { sampleArray[i] = localDequeue(); priorities[i] = (sampleArray[i])->p.priority; } /* ** re-enqueue the events, and restore state info */ for (i = 0; i < numSamples; i++) localEnqueue(sampleArray[i]); calLastBucket = localCalLastBucket; calBucketTop = localCalBucketTop; lastPriority = localLastPriority; lastBucketTop = localLastBucketTop; /* ** calculate the average separation of sampled events */ cumSeparation = (double)0.0; for (i = 0; i < (numSamples - 1); i++) cumSeparation += (priorities[i+1] - priorities[i]); avgSeparation = cumSeparation / (double)(numSamples - 1); /* ** recalculate the average using only separation smaller ** than twice the original average */ twiceAvgSeparation = (double)2.0 * avgSeparation; cumSeparation = (double)0.0; numSeparations = 0; for (i = 0; i < (numSamples - 1); i++) { curSeparation = priorities[i+1] - priorities[i]; if (curSeparation < twiceAvgSeparation) { cumSeparation += curSeparation; numSeparations++; } } /* jahn Nov. 28 for example 0 0 0 1000 */ if(numSeparations == 0) avgSeparation = twiceAvgSeparation/2.0; else avgSeparation = cumSeparation / (double)numSeparations; /* Assume that all priorities are integer */ if(avgSeparation < 1) { avgSeparation = 1; NeedNewWidth = 1; WhenCalResize = calQSize; } else NeedNewWidth = 0; /* ** return newBucketWidth as three times last calculated average */ return((double)3.0 * avgSeparation); } /* */ /********************************************************************** */ void localEnqueue(bucketEntry* queueEntry) /* ** this Enqueue routine is used internally by the calQ package. ** it enqueues an already allocated bucketEntry into the current ** calendar. **********************************************************************/ { unsigned long int virtualBucket; /* bucket index if calendar were infinite */ int actualBucket; /* bucket index for actual calendar */ bucketEntry * curBucketEntry; /* used to traverse entries in bucket */ bucketEntry * prevBucketEntry; /* used to traverse entries in bucket */ /* ** calculate which bucket to insert the bucketEntry into */ virtualBucket = (unsigned long int)(queueEntry->p.priority / calBucketWidth); actualBucket = (int)(virtualBucket % calNBuckets); /* ** insert the bucketEntry into the appropriate calendar bucket */ if (!calendar[actualBucket]) { calendar[actualBucket] = queueEntry; queueEntry->next = (bucketEntry *)NULL; } else { prevBucketEntry = (bucketEntry *)NULL; curBucketEntry = calendar[actualBucket]; while (curBucketEntry && (curBucketEntry->p.priority <= queueEntry->p.priority)) { if (curBucketEntry->p.priority == queueEntry->p.priority) if (curBucketEntry->p.cid > queueEntry->p.cid) break; prevBucketEntry = curBucketEntry; curBucketEntry = curBucketEntry->next; } if (!prevBucketEntry) calendar[actualBucket] = queueEntry; else prevBucketEntry->next = queueEntry; queueEntry->next = curBucketEntry; } /* ** increment queue size, but don't worry about resizeing calendar */ calQSize++; } /* */ /********************************************************************** */ bucketEntry *localDequeue() /* ** this Dequeue routine is used internally by the calQ package. ** it dequeues and returns an entire bucketEntry. **********************************************************************/ { bucketEntry * returnBucketEntry; /* ptr to event to dequeue */ int directSearchInitialized; /* has direct search been initialized */ double directSearchPriority; /* highest priority event found in ** direct search */ int directSearchBucket; /* bucket number containing highest ** priority found in direct search */ unsigned long int warpBuckets; /* number of buckets warped during ** direct search */ int i; /* loop index */ /* ** starting from the bucket where the last event was retrieved, ** search for the next event in this year */ for (i = calLastBucket; ; ) { /* ** check the head element of the current bucket (if it exists) */ if ((calendar[i] != (bucketEntry *)NULL) && ((calendar[i])->p.priority < calBucketTop)) { /* ** next event has been found ** remove it from the queue */ returnBucketEntry = calendar[i]; calendar[i] = returnBucketEntry->next; /* ** update position in calendar */ calLastBucket = i; lastPriority = returnBucketEntry->p.priority; lastBucketTop = calBucketTop; calQSize--; return(returnBucketEntry); } else { /* ** advance (circularly) to the next bucket in the calendar */ i++; if (i == calNBuckets) i = 0; calBucketTop += calBucketWidth; /* ** if we've cycled a complete year without finding ** an event, then break out and go to direct search */ if (i == calLastBucket) break; } } /* ** perform direct search through a whole year */ directSearchInitialized = FALSE; for (i = 0; i < calNBuckets; i++) { if (calendar[i]) { if (!directSearchInitialized) { directSearchPriority = (calendar[i])->p.priority; directSearchBucket = i; directSearchInitialized = TRUE; } else if ((calendar[i])->p.priority < directSearchPriority) { directSearchPriority = (calendar[i])->p.priority; directSearchBucket = i; } } } /* ** dequeue the event found */ returnBucketEntry = calendar[directSearchBucket]; calendar[directSearchBucket] = returnBucketEntry->next; /* ** update position in calendar */ warpBuckets = (unsigned long int)(directSearchPriority / calBucketWidth) - (unsigned long int)(lastPriority / calBucketWidth); calBucketTop = lastBucketTop + (double)warpBuckets * calBucketWidth; lastBucketTop = calBucketTop; calLastBucket = directSearchBucket; lastPriority = directSearchPriority; calQSize--; return(returnBucketEntry); } void GetStats(){ cout<