diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Milan Straka <fox@ucw.cz> 2010
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Milan Straka <fox@ucw.cz> nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,59 @@
+This package consists of a thorough benchmark for a containers package.
+
+Quick start
+===========
+To benchmark the installed version of containers, just do
+
+cd scripts
+sh benchmark.sh installed-containers none
+
+Running
+=======
+
+The benchmark is executed using scripts in scripts directory. The main
+executable is benchmark.sh, which is given several arguments:
+benchmark.sh
+  name_of_the_benchmark      -- date is added to it
+  containers_repo            -- repo with containers, write 'none' for
+                             --   system containers library
+  cabal_configure_opts       -- optional flags passed to cabal configure
+
+The benchmark.sh just calls other scripts:
+  compile.sh containers_repo cabal_configure_opts   -- builds the benchmark
+  run.sh name_of_the_benchmark                      -- run built benchmark
+  collect.pl name_of_benchmark      -- collect all results in one .csv file
+
+Other scripts:
+  see.sh < name_of_csv              -- formats the csv file for viewing
+  cmp.pl base_csv diff_csv          -- generate csv with comparison of two tests
+  cmp.sh base_csv diff_csv          -- formats the result of cmp.pl for viewing
+
+  ghc.sh containers_repo ghc_repo result_csv
+    -- Compiles the GHC repo with given containers and store results
+    -- the size of GHC and the memory allocation results of performance tests
+    -- are stored. These tests were once a regression, so we monitor them.
+    -- The GHC repo must be already booted and configured.
+
+
+Which implementation to benchmark
+=================================
+
+The benchmark can use system-installed containers package or any given repo.
+Because the criterion package used for benchmarking is using containers
+internally, we cannot safely expose the benchmarked implementation as
+Data.Map and others. Therefore we benchmark Container.{Map,Set,IntMap,IntSet}.
+The scripts/system_containers.sh and scripts/custom_containers.sh scripts
+chooses which implementation of containers is benchmarked.
+
+
+Benchmark design
+================
+
+Various input data are provided by InputData/*
+
+Various benchmark methods are provided by Benchmar/*
+
+As the different combinations of input data and containers result in different
+type signatures, we use CPP extension to put the input data and benchmark
+methods into one source file and let GHC to type-check for each combination of
+input data and container. This happens in Variants/*
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+import Distribution.Simple
+main = defaultMain
diff --git a/containers-benchmark.cabal b/containers-benchmark.cabal
new file mode 100644
--- /dev/null
+++ b/containers-benchmark.cabal
@@ -0,0 +1,68 @@
+Name:                containers-benchmark
+Version:             1.0
+Synopsis:            Extensive benchmark suite for containers package.
+Description:         This package evaluates performance of a containers package
+                     from multiple perspectives.
+                     .
+                     It measures time and memory allocation of methods specialised
+                     to several types. It can also measure the size and memory
+                     allocation of GHC compiled with the containers package.
+                     .
+                     The containers package used can be both system-installed or
+                     any darcs repository.
+Homepage:            http://fox.auryn.cz/darcs/containers-benchmark/
+License:             BSD3
+License-file:        LICENSE
+Author:              Milan Straka
+Maintainer:          fox@ucw.cz
+Stability:           Experimental
+Category:            Benchmarking
+Build-type:          Simple
+Cabal-version:       >=1.2
+Extra-source-files:  README
+                     scripts/benchmark.sh
+                     scripts/cmp.pl
+                     scripts/cmp.sh
+                     scripts/collect.pl
+                     scripts/compile.sh
+                     scripts/custom_containers.sh
+                     scripts/ghc.sh
+                     scripts/run.sh
+                     scripts/see.sh
+                     scripts/system_containers.sh
+                     src/Driver.inc.hs
+                     src/Benchmark/Map-like.inc.hs
+                     src/Benchmark/Set-like.inc.hs
+                     src/Variants/gen.sh
+
+Executable benchmark
+  Main-is:           Main.hs
+  Build-depends:     base >= 3 && < 5,
+                     bytestring >= 0.9 && < 1.0,
+                     containers >= 0.3 && < 0.5,
+                     criterion >= 0.5 && < 0.6,
+                     random >= 1.0 && < 1.1
+  Hs-source-dirs:    src
+  Other-modules:     Container.IntMap
+                     Container.IntSet
+                     Container.Map
+                     Container.Set
+                     InputData.ByteString
+                     InputData.Int
+                     InputData.IntegerBig
+                     InputData.IntegerSmall
+                     InputData.String
+                     Variants.IntMap_Int
+                     Variants.IntSet_Int
+                     Variants.Map_ByteString
+                     Variants.Map_Int
+                     Variants.Map_IntegerBig
+                     Variants.Map_IntegerSmall
+                     Variants.Map_String
+                     Variants.Set_ByteString
+                     Variants.Set_Int
+                     Variants.Set_IntegerBig
+                     Variants.Set_IntegerSmall
+                     Variants.Set_String
+  if impl(ghc >= 7.0)
+    Ghc-Options: -rtsopts
diff --git a/scripts/benchmark.sh b/scripts/benchmark.sh
new file mode 100644
--- /dev/null
+++ b/scripts/benchmark.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+[ -n "$1" ] || { echo Missing name of the benchmark run!; exit 1; }
+[ -n "$2" ] || { echo Missing name of the containers repo or \'none\'!; exit 1; }
+
+dir="$1-`date +%y%m%d`"
+[ -d "$dir" ] || mkdir "$dir"
+repo="$2"
+shift 2
+
+sh compile.sh "$repo" "$@"
+sh run.sh "$dir"
+perl collect.pl "$dir"
diff --git a/scripts/cmp.pl b/scripts/cmp.pl
new file mode 100644
--- /dev/null
+++ b/scripts/cmp.pl
@@ -0,0 +1,69 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+sub usage() {
+  print "Usage: $0 original.csv new.csv";
+  exit 1;
+}
+
+-f "$ARGV[0]" or usage();
+-f "$ARGV[1]" or usage();
+
+open (my $fori, "<", $ARGV[0]) or die "Cannot open $ARGV[0]!";
+open (my $fnew, "<", $ARGV[1]) or die "Cannot open $ARGV[1]!";
+
+my @totals;
+sub print_totals() {
+  for my $mean ("geo", "ari") {
+    print "total ($mean mean)";
+    for my $i (1..$#totals) {
+      print ";";
+      next unless @{$totals[$i]};
+      my $avg;
+      if ($mean eq "geo" ) {
+        $avg = 1.0;
+        foreach my $v (@{$totals[$i]}) { $avg *= $v; }
+        $avg **= 1/@{$totals[$i]};
+      } elsif ($mean eq "ari") {
+        $avg = 0.0;
+        foreach my $v (@{$totals[$i]}) { $avg += $v; }
+        $avg /= @{$totals[$i]};
+      }
+      printf "%.1f%%", 100 * $avg - 100;
+    }
+    print "\n";
+  }
+  @totals = ();
+}
+
+my ($lori, $lnew);
+while ($lori = <$fori> and $lnew = <$fnew>) {
+  chomp($lori);
+  chomp($lnew);
+
+  my @cori = split /;/, $lori;
+  my @cnew = split /;/, $lnew;
+
+  die "Nonequal number of columns on line $.!" if scalar(@cori) != scalar(@cnew);
+
+  for my $i (0..$#cori) {
+    my ($ori, $new) = ($cori[$i], $cnew[$i]);
+    die "Empty versus nonempty column $i on line $.!" if length($ori) > 0 && length($new) == 0;
+    die "Empty versus nonempty column $i on line $.!" if length($ori) == 0 && length($new) > 0;
+
+    print ";" if $i > 0;
+    if ($ori =~ /^[0-9.e+-]+$/ && $new =~ /^[0-9.e+-]+$/) {
+      printf "%.1f%%", 100 * $new / $ori - 100;
+      $totals[$i] = [] unless defined $totals[$i];
+      push @{$totals[$i]}, $new / $ori;
+    } elsif ($ori ne $new) {
+      die "Different nonnumeric column $i on line $., '$ori' vs '$new'!";
+    } else {
+      print $ori;
+    }
+  }
+  print_totals unless @cori;
+  print "\n";
+}
+print_totals if @totals;
diff --git a/scripts/cmp.sh b/scripts/cmp.sh
new file mode 100644
--- /dev/null
+++ b/scripts/cmp.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+perl ${0%cmp.sh}cmp.pl "$1" "$2" | column -nts\; | less -S
diff --git a/scripts/collect.pl b/scripts/collect.pl
new file mode 100644
--- /dev/null
+++ b/scripts/collect.pl
@@ -0,0 +1,75 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+-d $ARGV[0] or die "Missing name of directory to collect!";
+
+sub read_csv($) {
+  chomp(my $line = $_[0]);
+  $line =~ /^"?([^,"]*)"?,([^,]*)(,|$)/ or die "Bad line $line!";
+  return ($1, $2);
+}
+
+my %tests;
+my %variants;
+
+# Read individual results
+foreach my $csv (glob "$ARGV[0]/*[!m].csv") {
+  # Read time
+  $csv =~ m#/([^/]*)_[0-9]*m?.csv$# or die "Bad csv filename $csv!";
+  my $variant = $1;
+  $variants{$variant} = 1;
+  open(my $f,"<", $csv) or die "Cannot open file $csv!";
+  my $_header = <$f>;
+  foreach my $line (<$f>) {
+    my ($name, $res) = read_csv($line);
+    $tests{$name} = {} unless exists $tests{$name};
+    exists $tests{$name}->{$variant} and die "Repeated data $name-$variant!";
+    $tests{$name}->{$variant} = [$res];
+  }
+  close($f);
+
+  # Read memory
+  $csv =~ s#\.csv$#m.csv# or die "Bad csv filenaem $csv!";
+  open($f,"<", $csv) or die "Cannot open file $csv!";
+  $_header = <$f>;
+  foreach my $line (<$f>) {
+    my ($name, $res) = read_csv($line);
+    length @{$tests{$name}->{$variant}} == 1 or die "Repeated data $name-$variant!";
+    push @{$tests{$name}->{$variant}}, $res;
+  }
+  close($f);
+}
+
+# Write merged csv
+open (my $f, ">", "$ARGV[0].csv") or die "Cannot open $ARGV[0].csv!";
+print $f ";";
+foreach my $v (sort keys %variants) {
+  print $f "$v;;";
+}
+print $f "\n";
+
+foreach my $test (sort keys %tests) {
+  print $f "$test;";
+  foreach my $v (sort keys %variants) {
+    if (exists $tests{$test}->{$v}) {
+      print $f "$tests{$test}->{$v}->[0];$tests{$test}->{$v}->[1];";
+    } else {
+      print $f ";;";
+    }
+  }
+  print $f "\n";
+}
+
+# Write sizes of benchmark and modules.
+print $f "\nFile;Size\n";
+foreach my $n ("../dist/build/benchmark/benchmark",
+               "../dist/build/benchmark/benchmark-tmp/Container/Map.o",
+               "../dist/build/benchmark/benchmark-tmp/Container/Set.o",
+               "../dist/build/benchmark/benchmark-tmp/Container/IntMap.o",
+               "../dist/build/benchmark/benchmark-tmp/Container/IntSet.o") {
+  $n =~ m#/([^/]*)$#;
+  print $f "$1;" . (-s $n) . "\n";
+}
+
+close($f);
diff --git a/scripts/compile.sh b/scripts/compile.sh
new file mode 100644
--- /dev/null
+++ b/scripts/compile.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+if [ "$1" = none ]
+then
+  echo Using default containers
+  sh system_containers.sh
+else
+  echo Using containers from $1
+  sh custom_containers.sh $1 || { echo Containers repo not found in $1; exit 1; }
+fi
+shift
+
+(cd .. && cabal clean && cabal configure "$@" && cabal build && strip dist/build/benchmark/benchmark )
diff --git a/scripts/custom_containers.sh b/scripts/custom_containers.sh
new file mode 100644
--- /dev/null
+++ b/scripts/custom_containers.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+# This package _manually_ sets options for the containers
+# repo used. We could extract the options from cabal file
+# of from setup-config created by cabal configure.
+
+set -e
+
+FLAGS=-O2
+if grep -q '0\.3\.0\.0' $1/containers.cabal
+then
+  FLAGS="$FLAGS -cpp -XMagicHash"
+else
+  FLAGS="$FLAGS -fregs-graph"
+fi
+
+for c in Map Set IntMap IntSet
+do
+  cat "$1/Data/$c.hs" | sed '
+    1i {-# OPTIONS_GHC '"$FLAGS"' #-}
+    s/Data\.\(IntMap\|IntSet\|Map\|Set\)/Container.\1/
+  ' >../src/Container/$c.hs
+done
diff --git a/scripts/ghc.sh b/scripts/ghc.sh
new file mode 100644
--- /dev/null
+++ b/scripts/ghc.sh
@@ -0,0 +1,38 @@
+#!/bin.sh
+
+set -e
+
+function usage {
+  echo Usage: ghc.sh containers_repo ghc_repo result.csv
+}
+
+[ -d "$1" ] || { usage; exit 1; }
+[ -d "$2" ] || { usage; exit 1; }
+[ -n "$3" ] || { usage; exit 1; }
+
+# 1) get ready the GHC source tree
+cp "$1/containers.cabal" "$2/libraries/containers/"
+cp "$1/Data/IntMap.hs"   "$2/libraries/containers/Data/"
+cp "$1/Data/IntSet.hs"   "$2/libraries/containers/Data/"
+cp "$1/Data/Map.hs"      "$2/libraries/containers/Data/"
+cp "$1/Data/Set.hs"      "$2/libraries/containers/Data/"
+
+# 2) build GHC
+(cd "$2" && make -j4)
+
+# 3) collect the results
+> "$3"
+echo "File;Size" > "$3"
+stat -c "ghc-stage2;%s" "$2/inplace/lib/ghc-stage2" >> "$3"
+cp "$2/inplace/lib/ghc-stage2" /tmp/ghc-stage2
+strip /tmp/ghc-stage2
+stat -c "ghc-stage2 (stripped);%s" /tmp/ghc-stage2 >> "$3"
+rm /tmp/ghc-stage2
+
+echo -e "\nTest;Bytes allocated" >> "$3"
+(cd "$2/testsuite/tests/ghc-regress/perf/compiler/" && make)
+for t in T1969 T3294
+do
+  echo -n "$t;" >> "$3"
+  sed -n 's/^.*bytes allocated.*"\([0-9]*\)".*$/\1/;T;p' "$2/testsuite/tests/ghc-regress/perf/compiler/$t.comp.stats" >> "$3"
+done
diff --git a/scripts/run.sh b/scripts/run.sh
new file mode 100644
--- /dev/null
+++ b/scripts/run.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+[ -f "../dist/build/benchmark/benchmark" ] || { echo Compile the benchmark first!; exit 1; }
+[ -n "$1" ] || { echo Missing name of the benchmark run!; exit 1; }
+
+[ -d "$1" ] || mkdir "$1"
+
+for c in IntMap IntSet Map Set
+do
+   for b in "Int " "IntegerSmall " "IntegerBig " "String 8" "String 50" "ByteString 8" "ByteString 50"
+   do
+     [ "$c" = IntMap -o "$c" = IntSet ] && [ "$b" != "Int " ] && continue
+
+     for l in 1000 50000
+     do
+       (
+       csv="$1/${c}_${b% *}${b#* }_$l.csv"
+       csvm="${csv%.csv}m.csv"
+
+       # Time benchmarks
+       ../dist/build/benchmark/benchmark ${c}_$b $l -s 25 -g -u "$csv"
+
+       # Memory benchmarks
+       benchs=`tail -n+2 $csv | cut -d, -f1 | tr -d \"`
+       case $b in
+         Int*) repetitions=`expr 500000 / $l`;;
+         *String*8) repetitions=`expr 100000 / $l`;;
+         *String*50) repetitions=`expr 50000 / $l`;;
+       esac
+
+       head -1 "$csv" > "$csvm"
+       for bench in $benchs
+       do
+         echo -n \"$bench\", >> "$csvm"
+         ../dist/build/benchmark/benchmark ${c}_$b $l raw $bench $repetitions +RTS -t 2>&1 | sed -n "s/^.*ghc: \([0-9]*\) bytes.*$/\1/p" >> "$csvm"
+       done
+       ) &
+     done
+     wait
+
+   done
+done
diff --git a/scripts/see.sh b/scripts/see.sh
new file mode 100644
--- /dev/null
+++ b/scripts/see.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+perl -pe '
+  @res = ();
+  foreach $p (split /;/) {
+    if ($p > 0 && $p < 1000) {
+      push @res, sprintf("%.1e", $p);
+    } elsif ($p >= 1000) {
+      push @res, sprintf("%.0fMB", $p >> 20);
+    } else {
+      push @res, $p;
+    }
+  }
+  $_ = join ";", @res;
+' | column -nts\; | less -S
diff --git a/scripts/system_containers.sh b/scripts/system_containers.sh
new file mode 100644
--- /dev/null
+++ b/scripts/system_containers.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+for c in Map Set IntMap IntSet
+do
+  cat >../src/Container/$c.hs <<EOF
+module Container.$c (module Data.$c) where
+
+import Data.$c
+EOF
+done
diff --git a/src/Benchmark/Map-like.inc.hs b/src/Benchmark/Map-like.inc.hs
new file mode 100644
--- /dev/null
+++ b/src/Benchmark/Map-like.inc.hs
@@ -0,0 +1,58 @@
+create list = C.fromList (zip list list)
+benchs = [ ("insert", bench_insert)
+         , ("lookup0", bench_lookup0)
+         , ("lookup50", bench_lookup50)
+         , ("lookup100", bench_lookup100)
+         , ("delete", bench_delete)
+         , ("alter-insert", bench_alterinsert)
+         , ("alter-delete", bench_alterdelete)
+         , ("union", bench_union)
+         , ("difference", bench_difference)
+         , ("intersection", bench_intersection)
+         , ("fold-list", bench_foldlist)
+#ifdef FOLD_SUM
+         , ("fold-sum", bench_foldsum)
+#endif
+         ]
+
+bench_insert (list, _, _, _) = go C.empty list
+  where go !c [] = ()
+        go !c (x:xs) = go (C.insert x x c) xs
+
+bench_lookup100 (list, c, _, _) = go c list
+  where go c [] = ()
+        go c (x:xs) = C.lookup x c `seq` go c xs
+
+bench_lookup50 (list, _, _, c_odd) = go c_odd list
+  where go c [] = ()
+        go c (x:xs) = C.lookup x c `seq` go c xs
+
+bench_lookup0 (list, _, _, c_odd) = go c_odd list
+  where go c [] = ()
+        go c [_] = ()
+        go c (_:x:xs) = C.lookup x c `seq` go c xs
+
+bench_delete (list, c, _, _) = go c list
+  where go !c [] = ()
+        go !c (x:xs) = go (C.delete x c) xs
+
+bench_alterinsert (list, _, _, _) = go C.empty list
+  where go !c [] = ()
+        go !c (x:xs) = go (C.alter (const $ Just x) x c) xs
+
+bench_alterdelete (list, c, _, _) = go c list
+  where go !c [] = ()
+        go !c (x:xs) = go (C.alter (const $ Nothing) x c) xs
+
+bench_union (_, _, c_even, c_odd) = C.union c_even c_odd `seq` ()
+
+bench_difference (_, c, c_even, _) = C.difference c c_even `seq` ()
+
+bench_intersection (_, c, c_even, _) = C.intersection c c_even `seq` ()
+
+bench_foldlist (_, c, _, _) = force $ C.fold (:) [] c
+  where force list = length list `seq` ()
+
+#ifdef FOLD_SUM
+bench_foldsum (_, c, _, _) = C.fold (+) 0 c `seq` ()
+#endif
diff --git a/src/Benchmark/Set-like.inc.hs b/src/Benchmark/Set-like.inc.hs
new file mode 100644
--- /dev/null
+++ b/src/Benchmark/Set-like.inc.hs
@@ -0,0 +1,48 @@
+create list = C.fromList list
+benchs = [ ("insert", bench_insert)
+         , ("member0", bench_member0)
+         , ("member50", bench_member50)
+         , ("member100", bench_member100)
+         , ("delete", bench_delete)
+         , ("union", bench_union)
+         , ("difference", bench_difference)
+         , ("intersection", bench_intersection)
+         , ("fold-list", bench_foldlist)
+#ifdef FOLD_SUM
+         , ("fold-sum", bench_foldsum)
+#endif
+         ]
+
+bench_insert (list, _, _, _) = go C.empty list
+  where go !c [] = ()
+        go !c (x:xs) = go (C.insert x c) xs
+
+bench_member100 (list, c, _, _) = go c list
+  where go c [] = ()
+        go c (x:xs) = C.member x c `seq` go c xs
+
+bench_member50 (list, _, _, c_odd) = go c_odd list
+  where go c [] = ()
+        go c (x:xs) = C.member x c `seq` go c xs
+
+bench_member0 (list, _, _, c_odd) = go c_odd list
+  where go c [] = ()
+        go c [_] = ()
+        go c (_:x:xs) = C.member x c `seq` go c xs
+
+bench_delete (list, c, _, _) = go c list
+  where go !c [] = ()
+        go !c (x:xs) = go (C.delete x c) xs
+
+bench_union (_, _, c_even, c_odd) = C.union c_even c_odd `seq` ()
+
+bench_difference (_, c, c_even, _) = C.difference c c_even `seq` ()
+
+bench_intersection (_, c, c_even, _) = C.intersection c c_even `seq` ()
+
+bench_foldlist (_, c, _, _) = force $ C.fold (:) [] c
+  where force list = length list `seq` ()
+
+#ifdef FOLD_SUM
+bench_foldsum (_, c, _, _) = C.fold (+) 0 c `seq` ()
+#endif
diff --git a/src/Container/IntMap.hs b/src/Container/IntMap.hs
new file mode 100644
--- /dev/null
+++ b/src/Container/IntMap.hs
@@ -0,0 +1,3 @@
+module Container.IntMap (module Data.IntMap) where
+
+import Data.IntMap
diff --git a/src/Container/IntSet.hs b/src/Container/IntSet.hs
new file mode 100644
--- /dev/null
+++ b/src/Container/IntSet.hs
@@ -0,0 +1,3 @@
+module Container.IntSet (module Data.IntSet) where
+
+import Data.IntSet
diff --git a/src/Container/Map.hs b/src/Container/Map.hs
new file mode 100644
--- /dev/null
+++ b/src/Container/Map.hs
@@ -0,0 +1,3 @@
+module Container.Map (module Data.Map) where
+
+import Data.Map
diff --git a/src/Container/Set.hs b/src/Container/Set.hs
new file mode 100644
--- /dev/null
+++ b/src/Container/Set.hs
@@ -0,0 +1,3 @@
+module Container.Set (module Data.Set) where
+
+import Data.Set
diff --git a/src/Driver.inc.hs b/src/Driver.inc.hs
new file mode 100644
--- /dev/null
+++ b/src/Driver.inc.hs
@@ -0,0 +1,40 @@
+import Criterion.Main (bench, defaultMain, whnf)
+import System.Environment (getArgs, withArgs)
+
+bench_criterion benchs =
+  defaultMain $ map (\(name, method, input) -> bench name (whnf method input)) benchs
+
+bench_raw benchs = do
+  bencharg : numreparg : _ <- getArgs
+  let [(_, method, input)] = filter (\(name, _, _) -> name == bencharg) benchs
+      numrep = read numreparg
+  go numrep method input
+
+ where
+  go !0 _      _     = return ()
+  go !n method input = method input `seq` go (n-1) method input
+
+driver asc rnd = do
+  lenarg : args <- getArgs
+
+  let len = read lenarg
+      asc_list = asc len
+      asc_data = (asc_list, create asc_list, create (even asc_list), create (odd asc_list))
+      rnd_list = rnd len
+      rnd_data = (rnd_list, create rnd_list, create (even rnd_list), create (odd rnd_list))
+      benchs' = concatMap ( \(name, method) -> [(name ++ "_asc" ++ lenarg, method, asc_data),
+                                                (name ++ "_rnd" ++ lenarg, method, rnd_data)]
+                          ) benchs
+
+  case args of
+    "raw" : args' -> withArgs args' $ bench_raw benchs'
+    args'         -> withArgs args' $ bench_criterion benchs'
+
+ where
+  even []       = []
+  even [_]      = []
+  even (_:x:xs) = x : even xs
+
+  odd []       = []
+  odd [x]      = [x]
+  odd (x:_:xs) = x : odd xs
diff --git a/src/InputData/ByteString.hs b/src/InputData/ByteString.hs
new file mode 100644
--- /dev/null
+++ b/src/InputData/ByteString.hs
@@ -0,0 +1,11 @@
+module InputData.ByteString ( asc
+                            , rnd
+                            ) where
+import Data.ByteString.Char8 (ByteString, pack)
+import qualified InputData.String
+
+asc :: Int -> Int -> [ByteString]
+asc strlen num = map pack $ InputData.String.asc strlen num
+
+rnd :: Int -> Int -> [ByteString]
+rnd strlen num = map pack $ InputData.String.rnd strlen num
diff --git a/src/InputData/Int.hs b/src/InputData/Int.hs
new file mode 100644
--- /dev/null
+++ b/src/InputData/Int.hs
@@ -0,0 +1,10 @@
+module InputData.Int ( asc
+                     , rnd
+                     ) where
+import System.Random (mkStdGen, randomRs)
+
+asc :: Int -> [Int]
+asc len = [1..len]
+
+rnd :: Int -> [Int]
+rnd len = take len $ randomRs (0,1000 * len) $ mkStdGen 1234
diff --git a/src/InputData/IntegerBig.hs b/src/InputData/IntegerBig.hs
new file mode 100644
--- /dev/null
+++ b/src/InputData/IntegerBig.hs
@@ -0,0 +1,10 @@
+module InputData.IntegerBig ( asc
+                            , rnd
+                            ) where
+import System.Random (mkStdGen, randomRs)
+
+asc :: Int -> [Integer]
+asc len = [0, 2^64 .. 2^64 * (fromIntegral len - 1)]
+
+rnd :: Int -> [Integer]
+rnd len = take len $ randomRs (0, 1000 * 2^64 * (fromIntegral len - 1)) $ mkStdGen 1234
diff --git a/src/InputData/IntegerSmall.hs b/src/InputData/IntegerSmall.hs
new file mode 100644
--- /dev/null
+++ b/src/InputData/IntegerSmall.hs
@@ -0,0 +1,10 @@
+module InputData.IntegerSmall ( asc
+                              , rnd
+                              ) where
+import System.Random (mkStdGen, randomRs)
+
+asc :: Int -> [Integer]
+asc len = [1..fromIntegral len]
+
+rnd :: Int -> [Integer]
+rnd len = take len $ randomRs (0,1000 * fromIntegral len) $ mkStdGen 1234
diff --git a/src/InputData/String.hs b/src/InputData/String.hs
new file mode 100644
--- /dev/null
+++ b/src/InputData/String.hs
@@ -0,0 +1,16 @@
+module InputData.String ( asc
+                        , rnd
+                        ) where
+import System.Random (mkStdGen, randomRs)
+
+asc :: Int -> Int -> [String]
+asc strlen num = take num $ iterate (snd . inc) $ replicate strlen 'a'
+  where inc [] = (True, [])
+        inc (c:cs) = case inc cs of (True, cs') | c == 'z'  -> (True, 'a' : cs')
+                                                | otherwise -> (False, succ c : cs')
+                                    (False, cs')            -> (False, c : cs')
+
+rnd :: Int -> Int -> [String]
+rnd strlen num = take num $ split $ randomRs ('a', 'z') $ mkStdGen 1234
+  where
+    split cs = case splitAt strlen cs of (str, cs') -> str : split cs'
diff --git a/src/Main.hs b/src/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/Main.hs
@@ -0,0 +1,33 @@
+module Main where
+
+import System.Environment (getArgs, withArgs)
+
+import qualified Variants.IntMap_Int as IM_I
+import qualified Variants.IntSet_Int as IS_I
+import qualified Variants.Map_ByteString as M_BS
+import qualified Variants.Map_IntegerBig as M_IB
+import qualified Variants.Map_IntegerSmall as M_IS
+import qualified Variants.Map_Int as M_I
+import qualified Variants.Map_String as M_S
+import qualified Variants.Set_ByteString as S_BS
+import qualified Variants.Set_IntegerBig as S_IB
+import qualified Variants.Set_IntegerSmall as S_IS
+import qualified Variants.Set_Int as S_I
+import qualified Variants.Set_String as S_S
+
+main = do
+  variant : args <- getArgs
+  withArgs args $
+    case variant of
+      "IntMap_Int"       -> IM_I.benchmark
+      "IntSet_Int"       -> IS_I.benchmark
+      "Map_ByteString"   -> M_BS.benchmark
+      "Map_IntegerBig"   -> M_IB.benchmark
+      "Map_IntegerSmall" -> M_IS.benchmark
+      "Map_Int"          -> M_I.benchmark
+      "Map_String"       -> M_S.benchmark
+      "Set_ByteString"   -> S_BS.benchmark
+      "Set_IntegerBig"   -> S_IB.benchmark
+      "Set_IntegerSmall" -> S_IS.benchmark
+      "Set_Int"          -> S_I.benchmark
+      "Set_String"       -> S_S.benchmark
diff --git a/src/Variants/IntMap_Int.hs b/src/Variants/IntMap_Int.hs
new file mode 100644
--- /dev/null
+++ b/src/Variants/IntMap_Int.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE CPP, BangPatterns #-}
+
+module Variants.IntMap_Int ( benchmark ) where
+
+import qualified Container.IntMap as C
+import qualified InputData.Int
+#include "../Driver.inc.hs"
+
+#define FOLD_SUM
+#include "../Benchmark/Map-like.inc.hs"
+
+benchmark = driver (InputData.Int.asc) (InputData.Int.rnd)
diff --git a/src/Variants/IntSet_Int.hs b/src/Variants/IntSet_Int.hs
new file mode 100644
--- /dev/null
+++ b/src/Variants/IntSet_Int.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE CPP, BangPatterns #-}
+
+module Variants.IntSet_Int ( benchmark ) where
+
+import qualified Container.IntSet as C
+import qualified InputData.Int
+#include "../Driver.inc.hs"
+
+#define FOLD_SUM
+#include "../Benchmark/Set-like.inc.hs"
+
+benchmark = driver (InputData.Int.asc) (InputData.Int.rnd)
diff --git a/src/Variants/Map_ByteString.hs b/src/Variants/Map_ByteString.hs
new file mode 100644
--- /dev/null
+++ b/src/Variants/Map_ByteString.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE CPP, BangPatterns #-}
+
+module Variants.Map_ByteString ( benchmark ) where
+
+import qualified Container.Map as C
+import qualified InputData.ByteString
+#include "../Driver.inc.hs"
+
+#include "../Benchmark/Map-like.inc.hs"
+
+benchmark = do
+  strlenarg : args <- getArgs
+  let strlen = read strlenarg
+  withArgs args $ driver (InputData.ByteString.asc strlen) (InputData.ByteString.rnd strlen)
diff --git a/src/Variants/Map_Int.hs b/src/Variants/Map_Int.hs
new file mode 100644
--- /dev/null
+++ b/src/Variants/Map_Int.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE CPP, BangPatterns #-}
+
+module Variants.Map_Int ( benchmark ) where
+
+import qualified Container.Map as C
+import qualified InputData.Int
+#include "../Driver.inc.hs"
+
+#define FOLD_SUM
+#include "../Benchmark/Map-like.inc.hs"
+
+benchmark = driver (InputData.Int.asc) (InputData.Int.rnd)
diff --git a/src/Variants/Map_IntegerBig.hs b/src/Variants/Map_IntegerBig.hs
new file mode 100644
--- /dev/null
+++ b/src/Variants/Map_IntegerBig.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE CPP, BangPatterns #-}
+
+module Variants.Map_IntegerBig ( benchmark ) where
+
+import qualified Container.Map as C
+import qualified InputData.IntegerBig
+#include "../Driver.inc.hs"
+
+#define FOLD_SUM
+#include "../Benchmark/Map-like.inc.hs"
+
+benchmark = driver (InputData.IntegerBig.asc) (InputData.IntegerBig.rnd)
diff --git a/src/Variants/Map_IntegerSmall.hs b/src/Variants/Map_IntegerSmall.hs
new file mode 100644
--- /dev/null
+++ b/src/Variants/Map_IntegerSmall.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE CPP, BangPatterns #-}
+
+module Variants.Map_IntegerSmall ( benchmark ) where
+
+import qualified Container.Map as C
+import qualified InputData.IntegerSmall
+#include "../Driver.inc.hs"
+
+#define FOLD_SUM
+#include "../Benchmark/Map-like.inc.hs"
+
+benchmark = driver (InputData.IntegerSmall.asc) (InputData.IntegerSmall.rnd)
diff --git a/src/Variants/Map_String.hs b/src/Variants/Map_String.hs
new file mode 100644
--- /dev/null
+++ b/src/Variants/Map_String.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE CPP, BangPatterns #-}
+
+module Variants.Map_String ( benchmark ) where
+
+import qualified Container.Map as C
+import qualified InputData.String
+#include "../Driver.inc.hs"
+
+#include "../Benchmark/Map-like.inc.hs"
+
+benchmark = do
+  strlenarg : args <- getArgs
+  let strlen = read strlenarg
+  withArgs args $ driver (InputData.String.asc strlen) (InputData.String.rnd strlen)
diff --git a/src/Variants/Set_ByteString.hs b/src/Variants/Set_ByteString.hs
new file mode 100644
--- /dev/null
+++ b/src/Variants/Set_ByteString.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE CPP, BangPatterns #-}
+
+module Variants.Set_ByteString ( benchmark ) where
+
+import qualified Container.Set as C
+import qualified InputData.ByteString
+#include "../Driver.inc.hs"
+
+#include "../Benchmark/Set-like.inc.hs"
+
+benchmark = do
+  strlenarg : args <- getArgs
+  let strlen = read strlenarg
+  withArgs args $ driver (InputData.ByteString.asc strlen) (InputData.ByteString.rnd strlen)
diff --git a/src/Variants/Set_Int.hs b/src/Variants/Set_Int.hs
new file mode 100644
--- /dev/null
+++ b/src/Variants/Set_Int.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE CPP, BangPatterns #-}
+
+module Variants.Set_Int ( benchmark ) where
+
+import qualified Container.Set as C
+import qualified InputData.Int
+#include "../Driver.inc.hs"
+
+#define FOLD_SUM
+#include "../Benchmark/Set-like.inc.hs"
+
+benchmark = driver (InputData.Int.asc) (InputData.Int.rnd)
diff --git a/src/Variants/Set_IntegerBig.hs b/src/Variants/Set_IntegerBig.hs
new file mode 100644
--- /dev/null
+++ b/src/Variants/Set_IntegerBig.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE CPP, BangPatterns #-}
+
+module Variants.Set_IntegerBig ( benchmark ) where
+
+import qualified Container.Set as C
+import qualified InputData.IntegerBig
+#include "../Driver.inc.hs"
+
+#define FOLD_SUM
+#include "../Benchmark/Set-like.inc.hs"
+
+benchmark = driver (InputData.IntegerBig.asc) (InputData.IntegerBig.rnd)
diff --git a/src/Variants/Set_IntegerSmall.hs b/src/Variants/Set_IntegerSmall.hs
new file mode 100644
--- /dev/null
+++ b/src/Variants/Set_IntegerSmall.hs
@@ -0,0 +1,12 @@
+{-# LANGUAGE CPP, BangPatterns #-}
+
+module Variants.Set_IntegerSmall ( benchmark ) where
+
+import qualified Container.Set as C
+import qualified InputData.IntegerSmall
+#include "../Driver.inc.hs"
+
+#define FOLD_SUM
+#include "../Benchmark/Set-like.inc.hs"
+
+benchmark = driver (InputData.IntegerSmall.asc) (InputData.IntegerSmall.rnd)
diff --git a/src/Variants/Set_String.hs b/src/Variants/Set_String.hs
new file mode 100644
--- /dev/null
+++ b/src/Variants/Set_String.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE CPP, BangPatterns #-}
+
+module Variants.Set_String ( benchmark ) where
+
+import qualified Container.Set as C
+import qualified InputData.String
+#include "../Driver.inc.hs"
+
+#include "../Benchmark/Set-like.inc.hs"
+
+benchmark = do
+  strlenarg : args <- getArgs
+  let strlen = read strlenarg
+  withArgs args $ driver (InputData.String.asc strlen) (InputData.String.rnd strlen)
diff --git a/src/Variants/gen.sh b/src/Variants/gen.sh
new file mode 100644
--- /dev/null
+++ b/src/Variants/gen.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+for c in Map Set IntMap IntSet
+do
+  for i in Int IntegerSmall IntegerBig String ByteString
+  do
+    [ "$c" = IntMap -o "$c" = IntSet ] && [ "$i" != Int ] && continue
+
+    case $i in
+      Int | IntegerSmall | IntegerBig)
+        addons="
+#define FOLD_SUM";
+        benchmark="
+benchmark = driver (InputData.$i.asc) (InputData.$i.rnd)";;
+
+      String | ByteString)
+        addons="";
+        benchmark="
+benchmark = do
+  strlenarg : args <- getArgs
+  let strlen = read strlenarg
+  withArgs args $ driver (InputData.$i.asc strlen) (InputData.$i.rnd strlen)";;
+    esac
+
+    cat >${c}_$i.hs <<EOF
+{-# LANGUAGE CPP, BangPatterns #-}
+
+module Variants.${c}_$i ( benchmark ) where
+
+import qualified Container.$c as C
+import qualified InputData.$i
+#include "../Driver.inc.hs"
+$addons
+#include "../Benchmark/${c#Int}-like.inc.hs"
+$benchmark
+EOF
+  done
+done
