Making Firefox go faster on slow machines with Linux.

OK. So the story goes like this. I have an old laptop which get the job done. However, sometimes when watching flash videos or I have many tabs with different content on in Firefox, Firefox tend to get unresponsive and all video being played stops playing smoothly. The other day I learned that one can greatly improve Firefox’s performance by moving its Cache or the entire user profile directory to memory.

IMPORTANT!!

Doing this is not without dangers. Since RAM is volatile memory, any data on it when the machine is shut down or lose power is lost and can not be recovered. I will suggest two solutions to minimize the loss in cases where you can not store the latest changes to disk before rebooting or turning your computer off.

Before I start on talking about implementation I would like to point out that there are several ways of doing this, my suggestion is one of many and that my implementation has been tested on a almost standard Debian Squeeze install.

I will assume that your kernel has shared memory activated and that you can access it at /dev/shm, that your home directory is in /home, that your Firefox installation keeps its user profiles in ~/.mozilla/firefox and that both your volatile memory and non-volatile memory has space for the operations done in this howto.

Before starting this howto, take a backup of the ~/.mozilla/firefox directory. If anything goes wrong you will still have a backup to save you in the beginning. Something as easy as cp -R ~/.mozilla/firefox ~/Desktop is all that is needed to save you some nuisance in case something goes wrong.

I want to describe how the storing to memory part works. Linux has two different ways to make file storage space in memory. One way is to either manually or through the /etc/fstab file mount a tmpfs disk on a directory. By using tmpfs, Linux will by default create a storage space half the size of your total RAM (this can be controlled). If there is not enough space in RAM to store the data put onto the storage space mounted, Linux will use the available swap space to store the remaining data that could not fit. The second way is to use the /dev/shm (shared memory) device which either can be written to directly like a folder or can be bind mounted to a directory, meaning that any files and folder available in /dev/shm is also available where you bind mounted the device.

I created the script you see under which I stored somewhere defined in my $PATH environment (/usr/local/bin/ff-sync)and then ran chmod +x on that file. You will have to do the same. What is important here is that the script is stored somewhere accessible for all your intended users of this script and that they can run it.

#!/bin/sh

# We exit with a help message if the user did not supply a parameter.
if [ "$#" -ne 2 ]; then
 echo "Usage: $0 user id"
 echo "Example: $0 foo erj4gs6x"
 exit
fi

###
###

FIREFOXHOME=/home/$1/.mozilla/firefox
VOLATILE=/dev/shm/firefox-$1
LINK=$2.default
STATIC=$LINK.static
set -efu

###
###

# We create the volatile firefox folder in shared memory if it does not exist.
if [ ! -r $VOLATILE ]; then
 mkdir -m 0700 $VOLATILE
 chown $1.$1 $VOLATILE
fi

# We check if the profile folder is a link to the created shared memory folder
# or not. If not, we move the folder and link the profile folder to the created
# shared memory space.
cd $FIREFOXHOME
if [ "$(readlink $LINK)" != "$VOLATILE" ]; then
 mv $LINK $STATIC
 ln -s $VOLATILE $LINK
fi

# .unpacked exist, we make a backup in the static folder on hard-drive, if it
# does not exist it means that the static folder needs to be copied to shared
# memory. The ionice part is to make the priority of rsync as little as
# possible to make the operation less straining on the system.
if [ -e $LINK/.unpacked ]; then
 /usr/bin/ionice -c3 /usr/bin/nice -n 19 /usr/bin/rsync -av --delete --exclude .unpacked ./$LINK/ ./$STATIC/
else
 /usr/bin/ionice -c3 /usr/bin/nice -n 19 /usr/bin/rsync -av ./$STATIC/ ./$LINK/
 touch $LINK/.unpacked
fi

Now that you have stored the script somewhere your users can run it, all that is needed is to find the ID number of your users Firefox profile and run the script. If you look in the ~/.mozilla/firefox directory you will find a folder that has 8 alphanumerical characters and ends with .default. Remember this until you choose to run your script.

hamartin@Yggdrasil:~$ cd ~/.mozilla/firefox
hamartin@Yggdrasil:~/.mozilla/firefox$ ls -lh
total 8.0K
drwxr-xr-x 11 hamartin hamartin 4.0K Sep 15 21:18 erj4gs6x.default
-rw-r--r--  1 hamartin hamartin   94 Dec 28  2011 profiles.ini
hamartin@Yggdrasil:~/.mozilla/firefox$

Doing the following for the first time will create a folder in the shared memory folder (/dev/shm), move the original folder to a static place where the backups will be held. It will then use rsync to copy the backup to the shared memory folder and then make a symlink to the shared memory folder with the same name and place as your old profile. When ever this script run after the initial creation in shared memory, the script will just sync the content in shared memory to the backup storage.

hamartin@Yggdrasil:~$ firefox-sync hamartin erj4gs6x
sending incremental file list
./
webappsstore.sqlite
Cache/_CACHE_001_

sent 2190718 bytes  received 461 bytes  1460786.00 bytes/sec
total size is 210528147  speedup is 96.08
hamartin@Yggdrasil:~$

Now you have a way of putting things in memory and manually update the content of the backup when you want to. This is however unconvenient, what happens if you forget to update the backup for three hours and loose the entire user profile changes because of a mishap? To solve this problem i add the execution of this script in crontab (crontab -e) by the users who wish to run their profile in memory. You can see that for my own user account I am running this script every 5 minutes.

# m h dom mon dow command
*/5 * * * * /usr/local/bin/ff-sync hamartin erj4gs6x >> /dev/null

Now you have a system that updates its backup every 5 minutes or what ever time intervall you deem is an acceptable loss if things go wrong. There is one last thing that needs to be fixed. When ever you start your computer, you have to wait 5 minutes before you are certain that cron has run the script once so that you are using your backed up profile and not a new one created by Firefox. If you don’t wait, then the new profile will overwrite the old one and you loose all your saved data.

To solve this I made a init script which runs once at boot time before any user can log on and once at shutdown. This will copy the backed up data to the shared memory before any user is allowed access to the system. To use it, store it in /etc/init.d as ff-sync, run chmod +x on it and then run update-rc.d ff-sync defaults. This will make the script run when ever you are changing run levels (starting, rebooting or stopping the machine).

#!/bin/sh

### BEGIN INIT INFO
# Provides: ff-sync
# Required-Start:
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Script that initializes or updates shm sync
### END INIT INFO

# To add this script to stop and start at bootup / shutdown then do
# <strong>update-rc.d ff-sync defaults</strong> as root

set -e

SYNCUSER=hamartin
FIREFOXSYNC=/usr/local/bin/ff-sync
PROFILEID=erj4gs6x
COMMANDSTRING="$FIREFOXSYNC $SYNCUSER $PROFILEID"

if [ -x "$FIREFOXSYNC" ]; then
echo "Syncing shm firefox profile."
$COMMANDSTRING
echo "Done syncing shm firefox profile."
fi

exit 0

The init solution is only good for one user so you would have to add “services” for each user you want to have this available for when they log in. If you have a better way to solve this, please tell me so I can change the code. From my point of view this works since I am the only one using this laptop.

Cheers,
Hans Åge

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>