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

tools/getdelays: add backward compatibility for taskstats version

Add version checks to print_delayacct() to handle differences in struct
taskstats across kernel versions. Field availability depends on taskstats
version (t->version), corresponding to TASKSTATS_VERSION in kernel headers
(see include/uapi/linux/taskstats.h).

Version feature mapping:
- version >= 11 - supports COMPACT statistics
- version >= 13 - supports WPCOPY statistics
- version >= 14 - supports IRQ statistics
- version >= 16 - supports *_max and *_min delay statistics

This ensures the tool works correctly with both older and newer kernel
versions by conditionally printing fields based on the reported version.

eg.1
bash# grep -r "#define TASKSTATS_VERSION" /usr/include/linux/taskstats.h
"#define TASKSTATS_VERSION 10"
bash# ./getdelays -d -p 1
CPU count real total virtual total delay total delay average
7481 3786181709 3807098291 36393725 0.005ms
IO count delay total delay average
369 1116046035 3.025ms
SWAP count delay total delay average
0 0 0.000ms
RECLAIM count delay total delay average
0 0 0.000ms
THRASHING count delay total delay average
0 0 0.000ms

eg.2
bash# grep -r "#define TASKSTATS_VERSION" /usr/include/linux/taskstats.h
"#define TASKSTATS_VERSION 14"
bash# ./getdelays -d -p 1
CPU count real total virtual total delay total delay average
68862 163474790046 174584722267 19962496806 0.290ms
IO count delay total delay average
0 0 0.000ms
SWAP count delay total delay average
0 0 0.000ms
RECLAIM count delay total delay average
0 0 0.000ms
THRASHING count delay total delay average
0 0 0.000ms
COMPACT count delay total delay average
0 0 0.000ms
WPCOPY count delay total delay average
0 0 0.000ms
IRQ count delay total delay average
0 0 0.000ms

Link: https://lkml.kernel.org/r/20250731225326549CttJ7g9NfjTlaqBwl015T@zte.com.cn
Signed-off-by: Fan Yu <fan.yu9@zte.com.cn>
Cc: Fan Yu <fan.yu9@zte.com.cn>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Wang Yaxin <wang.yaxin@zte.com.cn>
Cc: xu xin <xu.xin16@zte.com.cn>
Cc: Yang Yang <yang.yang29@zte.com.cn>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Fan Yu and committed by
Andrew Morton
085dece6 b753522b

+100 -67
+100 -67
tools/accounting/getdelays.c
··· 194 194 #define average_ms(t, c) (t / 1000000ULL / (c ? c : 1)) 195 195 #define delay_ms(t) (t / 1000000ULL) 196 196 197 + /* 198 + * Version compatibility note: 199 + * Field availability depends on taskstats version (t->version), 200 + * corresponding to TASKSTATS_VERSION in kernel headers 201 + * see include/uapi/linux/taskstats.h 202 + * 203 + * Version feature mapping: 204 + * version >= 11 - supports COMPACT statistics 205 + * version >= 13 - supports WPCOPY statistics 206 + * version >= 14 - supports IRQ statistics 207 + * version >= 16 - supports *_max and *_min delay statistics 208 + * 209 + * Always verify version before accessing version-dependent fields 210 + * to maintain backward compatibility. 211 + */ 212 + #define PRINT_CPU_DELAY(version, t) \ 213 + do { \ 214 + if (version >= 16) { \ 215 + printf("%-10s%15s%15s%15s%15s%15s%15s%15s\n", \ 216 + "CPU", "count", "real total", "virtual total", \ 217 + "delay total", "delay average", "delay max", "delay min"); \ 218 + printf(" %15llu%15llu%15llu%15llu%15.3fms%13.6fms%13.6fms\n", \ 219 + (unsigned long long)(t)->cpu_count, \ 220 + (unsigned long long)(t)->cpu_run_real_total, \ 221 + (unsigned long long)(t)->cpu_run_virtual_total, \ 222 + (unsigned long long)(t)->cpu_delay_total, \ 223 + average_ms((double)(t)->cpu_delay_total, (t)->cpu_count), \ 224 + delay_ms((double)(t)->cpu_delay_max), \ 225 + delay_ms((double)(t)->cpu_delay_min)); \ 226 + } else { \ 227 + printf("%-10s%15s%15s%15s%15s%15s\n", \ 228 + "CPU", "count", "real total", "virtual total", \ 229 + "delay total", "delay average"); \ 230 + printf(" %15llu%15llu%15llu%15llu%15.3fms\n", \ 231 + (unsigned long long)(t)->cpu_count, \ 232 + (unsigned long long)(t)->cpu_run_real_total, \ 233 + (unsigned long long)(t)->cpu_run_virtual_total, \ 234 + (unsigned long long)(t)->cpu_delay_total, \ 235 + average_ms((double)(t)->cpu_delay_total, (t)->cpu_count)); \ 236 + } \ 237 + } while (0) 238 + #define PRINT_FILED_DELAY(name, version, t, count, total, max, min) \ 239 + do { \ 240 + if (version >= 16) { \ 241 + printf("%-10s%15s%15s%15s%15s%15s\n", \ 242 + name, "count", "delay total", "delay average", \ 243 + "delay max", "delay min"); \ 244 + printf(" %15llu%15llu%15.3fms%13.6fms%13.6fms\n", \ 245 + (unsigned long long)(t)->count, \ 246 + (unsigned long long)(t)->total, \ 247 + average_ms((double)(t)->total, (t)->count), \ 248 + delay_ms((double)(t)->max), \ 249 + delay_ms((double)(t)->min)); \ 250 + } else { \ 251 + printf("%-10s%15s%15s%15s\n", \ 252 + name, "count", "delay total", "delay average"); \ 253 + printf(" %15llu%15llu%15.3fms\n", \ 254 + (unsigned long long)(t)->count, \ 255 + (unsigned long long)(t)->total, \ 256 + average_ms((double)(t)->total, (t)->count)); \ 257 + } \ 258 + } while (0) 259 + 197 260 static void print_delayacct(struct taskstats *t) 198 261 { 199 - printf("\n\nCPU %15s%15s%15s%15s%15s%15s%15s\n" 200 - " %15llu%15llu%15llu%15llu%15.3fms%13.6fms%13.6fms\n" 201 - "IO %15s%15s%15s%15s%15s\n" 202 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n" 203 - "SWAP %15s%15s%15s%15s%15s\n" 204 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n" 205 - "RECLAIM %12s%15s%15s%15s%15s\n" 206 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n" 207 - "THRASHING%12s%15s%15s%15s%15s\n" 208 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n" 209 - "COMPACT %12s%15s%15s%15s%15s\n" 210 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n" 211 - "WPCOPY %12s%15s%15s%15s%15s\n" 212 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n" 213 - "IRQ %15s%15s%15s%15s%15s\n" 214 - " %15llu%15llu%15.3fms%13.6fms%13.6fms\n", 215 - "count", "real total", "virtual total", 216 - "delay total", "delay average", "delay max", "delay min", 217 - (unsigned long long)t->cpu_count, 218 - (unsigned long long)t->cpu_run_real_total, 219 - (unsigned long long)t->cpu_run_virtual_total, 220 - (unsigned long long)t->cpu_delay_total, 221 - average_ms((double)t->cpu_delay_total, t->cpu_count), 222 - delay_ms((double)t->cpu_delay_max), 223 - delay_ms((double)t->cpu_delay_min), 224 - "count", "delay total", "delay average", "delay max", "delay min", 225 - (unsigned long long)t->blkio_count, 226 - (unsigned long long)t->blkio_delay_total, 227 - average_ms((double)t->blkio_delay_total, t->blkio_count), 228 - delay_ms((double)t->blkio_delay_max), 229 - delay_ms((double)t->blkio_delay_min), 230 - "count", "delay total", "delay average", "delay max", "delay min", 231 - (unsigned long long)t->swapin_count, 232 - (unsigned long long)t->swapin_delay_total, 233 - average_ms((double)t->swapin_delay_total, t->swapin_count), 234 - delay_ms((double)t->swapin_delay_max), 235 - delay_ms((double)t->swapin_delay_min), 236 - "count", "delay total", "delay average", "delay max", "delay min", 237 - (unsigned long long)t->freepages_count, 238 - (unsigned long long)t->freepages_delay_total, 239 - average_ms((double)t->freepages_delay_total, t->freepages_count), 240 - delay_ms((double)t->freepages_delay_max), 241 - delay_ms((double)t->freepages_delay_min), 242 - "count", "delay total", "delay average", "delay max", "delay min", 243 - (unsigned long long)t->thrashing_count, 244 - (unsigned long long)t->thrashing_delay_total, 245 - average_ms((double)t->thrashing_delay_total, t->thrashing_count), 246 - delay_ms((double)t->thrashing_delay_max), 247 - delay_ms((double)t->thrashing_delay_min), 248 - "count", "delay total", "delay average", "delay max", "delay min", 249 - (unsigned long long)t->compact_count, 250 - (unsigned long long)t->compact_delay_total, 251 - average_ms((double)t->compact_delay_total, t->compact_count), 252 - delay_ms((double)t->compact_delay_max), 253 - delay_ms((double)t->compact_delay_min), 254 - "count", "delay total", "delay average", "delay max", "delay min", 255 - (unsigned long long)t->wpcopy_count, 256 - (unsigned long long)t->wpcopy_delay_total, 257 - average_ms((double)t->wpcopy_delay_total, t->wpcopy_count), 258 - delay_ms((double)t->wpcopy_delay_max), 259 - delay_ms((double)t->wpcopy_delay_min), 260 - "count", "delay total", "delay average", "delay max", "delay min", 261 - (unsigned long long)t->irq_count, 262 - (unsigned long long)t->irq_delay_total, 263 - average_ms((double)t->irq_delay_total, t->irq_count), 264 - delay_ms((double)t->irq_delay_max), 265 - delay_ms((double)t->irq_delay_min)); 262 + printf("\n\n"); 263 + 264 + PRINT_CPU_DELAY(t->version, t); 265 + 266 + PRINT_FILED_DELAY("IO", t->version, t, 267 + blkio_count, blkio_delay_total, 268 + blkio_delay_max, blkio_delay_min); 269 + 270 + PRINT_FILED_DELAY("SWAP", t->version, t, 271 + swapin_count, swapin_delay_total, 272 + swapin_delay_max, swapin_delay_min); 273 + 274 + PRINT_FILED_DELAY("RECLAIM", t->version, t, 275 + freepages_count, freepages_delay_total, 276 + freepages_delay_max, freepages_delay_min); 277 + 278 + PRINT_FILED_DELAY("THRASHING", t->version, t, 279 + thrashing_count, thrashing_delay_total, 280 + thrashing_delay_max, thrashing_delay_min); 281 + 282 + if (t->version >= 11) { 283 + PRINT_FILED_DELAY("COMPACT", t->version, t, 284 + compact_count, compact_delay_total, 285 + compact_delay_max, compact_delay_min); 286 + } 287 + 288 + if (t->version >= 13) { 289 + PRINT_FILED_DELAY("WPCOPY", t->version, t, 290 + wpcopy_count, wpcopy_delay_total, 291 + wpcopy_delay_max, wpcopy_delay_min); 292 + } 293 + 294 + if (t->version >= 14) { 295 + PRINT_FILED_DELAY("IRQ", t->version, t, 296 + irq_count, irq_delay_total, 297 + irq_delay_max, irq_delay_min); 298 + } 266 299 } 267 300 268 301 static void task_context_switch_counts(struct taskstats *t)