164 pref_level, chklvl::word_size_for_level(pref_level)); |
164 pref_level, chklvl::word_size_for_level(pref_level)); |
165 |
165 |
166 // 1) Attempt to find a free chunk of exactly the pref_level level |
166 // 1) Attempt to find a free chunk of exactly the pref_level level |
167 c = remove_first_chunk_at_level(pref_level); |
167 c = remove_first_chunk_at_level(pref_level); |
168 |
168 |
169 // Todo: |
169 // 2) Failing that, we are also willing to accept a chunk half that size, but nothing less for now... |
170 // |
170 if (c == NULL && pref_level < max_level) { |
171 // We need to meditate about steps (2) and (3) a bit more. |
171 c = remove_first_chunk_at_level(pref_level + 1); |
172 // By simply preferring to reuse small chunks vs splitting larger chunks we may emphasize |
172 } |
173 // fragmentation, strangely enough, if callers wanting medium sized chunks take small chunks |
173 |
174 // instead, and taking them away from the many users which prefer small chunks. |
174 // 3) Failing that, attempt to find a free chunk of larger size and split it to get the ideal size... |
175 // Alternatives: |
|
176 // - alternating between (2) (3) and (3) (2) |
|
177 // - mixing (2) and (3) into one loop with a growing delta, and maybe a "hesitance" barrier function |
|
178 // - keeping track of chunk demand and adding this into the equation: if e.g. 4K chunks were heavily |
|
179 // preferred in the past, maybe for callers wanting larger chunks leave those alone. |
|
180 // - Take into account which chunks are committed? This would require some extra bookkeeping... |
|
181 |
|
182 // 2) Failing that, attempt to find a chunk smaller or equal the minimal level. |
|
183 if (c == NULL) { |
|
184 for (chklvl_t lvl = pref_level + 1; lvl <= max_level; lvl ++) { |
|
185 c = remove_first_chunk_at_level(lvl); |
|
186 if (c != NULL) { |
|
187 break; |
|
188 } |
|
189 } |
|
190 } |
|
191 |
|
192 // 3) Failing that, attempt to find a free chunk of larger size and split it. |
|
193 if (c == NULL) { |
175 if (c == NULL) { |
194 for (chklvl_t lvl = pref_level - 1; lvl >= chklvl::ROOT_CHUNK_LEVEL; lvl --) { |
176 for (chklvl_t lvl = pref_level - 1; lvl >= chklvl::ROOT_CHUNK_LEVEL; lvl --) { |
195 c = remove_first_chunk_at_level(lvl); |
177 c = remove_first_chunk_at_level(lvl); |
196 if (c != NULL) { |
178 if (c != NULL) { |
197 // Split chunk; add splinters to freelist |
179 // Split chunk; add splinters to freelist |
199 break; |
181 break; |
200 } |
182 } |
201 } |
183 } |
202 } |
184 } |
203 |
185 |
204 // 4) Failing that, attempt to allocate a new chunk from the connected virtual space. |
186 // 4) Failing that, before we start allocating a new root chunk, lets really scrape the barrel. Any |
|
187 // smaller chunk is acceptable provided it fits the minimal size.... |
|
188 if (c == NULL) { |
|
189 for (chklvl_t lvl = pref_level + 1; lvl <= max_level; lvl ++) { |
|
190 c = remove_first_chunk_at_level(lvl); |
|
191 if (c != NULL) { |
|
192 break; |
|
193 } |
|
194 } |
|
195 } |
|
196 |
|
197 // 4) Failing that, attempt to allocate a new root chunk from the connected virtual space. |
205 if (c == NULL) { |
198 if (c == NULL) { |
206 |
199 |
207 // Tracing |
200 // Tracing |
208 log_debug(metaspace)("ChunkManager %s: need new root chunk.", _name); |
201 log_debug(metaspace)("ChunkManager %s: need new root chunk.", _name); |
209 |
202 |