diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7cdd83db10fbcf980a219ca2ef4f5f7aa6605d54..46cbc36922f536aa1e7214092b3600e2fe59d044 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -25,7 +25,9 @@ stages:
   - initialize
   - compile
   - generate
-  - process
+  - simulate
+  - reconstruct
+  - analyze
   - collect
   - finish
 
diff --git a/benchmarks/dis/config.yml b/benchmarks/dis/config.yml
index c5bcbb2a29f3c873ed2438789880df0d46459826..2277cb7ba60faa993d2c437a568ef1e3a204c8af 100644
--- a/benchmarks/dis/config.yml
+++ b/benchmarks/dis/config.yml
@@ -20,8 +20,8 @@ dis:generate:
   script:
     - bash benchmarks/dis/get.sh --config dis_${EBEAM}x${PBEAM} --ebeam ${EBEAM} --pbeam ${PBEAM}
 
-dis:process:
-  stage: process
+dis:simulate:
+  stage: simulate
   extends: .phy_benchmark
   needs: ["dis:generate"]
   parallel:
@@ -42,6 +42,6 @@ dis:process:
 
 dis:results:
   stage: collect
-  needs: ["dis:process"]
+  needs: ["dis:simulate"]
   script:
     - collect_tests.py dis
diff --git a/benchmarks/dvcs/config.yml b/benchmarks/dvcs/config.yml
index e1648bd338e91369a661fc247ed3135a0fd00bec..12a1bf6906d538ede294dfc44ee2de3c852baa92 100644
--- a/benchmarks/dvcs/config.yml
+++ b/benchmarks/dvcs/config.yml
@@ -4,8 +4,8 @@ dvcs:compile:
   script:
     - compile_analyses.py dvcs
 
-dvcs:process:
-  stage: process
+dvcs:simulate:
+  stage: simulate
   extends: .phy_benchmark
   tags:
     - phy
@@ -16,7 +16,7 @@ dvcs:process:
 
 dvcs:results:
   stage: collect
-  needs: ["dvcs:process"]
+  needs: ["dvcs:simulate"]
   script:
     - ls -lrth
       #pip install junitparser
diff --git a/benchmarks/dvmp/config.yml b/benchmarks/dvmp/config.yml
index ab66e16ab95f1ea457b75d758756194084bb34e3..d90a0be911354b06850c9409aec14e516b9b123a 100644
--- a/benchmarks/dvmp/config.yml
+++ b/benchmarks/dvmp/config.yml
@@ -17,8 +17,8 @@ dvmp:generate:
           --decay muon --decay electron
           --nproc 5
 
-dvmp:process:
-  stage: process
+dvmp:simulate:
+  stage: simulate
   extends: .phy_benchmark
   needs: ["dvmp:generate"]
   timeout: 2 hour
@@ -37,6 +37,6 @@ dvmp:process:
 
 dvmp:results:
   stage: collect
-  needs: ["dvmp:process"]
+  needs: ["dvmp:simulate"]
   script:
     - collect_tests.py dvmp
diff --git a/benchmarks/single/analyze.sh b/benchmarks/single/analyze.sh
new file mode 100644
index 0000000000000000000000000000000000000000..e9931c7845079934e82ade47c71c29693f41bac6
--- /dev/null
+++ b/benchmarks/single/analyze.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+source $(dirname $0)/common.sh $*
+
+# Analyze
+root -l -b -q "benchmarks/single/analysis/analyze.cxx+(\"${JUGGLER_REC_FILE}\")"
+if [[ "$?" -ne "0" ]] ; then
+  echo "ERROR analysis failed"
+  exit 1
+fi
diff --git a/benchmarks/single/common.sh b/benchmarks/single/common.sh
new file mode 100644
index 0000000000000000000000000000000000000000..e7ef78aef96ecfffd4e115cb289f38aa9808e29f
--- /dev/null
+++ b/benchmarks/single/common.sh
@@ -0,0 +1,8 @@
+if [[ ! -n  "${JUGGLER_N_EVENTS}" ]] ; then 
+  export JUGGLER_N_EVENTS=100
+fi
+
+export JUGGLER_FILE_NAME_TAG="${1:-e-_1GeV_45to135deg}"
+export JUGGLER_GEN_FILE="benchmarks/single/${JUGGLER_FILE_NAME_TAG}.steer"
+export JUGGLER_SIM_FILE="sim_output/sim_${JUGGLER_FILE_NAME_TAG}.edm4hep.root"
+export JUGGLER_REC_FILE="sim_output/rec_${JUGGLER_FILE_NAME_TAG}.root"
diff --git a/benchmarks/single/config.yml b/benchmarks/single/config.yml
index cac524ca8b03a85348f6562c0f988514ee0213d7..291bdeb5df60f9320824a1ce2b56990e5535a2f5 100644
--- a/benchmarks/single/config.yml
+++ b/benchmarks/single/config.yml
@@ -4,10 +4,26 @@ single:compile:
   script:
     - compile_analyses.py single
 
-single:process:
+single:simulate:
   extends: .phy_benchmark
-  timeout: 24 hours
-  stage: process
-  needs: ["common:detector", "single:compile"]
+  timeout: 2 hours
+  stage: simulate
+  needs: ["common:detector"]
   script:
-    - bash benchmarks/single/single.sh e-_1GeV_45to135deg
+    - bash benchmarks/single/simulate.sh e-_1GeV_45to135deg
+
+single:reconstruct:
+  extends: .phy_benchmark
+  timeout: 2 hours
+  stage: reconstruct
+  needs: ["single:simulate"]
+  script:
+    - bash benchmarks/single/reconstruct.sh e-_1GeV_45to135deg
+
+single:analyze:
+  extends: .phy_benchmark
+  timeout: 2 hours
+  stage: analyze
+  needs: ["single:reconstruct", "single:compile"]
+  script:
+    - bash benchmarks/single/analyze.sh e-_1GeV_45to135deg
diff --git a/benchmarks/single/reconstruct.sh b/benchmarks/single/reconstruct.sh
new file mode 100644
index 0000000000000000000000000000000000000000..7c9d611323b24e137d30dd9c3dea3253b3edebf6
--- /dev/null
+++ b/benchmarks/single/reconstruct.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+source $(dirname $0)/common.sh $*
+
+# Reconstruct
+for rec in options/*.py ; do
+  unset tag
+  [[ $(basename ${rec} .py) =~ (.*)\.(.*) ]] && tag=".${BASH_REMATCH[2]}"
+  JUGGLER_REC_FILE=${JUGGLER_REC_FILE/.root/${tag:-}.root} \
+    gaudirun.py ${JUGGLER_GAUDI_OPTIONS:-} ${rec}
+  if [[ "$?" -ne "0" ]] ; then
+    echo "ERROR running juggler"
+    exit 1
+  fi
+done
diff --git a/benchmarks/single/simulate.sh b/benchmarks/single/simulate.sh
new file mode 100644
index 0000000000000000000000000000000000000000..ddb191a8d8e6012a12dbbd3bf9fbb04dc6acdd96
--- /dev/null
+++ b/benchmarks/single/simulate.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+source $(dirname $0)/common.sh $*
+
+# Simulate
+ddsim --runType run \
+      --printLevel WARNING \
+      --enableGun \
+      --steeringFile ${JUGGLER_GEN_FILE} \
+      --numberOfEvents ${JUGGLER_N_EVENTS} \
+      --part.minimalKineticEnergy 1*TeV  \
+      --filter.tracker edep0 \
+      --compactFile ${DETECTOR_PATH}/${JUGGLER_DETECTOR}.xml \
+      --outputFile  ${JUGGLER_SIM_FILE}
+if [[ "$?" -ne "0" ]] ; then
+  echo "ERROR running ddsim"
+  exit 1
+fi
diff --git a/benchmarks/single/single.sh b/benchmarks/single/single.sh
deleted file mode 100644
index f4b4c9cc65194d1d65c99b85f20d26083a750750..0000000000000000000000000000000000000000
--- a/benchmarks/single/single.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/bash
-
-if [[ ! -n  "${JUGGLER_N_EVENTS}" ]] ; then 
-  export JUGGLER_N_EVENTS=100
-fi
-
-export JUGGLER_FILE_NAME_TAG="${1:-e-_1GeV_45to135deg}"
-export JUGGLER_GEN_FILE="benchmarks/single/${JUGGLER_FILE_NAME_TAG}.steer"
-export JUGGLER_SIM_FILE="sim_${JUGGLER_FILE_NAME_TAG}.edm4hep.root"
-export JUGGLER_REC_FILE="rec_${JUGGLER_FILE_NAME_TAG}.root"
-
-# Simulate
-ddsim --runType run \
-      --printLevel WARNING \
-      --enableGun \
-      --steeringFile ${JUGGLER_GEN_FILE} \
-      --numberOfEvents ${JUGGLER_N_EVENTS} \
-      --part.minimalKineticEnergy 1*TeV  \
-      --filter.tracker edep0 \
-      --compactFile ${DETECTOR_PATH}/${JUGGLER_DETECTOR}.xml \
-      --outputFile  ${JUGGLER_SIM_FILE}
-if [[ "$?" -ne "0" ]] ; then
-  echo "ERROR running ddsim"
-  exit 1
-fi
-
-# Reconstruct
-for rec in options/*.py ; do
-  unset tag
-  [[ $(basename ${rec} .py) =~ (.*)\.(.*) ]] && tag=".${BASH_REMATCH[2]}"
-  JUGGLER_REC_FILE=${JUGGLER_REC_FILE/.root/${tag:-}.root} \
-    gaudirun.py ${rec}
-  if [[ "$?" -ne "0" ]] ; then
-    echo "ERROR running juggler"
-    exit 1
-  fi
-done
-
-# Analysis
-root -l -b -q "benchmarks/single/analysis/analyze.cxx+(\"${JUGGLER_REC_FILE}\")"
-if [[ "$?" -ne "0" ]] ; then
-  echo "ERROR analysis failed"
-  exit 1
-fi
diff --git a/benchmarks/synchrotron/config.yml b/benchmarks/synchrotron/config.yml
index bf95232d8ea60ef21b03e5edfd935c09aaa1d34a..f1664212fc31b53867957df4bc5a06e8d8184387 100644
--- a/benchmarks/synchrotron/config.yml
+++ b/benchmarks/synchrotron/config.yml
@@ -4,8 +4,8 @@ synchrotron:compile:
   script:
     - compile_analyses.py synchrotron
 
-synchrotron:process:
-  stage: process
+synchrotron:simulate:
+  stage: simulate
   extends: .phy_benchmark
   tags:
     - s3
@@ -15,6 +15,6 @@ synchrotron:process:
 
 synchrotron:results:
   stage: collect
-  needs: ["synchrotron:process"]
+  needs: ["synchrotron:simulate"]
   script:
     - ls -lrth
diff --git a/benchmarks/tcs/config.yml b/benchmarks/tcs/config.yml
index 1fa13e1a0a3857edb85aa0628c8d894e92665402..35cf71533d5a87c8d6efe1dad43fee03ab8b1481 100644
--- a/benchmarks/tcs/config.yml
+++ b/benchmarks/tcs/config.yml
@@ -4,8 +4,8 @@ tcs:compile:
   script:
     - compile_analyses.py tcs
 
-tcs:process:
-  stage: process
+tcs:simulate:
+  stage: simulate
   extends: .phy_benchmark
   tags:
     - phy
@@ -27,6 +27,6 @@ tcs:process:
 
 tcs:results:
   stage: collect
-  needs: ["tcs:process"]
+  needs: ["tcs:simulate"]
   script:
     - ls -lrth
diff --git a/benchmarks/u_omega/config.yml b/benchmarks/u_omega/config.yml
index cca2b656832e071c86fe6219b2e65c418c3126e2..e53ce1a3a585e1c2dd8518fc4aaf3914bc1e789c 100644
--- a/benchmarks/u_omega/config.yml
+++ b/benchmarks/u_omega/config.yml
@@ -4,8 +4,8 @@ u_omega:compile:
   script:
     - compile_analyses.py u_omega
 
-u_omega:process:
-  stage: process
+u_omega:simulate:
+  stage: simulate
   extends: .phy_benchmark
   tags:
     - phy
@@ -16,6 +16,6 @@ u_omega:process:
 
 u_omega:results:
   stage: collect
-  needs: ["u_omega:process"]
+  needs: ["u_omega:simulate"]
   script:
     - ls -lrth