In my previous post, I showed how you can search for a range of cleared bit in a bitmap, as part of an allocation strategy. I want to do better than just finding a range, I want to find the best range. Best is define as:
- Near a particular location (to increase locality).
- Create the least amount of fragmentation.
Here is the bitmap in question: [0x80520A27102E21, 0xE0000E00020, 0x1A40027F025802C8, 0xEE6ACAE56C6C3DCC].
And a visualization of it:
What we want is to find the following ranges:
- single cell near the red marker (9th cell)
- 2 cells range near the red marker (9th cell)
- 4 cells range near the yellow marker (85th cell)
- 7 cells range near the green marker (198th cell)
We have an existing primitive already, the find_next() function. Let’s see how we can use it to find the right buffer for us.
Here is how it goes, we scan forward from the beginning of the word that you and trying to find a range that match the requirement. We’ll find the smallest range we can find, but as we go further from the starting point, we’ll loosen our requirements. If we can’t find anything higher, we’ll search lower that the given position. Regardless, if we find an exact match, one where we don’t need to fragment for, we’ll take that if it is close enough.
Here are the results from the code (the code itself will follow shortly):
- single cell near the 9th – 12 – as expected
- 2 cells near the 9th – 27 – because there is a two cell hole there and we won’t fragment
- 4 cells near 85 – 64 – I mentioned that we are scanning only forward, right? But we are scanning on a word boundary. So the 85th cell’s bit is in the 2nd word and the first 4 bits there are free.
- 7 cells near 198 – 47 – we couldn’t find anything suitable higher, so we started to look from the bottom.
Here is the full code for this. I want to highlight a couple of functions:
Here you can see how I’m approach the issue. First, get the data from the start of the word containing the desired location, then see if I can get the best match. Or, if I can’t, just try to get anything.
The fact that I can play around with the state of the system and resume operations at ease make it possible to write this code.
Note that there is a tension in allocation code between:
- Finding the best possible match
- The time that it takes to find the match
- The resources consumed by the find
In particular, if I need to scan a lot of memory, I may run into issue. It is usually better to get something as soon as possible than wait for the perfect match.
If you are interested in a nice mental workout, implement the find_prev function. That is a somewhat of a challenge, because you need to manage the state in reverse. Hint, use: __builtin_ctzll().