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.

io_uring/sqpoll: switch away from getrusage() for CPU accounting

getrusage() does a lot more than what the SQPOLL accounting needs, the
latter only cares about (and uses) the stime. Rather than do a full
RUSAGE_SELF summation, just query the used stime instead.

Cc: stable@vger.kernel.org
Fixes: 3fcb9d17206e ("io_uring/sqpoll: statistics of the true utilization of sq threads")
Reviewed-by: Gabriel Krisman Bertazi <krisman@suse.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

+23 -18
+4 -4
io_uring/fdinfo.c
··· 59 59 { 60 60 struct io_overflow_cqe *ocqe; 61 61 struct io_rings *r = ctx->rings; 62 - struct rusage sq_usage; 63 62 unsigned int sq_mask = ctx->sq_entries - 1, cq_mask = ctx->cq_entries - 1; 64 63 unsigned int sq_head = READ_ONCE(r->sq.head); 65 64 unsigned int sq_tail = READ_ONCE(r->sq.tail); ··· 151 152 * thread termination. 152 153 */ 153 154 if (tsk) { 155 + u64 usec; 156 + 154 157 get_task_struct(tsk); 155 158 rcu_read_unlock(); 156 - getrusage(tsk, RUSAGE_SELF, &sq_usage); 159 + usec = io_sq_cpu_usec(tsk); 157 160 put_task_struct(tsk); 158 161 sq_pid = sq->task_pid; 159 162 sq_cpu = sq->sq_cpu; 160 - sq_total_time = (sq_usage.ru_stime.tv_sec * 1000000 161 - + sq_usage.ru_stime.tv_usec); 163 + sq_total_time = usec; 162 164 sq_work_time = sq->work_time; 163 165 } else { 164 166 rcu_read_unlock();
+18 -14
io_uring/sqpoll.c
··· 11 11 #include <linux/audit.h> 12 12 #include <linux/security.h> 13 13 #include <linux/cpuset.h> 14 + #include <linux/sched/cputime.h> 14 15 #include <linux/io_uring.h> 15 16 16 17 #include <uapi/linux/io_uring.h> ··· 170 169 return READ_ONCE(sqd->state); 171 170 } 172 171 172 + u64 io_sq_cpu_usec(struct task_struct *tsk) 173 + { 174 + u64 utime, stime; 175 + 176 + task_cputime_adjusted(tsk, &utime, &stime); 177 + do_div(stime, 1000); 178 + return stime; 179 + } 180 + 181 + static void io_sq_update_worktime(struct io_sq_data *sqd, u64 usec) 182 + { 183 + sqd->work_time += io_sq_cpu_usec(current) - usec; 184 + } 185 + 173 186 static int __io_sq_thread(struct io_ring_ctx *ctx, bool cap_entries) 174 187 { 175 188 unsigned int to_submit; ··· 270 255 return retry_list || !llist_empty(&tctx->task_list); 271 256 } 272 257 273 - static void io_sq_update_worktime(struct io_sq_data *sqd, struct rusage *start) 274 - { 275 - struct rusage end; 276 - 277 - getrusage(current, RUSAGE_SELF, &end); 278 - end.ru_stime.tv_sec -= start->ru_stime.tv_sec; 279 - end.ru_stime.tv_usec -= start->ru_stime.tv_usec; 280 - 281 - sqd->work_time += end.ru_stime.tv_usec + end.ru_stime.tv_sec * 1000000; 282 - } 283 - 284 258 static int io_sq_thread(void *data) 285 259 { 286 260 struct llist_node *retry_list = NULL; 287 261 struct io_sq_data *sqd = data; 288 262 struct io_ring_ctx *ctx; 289 - struct rusage start; 290 263 unsigned long timeout = 0; 291 264 char buf[TASK_COMM_LEN] = {}; 292 265 DEFINE_WAIT(wait); 266 + u64 start; 293 267 294 268 /* offload context creation failed, just exit */ 295 269 if (!current->io_uring) { ··· 321 317 } 322 318 323 319 cap_entries = !list_is_singular(&sqd->ctx_list); 324 - getrusage(current, RUSAGE_SELF, &start); 320 + start = io_sq_cpu_usec(current); 325 321 list_for_each_entry(ctx, &sqd->ctx_list, sqd_list) { 326 322 int ret = __io_sq_thread(ctx, cap_entries); 327 323 ··· 337 333 338 334 if (sqt_spin || !time_after(jiffies, timeout)) { 339 335 if (sqt_spin) { 340 - io_sq_update_worktime(sqd, &start); 336 + io_sq_update_worktime(sqd, start); 341 337 timeout = jiffies + sqd->sq_thread_idle; 342 338 } 343 339 if (unlikely(need_resched())) {
+1
io_uring/sqpoll.h
··· 29 29 void io_put_sq_data(struct io_sq_data *sqd); 30 30 void io_sqpoll_wait_sq(struct io_ring_ctx *ctx); 31 31 int io_sqpoll_wq_cpu_affinity(struct io_ring_ctx *ctx, cpumask_var_t mask); 32 + u64 io_sq_cpu_usec(struct task_struct *tsk); 32 33 33 34 static inline struct task_struct *sqpoll_task_locked(struct io_sq_data *sqd) 34 35 {