diff --git a/benches/sync_mpsc.rs b/benches/sync_mpsc.rs
index 5a3f7500..2581d3a7 100644
--- a/benches/sync_mpsc.rs
+++ b/benches/sync_mpsc.rs
@@ -1,7 +1,7 @@
 use tokio::sync::mpsc;
 
 use criterion::measurement::WallTime;
-use criterion::{black_box, criterion_group, criterion_main, BenchmarkGroup, Criterion};
+use criterion::{black_box, criterion_group, criterion_main, BatchSize, BenchmarkGroup, Criterion};
 
 #[derive(Debug, Copy, Clone)]
 struct Medium(#[allow(dead_code)] [usize; 64]);
@@ -303,6 +303,41 @@ fn bench_send(c: &mut Criterion) {
     group.finish();
 }
 
+fn recv_data<T: Default + Send + 'static, const N: usize>(
+    g: &mut BenchmarkGroup<WallTime>,
+    prefix: &str,
+) {
+    let rt = rt();
+
+    g.bench_function(format!("{prefix}_{N}"), |b| {
+        b.iter_batched(
+            || {
+                let (tx, rx) = mpsc::channel::<T>(N);
+                for _ in 0..N {
+                    tx.try_send(T::default()).unwrap();
+                }
+                rx
+            },
+            |mut rx| {
+                rt.block_on(async move {
+                    for _ in 0..N {
+                        rx.recv().await.unwrap();
+                    }
+                });
+            },
+            BatchSize::SmallInput,
+        )
+    });
+}
+
+fn bench_recv_only(c: &mut Criterion) {
+    let mut group = c.benchmark_group("recv_only");
+    recv_data::<usize, 1000>(&mut group, "small");
+    recv_data::<Medium, 1000>(&mut group, "medium");
+    recv_data::<Large, 1000>(&mut group, "large");
+    group.finish();
+}
+
 fn bench_contention(c: &mut Criterion) {
     let mut group = c.benchmark_group("contention");
     contention_bounded(&mut group);
@@ -325,7 +360,8 @@ fn bench_uncontented(c: &mut Criterion) {
 
 criterion_group!(create, bench_create_medium);
 criterion_group!(send, bench_send);
+criterion_group!(recv_only, bench_recv_only);
 criterion_group!(contention, bench_contention);
 criterion_group!(uncontented, bench_uncontented);
 
-criterion_main!(create, send, contention, uncontented);
+criterion_main!(create, send, recv_only, contention, uncontented);
diff --git a/tokio/src/sync/mpsc/block.rs b/tokio/src/sync/mpsc/block.rs
index e231b8e5..f51d3194 100644
--- a/tokio/src/sync/mpsc/block.rs
+++ b/tokio/src/sync/mpsc/block.rs
@@ -149,6 +149,7 @@ impl<T> Block<T> {
     /// To maintain safety, the caller must ensure:
     ///
     /// * No concurrent access to the slot.
+    #[inline]
     pub(crate) unsafe fn read(&self, slot_index: usize) -> Option<Read<T>> {
         let offset = offset(slot_index);
 
diff --git a/tokio/src/sync/mpsc/list.rs b/tokio/src/sync/mpsc/list.rs
index c5f21b8b..1e6300f7 100644
--- a/tokio/src/sync/mpsc/list.rs
+++ b/tokio/src/sync/mpsc/list.rs
@@ -317,6 +317,7 @@ impl<T> Rx<T> {
     }
 
     /// Pops the next value off the queue.
+    #[inline]
     pub(crate) fn pop(&mut self, tx: &Tx<T>) -> Option<block::Read<T>> {
         // Advance `head`, if needed
         if !self.try_advancing_head() {
