1 /++ 2 A POSIX application wrapping getrusage(2) for simple benchmarks. 3 4 SYNOPSIS: 5 `getr <#runs> <command> [<args> ...]` 6 7 OUTPUT: 8 --- 9 $ getr 1000 ./fizzbuzz >/dev/null 10 User time : 0 s, 894347 us 11 System time : 0 s, 673832 us 12 Time : 1568.179 ms (1.568 ms/per) 13 Max RSS : 952 kB 14 Page reclaims : 239344 15 Page faults : 1 16 Block inputs : 0 17 Block outputs : 0 18 vol ctx switches : 0 19 invol ctx switches : 1298 20 --- 21 22 DESCRIPTION: 23 getr is a simple wrapper around the `getrusage`(2) syscall, which can be 24 relied on for basic resource usage reports under Linux, OpenBSD, and macOS 25 (among others). A child command is repeatedly spawned and waited for, and 26 then a `RUSAGE_CHILDREN` report is generated. This program was created as 27 the author was used to very simple bash loops to test performance, which 28 was then found didn't work at all under ksh on OpenBSD. getr is just as 29 easy and just as simple. 30 31 EXIT_STATUS: 32 getr exits with status 1 if it fails to spawn a process, or if its own 33 arguments aren't understood. It exits with status 0 in all other cases, 34 including if the spawned program returns a nonzero exit status. 35 36 EXAMPLES: 37 `getr 1000 ./fizzbuzz > /dev/null` 38 39 `fizzbuzz` is invoked 1000 times, with no arguments, and with getr's own 40 (and therefore `fizzbuzz`'s) standard output piped to /dev/null. The 41 resulting usage report would still be printed to standard error. 42 43 `getr 100 rdmd -c ''` 44 45 `rdmd` in PATH is asked, 100 times, to evaluate the empty string. 46 47 SEE_ALSO: 48 `getrusage`(2), `which`(1), `time`(1), `perf`(1), `valgrind`(1). 49 +/ 50 51 module getr; 52 53 extern (C) int getrusage(int who, RUsage* usage); 54 55 enum RUSAGE_CHILDREN = -1; 56 57 struct Timeval { 58 long tv_sec; 59 long tv_usec; 60 } 61 62 struct RUsage { 63 Timeval ru_utime; 64 Timeval ru_stime; 65 long ru_maxrss; 66 long ru_ixrss; 67 long ru_idrss; 68 long ru_isrss; 69 long ru_minflt; 70 long ru_majflt; 71 long ru_nswap; 72 long ru_inblock; 73 long ru_oublock; 74 long ru_msgsnd; 75 long ru_msgrcv; 76 long ru_nsignals; 77 long ru_nvcsw; 78 long ru_nivcsw; 79 } 80 81 void report(int times) { 82 import std.stdio : stderr; 83 84 RUsage usage = void; 85 86 getrusage(RUSAGE_CHILDREN, &usage); 87 auto seconds = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec; 88 auto microseconds = usage.ru_utime.tv_usec + usage.ru_stime.tv_usec; 89 auto milliseconds = seconds * 1000 + microseconds / 1000; 90 auto ms_per = cast(double) milliseconds / cast(double) times; 91 92 stderr.writef!q"REPORT 93 User time : %d s, %d us 94 System time : %d s, %d us 95 Time : %d ms (%.3f ms/per) 96 Max RSS : %s 97 Page reclaims : %d 98 Page faults : %d 99 Block inputs : %d 100 Block outputs : %d 101 vol ctx switches : %d 102 invol ctx switches : %d 103 REPORT"(usage.ru_utime.tv_sec, usage.ru_utime.tv_usec, 104 usage.ru_stime.tv_sec, usage.ru_stime.tv_usec, milliseconds, ms_per, 105 readable_rss(cast(real) usage.ru_maxrss), usage.ru_minflt, usage.ru_majflt, 106 usage.ru_inblock, usage.ru_oublock, usage.ru_nvcsw, usage.ru_nivcsw); 107 } 108 109 string readable_rss(real kb) { 110 import std.format : format; 111 112 if (kb < 1024.0) 113 return format!"%.0f kB"(kb); 114 else if (kb < 1024.0 * 1024.0) 115 return format!"%.1f MB"(kb / 1024.0); 116 else 117 return format!"%.2f GB"(kb / (1024.0 * 1024.0)); 118 } 119 120 void main(string[] args) { 121 import std.stdio : stderr; 122 import core.stdc.stdlib : exit; 123 import std.exception : ifThrown; 124 import std.conv : to; 125 import std.process : spawnProcess, wait; 126 127 void usage() { 128 stderr.writeln("usage: ", args[0], " <#runs> <command> [<args> ...]"); 129 exit(1); 130 } 131 132 if (args.length < 3) 133 usage(); 134 135 immutable int count = to!int(args[1]).ifThrown(0); 136 137 if (count < 1) 138 usage(); 139 140 foreach (i; 0 .. count) { 141 wait(spawnProcess(args[2 .. $])); 142 } 143 144 report(count); 145 }