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

Shared FilePool #1236

Closed
wants to merge 23 commits into from
Closed

Shared FilePool #1236

wants to merge 23 commits into from

Conversation

KKQ-KKQ
Copy link
Contributor

@KKQ-KKQ KKQ-KKQ commented Feb 5, 2024

In iOS/iPadOS, an AU plugin's process is shared.
In order to reduce its memory, I made this changes.

I fixed some issues but I cannot reopen the PR because I squashed commits.

@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 6, 2024

I added a stress test and it crashes.

@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 6, 2024

@paulfd The running action hangs! Please stop it.

@redtide
Copy link
Member

redtide commented Feb 6, 2024

I thought it stopped by itself, not running for more than one hour... I canceled it.

@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 8, 2024

@redtide @paulfd I'm sorry but could you stop actions? I will set timeout next time.

@paulfd
Copy link
Member

paulfd commented Feb 8, 2024

Should be stopped!

@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 8, 2024

I'm sorry. but the tests finish normally when they run locally on ubuntu 22.04.
And with the older Abseil, the tests passes.

@paulfd
Copy link
Member

paulfd commented Feb 8, 2024

I can revert abseil up to some version. I think I needed some form of the variant, I can double check. Do you know why it hangs with the newer abseil?

@redtide
Copy link
Member

redtide commented Feb 8, 2024

Sorry but I don't understand why you care about Actions, it's a way for us to test the builds, if they hangs it's an Actions issue IMO, not yours for sure, they should timeout but for some reason they don't?

@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 8, 2024

the default timeout is 6 hours.

hangs is my miss, I think. I will change std::condition_variable::wait() to std::condition_variable::wait_for().
but the finish of initializing should be notified to the all receiver without fork, I think. I don't know why.

Anyway with the newer Abseil-cpp, the develop branch tests fails in my environment.

@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 8, 2024

I can set timeout by writing build.yml. next time I will set it to 20 minutes.

@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 8, 2024

@redtide the time is for fee. in the free plan it is limited to 2000 minutes as I know.

@redtide
Copy link
Member

redtide commented Feb 8, 2024

I see, thank you, so we must limit that but I'm not sure which timing is best, with macOS step in particular I'm not sure 20 could be OK, it should I guess. TBH I wasn't much aware about setting limits in the workflow file

@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 8, 2024

the actual limit is 3000 minutes per month.
I will set timeout next time.

@redtide
Copy link
Member

redtide commented Feb 8, 2024

I think we should see the average and set the appropriate one, I see it's per job, so some are quick, other not

@redtide
Copy link
Member

redtide commented Feb 8, 2024

Looking at the process that takes longer (macOS, max 6 minutes) would be OK to set them all to 10 and later maybe we can fine tune each?
It seems a global setting is not yet implemented.

redtide and others added 3 commits February 8, 2024 17:27
@redtide
Copy link
Member

redtide commented Feb 8, 2024

Oh, I didn't know we used release candidate versions other than LTS, so at this point maybe it worth to try the current 20240116.0 of 2 weeks ago maybe?

@KKQ-KKQ do you mind to try to update the abseil submodule to abseil/abseil-cpp@4a2c633 and see if it is good, so in which case we can update instead roll back to 20230125.3?

EDIT: I see now that Paul needed some newer version for new code, so IIUC roll back couldn't even be possible, so maybe updating might fix the issue?

BTW some time ago I added manual workflows, so in future, if you want to test your fork before submit a PR you should be able to do it. If not then we have a problem and I need to set it so people can enable actions on their side without the need to submit the PR first.

@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 9, 2024

This PR is too buggy!

For better performance, the number of loading thread is 1.
Disk is too slow to access randomly, so sliced loading job is better.

@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 10, 2024

I think it becomes more stable. Please check this PR.

Copy link
Member

@paulfd paulfd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot of work here, thanks a lot. Sadly I think I need to find more than an hour here and there to fully sit down and look at all this. I put some random comments but nothing really deep, sorry.

One thing: is it OK if I separate the seek part of the audiofile library? It's not much but it'll help this PR to be more focused.

src/sfizz/AudioReader.cpp Show resolved Hide resolved
src/sfizz/FilePool.cpp Show resolved Hide resolved
std::vector<FileId> lastUsedFiles;
std::vector<FileAudioBuffer> garbageToCollect;
public:
struct GlobalObject
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not the biggest fan of this name, it feel a bit vague. I guess that this is somehow an extension of the "global threadpool" which includes both the threadpool and the filepool, but maybe we can find another more precise name (or even just change the name of the per-instance "filepools" to something else).

As I'm reading more I might have other ideas :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. but I am not good at English. Could you suggest one or more?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will look at the rest. My intuition is that "Filepool" can actually be the Global Object and that we have other names for the filepool reference in each synth.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. we don't have to change the names, in my opinion.
a FilePool object belongs to a Synth object (resources), FilePool::GlobalObject is a singleton object.

std::thread t1([&p] { p.wait(); });
std::thread t2([&p] { p.prepare(); });
t1.join();
t2.join();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where these the reasons for hanging tests? We could also time out on a condition variable shared by the threads. It's a bit more verbose though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this for my local tests. I agree for that time out should be implemented.

CHECK(synth3->getNumPreloadedSamples() == 0);
CHECK(filePoolGlobalObj->getNumLoadedSamples() == 1);

synth1->loadSfzFile("");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to be here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Locally the line 107 was failed before because of too much release.

src/sfizz/FilePool.cpp Show resolved Hide resolved
tests/FilePoolT.cpp Show resolved Hide resolved
tests/FilePoolT.cpp Show resolved Hide resolved
@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 11, 2024

They should be "Shared File Pool" and "Sliced Loading Job" when we separate this PR.
I implemented both in this PR. seek function is needed by "Sliced Loading Job".

std::mutex preloadedFilesMutex;

// Preloaded data
absl::flat_hash_map<FileId, std::shared_ptr<FileData>> preloadedFiles;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, just a quick question: what made you change these to shared pointers? My concern is that this shared pointer is copied in getFilePromise, and this copy will most probably take a locking mutex, which I want to avoid on the realtime thread.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getFilePromise doesn't lock any mutex
In my PR, FilePool's preloadedFiles is synchronized GlobalObject's one.
std::shared_ptr itself doesn't use mutex because it is not thread-safe when written.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, the performance is much improved when I just changed FileData to std::shared_ptr<FileData>.

if (seekable)
reader.seek(inputFrameCounter);

int chunkCounter = (freeWheeling || !seekable) ? INT_MAX : static_cast<int>(sfz::config::numChunkForLoadingAtOnce);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this chunking allows for a better scheduling of loading multiple files at once right? Forcing a round robin.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 13, 2024

I describe this PR. I'm sorry for late.

Shared File Pool:

In FilePool::preloadFiles(), FilePool::loadFiles(), FilePool::loadFromRam():

Load data from GlobalObject::(pre)loadedFiles when the GlobalObject::(pre)loadedFiles contains the FileId.
Add data to GlobalObject::(pre)loadedFiles when the FileId is newly created.
The stored data became std::shared_ptr in order to share the same data.

Sliced Loading Job:

Added status:

FileData::Status::PendingStreaming

In streamFromFile():

It returns false when the size of the loading reaches a certain size.

In FilePool::loadingJob():

Only execute when the FileData::status is PendingStreaming.
It queues the job again when streamFromFile() returns false.

Avoid from loading when the data is full-loaded

Added status:

FileData::Status::FullLoaded

In FilePool::preloadFiles(), FilePool::loadFiles(), FilePool::loadFromRam():

Set its status to FullLoaded when full-loaded.

In FilePool::getFilePromise():

It queue the job only when the status is not FullLoaded.

@paulfd
Copy link
Member

paulfd commented Feb 13, 2024

Thanks! So if that's OK, I will split this work into these separate components so we can integrate and work on them one by one.

@paulfd
Copy link
Member

paulfd commented Feb 13, 2024

The stored data became std::shared_ptr in order to share the same data.

This was regarding my comment above? I'm still concerned about this but I do understand the underlying need. Let's pick up this discussion on the split pull request.

Copy link
Contributor Author

@KKQ-KKQ KKQ-KKQ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am very new to github, so many comments were "pending".

CHECK(synth3->getNumPreloadedSamples() == 0);
CHECK(filePoolGlobalObj->getNumLoadedSamples() == 1);

synth1->loadSfzFile("");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Locally the line 107 was failed before because of too much release.

std::mutex preloadedFilesMutex;

// Preloaded data
absl::flat_hash_map<FileId, std::shared_ptr<FileData>> preloadedFiles;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getFilePromise doesn't lock any mutex
In my PR, FilePool's preloadedFiles is synchronized GlobalObject's one.
std::shared_ptr itself doesn't use mutex because it is not thread-safe when written.

std::vector<FileId> lastUsedFiles;
std::vector<FileAudioBuffer> garbageToCollect;
public:
struct GlobalObject
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. we don't have to change the names, in my opinion.
a FilePool object belongs to a Synth object (resources), FilePool::GlobalObject is a singleton object.

std::mutex preloadedFilesMutex;

// Preloaded data
absl::flat_hash_map<FileId, std::shared_ptr<FileData>> preloadedFiles;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, the performance is much improved when I just changed FileData to std::shared_ptr<FileData>.

if (seekable)
reader.seek(inputFrameCounter);

int chunkCounter = (freeWheeling || !seekable) ? INT_MAX : static_cast<int>(sfz::config::numChunkForLoadingAtOnce);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

Copy link
Contributor Author

@KKQ-KKQ KKQ-KKQ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a mistake in resolving. Sorry about that.

@KKQ-KKQ
Copy link
Contributor Author

KKQ-KKQ commented Feb 14, 2024

I have divided this PR into 4 PRs.
I close this PR temporally.

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

Successfully merging this pull request may close these issues.

3 participants