diff --git a/BUGS b/BUGS
--- a/BUGS
+++ b/BUGS
@@ -1,1 +1,8 @@
 empty heap profile gives NaN in SVG - detect and abort?
+use Text for correct unicode instead of ByteString
+	$ ./unicode +RTS -h
+	$ hp2pretty unicode.hp
+	$ rsvg unicode.svg unicode.png
+	Error reading SVG:Error domain 1 code 9 on line 83 column 39 unicode.svg: Input is not proper UTF-8, indicate encoding !
+	Bytes: 0xF8 0x62 0x2F 0x6D
+	$
diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,12 @@
+v0.5	2011-10-15	acceleration
+
+Vastly improved runtime performance thanks to 'floatshow'
+and 'attoparsec' for (respectively) printing and parsing
+floating point numbers.
+
+Source code statistics: 544 lines, 3275 words, 20061 chars.
+
+
 v0.4	2011-05-18	comparability
 
 Colours are stable across program runs (based on a hash of
diff --git a/hp2pretty.cabal b/hp2pretty.cabal
--- a/hp2pretty.cabal
+++ b/hp2pretty.cabal
@@ -1,5 +1,5 @@
 Name:                hp2pretty
-Version:             0.4
+Version:             0.5
 Synopsis:            generate pretty graphs from heap profiles
 Description:         hp2pretty is a rewrite of hp2ps, implemented in Haskell, with
                      the aims of being maintainable, with more flexible output, and
@@ -8,8 +8,11 @@
                      Also none (count'em) of hp2ps' options are implemented yet in
                      hp2pretty.
                      .
-                     Usage has changed since the previous release:
+                     In hp2pretty-0.5 using attoparsec and floatshow internally
+                     should give a healthy speedup.
                      .
+                     In hp2pretty-0.4 usage changed since the previous release:
+                     .
                         hp2pretty *.hp
                      .
                         hp2pretty --uniform-scale=time   *.hp
@@ -18,7 +21,7 @@
                      .
                         hp2pretty --uniform-scale=both   *.hp
                      .
-                     Colours have also changed: now they are based on a hash of the
+                     Colours also changed: now they are based on a hash of the
                      cost label, which should make colours have stable semantics
                      across program runs.
 
@@ -34,9 +37,9 @@
 Cabal-version:       >=1.6
 
 Executable hp2pretty
-  Build-depends:       base >= 4 && < 5, array, bytestring, containers, filepath, mtl
-  GHC-options:         -Wall
-  GHC-prof-options:    -prof -auto-all
+  Build-depends:       base >= 4 && < 5, array, attoparsec, bytestring, containers, filepath, floatshow, mtl
+  GHC-options:         -Wall -rtsopts
+  GHC-prof-options:    -prof -auto-all -caf-all
   HS-source-dirs:      src
   Main-is:             Main.hs
   Other-modules:       Types
@@ -55,4 +58,4 @@
 Source-repository this
   type:                git
   location:            git://gitorious.org/hp2pretty/hp2pretty.git
-  tag:                 v0.4
+  tag:                 v0.5
diff --git a/src/Bands.hs b/src/Bands.hs
--- a/src/Bands.hs
+++ b/src/Bands.hs
@@ -7,10 +7,10 @@
 import Data.Array.ST (writeArray, readArray, newArray)
 import Data.Array.Unboxed (UArray)
 import Data.Map (Map, lookup, size)
-import Numeric (readSigned, readFloat)
 import Prelude hiding (lookup, lines, words, length)
 import Data.ByteString.Char8 (ByteString, pack, unpack, lines, words, isPrefixOf, length)
 import qualified Data.ByteString.Char8 as BS
+import Data.Attoparsec.Char8 (parseOnly, double)
 
 import Types
 
@@ -47,8 +47,8 @@
   else error $ "Parse.sampleTime: expected " ++ unpack name ++ " but got " ++ unpack h
 
 readDouble :: ByteString -> Double
-readDouble s = case readSigned readFloat (unpack s) of
-  ((x,_):_) -> x
+readDouble s = case parseOnly double s of
+  Right x -> x
   _ -> error $ "Parse.readDouble: no parse " ++ unpack s
 
 sBEGIN_SAMPLE, sEND_SAMPLE :: ByteString
diff --git a/src/SVG.hs b/src/SVG.hs
--- a/src/SVG.hs
+++ b/src/SVG.hs
@@ -3,7 +3,8 @@
 
 import Data.ByteString.Char8 (ByteString, pack)
 import qualified Data.ByteString.Char8 as BS
-import Numeric (showHex, showFFloat)
+import Numeric (showHex)
+import Text.FShow.RealFloat (fshow, Double7(D7))
 
 import Graphics (Graphics(Graphics), Point, Size, Angle, FontSize, Anchor(..), StrokeWidth, Opacity, RGB(..))
 import qualified Graphics as G
@@ -77,4 +78,4 @@
 showP (x,y) = [showF x, ",", showF y]
 
 showF :: Double -> ByteString
-showF x = pack $ showFFloat Nothing x ""
+showF x = pack $ fshow (D7 x)
diff --git a/src/Total.hs b/src/Total.hs
--- a/src/Total.hs
+++ b/src/Total.hs
@@ -4,9 +4,9 @@
 import Control.Monad.State.Strict (State(), execState, get, put)
 import Data.List (foldl')
 import Data.Map (Map, empty, lookup, insert, alter)
-import Numeric (readSigned, readFloat)
 import Prelude hiding (lookup, lines, words, drop, length)
 import Data.ByteString.Char8 (ByteString, pack, unpack, lines, words, isPrefixOf, drop, length)
+import Data.Attoparsec.Char8 (parseOnly, double)
 
 import Types
 
@@ -97,8 +97,8 @@
   else error $ "Parse.sampleTime: expected " ++ unpack name ++ " but got " ++ unpack h
 
 readDouble :: ByteString -> Double
-readDouble s = case readSigned readFloat (unpack s) of
-  ((x,_):_) -> x
+readDouble s = case parseOnly double s of
+  Right x -> x
   _ -> error $ "Parse.readDouble: no parse " ++ unpack s
 
 sJOB, sDATE, sSAMPLE_UNIT, sVALUE_UNIT, sBEGIN_SAMPLE, sEND_SAMPLE :: ByteString
