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

Disable http disk cache and implempent in-memory image cache #2498

Merged
merged 12 commits into from
Oct 25, 2022

Conversation

absidue
Copy link
Member

@absidue absidue commented Aug 20, 2022


Disable http disk cache and implempent in-memory image cache

Important note
We may remove your pull request if you do not use this provided PR template correctly.

Pull Request Type

  • Bugfix
  • Feature Implementation

Related issue
#1837 could be related but I'm not sure

Description
Thank you to the Matrix user for bringing this issue to our attention.

To reduce RAM usage electron stores the http cache on disk. While that might be alright for other applications, in FreeTube that means that while you are watching a video, all of the buffered video data is actually being constantly streamed to and from your disk. In the long term this will likely have an inpact on disk health.

This pull request is made up of two parts:

  1. Disabling the http cache, unfortunately there doesn't seem to be a way to get rid of the disk one without also getting rid of the in-memory one
  2. To compensate for the now missing in-memory http cache, this pull request also implements an in-memory image cache.

How the cache works:
When FreeTube tries to load an image over HTTP(S), the request gets redirected to the imagecache:// custom protocol handler. The protocol handler checks the cache for the image, if it finds it, the image data is returned. Otherwise it fetches the image, stores it to the cache and then returns the image data.

The amount of time an image stays in the cache is based on the Cache-Control: max-age=<seconds> and Age: <seconds> headers that are returned by the server when the image is fetched. The cache checks for and removes expired images every 5 minutes, this interval can altered in the future if needed.

Performance:
In my testing disabling the http cache reduced the disk usage while playing a 1080p DASH video from 1.4 - 2.2MB/s to 0MB/s, when you first start the video it will sit at about 0.1MB/s as the DASH manifest and storyboards are written to the disk and subsequently used.

I tried profiling the memory usage of the image cache using the --inspect-brk flag and connecting to the main process using the devtools in an external chromium browser. Unfortunately I'm not quite sure what the actual memory usage is, as the heap snapshot said it was using about 28.4MB for 1053 images, however the entire heap was only 19.1MB at the time of the snapshot, so something isn't adding up.

Screenshots (if appropriate)
Please add before and after screenshots if there is a visible change.

Testing (for code that is not small enough to be easily understandable)
Please test this PR with production/release builds as dev and debug builds use extra RAM because of the devtools.

To check the disk usage I used the Task Manager in Windows to monitor the disk usage during video playback (e.g. https://youtu.be/bafzQBSktwk)

RAM usage can be monitored using the Task Manager or by hooking up the devtools in an external chromium installation up to the main process:

  1. Start FreeTube with the --inspect-brk (allows remote debugging of the main process and wait until you are ready before executing any javascript code).
  2. Open an external chromium installation and open chrome://inspect
  3. Depending on your browser their might be a link to open the dedicated node devtools
  4. Connect to FreeTube using the connection details that FreeTube spat out in your terminal
  5. In the Sources tab in the devtools, start code execution by pressing the play button in the top right corner
  6. You can take heap snapshots in the Memory tab
  7. As we are using a production build the ImageCache won't be called ImageCache, instead it will have a single letter name, in my case it was q. You can find the name by searching for No image cache entry for in the Sources tab, going back a bit until you find the constructor and then looking at the class name.

Desktop (please complete the following information):

  • OS: Windows
  • OS Version: 10
  • FreeTube version: 0.17.1

Additional context
If the uptick in RAM usage is too significant we can always consider caching the images on disk instead of in-memory. This will be slower but will have the advantage of lower RAM usage. It will also allow us to use the cached images, that haven't expired yet, the next time you open FreeTube.

@absidue absidue added the PR: waiting for review For PRs that are complete, tested, and ready for review label Aug 20, 2022
@PrestonN PrestonN enabled auto-merge (squash) August 20, 2022 12:31
Comment on lines 52 to 61
electronProcess = spawn(electron, [
path.join(__dirname, '../dist/main.js'),
// '--enable-logging', Enable to show logs from all electron processes
// '--enable-logging', // Enable to show logs from all electron processes
remoteDebugging ? '--inspect=9222' : '',
remoteDebugging ? '--remote-debugging-port=9223' : '',
])
],
// { stdio: 'inherit' } // required for logs to actually appear in the stdout
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

What are these changes?

Copy link
Member Author

Choose a reason for hiding this comment

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

{ stdio: 'inherit' } makes spawn() pipe the stdout and stderr of the spawned command to the stdout and stderr of the parent process, in this case _scripts/dev-runner.js. Without that change you won't see any logs from the main process, I've left it in there commented out so that if someone needs to log something from the main process in the future they don't need to spend hours trying to work out why they can't see the logs, like I did.

Adding the extra // to the enable logging line, makes it easier to use your IDE's keyboard shortcuts to uncomment the line without needing to go and add the slashes in manually after you have uncommented it. As Enable to show logs from all electron processes is not valid javascript code and will need to stay commented even when you uncomment that line.

@@ -48,6 +50,10 @@ function runApp() {
app.commandLine.appendSwitch('enable-file-cookies')
app.commandLine.appendSwitch('ignore-gpu-blacklist')

// the http cache causes excessive disk usage during video playback
// we've got a custom image cache to make up for disabling the http cache
app.commandLine.appendSwitch('disable-http-cache')
Copy link
Collaborator

Choose a reason for hiding this comment

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

Has --disk-cache-size=0 been tried?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep and it doesn't make a difference to disk usage during video playback. I also tried setting it to 1 which makes it only do 0.1MB/s which is already a lot better than it was, but it doesn't eliminate the problem completely. I suspect that setting it to 0 tells it to just use their default limit.

src/main/index.js Outdated Show resolved Hide resolved
src/main/index.js Outdated Show resolved Hide resolved
@PikachuEXE
Copy link
Collaborator

I confirmed on MacOS 12.5.1 with Activity Monitor that the disk usage (bytes written) has not increased during video playback after switching to this branch
image

@PikachuEXE
Copy link
Collaborator

This error occurs on my custom build
image

src/main/index.js Outdated Show resolved Hide resolved
@PikachuEXE
Copy link
Collaborator

Using it locally (MacOS)
Will use it in Windows after 1 week of testing if no issue found

@absidue
Copy link
Member Author

absidue commented Aug 22, 2022

I've added fallback so for the expiry timestamp so that it should never fail, if none of the headers are available it defaults to a hardcoded 2 hour expiry time (can be changed with the const at the top of the ImageClass file).

As discussed I've also moved these changes behind a CLI argument so that this behaviour is opt in for now. (If you want to enable it while using yarn dev, you can uncomment the flag in the _scripts/dev-runner.js file.)

@PikachuEXE
Copy link
Collaborator

I wonder how this can be enabled when released...

@absidue
Copy link
Member Author

absidue commented Aug 23, 2022

On Windows you can either run the .exe from the CLI e.g. C:\path\to\FreeTube.exe --experiments-disable-disk-cache or just add the arg to the target field in your shortcut to FreeTube.

On Linux you can either run FreeTube from the CLI or add it to the .desktop file.

macOS is annoying though, you can only pass the flag when you launch FreeTube from the terminal: open -a /Applications/FreeTube.app --args '--experiments-disable-disk-cache'.

@PikachuEXE
Copy link
Collaborator

Really need a new settings to enable/disable this... (and be effective on restart)

@absidue
Copy link
Member Author

absidue commented Aug 30, 2022

Finally figured out a way to add a GUI setting for this. Also removed the CLI flag.

@absidue
Copy link
Member Author

absidue commented Aug 31, 2022

copy of @PikachuEXE's comment here #2511 (comment)

Style suggestion on settings UI

image
image

Code changes:
image
image

@PikachuEXE
Copy link
Collaborator

PikachuEXE commented Aug 31, 2022

An error encountered on Windows 10
Disabling via settings to see if it happens again

Edit: encountered when opening a video

image

@PikachuEXE
Copy link
Collaborator

I still see error popups on windows, disabled on windows for now
No issue on MacOS though
But I am having VPN enabled all the time on Windows while no VPN on Mac
I can try to turn on VPN on Mac later to see if the error would be reproduced

@manifest-9
Copy link

manifest-9 commented Sep 23, 2022

Working for me on arch linux 5.19.10 playing 1080p dash.
Disk writes went from 1.0MB/s to 0MB/s.
Screenshot_20220923_104032

@PikachuEXE
Copy link
Collaborator

This can almost be merged except those random JS errors
Is there anything can be done?

@PikachuEXE
Copy link
Collaborator

Also just found out the code is outdated due to settings panel update
I got a fix PikachuEXE@ae9fad8 for my custom build
Use it ~

callback({
statusCode: response.statusCode ?? 400
})
throw error
Copy link
Member Author

Choose a reason for hiding this comment

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

@PikachuEXE I suspect the error you are seeing is happening here. Instead of throwing it I could probably return the error in the response and then it would be visible in the devtools instead of throwing up a random error popup?

Copy link
Collaborator

Choose a reason for hiding this comment

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

As long as it behaves the same as when it's disabled

Copy link
Member Author

Choose a reason for hiding this comment

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

Okay so instead of throwing the error it will return it as JSON, so you should be able to see it in the network tab in the devtools. I still don't understand why the error is happening in the first place, but this should at least make errors less intrusive and should make it easier for you to debug it. Of course the images that caused the errors still won't load but you shouldn't get the popup now.

Please let me know when you have some error JSON so I can try and work out what the problem is.

PikachuEXE
PikachuEXE previously approved these changes Sep 29, 2022
Copy link
Collaborator

@PikachuEXE PikachuEXE left a comment

Choose a reason for hiding this comment

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

I think this is OK to merge as an experimental setting

@github-actions github-actions bot added PR: merge conflicts / rebase needed and removed PR: waiting for review For PRs that are complete, tested, and ready for review labels Sep 29, 2022
@github-actions
Copy link
Contributor

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@absidue absidue added PR: waiting for review For PRs that are complete, tested, and ready for review and removed PR: changes requested PR: WIP labels Oct 24, 2022
@PrestonN PrestonN merged commit 697bed2 into FreeTubeApp:development Oct 25, 2022
@github-actions github-actions bot removed the PR: waiting for review For PRs that are complete, tested, and ready for review label Oct 25, 2022
@absidue absidue deleted the reduce-disk-usage branch October 25, 2022 09:34
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.

6 participants