Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix block allocation size (IDFGH-13453) #2

Closed
wants to merge 4 commits into from

Conversation

tannewt
Copy link

@tannewt tannewt commented Mar 5, 2024

It needs to include the rounding done by mapping_search() otherwise we'll trim the block too much and not be able to re-allocate the same amount of space after the block is freed.

In the paper's version of mapping_search, this is subtle because r is marked as "in out". http://www.gii.upv.es/tlsf/files/papers/jrts2008.pdf

To reproduce:

  • Allocate an amount that is rounded up.
  • Allocate a second block that takes up the remaining space. This prevents the second allocation from occurring in a new spot.
  • Free the first block.
  • Allocate the first amount a second time. It will fail without this change even though the requested space is actually available because the free block was added to the non-rounded segmented list.

It needs to include the rounding done by `mapping_search()`
otherwise we'll trim the block too much and not be able to
re-allocate the same amount of space after the block is freed.

In the paper's version of mapping_search, this is subtle because
r is marked as "in out". http://www.gii.upv.es/tlsf/files/papers/jrts2008.pdf

To reproduce:
* Allocate an amount that is rounded up.
* Allocate a second block that takes up the remaining space. This
  prevents the second allocation from occurring in a new spot.
* Free the first block.
* Allocate the first amount a second time. It will fail without this
  change even though the requested space is actually available because the
  free block was added to the non-rounded segmented list.
The original code missed a * to check the value of size for
non-zero. This corrects that error and adds an additional check
after the first alignment.
@SoucheSouche
Copy link
Collaborator

Hi @tannewt,
I will try to take a look at it as soon as possible. Thanks for the PR.

@AxelLin
Copy link

AxelLin commented May 6, 2024

@SoucheSouche

Any update for reviewing this PR?

BTW, I noteice the tlsf in esp-idf-v5.2 branch is quite old.
Do you consider updating the tlsf submodule for v5.2 branch?

@AxelLin
Copy link

AxelLin commented May 30, 2024

Hi @tannewt, I will try to take a look at it as soon as possible. Thanks for the PR.

@SoucheSouche
Any update for reviewing this PR? It looks like a bug fix.

@AxelLin
Copy link

AxelLin commented Jul 31, 2024

Hi @tannewt, I will try to take a look at it as soon as possible. Thanks for the PR.

@SoucheSouche @igrr
There is no update at all, too bad.
This just discourges peope to contribute fixes.

@SoucheSouche
Copy link
Collaborator

Hi @tannewt, @AxelLin, sorry for not taking a look at this earlier. I will get started on it this week.

@AxelLin concerning v5.2 and the TLSF, it is a bit tricky since some target have the option to use the ROM version of the TLSF. So for a given change in the TLSF submodule we have to make sure it can be patched to the existing TLSF in the ROM.

@SoucheSouche
Copy link
Collaborator

SoucheSouche commented Aug 2, 2024

Hi @tannewt, I had a look at your proposed changes.
By returning the rounded size used to find a suitable block instead of the requested size, you prevent the algorithm from merging the difference between the requested size and the suitable block size (if any) back to the next free block. Meaning that those bytes will be unusable after the allocation returns, until the memory is freed.

For small allocations this difference is quite minimal but once you start getting into allocations of a few KB it gets less neglectable. (e.g, for 3000 bytes allocations on esp32s3 using the default capability, 3072 bytes end up being allocated from which 60 bytes are related to your changes).

However, I can see that when freeing the memory, instead of recalculating the rounded size from the size of the block to get the fl, sl value pair that was actually used in the allocation to mark the block as used in the bitmap, we just calculate the fl, sl value pair based on the size of the block without rounding it and this leads to a different pair of fl, sl being calculated, hence your issue.

I updated the tlsf_free function to use the rounded size of the block instead of the size only and it fixes the problem, without having to allocate more memory than necessary. I will look more into it to make sure it doesn't create any problem but if not, then I would suggest using this strategy instead.

@tannewt
Copy link
Author

tannewt commented Aug 2, 2024 via email

@SoucheSouche
Copy link
Collaborator

@tannewt, yes I totally understand the reason for your changes. As I mentioned in the last 2 paragraphs of my last message, instead of including this rounded size overhead in the allocation, we can calculate the rounded size of the allocated memory in the free. This will ensure that we get the same sl, fl value pair that was calculated in the alloc, so we change the right bitmap value back to free.

E.g., (not shure the fl, sl values are actually right but this is just for demonstration purposes)

  • Allocate 20000 bytes, rounded value is 20523, calculated FL = 8, calculated SL = 8 so the bitmap[8][8] is set to used.
  • Free the 20000 bytes, FL and SL calculated based on alloc size (here 20000) which gives FL = 8, SL = 7, bitmap[8][7] is set to free. So when you want to allocate 20000 bytes again, it will fail because bitmap[8][8] is still set to used.

So either we include the rounded value in the allocation so that when we free, the FL/SL value calculated will be matching the one calculated in the allocation
OR ( not sure if it works but it looks like it could and save us from including those unused bytes in the allocation)
we don't include the rounded value in the alloc. But when freeing instead of calculating FL / SL based on the size of the block, we again do the rounding calculation to get the FL / SL values from the allocation.

@tannewt
Copy link
Author

tannewt commented Aug 5, 2024

OR ( not sure if it works but it looks like it could and save us from including those unused bytes in the allocation)
we don't include the rounded value in the alloc. But when freeing instead of calculating FL / SL based on the size of the block, we again do the rounding calculation to get the FL / SL values from the allocation.

This would be incorrect because a following allocation of 20001 would round to the same 20523 but the free space wouldn't be enough. The list that the fl/sl values points to is of blocks with a minimum size at least 20523. That way you don't need to transverse the list to find one that actually works. You just take the 20523 block and mark any more extra as free.

@SoucheSouche
Copy link
Collaborator

@tannewt, you are right. It does seem to be the only way to resolve the issue. Great job with this find. I will submit the PR for review.

@tannewt
Copy link
Author

tannewt commented Aug 8, 2024 via email

@SoucheSouche
Copy link
Collaborator

Hi @tannewt, I just merged your fix. Thanks again for the contribution and sorry it took so long to get to it.

@tannewt
Copy link
Author

tannewt commented Aug 9, 2024

Where did you merge it? I don't see it.

No problem! I like TLSF and am happy to see it fixed. (We use it on all CircuitPython ports now.)

@SoucheSouche
Copy link
Collaborator

It's been merged on our internal gitlab server. It should sync your contribution in GitHub shortly.

If not, I'll take a look at it on Monday.

@tannewt
Copy link
Author

tannewt commented Aug 12, 2024

I think the last commit breaks this on ESP. It works on RP2350 but I may have adjusted the size so it does.

@github-actions github-actions bot changed the title Fix block allocation size Fix block allocation size (IDFGH-13453) Aug 13, 2024
@SoucheSouche
Copy link
Collaborator

@tannewt, I already fixed the next_free issue before merging the PR.
It has now been synced with github.

@tannewt
Copy link
Author

tannewt commented Aug 14, 2024

Done in ea82911

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants