Memory_temporal code is complete, and builds along side POSE. Not
[charm.git] / src / libs / ck-libs / pose / memory_temporal.h
1 /*
2 ** memory_temporal.h
3 ** 
4 ** Made by Terry Wilmarth
5 ** Login   <wilmarth@order.cs.uiuc.edu>
6 ** 
7 ** Started on  Wed Nov  7 15:43:21 2007 Terry Wilmarth
8 ** Last update Wed Nov  7 17:09:23 2007 Terry Wilmarth
9 */
10
11 /* Temporal memory management:
12    This consists of a TimePool, (a group, so there is one per
13    processor), which contains a list of "in use" memory, and a list of 
14    "not in use" memory (to be recycled).
15    These lists are ordered buckets, or TimeBuckets.  Each time bucket
16    corresponds to a range of time, and has one or more blocks of
17    memory within it.  We wish to keep the number of blocks of memory
18    in each time bucket low.
19    These blocks are called SuperBlocks, and maintain their own size, a
20    reference count, and pointers to the front and empty portions of
21    the block.
22 */
23
24 #ifndef MEMORY_TEMPORAL_H_
25 #define MEMORY_TEMPORAL_H_
26
27 #include "pose_config.h"
28 #include "memory_temporal.decl.h"
29
30 extern CkGroupID TempMemID;  // global readonly to access pool anywhere
31
32 //#define ALIGN16 // for 16-byte alignment
33 #define BLOCK_SIZE 4096  // size of SuperBlocks in bytes
34
35 /// SuperBlock holds the actual memory block that is allocated in blk
36 class SuperBlock {
37   int refCount; // number of non-freed blocks within this SuperBlock
38   char *blk; // pointer to this block
39   char *pos; // pointer to next 16-byte aligned free location in block
40   int percent_full; // percentage of first SuperBlock that is/was used 
41   SuperBlock *nextBlock; // pointer to next SuperBlock in TimeBucket
42   
43  public:
44  SuperBlock() : refCount(0), blk(NULL), pos(NULL) {};
45   ~SuperBlock() { free(blk); }
46   /// Allocate and set initial values
47   void initBlock() {
48     refCount = 0; 
49     blk = (char *)malloc(BLOCK_SIZE);
50     pos = blk;
51     nextBlock = NULL;
52     percent_full = 0;
53   }
54   void resetBlock() {
55     // assumes this is a recycled SuperBlock, thus blk was already allocated
56     refCount = 0; 
57     pos = blk;
58     nextBlock = NULL;
59     percent_full = 0;
60   }
61   bool noLongerReferenced() { return(refCount == 0); }
62   /// return pos, and advance pos by sz, aligned to 16 bytes, inc refCount
63   char *sb_alloc(int sz) {
64     int remaining = BLOCK_SIZE - (pos - blk);
65 #ifdef ALIGN16
66     int actual_sz = (sz%16 == 0)? sz : (sz+16)/16 * 16;
67 #else
68     int actual_sz = sz;
69 #endif
70     char *ret = NULL;
71     if (actual_sz <= remaining) {
72       ret = pos;
73       pos += actual_sz;
74       refCount++;
75     }
76     percent_full = (int)((float)(pos-blk)/4096.0)*100;
77     return ret;
78   }
79   // dec refCount
80   bool sb_free(void *mem) { 
81     if ((mem >= blk) && (blk < pos)) {
82       refCount--; 
83       return true;
84     }
85     else return false;
86   }
87   SuperBlock *getNextBlock() { return nextBlock; }
88   void setNextBlock(SuperBlock *loc) { nextBlock = loc; }
89   int getPercentFull() { return percent_full; }
90 };
91
92 /// TimeBucket associates a time range with (a) large block(s) of memory
93 class TimeBucket {
94   POSE_TimeType start; // start of time range
95   POSE_TimeType range; // range of time covered by this bucket
96   int numSuperBlocks; // number of SuperBlocks in sBlocks list
97   SuperBlock *sBlocks; // list of SuperBlocks
98   TimeBucket *nextBucket; // pointer to next Bucket in TimePool
99   TimeBucket *prevBucket; // pointer to previous Bucket in TimePool
100   SuperBlock **pool;
101
102  public:
103   TimeBucket() : start(POSE_UnsetTS), range(POSE_UnsetTS), numSuperBlocks(0),
104     sBlocks(NULL), nextBucket(NULL), prevBucket(NULL) {}
105   ~TimeBucket() {} // these are garbage collected in the cleanup function
106   // Initialize time range and create first SuperBlock
107   void initBucket(POSE_TimeType start_t, POSE_TimeType range_t, SuperBlock **p) {
108     pool = p;
109     start = start_t;
110     range = range_t;
111     if (!(*pool)) {
112       sBlocks = new SuperBlock; // later, check the recycle bin
113       sBlocks->initBlock();
114     }
115     else {
116       sBlocks = (*pool);
117       (*pool) = (*pool)->getNextBlock();
118       sBlocks->resetBlock();
119     }
120     numSuperBlocks = 1;
121   }
122   int getStart() { return start; }
123   int getRange() { return range; }
124   void setStart(int s) { start = s; }
125   void setRange(int r) { range = r; }
126   bool isVeryFull() {
127     if (numSuperBlocks > 1) return true;
128     else if (sBlocks->getPercentFull() > 90) return true;
129     else return false;
130   }
131   SuperBlock *getFirstSuperBlock() { return sBlocks; }
132   void setPrevBucket(TimeBucket *p) { prevBucket = p; }
133   void setNextBucket(TimeBucket *n) { nextBucket = n; }
134   TimeBucket *getPrevBucket() { return prevBucket; }
135   TimeBucket *getNextBucket() { return nextBucket; }
136   // Get some memory in this time range
137   char *tb_alloc(int sz) {
138     char *newblk = sBlocks->sb_alloc(sz);
139     if (!newblk) {
140       SuperBlock *tmp;
141       if (!(*pool)) {
142         tmp = new SuperBlock; // later, check the recycle bin
143         tmp->initBlock();
144       }
145       else {
146         tmp = (*pool);
147         (*pool) = (*pool)->getNextBlock();
148         tmp->resetBlock();
149       }
150       tmp->setNextBlock(sBlocks);
151       sBlocks = tmp;
152       numSuperBlocks++;
153       newblk = sBlocks->sb_alloc(sz);
154     }
155     return newblk;
156   }
157   // "Free" some memory from this time range
158   void tb_free(char *mem) {
159     SuperBlock *tmp = sBlocks;
160     bool done = false;
161     while (tmp && !done) {
162       done = tmp->sb_free(mem);
163       sBlocks = tmp->getNextBlock();
164       tmp = sBlocks;
165     }
166     if (!done) printf("ERROR: block to deallocate not found in time range.\n");
167   }
168 };
169
170 class TimePool : public Group {
171   TimeBucket *last_in_use;  // head of doubly-linked list
172   TimeBucket *first_in_use; // tail of doubly-linked list
173   SuperBlock *not_in_use;   // separate singly-linked list
174   
175   POSE_TimeType min_time;   // blocks older than this can be recycled
176
177   // The following fields are dynamically adjusted with application behavior
178   int BLOCK_RANGE; // This is selected and adjusted to avoid having >1
179                    // SuperBlock per TimeBucket
180
181   void clean_up(); // Move old defunct SuperBlocks to not_in_use list
182  public:
183   TimePool() : min_time(POSE_UnsetTS), last_in_use(NULL), first_in_use(NULL), 
184     not_in_use(NULL) {}
185   TimePool(CkMigrateMessage *) {}
186   ~TimePool();
187   // Return memory from a time range
188   char *tmp_alloc(POSE_TimeType timestamp, int sz_in_bytes);
189   // "Free" up memory from a time range
190   void tmp_free(POSE_TimeType timestamp, void *mem);
191   // Update the minimum time before which SuperBlocks can be recycled
192   void set_min_time(POSE_TimeType min_t) { min_time = min_t; clean_up(); }
193 };
194
195 #endif /* !MEMORY_TEMPORAL_H_ */