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.

debugobjects: Rework free_object_work()

Convert it to batch processing with intermediate helper functions. This
reduces the final changes for batch processing.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Zhen Lei <thunder.leizhen@huawei.com>
Link: https://lore.kernel.org/all/20241007164914.015906394@linutronix.de

+38 -42
+38 -42
lib/debugobjects.c
··· 35 35 * frequency of 10Hz and about 1024 objects for each freeing operation. 36 36 * So it is freeing at most 10k debug objects per second. 37 37 */ 38 - #define ODEBUG_FREE_WORK_MAX 1024 38 + #define ODEBUG_FREE_WORK_MAX (1024 / ODEBUG_BATCH_SIZE) 39 39 #define ODEBUG_FREE_WORK_DELAY DIV_ROUND_UP(HZ, 10) 40 40 41 41 struct debug_bucket { ··· 154 154 155 155 hlist_del(node); 156 156 hlist_add_head(node, &dst->objects); 157 + } 158 + return true; 159 + } 160 + 161 + static bool pool_pop_batch(struct hlist_head *head, struct obj_pool *src) 162 + { 163 + if (!src->cnt) 164 + return false; 165 + 166 + for (int i = 0; src->cnt && i < ODEBUG_BATCH_SIZE; i++) { 167 + struct hlist_node *node = src->objects.first; 168 + 169 + WRITE_ONCE(src->cnt, src->cnt - 1); 170 + hlist_del(node); 171 + hlist_add_head(node, head); 157 172 } 158 173 return true; 159 174 } ··· 358 343 return obj; 359 344 } 360 345 361 - /* 362 - * workqueue function to free objects. 363 - * 364 - * To reduce contention on the global pool_lock, the actual freeing of 365 - * debug objects will be delayed if the pool_lock is busy. 366 - */ 346 + /* workqueue function to free objects. */ 367 347 static void free_obj_work(struct work_struct *work) 368 348 { 369 - struct debug_obj *obj; 370 - unsigned long flags; 371 - HLIST_HEAD(tofree); 349 + bool free = true; 372 350 373 351 WRITE_ONCE(obj_freeing, false); 374 - if (!raw_spin_trylock_irqsave(&pool_lock, flags)) 352 + 353 + if (!pool_count(&pool_to_free)) 375 354 return; 376 355 377 - if (pool_global.cnt >= pool_global.max_cnt) 378 - goto free_objs; 356 + for (unsigned int cnt = 0; cnt < ODEBUG_FREE_WORK_MAX; cnt++) { 357 + HLIST_HEAD(tofree); 379 358 380 - /* 381 - * The objs on the pool list might be allocated before the work is 382 - * run, so recheck if pool list it full or not, if not fill pool 383 - * list from the global free list. As it is likely that a workload 384 - * may be gearing up to use more and more objects, don't free any 385 - * of them until the next round. 386 - */ 387 - while (pool_to_free.cnt && pool_global.cnt < pool_global.max_cnt) { 388 - obj = hlist_entry(pool_to_free.objects.first, typeof(*obj), node); 389 - hlist_del(&obj->node); 390 - hlist_add_head(&obj->node, &pool_global.objects); 391 - WRITE_ONCE(pool_to_free.cnt, pool_to_free.cnt - 1); 392 - WRITE_ONCE(pool_global.cnt, pool_global.cnt + 1); 359 + /* Acquire and drop the lock for each batch */ 360 + scoped_guard(raw_spinlock_irqsave, &pool_lock) { 361 + if (!pool_to_free.cnt) 362 + return; 363 + 364 + /* Refill the global pool if possible */ 365 + if (pool_move_batch(&pool_global, &pool_to_free)) { 366 + /* Don't free as there seems to be demand */ 367 + free = false; 368 + } else if (free) { 369 + pool_pop_batch(&tofree, &pool_to_free); 370 + } else { 371 + return; 372 + } 373 + } 374 + free_object_list(&tofree); 393 375 } 394 - raw_spin_unlock_irqrestore(&pool_lock, flags); 395 - return; 396 - 397 - free_objs: 398 - /* 399 - * Pool list is already full and there are still objs on the free 400 - * list. Move remaining free objs to a temporary list to free the 401 - * memory outside the pool_lock held region. 402 - */ 403 - if (pool_to_free.cnt) { 404 - hlist_move_list(&pool_to_free.objects, &tofree); 405 - WRITE_ONCE(pool_to_free.cnt, 0); 406 - } 407 - raw_spin_unlock_irqrestore(&pool_lock, flags); 408 - 409 - free_object_list(&tofree); 410 376 } 411 377 412 378 static void __free_object(struct debug_obj *obj)