diff --git a/Cargo.lock b/Cargo.lock
index 170a7f3e5edd54afa809a2874a2b364d4d9b7d7f..61cde7f161b7c4177cb781addeb2f484af3b7477 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1493,6 +1493,7 @@ version = "0.1.0"
 dependencies = [
  "async-std",
  "clap",
+ "criterion",
  "hercules_rt",
  "juno_build",
  "nom 8.0.0",
diff --git a/juno_samples/rodinia/srad/Cargo.toml b/juno_samples/rodinia/srad/Cargo.toml
index e41a8871d3694045d42206028d56c429698e41fc..facf8c3bc7c92fe0b77dd85900c3e53307d358e5 100644
--- a/juno_samples/rodinia/srad/Cargo.toml
+++ b/juno_samples/rodinia/srad/Cargo.toml
@@ -8,6 +8,9 @@ edition = "2021"
 name = "juno_srad"
 path = "src/main.rs"
 
+[lib]
+path = "src/lib.rs"
+
 [features]
 cuda = ["juno_build/cuda", "hercules_rt/cuda"]
 
@@ -21,3 +24,10 @@ async-std = "*"
 clap = { version = "*", features = ["derive"] }
 with_builtin_macros = "0.1.0"
 nom = "*"
+
+[dev-dependencies]
+criterion = { version = "0.5", features = ["html_reports"] }
+
+[[bench]]
+name = "srad_bench"
+harness = false
diff --git a/juno_samples/rodinia/srad/benches/srad_bench.rs b/juno_samples/rodinia/srad/benches/srad_bench.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d327454002a6f9cabe4c40f74098570ea0d22d66
--- /dev/null
+++ b/juno_samples/rodinia/srad/benches/srad_bench.rs
@@ -0,0 +1,62 @@
+#![feature(concat_idents)]
+use criterion::{criterion_group, criterion_main, Criterion};
+
+use hercules_rt::{runner, HerculesImmBox, HerculesImmBoxTo, HerculesMutBox, HerculesMutBoxTo};
+
+juno_build::juno!("srad");
+
+use juno_srad::*;
+
+fn srad_bench(c: &mut Criterion) {
+    let mut group = c.benchmark_group("srad bench");
+
+    let mut r = runner!(srad);
+    let niter = 100;
+    let lambda = 0.5;
+    let nrows = 502;
+    let ncols = 458;
+    let image = "data/image.pgm".to_string();
+    let Image {
+        image: image_ori,
+        max,
+        rows: image_ori_rows,
+        cols: image_ori_cols,
+    } = read_graphics(image);
+    let image = resize(&image_ori, image_ori_rows, image_ori_cols, nrows, ncols);
+    let mut image_h = HerculesMutBox::from(image.clone());
+    let mut iN = (0..nrows).map(|i| i as i32 - 1).collect::<Vec<_>>();
+    let mut iS = (0..nrows).map(|i| i as i32 + 1).collect::<Vec<_>>();
+    let mut jW = (0..ncols).map(|j| j as i32 - 1).collect::<Vec<_>>();
+    let mut jE = (0..ncols).map(|j| j as i32 + 1).collect::<Vec<_>>();
+    // Fix boundary conditions
+    iN[0] = 0;
+    iS[nrows - 1] = (nrows - 1) as i32;
+    jW[0] = 0;
+    jE[ncols - 1] = (ncols - 1) as i32;
+    let iN_h = HerculesImmBox::from(iN.as_slice());
+    let iS_h = HerculesImmBox::from(iS.as_slice());
+    let jW_h = HerculesImmBox::from(jW.as_slice());
+    let jE_h = HerculesImmBox::from(jE.as_slice());
+    group.bench_function("srad bench", |b| {
+        b.iter(|| {
+            async_std::task::block_on(async {
+                r.run(
+                    nrows as u64,
+                    ncols as u64,
+                    niter as u64,
+                    image_h.to(),
+                    iN_h.to(),
+                    iS_h.to(),
+                    jW_h.to(),
+                    jE_h.to(),
+                    max,
+                    lambda,
+                )
+                .await
+            });
+        })
+    });
+}
+
+criterion_group!(benches, srad_bench);
+criterion_main!(benches);
diff --git a/juno_samples/rodinia/srad/src/lib.rs b/juno_samples/rodinia/srad/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d63660070ff0f61d47057ea00b14b3fb31db6e09
--- /dev/null
+++ b/juno_samples/rodinia/srad/src/lib.rs
@@ -0,0 +1,123 @@
+#![feature(concat_idents)]
+mod graphics;
+mod rust_srad;
+
+pub use graphics::*;
+
+use clap::Parser;
+
+use hercules_rt::{runner, HerculesImmBox, HerculesImmBoxTo, HerculesMutBox, HerculesMutBoxTo};
+
+juno_build::juno!("srad");
+
+#[derive(Parser)]
+#[clap(author, version, about, long_about = None)]
+pub struct SRADInputs {
+    pub niter: usize,
+    pub lambda: f32,
+    pub nrows: usize,
+    pub ncols: usize,
+    pub image: String,
+    #[clap(short, long)]
+    pub output: Option<String>,
+    #[clap(short, long)]
+    pub verify: bool,
+    #[clap(long = "output-verify", value_name = "PATH")]
+    pub output_verify: Option<String>,
+}
+
+pub fn srad_harness(args: SRADInputs) {
+    async_std::task::block_on(async {
+        let SRADInputs {
+            niter,
+            lambda,
+            nrows,
+            ncols,
+            image,
+            output,
+            verify,
+            output_verify,
+        } = args;
+
+        let Image {
+            image: image_ori,
+            max,
+            rows: image_ori_rows,
+            cols: image_ori_cols,
+        } = read_graphics(image);
+        let image = resize(&image_ori, image_ori_rows, image_ori_cols, nrows, ncols);
+        let mut image_h = HerculesMutBox::from(image.clone());
+
+        let mut iN = (0..nrows).map(|i| i as i32 - 1).collect::<Vec<_>>();
+        let mut iS = (0..nrows).map(|i| i as i32 + 1).collect::<Vec<_>>();
+        let mut jW = (0..ncols).map(|j| j as i32 - 1).collect::<Vec<_>>();
+        let mut jE = (0..ncols).map(|j| j as i32 + 1).collect::<Vec<_>>();
+
+        // Fix boundary conditions
+        iN[0] = 0;
+        iS[nrows - 1] = (nrows - 1) as i32;
+        jW[0] = 0;
+        jE[ncols - 1] = (ncols - 1) as i32;
+
+        let iN_h = HerculesImmBox::from(iN.as_slice());
+        let iS_h = HerculesImmBox::from(iS.as_slice());
+        let jW_h = HerculesImmBox::from(jW.as_slice());
+        let jE_h = HerculesImmBox::from(jE.as_slice());
+
+        let mut runner = runner!(srad);
+        let result: Vec<f32> = HerculesMutBox::from(
+            runner
+                .run(
+                    nrows as u64,
+                    ncols as u64,
+                    niter as u64,
+                    image_h.to(),
+                    iN_h.to(),
+                    iS_h.to(),
+                    jW_h.to(),
+                    jE_h.to(),
+                    max,
+                    lambda,
+                )
+                .await,
+        )
+        .as_slice()
+        .to_vec();
+
+        if let Some(output) = output {
+            write_graphics(output, &result, nrows, ncols, max);
+        }
+
+        if verify {
+            let mut rust_result = image;
+            rust_srad::srad(
+                nrows,
+                ncols,
+                niter,
+                &mut rust_result,
+                &iN,
+                &iS,
+                &jW,
+                &jE,
+                max,
+                lambda,
+            );
+
+            if let Some(output) = output_verify {
+                write_graphics(output, &rust_result, nrows, ncols, max);
+            }
+
+            let max_diff = result
+                .iter()
+                .zip(rust_result.iter())
+                .map(|(a, b)| (*a as i32 - *b as i32).abs())
+                .max()
+                .unwrap_or(0);
+            assert!(
+                max_diff <= 1,
+                "Verification failed: maximum pixel difference of {} exceeds threshold of 1",
+                max_diff
+            );
+        }
+    })
+}
diff --git a/juno_samples/rodinia/srad/src/main.rs b/juno_samples/rodinia/srad/src/main.rs
index 1b99b41aada5341fb3157cfb0d97be3a99e73796..87d1e7e8504584478f51ac2b9dc20dbc04716c81 100644
--- a/juno_samples/rodinia/srad/src/main.rs
+++ b/juno_samples/rodinia/srad/src/main.rs
@@ -1,126 +1,6 @@
-#![feature(concat_idents)]
-mod graphics;
-mod rust_srad;
-
-use graphics::*;
-
 use clap::Parser;
 
-use hercules_rt::{runner, HerculesImmBox, HerculesImmBoxTo, HerculesMutBox, HerculesMutBoxTo};
-
-juno_build::juno!("srad");
-
-#[derive(Parser)]
-#[clap(author, version, about, long_about = None)]
-struct SRADInputs {
-    niter: usize,
-    lambda: f32,
-    nrows: usize,
-    ncols: usize,
-    image: String,
-    #[clap(short, long)]
-    output: Option<String>,
-    #[clap(short, long)]
-    verify: bool,
-    #[clap(long = "output-verify", value_name = "PATH")]
-    output_verify: Option<String>,
-}
-
-fn srad_harness(args: SRADInputs) {
-    async_std::task::block_on(async {
-        let SRADInputs {
-            niter,
-            lambda,
-            nrows,
-            ncols,
-            image,
-            output,
-            verify,
-            output_verify,
-        } = args;
-
-        let Image {
-            image: image_ori,
-            max,
-            rows: image_ori_rows,
-            cols: image_ori_cols,
-        } = read_graphics(image);
-        let image = resize(&image_ori, image_ori_rows, image_ori_cols, nrows, ncols);
-        let mut image_h = HerculesMutBox::from(image.clone());
-
-        let mut iN = (0..nrows).map(|i| i as i32 - 1).collect::<Vec<_>>();
-        let mut iS = (0..nrows).map(|i| i as i32 + 1).collect::<Vec<_>>();
-        let mut jW = (0..ncols).map(|j| j as i32 - 1).collect::<Vec<_>>();
-        let mut jE = (0..ncols).map(|j| j as i32 + 1).collect::<Vec<_>>();
-
-        // Fix boundary conditions
-        iN[0] = 0;
-        iS[nrows - 1] = (nrows - 1) as i32;
-        jW[0] = 0;
-        jE[ncols - 1] = (ncols - 1) as i32;
-
-        let iN_h = HerculesImmBox::from(iN.as_slice());
-        let iS_h = HerculesImmBox::from(iS.as_slice());
-        let jW_h = HerculesImmBox::from(jW.as_slice());
-        let jE_h = HerculesImmBox::from(jE.as_slice());
-
-        let mut runner = runner!(srad);
-        let result: Vec<f32> = HerculesMutBox::from(
-            runner
-                .run(
-                    nrows as u64,
-                    ncols as u64,
-                    niter as u64,
-                    image_h.to(),
-                    iN_h.to(),
-                    iS_h.to(),
-                    jW_h.to(),
-                    jE_h.to(),
-                    max,
-                    lambda,
-                )
-                .await,
-        )
-        .as_slice()
-        .to_vec();
-
-        if let Some(output) = output {
-            write_graphics(output, &result, nrows, ncols, max);
-        }
-
-        if verify {
-            let mut rust_result = image;
-            rust_srad::srad(
-                nrows,
-                ncols,
-                niter,
-                &mut rust_result,
-                &iN,
-                &iS,
-                &jW,
-                &jE,
-                max,
-                lambda,
-            );
-
-            if let Some(output) = output_verify {
-                write_graphics(output, &rust_result, nrows, ncols, max);
-            }
-
-            let max_diff = result
-                .iter()
-                .zip(rust_result.iter())
-                .map(|(a, b)| (*a as i32 - *b as i32).abs())
-                .max()
-                .unwrap_or(0);
-            assert!(
-                max_diff <= 1,
-                "Verification failed: maximum pixel difference of {} exceeds threshold of 1",
-                max_diff
-            );
-        }
-    })
-}
+use juno_srad::*;
 
 fn main() {
     let args = SRADInputs::parse();