00001 /* 00002 ** memory_temporal.C 00003 ** 00004 ** Made by Terry Wilmarth 00005 */ 00006 #include "charm++.h" 00007 #include "pose.h" 00008 #include "memory_temporal.def.h" 00009 00010 CkGroupID TempMemID; // global readonly to access pool anywhere 00011 00012 void SuperBlock::sanity_check() { 00013 // no obvious way to verify the sanity of a SuperBlock 00014 } 00015 00016 POSE_TimeType TimeBucket::sanity_check(POSE_TimeType last_time) { 00017 CkAssert(start > last_time); 00018 if (!sBlocks) CkAssert(numSuperBlocks == 0); 00019 if (sBlocks) { 00020 int count=0; 00021 SuperBlock *tmpblk = sBlocks; 00022 while (tmpblk) { 00023 if (!tmpblk->noLongerReferenced()) count++; 00024 tmpblk = tmpblk->getNextBlock(); 00025 } 00026 CkAssert(count == numSuperBlocks); 00027 tmpblk = sBlocks; 00028 while (tmpblk) { 00029 tmpblk->sanity_check(); 00030 tmpblk = tmpblk->getNextBlock(); 00031 } 00032 } 00033 return (start+range-1); 00034 } 00035 00036 void TimePool::clean_up() { 00037 #ifdef VERBOSE_DEBUG 00038 sanity_check(); 00039 #endif 00040 TimeBucket *tmpbkt = first_in_use; 00041 while (tmpbkt && (min_time >= (tmpbkt->getStart()+tmpbkt->getRange()))) { 00042 // move the blocks of this bucket to not_in_use 00043 SuperBlock *sb = tmpbkt->getFirstSuperBlock(); 00044 while (sb) { 00045 if (sb->noLongerReferenced()) { 00046 SuperBlock *next = sb->getNextBlock(); 00047 if (not_in_use_sz < RECYCLE_BIN_CAPACITY) { 00048 sb->setNextBlock(not_in_use); 00049 not_in_use = sb; 00050 not_in_use_sz++; 00051 } 00052 else { 00053 #ifdef VERBOSE_DEBUG 00054 CkPrintf("INFO: recycle bin at capacity; deleting blocks\n"); 00055 #endif 00056 delete sb; 00057 } 00058 sb = next; 00059 } 00060 else break; 00061 } 00062 if (!sb) { // bucket is totally empty, delete it 00063 // move the first_in_use ptr forward 00064 if (tmpbkt == first_in_use) { 00065 if (first_in_use == last_in_use) { 00066 first_in_use = last_in_use = NULL; 00067 } 00068 else { 00069 first_in_use = first_in_use->getPrevBucket(); 00070 first_in_use->setNextBucket(NULL); 00071 } 00072 delete tmpbkt; 00073 tmpbkt = first_in_use; 00074 } 00075 else if (tmpbkt == last_in_use) { 00076 last_in_use = last_in_use->getNextBucket(); 00077 last_in_use->setPrevBucket(NULL); 00078 delete tmpbkt; 00079 tmpbkt = NULL; 00080 } 00081 else { 00082 TimeBucket *tmp = tmpbkt->getPrevBucket(); 00083 tmp->setNextBucket(tmpbkt->getNextBucket()); 00084 tmpbkt->getNextBucket()->setPrevBucket(tmp); 00085 delete tmpbkt; 00086 tmpbkt = tmp; 00087 } 00088 } 00089 else { 00090 tmpbkt->setFirstSuperBlock(sb); 00091 tmpbkt = tmpbkt->getPrevBucket(); 00092 } 00093 } 00094 #ifdef VERBOSE_DEBUG 00095 sanity_check(); 00096 #endif 00097 } 00098 00099 TimePool::~TimePool() 00100 { 00101 TimeBucket *tmpbkt = last_in_use; 00102 while (tmpbkt) { 00103 last_in_use = last_in_use->getNextBucket(); 00104 delete tmpbkt; 00105 tmpbkt = last_in_use; 00106 } 00107 SuperBlock *tmpblk = not_in_use; 00108 while (tmpblk) { 00109 not_in_use = not_in_use->getNextBlock(); 00110 delete tmpblk; 00111 tmpblk = not_in_use; 00112 } 00113 } 00114 00115 // Return memory from a time range 00116 char *TimePool::tmp_alloc(POSE_TimeType timestamp, int sz_in_bytes) 00117 { // List looks like this: 00118 // last (newer, higher ts) .... first (older, lower ts) 00119 #ifdef VERBOSE_DEBUG 00120 sanity_check(); 00121 CkPrintf("[tmp_alloc:\n"); 00122 #endif 00123 TimeBucket *bkt = last_in_use; 00124 while (bkt && (timestamp < bkt->getStart())) { 00125 bkt = bkt->getNextBucket(); 00126 } 00127 if (!bkt) { // either empty, or ts is older than anything we have 00128 if (!first_in_use) { // empty 00129 first_in_use = new TimeBucket(); 00130 first_in_use->initBucket(timestamp, 1, ¬_in_use, ¬_in_use_sz); 00131 last_in_use = first_in_use; 00132 char *mem = last_in_use->tb_alloc(sz_in_bytes); 00133 #ifdef VERBOSE_DEBUG 00134 CkPrintf(".tmp_alloc]\n"); 00135 sanity_check(); 00136 #endif 00137 return mem; 00138 } 00139 else if (timestamp < first_in_use->getStart()) { //not empty, ts is oldest 00140 first_in_use->setStart(timestamp); 00141 char *mem = first_in_use->tb_alloc(sz_in_bytes); 00142 #ifdef VERBOSE_DEBUG 00143 CkPrintf(".tmp_alloc]\n"); 00144 sanity_check(); 00145 #endif 00146 return mem; 00147 } 00148 else { 00149 return NULL; 00150 } 00151 } 00152 else if (bkt == last_in_use) { // we have some options if the target is last 00153 if (bkt->isVeryFull() && (timestamp >= (bkt->getStart() + bkt->getRange()))) { // let's make a new bucket, timestamp is far out enough 00154 int start = bkt->getStart()+bkt->getRange(); 00155 int range = timestamp - start + 1; 00156 last_in_use = new TimeBucket(); 00157 last_in_use->initBucket(start, range, ¬_in_use, ¬_in_use_sz); 00158 bkt->setPrevBucket(last_in_use); 00159 last_in_use->setNextBucket(bkt); 00160 char *mem = last_in_use->tb_alloc(sz_in_bytes); 00161 #ifdef VERBOSE_DEBUG 00162 CkPrintf(".tmp_alloc]\n"); 00163 sanity_check(); 00164 #endif 00165 return mem; 00166 } 00167 else { // let's put it here, expanding the range if necessary 00168 if (timestamp >= (bkt->getStart() + bkt->getRange())) { 00169 bkt->setRange(timestamp - bkt->getStart() + 1); 00170 } 00171 char *mem = bkt->tb_alloc(sz_in_bytes); 00172 #ifdef VERBOSE_DEBUG 00173 CkPrintf(".tmp_alloc]\n"); 00174 sanity_check(); 00175 #endif 00176 return mem; 00177 } 00178 } 00179 else { // this is in the range of this bucket, must put it here 00180 char *mem = bkt->tb_alloc(sz_in_bytes); 00181 #ifdef VERBOSE_DEBUG 00182 CkPrintf(".tmp_alloc]\n"); 00183 sanity_check(); 00184 #endif 00185 return mem; 00186 } 00187 } 00188 00189 // "Free" up memory from a time range 00190 void TimePool::tmp_free(POSE_TimeType timestamp, void *mem) 00191 { 00192 #ifdef VERBOSE_DEBUG 00193 sanity_check(); 00194 CkPrintf("[tmp_free:\n"); 00195 #endif 00196 if (mem) { 00197 TimeBucket *tmpbkt = first_in_use; 00198 while (tmpbkt && (timestamp >= (tmpbkt->getStart()+tmpbkt->getRange()))) { 00199 tmpbkt = tmpbkt->getPrevBucket(); 00200 } 00201 if (tmpbkt) { 00202 tmpbkt->tb_free((char *)mem); 00203 } 00204 else CkAbort("ERROR: Memory in that time range not found for deallocation.\n"); 00205 #ifdef VERBOSE_DEBUG 00206 CkPrintf(".tmp_free]\n"); 00207 sanity_check(); 00208 #endif 00209 } 00210 } 00211 00212 void TimePool::sanity_check() { 00213 // first check the quality of the list of in-use buckets 00214 if (!last_in_use) CkAssert(!first_in_use); 00215 if (!first_in_use) CkAssert(!last_in_use); 00216 if (last_in_use) CkAssert(!(last_in_use->getPrevBucket())); 00217 if (first_in_use) CkAssert(!(first_in_use->getNextBucket())); 00218 TimeBucket *tmpbkt = last_in_use; 00219 if (tmpbkt) { 00220 while (tmpbkt->getNextBucket()) { 00221 CkAssert(tmpbkt->getNextBucket()->getPrevBucket() == tmpbkt); 00222 tmpbkt = tmpbkt->getNextBucket(); 00223 } 00224 CkAssert(tmpbkt == first_in_use); 00225 } 00226 tmpbkt = first_in_use; 00227 if (tmpbkt) { 00228 while (tmpbkt->getPrevBucket()) { 00229 CkAssert(tmpbkt->getPrevBucket()->getNextBucket() == tmpbkt); 00230 tmpbkt = tmpbkt->getPrevBucket(); 00231 } 00232 CkAssert(tmpbkt == last_in_use); 00233 } 00234 // ASSERT: Bucket structure of TimePool is fine at this point. 00235 // Now, we examine the bucket contents 00236 tmpbkt = first_in_use; 00237 if (tmpbkt) { 00238 POSE_TimeType lastTime = POSE_UnsetTS; 00239 while (tmpbkt) { 00240 lastTime = tmpbkt->sanity_check(lastTime); 00241 tmpbkt = tmpbkt->getPrevBucket(); 00242 } 00243 } 00244 }