diff --git a/Makefile b/Makefile
index 1f0a786dff2c4fa19545dbbb20d951806a921edb..0ce8ec866c20d5226e794fb335b235ee5aee3d49 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,8 @@ CFLAGS=-O3 -fompss-2
BENCHMARKS=\
sched_get \
sched_add \
- register_deps
+ register_deps \
+ readywave
BIN=$(addprefix bench6.,$(BENCHMARKS))
DATA=$(addsuffix .csv, $(addprefix data/,$(BENCHMARKS)))
diff --git a/README.md b/README.md
index 68e6f47effb812cfa707b00b56ab96c67d56da5b..7ed7f9b8ead7630f1f3088961d0ae5adfeaab451 100644
--- a/README.md
+++ b/README.md
@@ -11,3 +11,5 @@ Examples:
+
+
diff --git a/examples/readywave-instr.csv.png b/examples/readywave-instr.csv.png
new file mode 100644
index 0000000000000000000000000000000000000000..c6747d395f6957b6773447d07daf1fe2850eb0ee
Binary files /dev/null and b/examples/readywave-instr.csv.png differ
diff --git a/plot/readywave.R b/plot/readywave.R
new file mode 100644
index 0000000000000000000000000000000000000000..2f937f8cefed1f86260315fcd18799e804c551a4
--- /dev/null
+++ b/plot/readywave.R
@@ -0,0 +1,26 @@
+library(ggplot2)
+library(dplyr, warn.conflicts = FALSE)
+library(scales)
+library(jsonlite)
+library(readr)
+
+# Load the arguments (argv)
+args = commandArgs(trailingOnly=TRUE)
+
+input_file = args[1]
+
+df = read_delim(input_file, delim=",", show_col_types = FALSE)
+
+dpi = 96
+h = 2
+w = 6
+
+# ---------------------------------------------------------------------
+
+p = ggplot(df, aes(time_ms)) +
+ geom_histogram(bins=80) +
+ theme_bw() +
+ labs(x = "Time (ms)", title="Nanos6: readywave time")
+ # TODO: Add ntasks and taskwork to labels
+
+ggsave(sprintf("%s.png", input_file), plot=p, width=w, height=h, dpi=dpi)
diff --git a/shell.nix b/shell.nix
new file mode 100644
index 0000000000000000000000000000000000000000..c04b746b378ad21c79f74f00c802e5e7bf272187
--- /dev/null
+++ b/shell.nix
@@ -0,0 +1,15 @@
+let
+ pkgs = import (builtins.fetchTarball
+ "https://pm.bsc.es/gitlab/rarias/bscpkgs/-/archive/master/bscpkgs-master.tar.gz");
+
+ rWrapper = pkgs.rWrapper.override {
+ packages = with pkgs.rPackages; [ tidyverse rjson jsonlite egg viridis ];
+ };
+in
+ pkgs.mkShell {
+ nativeBuildInputs = [
+ pkgs.bsc.clangOmpss2
+ pkgs.bsc.nanos6
+ rWrapper
+ ];
+ }
diff --git a/src/readywave.c b/src/readywave.c
new file mode 100644
index 0000000000000000000000000000000000000000..bec436c073e208d8f05591e0db0dc7227b6c6a08
--- /dev/null
+++ b/src/readywave.c
@@ -0,0 +1,116 @@
+/* Copyright (c) 2023 Barcelona Supercomputing Center (BSC)
+ * SPDX-License-Identifier: GPL-3.0-or-later */
+
+#define _DEFAULT_SOURCE
+
+#include "bench6.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+static int ncpus = -1;
+static long nruns = 100L;
+static long ntasks_per_cpu = 5000L;
+static double taskwork_us = 10.0;
+
+static double t0;
+
+#define M_WORK 10000000L
+
+static void
+busywork(long loops)
+{
+ for (volatile long j = 0; j < loops; j++);
+}
+
+static void
+dummy_work(double ms)
+{
+ double end = get_time() + ms * 1e-3;
+ while (get_time() < end);
+}
+
+static void
+do_run(int run)
+{
+ /* Warm up all the threads */
+ for (long i = 0L; i < ncpus; i++) {
+ #pragma oss task label("warmup")
+ dummy_work(20.0);
+ }
+
+ #pragma oss taskwait
+
+ int flag = 0;
+
+ /* Delay task start so we can create lots of tasks */
+ #pragma oss task inout(flag) label("trigger")
+ {
+ dummy_work(10.0);
+ busywork(M_WORK); /* So we can see it in perf */
+ t0 = get_time();
+ }
+
+ for (long i = 0L; i < ntasks_per_cpu * ncpus; i++) {
+ #pragma oss task in(flag) label("quickie")
+ dummy_work(taskwork_us * 1e-3);
+ }
+
+ /* When trigger finishes all small tasks will become ready */
+ #pragma oss taskwait
+ double t1 = get_time();
+ printf("%d,%ld,%d,%.3f,%.3f\n", run, ntasks_per_cpu, ncpus, taskwork_us, (t1 - t0) * 1e3);
+}
+
+static int
+usage(char *argv[])
+{
+ fprintf(stderr, "Bench6: A set of Nanos6 micro-benchmarks\n");
+ fprintf(stderr, "Usage: %s [-r NRUNS] [-t NTASKS_PER_CPU] [-w TASKWORK_US]\n", argv[0]);
+ fprintf(stderr, "\n");
+ fprintf(stderr,
+"Creates NTASKS_PER_CPU tasks per CPU that become ready at the\n"
+"same time, like a wave. The time between the moment they become\n"
+"ready and when the all end is measured. Tasks run for TASKWORK_US\n"
+"microseconds. The test is repeated NRUNS times.\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Defaults: NRUNS=%ld NTASKS_PER_CPU=%ld TASKWORK_US=%.3f\n",
+ nruns, ntasks_per_cpu, taskwork_us);
+
+ return -1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int opt;
+
+ while ((opt = getopt(argc, argv, "hr:t:w:")) != -1) {
+ switch (opt) {
+ case 'r':
+ nruns = atol(optarg);
+ break;
+ case 't':
+ ntasks_per_cpu = atol(optarg);
+ break;
+ case 'w':
+ taskwork_us = atof(optarg);
+ break;
+ case 'h': /* Fall through */
+ default: /* '?' */
+ return usage(argv);
+ }
+ }
+
+ ncpus = get_ncpus();
+
+ printf("%s,%s,%s,%s,%s\n", "run", "ntasks_per_cpu", "ncpus", "taskwork_us", "time_ms");
+ for (int run = 0; run < nruns; run++)
+ do_run(run);
+
+ return 0;
+}