Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

selftests: ublk: make ublk_thread thread-local variable

Refactor ublk_thread to be a thread-local variable instead of storing
it in ublk_dev:

- Remove pthread_t thread field from struct ublk_thread and move it to
struct ublk_thread_info

- Remove struct ublk_thread array from struct ublk_dev, reducing memory
footprint

- Define struct ublk_thread as local variable in __ublk_io_handler_fn()
instead of accessing it from dev->threads[]

- Extract main IO handling logic into __ublk_io_handler_fn() which is
marked as noinline

- Move CPU affinity setup to ublk_io_handler_fn() before calling
__ublk_io_handler_fn()

- Update ublk_thread_set_sched_affinity() to take struct ublk_thread_info *
instead of struct ublk_thread *, and use pthread_setaffinity_np()
instead of sched_setaffinity()

- Reorder struct ublk_thread fields to group related state together

This change makes each thread's ublk_thread structure truly local to
the thread, improving cache locality and reducing memory usage.

Signed-off-by: Ming Lei <ming.lei@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Ming Lei and committed by
Jens Axboe
3f5b1169 0123bb91

+48 -43
+45 -37
tools/testing/selftests/ublk/kublk.c
··· 836 836 return reapped; 837 837 } 838 838 839 - static void ublk_thread_set_sched_affinity(const struct ublk_thread *t, 840 - cpu_set_t *cpuset) 841 - { 842 - if (pthread_setaffinity_np(pthread_self(), sizeof(*cpuset), cpuset) < 0) 843 - ublk_err("ublk dev %u thread %u set affinity failed", 844 - t->dev->dev_info.dev_id, t->idx); 845 - } 846 - 847 839 struct ublk_thread_info { 848 840 struct ublk_dev *dev; 841 + pthread_t thread; 849 842 unsigned idx; 850 843 sem_t *ready; 851 844 cpu_set_t *affinity; 852 845 unsigned long long extra_flags; 853 846 }; 854 847 855 - static void *ublk_io_handler_fn(void *data) 848 + static void ublk_thread_set_sched_affinity(const struct ublk_thread_info *info) 856 849 { 857 - struct ublk_thread_info *info = data; 858 - struct ublk_thread *t = &info->dev->threads[info->idx]; 850 + if (pthread_setaffinity_np(pthread_self(), sizeof(*info->affinity), info->affinity) < 0) 851 + ublk_err("ublk dev %u thread %u set affinity failed", 852 + info->dev->dev_info.dev_id, info->idx); 853 + } 854 + 855 + static __attribute__((noinline)) int __ublk_io_handler_fn(struct ublk_thread_info *info) 856 + { 857 + struct ublk_thread t = { 858 + .dev = info->dev, 859 + .idx = info->idx, 860 + }; 859 861 int dev_id = info->dev->dev_info.dev_id; 860 862 int ret; 861 863 862 - t->dev = info->dev; 863 - t->idx = info->idx; 864 + ret = ublk_thread_init(&t, info->extra_flags); 865 + if (ret) { 866 + ublk_err("ublk dev %d thread %u init failed\n", 867 + dev_id, t.idx); 868 + return ret; 869 + } 870 + sem_post(info->ready); 871 + 872 + ublk_dbg(UBLK_DBG_THREAD, "tid %d: ublk dev %d thread %u started\n", 873 + gettid(), dev_id, t.idx); 874 + 875 + /* submit all io commands to ublk driver */ 876 + ublk_submit_fetch_commands(&t); 877 + do { 878 + if (ublk_process_io(&t) < 0) 879 + break; 880 + } while (1); 881 + 882 + ublk_dbg(UBLK_DBG_THREAD, "tid %d: ublk dev %d thread %d exiting\n", 883 + gettid(), dev_id, t.idx); 884 + ublk_thread_deinit(&t); 885 + return 0; 886 + } 887 + 888 + static void *ublk_io_handler_fn(void *data) 889 + { 890 + struct ublk_thread_info *info = data; 864 891 865 892 /* 866 893 * IO perf is sensitive with queue pthread affinity on NUMA machine ··· 896 869 * could be CPU/NUMA aware. 897 870 */ 898 871 if (info->affinity) 899 - ublk_thread_set_sched_affinity(t, info->affinity); 872 + ublk_thread_set_sched_affinity(info); 900 873 901 - ret = ublk_thread_init(t, info->extra_flags); 902 - if (ret) { 903 - ublk_err("ublk dev %d thread %u init failed\n", 904 - dev_id, t->idx); 905 - return NULL; 906 - } 907 - sem_post(info->ready); 874 + __ublk_io_handler_fn(info); 908 875 909 - ublk_dbg(UBLK_DBG_THREAD, "tid %d: ublk dev %d thread %u started\n", 910 - gettid(), dev_id, t->idx); 911 - 912 - /* submit all io commands to ublk driver */ 913 - ublk_submit_fetch_commands(t); 914 - do { 915 - if (ublk_process_io(t) < 0) 916 - break; 917 - } while (1); 918 - 919 - ublk_dbg(UBLK_DBG_THREAD, "tid %d: ublk dev %d thread %d exiting\n", 920 - gettid(), dev_id, t->idx); 921 - ublk_thread_deinit(t); 922 876 return NULL; 923 877 } 924 878 ··· 997 989 */ 998 990 if (dev->nthreads == dinfo->nr_hw_queues) 999 991 tinfo[i].affinity = &affinity_buf[i]; 1000 - pthread_create(&dev->threads[i].thread, NULL, 992 + pthread_create(&tinfo[i].thread, NULL, 1001 993 ublk_io_handler_fn, 1002 994 &tinfo[i]); 1003 995 } 1004 996 1005 997 for (i = 0; i < dev->nthreads; i++) 1006 998 sem_wait(&ready); 1007 - free(tinfo); 1008 999 free(affinity_buf); 1009 1000 1010 1001 /* everything is fine now, start us */ ··· 1026 1019 1027 1020 /* wait until we are terminated */ 1028 1021 for (i = 0; i < dev->nthreads; i++) 1029 - pthread_join(dev->threads[i].thread, &thread_ret); 1022 + pthread_join(tinfo[i].thread, &thread_ret); 1023 + free(tinfo); 1030 1024 fail: 1031 1025 for (i = 0; i < dinfo->nr_hw_queues; i++) 1032 1026 ublk_queue_deinit(&dev->q[i]);
+3 -6
tools/testing/selftests/ublk/kublk.h
··· 175 175 176 176 struct ublk_thread { 177 177 struct ublk_dev *dev; 178 - struct io_uring ring; 179 - unsigned int cmd_inflight; 180 - unsigned int io_inflight; 181 - 182 - pthread_t thread; 183 178 unsigned idx; 184 179 185 180 #define UBLKS_T_STOPPING (1U << 0) 186 181 #define UBLKS_T_IDLE (1U << 1) 187 182 unsigned state; 183 + unsigned int cmd_inflight; 184 + unsigned int io_inflight; 185 + struct io_uring ring; 188 186 }; 189 187 190 188 struct ublk_dev { 191 189 struct ublk_tgt tgt; 192 190 struct ublksrv_ctrl_dev_info dev_info; 193 191 struct ublk_queue q[UBLK_MAX_QUEUES]; 194 - struct ublk_thread threads[UBLK_MAX_THREADS]; 195 192 unsigned nthreads; 196 193 unsigned per_io_tasks; 197 194