-
-
Notifications
You must be signed in to change notification settings - Fork 337
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
Mirrored memory ring buffer #671
Comments
Are you asking for it to be done in miniaudio or are you askiing if this is something feasible for you to do? Can you say more about your use case -- what is the situation where you consider a ring buffer to be helpful? Off-the-top-of-my-head: The solution you linked to involves operating-system and hardware level messing with the mapping of virtual memory. I don't know what that would do for threading issues. I shudder to even think about it. Generally, the reading and writing in a ring buffer is one fixed-size element at a time. It is perfect for that. It does mean there has to be wrap-around checking on each read or write, and there also has to be collision detection -- i.e., the buffer is full and can't take more yet, or it is empty, and can't be read more yet. There are ways to accelerate this by working in larger chunks. The computations A compromise might be by increasing the size of elements, doing reading and writing in bigger fixed-size chunks in effect. Yet another alternative might be having fixed-size elements in the buffer but each element has a separately-allocated chunk that hangs off of it. This gets complicated too. I will stop speculating. It is important to understand the use case, rather than start with ring buffer as a solution. |
Asking for it to be done in miniaudio. I think the use-case would be to simplify the ring buffer interface. For example, the way I understand it, there might be 500 samples to read in the buffer, but the first time I call With a mirrored buffer as long as I want to read or write less than current capacity, it should work, no need to think about the internal state of the buffer. In this case I would get those 500 samples in one contiguous memory pointer. It seems that Portaudio if I'm not mistaken, doesn't mirror but instead keeps two regions and has some internal logic hidden inside user-facing methods. Feel free to close the request if it's not something that can be entertained at this point. |
@dsego You are correct. The You also have to do The key factor in all of this is that when you acquire_read() you are returned a point to an array of a returned size that you then need to consume yourself. This is storage in the ring buffer itself and it is effectively locked against the writer until your code reports that the data is no longer needed there and the array cells are available for the writer to use. PONDERING FURTHER I'm unclear why this is a bother. It is really no different than if you caught up with the writer or the writer was working so rapidly that it had wrapped around and was hot on the reader's heals, if not breathing down its neck. If you always want to grab everything that the writer has buffered when you do a read, expecting to find that in a single block that you can index through is simply contrary to how ring buffers work. The alternative is to quickly copy available material from the ring buffer into an array of contiguous elements doing at most two copies. Then the writer is free to keep going while your program digests the sequential buffer you created for yourself. At this point, I think there is more appeal to a buffering scheme that does not use a (conventional) ring buffer. |
@dsego Thanks for this. You're correct in miniaudio's ring buffer. When I wrote the ring buffer, I just wrote it off the top of my head without a reference, but that mirrored technique is rather clever. I don't think I would ever have thought of that. It looks like the only disadvantage is that it takes up double the memory and will require two writes instead of one. I wonder if I could do a I like this idea and will have a look at it when I get the chance, but it might be a while before I get to it. Let's leave this ticket open. |
@mackron That is clever. So, once anything in the upper copy is committed, the read pointer comes back down to a lower next-read point in the buffer it never leaves. That looks like there is no thread difficulty. Of course, the writer is always writing in two places just to keep readers happy. Some other calculations are a little tricky, I suppose, and fun to work out. The cost is doubling the space and doubling the number of writes so that reader can use read_acquire to process consecutive entries right in the buffer rather than quickly freeing buffer space ahead of the writer by grabbing copies. And the writer still has to wrap as usual. A mystery. |
@mackron I thought about this some more and realized it is far better to transfer to user-supplied blocks of contiguous memory. Now there's Another nice feature is this can be done with a get-type function that uses the existing PS: I should have thought of this sooner. I did something like this in an API for a minicom;puter terminal-interface service long ago. |
https://lo.calho.st/posts/black-magic-buffer/ https://nullprogram.com/blog/2016/04/10/ This is not going to work well on an OS (or processor) that does not support this though. |
From what I understand, reading the ring buffer currently requires a loop to make sure all the required frames are read. This is stated in the docs:
However, I have found a mirroring method described online which uses a copy of the data to create a contiguous block and avoids wrapping around when reading the buffer.
https://mikeash.com/pyblog/friday-qa-2012-02-03-ring-buffers-and-mirrored-memory-part-i.html
Would something like this be possible to implement?
The text was updated successfully, but these errors were encountered: