/********************************************************************** ** 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 "calq.h" #include /* ** 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? */ calendarHdr bucketArray[MAXBUCKETS]; /* array of buckets */ calendarHdr * 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*/ int mostLongBucket; /* ptr to the most long Bucket list shoh */ int repeatCnt = 0; /* upward resizing shoh */ int Qsearch = 0; int Bsearch = 0; int SumQsearch = 0; int SumBsearch = 0; double TotQsch = 0; double TotSumQsch = 0; double TotBsch = 0; double TotSumBsch = 0; int rescnt=0; /* ** LOCAL ROUTINES */ void calInit(int,int,int,double); void calResize(int); double bucketNewWidth(int); void localEnqueue(bucketEntry*); bucketEntry* localDequeue(); void GetStats(); /* */ /* ** 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. **********************************************************************/ // double timeStamp; /* timestamp (priority) of event */ // int cid; // struct event *eventStruct; /* the event to enqueue */ { 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; //long int vdx; //int adx; /* ** 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].bp) { calendar[actualBucket].bp = newBucketEntry; newBucketEntry->next = (bucketEntry *)NULL; calendar[actualBucket].eventCnt = 1; } else { prevBucketEntry = (bucketEntry *)NULL; curBucketEntry = calendar[actualBucket].bp; 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].bp = newBucketEntry; else prevBucketEntry->next = newBucketEntry; calendar[actualBucket].eventCnt++; newBucketEntry->next = curBucketEntry; } /* ** increment queue size and expand calendar if necessary */ calQSize++; if (calQSize > calTopThreshold) { repeatCnt++; calResize(2 * calNBuckets); } else { SumQsearch += SCnt; Qsearch++; if (Qsearch > calNBuckets) { //QOP=0.1*QOP+0.9*(double)SumQsearch/Qsearch; if ((SumQsearch / Qsearch) > 3) { repeatCnt=1; calResize(calNBuckets); } else { Qsearch = 0; SumQsearch = 0; } } } /* countng the Entry search no */ TotQsch += 1.0; 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 */ 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].bp != (bucketEntry *)NULL) && ((calendar[i].bp)->p.priority < calBucketTop)) { /* ** next event has been found ** remove it from the queue */ returnBucketEntry = calendar[i].bp; returnEvent = returnBucketEntry->event; calendar[i].bp = returnBucketEntry->next; calendar[i].eventCnt--; /* ** 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) { repeatCnt = 0; calResize(calNBuckets / 2); } else { SumBsearch += SCnt; Bsearch++; if (Bsearch > calNBuckets) { //BOP=0.1*BOP+0.9*(double)SumBsearch/Bsearch; if ((SumBsearch / Bsearch) > 3) { repeatCnt = 0; calResize(calNBuckets); } else { Bsearch = 0; SumBsearch = 0; } } } /* counting the bucket search no */ TotBsch += 1.0; 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].bp) { if (!directSearchInitialized) { directSearchPriority = (calendar[i].bp)->p.priority; directSearchBucket = i; directSearchInitialized = TRUE; } else if ((calendar[i].bp)->p.priority < directSearchPriority) { directSearchPriority = (calendar[i].bp)->p.priority; directSearchBucket = i; } } } /* ** dequeue the event found */ returnBucketEntry = calendar[directSearchBucket].bp; returnEvent = returnBucketEntry->event; calendar[directSearchBucket].bp = returnBucketEntry->next; calendar[directSearchBucket].eventCnt--; /* ** update position in calendar */ warpBuckets = (long int)(directSearchPriority / calBucketWidth) - (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) { repeatCnt = 0; calResize(calNBuckets / 2); } else { SumBsearch += SCnt; Bsearch++; if (Bsearch > calNBuckets) { //BOP=0.1*BOP+0.9*(double)SumBsearch/Bsearch; if ((SumBsearch / Bsearch) > 3) { repeatCnt = 0; calResize(calNBuckets); } else { Bsearch = 0; SumBsearch = 0; } } } /* counting the bucket search no */ TotBsch += 1.0; TotSumBsch += SCnt; /* ** 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. **********************************************************************/ // int bucketArrayBase; /* index of calendar base in bucketArray */ // int numBuckets; /* number of buckets in calendar */ // int bucketWidth; /* width of each bucket in time units */ // double startPriority; /* timeStamp to start at */ { 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)){ /* fatal("The number of buckets is not enough at CalInit"); */ } calQSize = 0; for (i = 0; i < calNBuckets; i++) { calendar[i].bp = (bucketEntry *)NULL; calendar[i].eventCnt = 0; } /* ** set initial position in queue */ lastPriority = startPriority; virtualBucket = (unsigned long int)(startPriority / bucketWidth); calLastBucket = (int)(virtualBucket % calNBuckets); calBucketTop = (virtualBucket + 1.0) * bucketWidth+ 0.5 * bucketWidth;//mod by tkl lastBucketTop = calBucketTop; mostLongBucket = 0; /* ** set queue size change thresholds */ calBotThreshold = numBuckets / 2 - 2; calTopThreshold = 2 * numBuckets; } /* */ /********************************************************************** */ void calResize(int calNewSize) /* ** Copy the current queue onto a calendar with newCalSize buckets. ** The new bucket array is on the opposite end of the array ** bucketArray from the original. **********************************************************************/ // int calNewSize; /* number of buckets in new calendar */ { int bucketWidth; /* width of each bucket in time units */ calendarHdr * calOld; /* ptr to current calendar base bucket */ int calOldSize; /* current calendar size */ bucketEntry * curBucketEntry; bucketEntry * nextBucketEntry; /* used while transferring queue elements ** from old calendar to new */ int i; /* loop index */ int evenFlag; int jdx, kdx; /* ** calculate the new bucket width (in time units) */ evenFlag = 1; RETRY: bucketWidth = (int)bucketNewWidth(evenFlag); if (!evenFlag){ #ifdef DEBUG1 printf ("af: mostL=%d, #events=%d, #total=%d, #bucket=%d\n", mostLongBucket, kdx, calQSize, calNBuckets); #endif } Qsearch = Bsearch = 0; SumQsearch = SumBsearch = 0; #ifdef DEBUG if (calNewSize > calNBuckets) printf("Up:BucketWidth=%d -> newWidth=%d\n",calBucketWidth,bucketWidth); else if (calNewSize < calNBuckets) printf("Dn:BucketWidth=%d -> newWidth=%d\n",calBucketWidth,bucketWidth); else printf("ReDst:BucktWidth=%d->newWidth=%d\n",calBucketWidth,bucketWidth); #endif /* No need to resize */ if ((calNBuckets == calNewSize) && (bucketWidth == calBucketWidth)) return; /* ** save the location and size of the old calendar for use ** when copying to new location */ calOld = calendar; calOldSize = calNBuckets; /* ** initialize the new calendar ** ** if (current calendar at end of bucketArray) then ** place the new calendar at start of bucketArray ** else ** place the new calendar at the end of bucketArray */ if (calFirstSubscript != 0) calInit(0, calNewSize, bucketWidth, lastPriority); else calInit((MAXBUCKETS-calNewSize), calNewSize, bucketWidth, lastPriority); /* ** move all of the current queue entries from the current calendar ** to the appropriate bucket in the new calendar */ for (i = (calOldSize - 1); i >= 0; i--) { if (calOld[i].bp) { curBucketEntry = calOld[i].bp; while (curBucketEntry) { nextBucketEntry = curBucketEntry->next; localEnqueue(curBucketEntry); curBucketEntry = nextBucketEntry; } } } ++rescnt; // GetStats(); /* ** recheck the status of even distribution after normal redistribution */ if (evenFlag) { kdx = 0; for (jdx = mostLongBucket-2; jdx < mostLongBucket+3; jdx++) { kdx += calendar[(jdx+calNBuckets)%calNBuckets].eventCnt; } kdx = (int)kdx/5; } if (evenFlag && kdx > 10) { #ifdef DEBUG1 printf ("mostL=%d, #events=%d, #total=%d, #bucket=%d\n", mostLongBucket, kdx, calQSize, calNBuckets); #endif evenFlag = 0; goto RETRY; } } /* */ /********************************************************************** */ double bucketNewWidth(int evenFlag) /* ** 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 (1000) 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 */ bucketEntry * curEntry; /* dequeued events to sample */ /* ** decide how many samples to use in calculation of bucketWidth */ if (calQSize < 2) return((double)1.0); if (evenFlag) { /* even distribution state */ /* ** save state info */ if (calQSize <= 5) numSamples = calQSize; else numSamples = 5 + calQSize / 10; if (numSamples > 25) numSamples = 25; localCalLastBucket = calLastBucket; localCalBucketTop = calBucketTop; localLastPriority = lastPriority; localLastBucketTop = lastBucketTop; 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; } else { /* not even distribution state */ if (calQSize <= 5) numSamples = calQSize; else numSamples = 5 + calQSize / 10; if (numSamples > 500) numSamples = 500; curEntry = calendar[mostLongBucket].bp; for (i = 0; i < numSamples; i++) { while (!curEntry) { mostLongBucket++; mostLongBucket = (int) mostLongBucket % calNBuckets; curEntry = calendar[mostLongBucket].bp; } priorities[i] = curEntry->p.priority; curEntry = curEntry->next; } } /* ** calculate the average separation of sampled events */ cumSeparation = (double)0.0; if (evenFlag) { for (i = 0; i < (numSamples - 1); i++) cumSeparation += (priorities[i+1] - priorities[i]); avgSeparation = cumSeparation / (double)(numSamples - 1); } else { numSeparations = 0; for (i = 0; i < (numSamples - 1); i++) { curSeparation = priorities[i+1] - priorities[i]; if (curSeparation < calBucketWidth && curSeparation>0) { cumSeparation += curSeparation; numSeparations++; } } avgSeparation = cumSeparation / (double)(numSeparations - 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 && curSeparation>0) { cumSeparation += curSeparation; numSeparations++; } } /* jahn Nov. 28 for example 0 0 0 1000 */ if (numSeparations == 0) avgSeparation = twiceAvgSeparation/2; else avgSeparation = cumSeparation / (double)numSeparations; /* Assume that all priorities are integer */ if (avgSeparation < 1) avgSeparation = 1; /* ** 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. **********************************************************************/ // bucketEntry * queueEntry; { 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].bp) { calendar[actualBucket].bp = queueEntry; queueEntry->next = (bucketEntry *)NULL; calendar[actualBucket].eventCnt = 1; } else { prevBucketEntry = (bucketEntry *)NULL; curBucketEntry = calendar[actualBucket].bp; 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].bp = queueEntry; else prevBucketEntry->next = queueEntry; calendar[actualBucket].eventCnt++; queueEntry->next = curBucketEntry; } if (calendar[actualBucket].eventCnt > calendar[mostLongBucket].eventCnt) mostLongBucket = actualBucket; /* ** 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 */ 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].bp != (bucketEntry *)NULL) && ((calendar[i].bp)->p.priority < calBucketTop)) { /* ** next event has been found ** remove it from the queue */ returnBucketEntry = calendar[i].bp; calendar[i].bp = returnBucketEntry->next; calendar[i].eventCnt--; /* ** 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].bp) { if (!directSearchInitialized) { directSearchPriority = (calendar[i].bp)->p.priority; directSearchBucket = i; directSearchInitialized = TRUE; } else if ((calendar[i].bp)->p.priority < directSearchPriority) { directSearchPriority = (calendar[i].bp)->p.priority; directSearchBucket = i; } } } /* ** dequeue the event found */ returnBucketEntry = calendar[directSearchBucket].bp; calendar[directSearchBucket].bp = returnBucketEntry->next; calendar[directSearchBucket].eventCnt--; /* ** update position in calendar */ warpBuckets = (long int)(directSearchPriority / calBucketWidth) - (long int)(lastPriority / calBucketWidth); calBucketTop = lastBucketTop + (double)warpBuckets * calBucketWidth; lastBucketTop = calBucketTop; calLastBucket = directSearchBucket; lastPriority = directSearchPriority; calQSize--; return(returnBucketEntry); } void GetStats(){ cout<