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

delay-accounting: reimplement -c for getdelays.c to report information on a target command

Task delay-accounting was identified as one means of determining how long
a process spends in congestion_wait() without adding new statistics. For
example, if the workload should not be doing IO, delay-accounting could
reveal how long it was spending in unexpected IO or delays.
Unfortunately, on closer examination it was clear that getdelays does not
act as documented.

Commit a3baf649 ("per-task-delay-accounting: documentation") added
Documentation/accounting/getdelays.c with a -c switch that was documented
to fork/exec a child and report statistics on it but for reasons that are
unclear to me, commit 9e06d3f9 deleted support for this switch but did not
update the documentation. It might be an oversight or it might be because
the control flow of the program meant that accounting information would be
printed once early in the lifetime of the program making it of limited
use.

This patch reimplements -c for getdelays.c to act as documented. Unlike
the original version, it waits until the command completes before printing
any information on it. An example of it being used looks like

$ ./getdelays -d -c find /home/mel -name mel
print delayacct stats ON
/home/mel
/home/mel/.notes-wine/drive_c/windows/profiles/mel
/home/mel/.wine/drive_c/windows/profiles/mel
/home/mel/git-configs/dot.kde/share/apps/konqueror/home/mel
PID 5923

CPU count real total virtual total delay total
42779 5051232096 5164722692 564207988
IO count delay total
41727 97804147758
SWAP count delay total
0 0
RECLAIM count delay total
0 0

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Mel Gorman <mel@csn.ul.ie>
Acked-by: Balbir Singh <balbir@in.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Mel Gorman and committed by
Linus Torvalds
db9e5679 7af37bec

+36 -2
+36 -2
Documentation/accounting/getdelays.c
··· 21 21 #include <sys/types.h> 22 22 #include <sys/stat.h> 23 23 #include <sys/socket.h> 24 + #include <sys/wait.h> 24 25 #include <signal.h> 25 26 26 27 #include <linux/genetlink.h> ··· 267 266 int containerset = 0; 268 267 char containerpath[1024]; 269 268 int cfd = 0; 269 + int forking = 0; 270 + sigset_t sigset; 270 271 271 272 struct msgtemplate msg; 272 273 273 - while (1) { 274 - c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:"); 274 + while (!forking) { 275 + c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:c:"); 275 276 if (c < 0) 276 277 break; 277 278 ··· 321 318 if (!tid) 322 319 err(1, "Invalid pid\n"); 323 320 cmd_type = TASKSTATS_CMD_ATTR_PID; 321 + break; 322 + case 'c': 323 + 324 + /* Block SIGCHLD for sigwait() later */ 325 + if (sigemptyset(&sigset) == -1) 326 + err(1, "Failed to empty sigset"); 327 + if (sigaddset(&sigset, SIGCHLD)) 328 + err(1, "Failed to set sigchld in sigset"); 329 + sigprocmask(SIG_BLOCK, &sigset, NULL); 330 + 331 + /* fork/exec a child */ 332 + tid = fork(); 333 + if (tid < 0) 334 + err(1, "Fork failed\n"); 335 + if (tid == 0) 336 + if (execvp(argv[optind - 1], 337 + &argv[optind - 1]) < 0) 338 + exit(-1); 339 + 340 + /* Set the command type and avoid further processing */ 341 + cmd_type = TASKSTATS_CMD_ATTR_PID; 342 + forking = 1; 324 343 break; 325 344 case 'v': 326 345 printf("debug on\n"); ··· 393 368 if (tid && containerset) { 394 369 fprintf(stderr, "Select either -t or -C, not both\n"); 395 370 goto err; 371 + } 372 + 373 + /* 374 + * If we forked a child, wait for it to exit. Cannot use waitpid() 375 + * as all the delicious data would be reaped as part of the wait 376 + */ 377 + if (tid && forking) { 378 + int sig_received; 379 + sigwait(&sigset, &sig_received); 396 380 } 397 381 398 382 if (tid) {