extern const struct bench bench_trig_fentry_sleep;
 extern const struct bench bench_trig_fmodret;
 extern const struct bench bench_trig_uprobe_base;
-extern const struct bench bench_trig_uprobe_with_nop;
-extern const struct bench bench_trig_uretprobe_with_nop;
-extern const struct bench bench_trig_uprobe_without_nop;
-extern const struct bench bench_trig_uretprobe_without_nop;
+extern const struct bench bench_trig_uprobe_nop;
+extern const struct bench bench_trig_uretprobe_nop;
+extern const struct bench bench_trig_uprobe_push;
+extern const struct bench bench_trig_uretprobe_push;
+extern const struct bench bench_trig_uprobe_ret;
+extern const struct bench bench_trig_uretprobe_ret;
 extern const struct bench bench_rb_libbpf;
 extern const struct bench bench_rb_custom;
 extern const struct bench bench_pb_libbpf;
        &bench_trig_fentry_sleep,
        &bench_trig_fmodret,
        &bench_trig_uprobe_base,
-       &bench_trig_uprobe_with_nop,
-       &bench_trig_uretprobe_with_nop,
-       &bench_trig_uprobe_without_nop,
-       &bench_trig_uretprobe_without_nop,
+       &bench_trig_uprobe_nop,
+       &bench_trig_uretprobe_nop,
+       &bench_trig_uprobe_push,
+       &bench_trig_uretprobe_push,
+       &bench_trig_uprobe_ret,
+       &bench_trig_uretprobe_ret,
        &bench_rb_libbpf,
        &bench_rb_custom,
        &bench_pb_libbpf,
 
  * GCC doesn't generate stack setup preample for these functions due to them
  * having no input arguments and doing nothing in the body.
  */
-__weak void uprobe_target_with_nop(void)
+__weak void uprobe_target_nop(void)
 {
        asm volatile ("nop");
 }
 
-__weak void uprobe_target_without_nop(void)
+__weak void opaque_noop_func(void)
+{
+}
+
+__weak int uprobe_target_push(void)
+{
+       /* overhead of function call is negligible compared to uprobe
+        * triggering, so this shouldn't affect benchmark results much
+        */
+       opaque_noop_func();
+       return 1;
+}
+
+__weak void uprobe_target_ret(void)
 {
        asm volatile ("");
 }
 static void *uprobe_base_producer(void *input)
 {
        while (true) {
-               uprobe_target_with_nop();
+               uprobe_target_nop();
                atomic_inc(&base_hits.value);
        }
        return NULL;
 }
 
-static void *uprobe_producer_with_nop(void *input)
+static void *uprobe_producer_nop(void *input)
+{
+       while (true)
+               uprobe_target_nop();
+       return NULL;
+}
+
+static void *uprobe_producer_push(void *input)
 {
        while (true)
-               uprobe_target_with_nop();
+               uprobe_target_push();
        return NULL;
 }
 
-static void *uprobe_producer_without_nop(void *input)
+static void *uprobe_producer_ret(void *input)
 {
        while (true)
-               uprobe_target_without_nop();
+               uprobe_target_ret();
        return NULL;
 }
 
-static void usetup(bool use_retprobe, bool use_nop)
+static void usetup(bool use_retprobe, void *target_addr)
 {
        size_t uprobe_offset;
        struct bpf_link *link;
                exit(1);
        }
 
-       if (use_nop)
-               uprobe_offset = get_uprobe_offset(&uprobe_target_with_nop);
-       else
-               uprobe_offset = get_uprobe_offset(&uprobe_target_without_nop);
-
+       uprobe_offset = get_uprobe_offset(target_addr);
        link = bpf_program__attach_uprobe(ctx.skel->progs.bench_trigger_uprobe,
                                          use_retprobe,
                                          -1 /* all PIDs */,
        ctx.skel->links.bench_trigger_uprobe = link;
 }
 
-static void uprobe_setup_with_nop(void)
+static void uprobe_setup_nop(void)
+{
+       usetup(false, &uprobe_target_nop);
+}
+
+static void uretprobe_setup_nop(void)
+{
+       usetup(true, &uprobe_target_nop);
+}
+
+static void uprobe_setup_push(void)
 {
-       usetup(false, true);
+       usetup(false, &uprobe_target_push);
 }
 
-static void uretprobe_setup_with_nop(void)
+static void uretprobe_setup_push(void)
 {
-       usetup(true, true);
+       usetup(true, &uprobe_target_push);
 }
 
-static void uprobe_setup_without_nop(void)
+static void uprobe_setup_ret(void)
 {
-       usetup(false, false);
+       usetup(false, &uprobe_target_ret);
 }
 
-static void uretprobe_setup_without_nop(void)
+static void uretprobe_setup_ret(void)
 {
-       usetup(true, false);
+       usetup(true, &uprobe_target_ret);
 }
 
 const struct bench bench_trig_base = {
        .report_final = hits_drops_report_final,
 };
 
-const struct bench bench_trig_uprobe_with_nop = {
-       .name = "trig-uprobe-with-nop",
-       .setup = uprobe_setup_with_nop,
-       .producer_thread = uprobe_producer_with_nop,
+const struct bench bench_trig_uprobe_nop = {
+       .name = "trig-uprobe-nop",
+       .setup = uprobe_setup_nop,
+       .producer_thread = uprobe_producer_nop,
+       .measure = trigger_measure,
+       .report_progress = hits_drops_report_progress,
+       .report_final = hits_drops_report_final,
+};
+
+const struct bench bench_trig_uretprobe_nop = {
+       .name = "trig-uretprobe-nop",
+       .setup = uretprobe_setup_nop,
+       .producer_thread = uprobe_producer_nop,
+       .measure = trigger_measure,
+       .report_progress = hits_drops_report_progress,
+       .report_final = hits_drops_report_final,
+};
+
+const struct bench bench_trig_uprobe_push = {
+       .name = "trig-uprobe-push",
+       .setup = uprobe_setup_push,
+       .producer_thread = uprobe_producer_push,
        .measure = trigger_measure,
        .report_progress = hits_drops_report_progress,
        .report_final = hits_drops_report_final,
 };
 
-const struct bench bench_trig_uretprobe_with_nop = {
-       .name = "trig-uretprobe-with-nop",
-       .setup = uretprobe_setup_with_nop,
-       .producer_thread = uprobe_producer_with_nop,
+const struct bench bench_trig_uretprobe_push = {
+       .name = "trig-uretprobe-push",
+       .setup = uretprobe_setup_push,
+       .producer_thread = uprobe_producer_push,
        .measure = trigger_measure,
        .report_progress = hits_drops_report_progress,
        .report_final = hits_drops_report_final,
 };
 
-const struct bench bench_trig_uprobe_without_nop = {
-       .name = "trig-uprobe-without-nop",
-       .setup = uprobe_setup_without_nop,
-       .producer_thread = uprobe_producer_without_nop,
+const struct bench bench_trig_uprobe_ret = {
+       .name = "trig-uprobe-ret",
+       .setup = uprobe_setup_ret,
+       .producer_thread = uprobe_producer_ret,
        .measure = trigger_measure,
        .report_progress = hits_drops_report_progress,
        .report_final = hits_drops_report_final,
 };
 
-const struct bench bench_trig_uretprobe_without_nop = {
-       .name = "trig-uretprobe-without-nop",
-       .setup = uretprobe_setup_without_nop,
-       .producer_thread = uprobe_producer_without_nop,
+const struct bench bench_trig_uretprobe_ret = {
+       .name = "trig-uretprobe-ret",
+       .setup = uretprobe_setup_ret,
+       .producer_thread = uprobe_producer_ret,
        .measure = trigger_measure,
        .report_progress = hits_drops_report_progress,
        .report_final = hits_drops_report_final,