| November 2008 | ||||||
|---|---|---|---|---|---|---|
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 | ||||||
Firefox OptimizedAs a programmer, one of the things I love about being able to get the source to my favorite tools is then I can learn from it and build it to my specifications. Recently I got the source to Firefox 1.0 and played around with optimizing the build for my desktop machine, an AMD Athlon 1GHz. Not that the generic Firefox builds from the Mozilla foundation were slow, but I wanted to see what was possible. The hardest part was finding the right gcc options that would work and generate acceptable code. My first few attempts failed in the middle of the build because various intermediate build products, like xpidl, would crash when trying to process some step, because they had been built with bad options.
Using gcc 3.3.5 I end up with the following optimization flags: -march=athlon-tbird -mmmx -m3dnow -O3 -funroll-loops -fomit-frame-pointer
I tried various fastmath options but in general I couldn't get a good build. I don't know how much math a browser really needs to do, anyway, so I didn't spend too much time on it.
I would not assert that the resulting binary is spectacularly faster, but there are places where it seems snappier. If you want to try yourself, in addition to the build instructions from Mozilla, here are the settings and scripts I used. I'd be interested to hear of your experiences, and in particular if you have any tips for getting the fastmath options to work.
The specific gcc I used, as reported by gcc -v
Configured with: ../src/configure -v --enable-languages=c,c++,java,f77,pascal,objc,ada,treelang --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-gxx-include-dir=/usr/include/c++/3.3 --enable-shared --with-system-zlib --enable-nls --without-included-gettext --enable-__cxa_atexit --enable-clocale=gnu --enable-debug --enable-java-gc=boehm --enable-java-awt=xlib --enable-objc-gc i486-linux Thread model: posix gcc version 3.3.5 (Debian 1:3.3.5-2)
The complete set of build options for Firefox.
. $topsrcdir/browser/config/mozconfig export MOZILLA_OFFICIAL=1 export BUILD_OFFICIAL=1 mk_add_options MOZILLA_OFFICIAL=1 mk_add_options BUILD_OFFICIAL=1 ac_add_options --enable-strip ac_add_options --enable-strip-libs # Optimization configurations ac_add_options --enable-optimize="-march=athlon-tbird -mmmx -m3dnow -O3 -funroll-loops -fomit-frame-pointer" ac_add_options --disable-logging ac_add_options --disable-tests ac_add_options --disable-debug ac_add_options --enable-default-toolkit=gtk2 ac_add_options --enable-xft #ac_add_options --enable-freetype2 mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/firefox-bin
Here's the script I found that helped me find the options for my CPU.
#!/bin/sh
# Author: pixelbeat
#This script is Linux specific
#It should work on any gcc >= 2.95 at least
#these apply to any arch (just here for reference)
unsafe_math_opts="-ffast-math -fno-math-errno -funsafe-math-optimizations -fno-trapping-math"
gcc_version=`gcc -dumpversion | sed 's/\([0-9]\{1,\}\.[0-9]\{1,\}\)\.*\([0-9]\{1,\}\)\{0,1\}/\1\2/'`
IFS=":"
while read name value; do
unset IFS
name=`echo $name`
value=`echo $value`
IFS=":"
if [ "$name" == "vendor_id" ]; then
vendor_id="$value"
elif [ "$name" == "cpu family" ]; then
cpu_family="$value"
elif [ "$name" == "model" ]; then
cpu_model="$value"
elif [ "$name" == "flags" ]; then
flags="$value"
fi
done < /proc/cpuinfo
unset IFS
if [ "$vendor_id" == "AuthenticAMD" ]; then
if [ "$cpu_family" == "4" ]; then
_CFLAGS="$_CFLAGS -march=i486"
elif [ "$cpu_family" == "5" ]; then
if [ "$cpu_model" -lt "4" ]; then
_CFLAGS="$_CFLAGS -march=pentium"
elif [ "$cpu_model" == "6" ] || [ "$cpu_model" == "7" ]; then
_CFLAGS="$_CFLAGS -march=k6"
elif [ "$cpu_model" == "8" ] || [ "$cpu_model" == "12" ]; then
if expr $gcc_version '>=' 3.1 >/dev/null; then
_CFLAGS="$_CFLAGS -march=k6-2"
else
_CFLAGS="$_CFLAGS -march=k6"
fi
elif [ "$cpu_model" == "9" ] || [ "$cpu_model" == "13" ]; then
if expr $gcc_version '>=' 3.1 >/dev/null; then
_CFLAGS="$_CFLAGS -march=k6-3"
else
_CFLAGS="$_CFLAGS -march=k6"
fi
fi
elif [ "$cpu_family" == "6" ]; then
if [ "$cpu_model" -le "3" ]; then
if expr $gcc_version '>=' 3.0 >/dev/null; then
_CFLAGS="$_CFLAGS -march=athlon"
else
_CFLAGS="$_CFLAGS -march=k6"
fi
elif [ "$cpu_model" == "4" ]; then
if expr $gcc_version '>=' 3.1 >/dev/null; then
_CFLAGS="$_CFLAGS -march=athlon-tbird"
elif expr $gcc_version '>=' 3.0 >/dev/null; then
_CFLAGS="$_CFLAGS -march=athlon"
else
_CFLAGS="$_CFLAGS -march=k6"
fi
elif [ "$cpu_model" -ge "6" ]; then #athlon-{4,xp,mp}
if expr $gcc_version '>=' 3.1 >/dev/null; then
_CFLAGS="$_CFLAGS -march=athlon-xp"
elif expr $gcc_version '>=' 3.0 >/dev/null; then
_CFLAGS="$_CFLAGS -march=athlon"
else
_CFLAGS="$_CFLAGS -march=k6"
fi
fi
fi
else #everything else "GenuineIntel"
if [ "$cpu_family" == "3" ]; then
_CFLAGS="$_CFLAGS -march=i386"
elif [ "$cpu_family" == "4" ]; then
_CFLAGS="$_CFLAGS -march=i486"
elif [ "$cpu_family" == "5" ] && expr $gcc_version '<' 3.1 >/dev/null; then
_CFLAGS="$_CFLAGS -march=pentium"
elif [ "$cpu_family" -ge "6" ] && expr $gcc_version '<' 3.1 >/dev/null; then
_CFLAGS="$_CFLAGS -march=pentiumpro"
elif [ "$cpu_family" == "5" ]; then
if [ "$cpu_model" != "4" ]; then
_CFLAGS="$_CFLAGS -march=pentium"
else
_CFLAGS="$_CFLAGS -march=pentium-mmx" #No overlap with other vendors
fi
elif [ "$cpu_family" == "6" ]; then
if echo "$flags" | grep -vq cmov; then #gcc incorrectly assumes i686 always has cmov
_CFLAGS="$_CFLAGS -march=pentium -mcpu=pentiumpro" #VIA CPUs exhibit this
else
if [ "$cpu_model" == "0" ] || [ "$cpu_model" == "1" ]; then
_CFLAGS="$_CFLAGS -march=pentiumpro"
elif [ "$cpu_model" -ge "3" ] && [ "$cpu_model" -le "6" ]; then #4=TM5600 at least
_CFLAGS="$_CFLAGS -march=pentium2"
elif [ "$cpu_model" -ge "7" ] && [ "$cpu_model" -le "11" ]; then #9 invalid
_CFLAGS="$_CFLAGS -march=pentium3"
fi
fi
elif [ "$cpu_family" == "15" ]; then
_CFLAGS="$_CFLAGS -march=pentium4"
fi
fi
if expr $gcc_version '>=' 3.1 >/dev/null; then
if echo "$flags" | grep -q sse2; then
_CFLAGS="$_CFLAGS -mfpmath=sse -msse2"
elif echo "$flags" | grep -q sse; then
_CFLAGS="$_CFLAGS -mfpmath=sse -msse"
fi
if echo "$flags" | grep -q mmx; then
_CFLAGS="$_CFLAGS -mmmx"
fi
if echo "$flags" | grep -q 3dnow; then
_CFLAGS="$_CFLAGS -m3dnow"
fi
fi
echo "$_CFLAGS"