parse_logs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. #!/usr/bin/perl
  2. # Parse the log output files of run-experiment
  3. # Send concatenated log files to stdin, or list them on the command
  4. # line.
  5. use strict;
  6. my $mode = '';
  7. my $depth = 0;
  8. my $numops = 0;
  9. my $phase = '';
  10. my $numparties = '';
  11. my $what = '';
  12. my $setupsize = 0;
  13. my $opsize = 0;
  14. my @seconds = (0, 0);
  15. my $netsetup = '';
  16. my %preproc_s_data = ();
  17. my %preproc_kib_data = ();
  18. my %online_s_data = ();
  19. my %online_kib_data = ();
  20. while(<>) {
  21. chomp;
  22. if (/Network setup: (.*)/) {
  23. $netsetup = "$1 ";
  24. next;
  25. }
  26. if (/===== Running duoram (\S+) (\d+) (\d+) (\S+) ([23]P)/) {
  27. $mode = $1;
  28. $depth = $2;
  29. $numops = $3;
  30. $phase = $4;
  31. $numparties = $5;
  32. my $label = "${numparties}Duoram $mode $depth $netsetup$numops";
  33. if ($mode eq "read" && $numparties eq "2P") {
  34. &parse_2P_read($label);
  35. } elsif ($mode eq "write" && $numparties eq "2P" && $phase eq "preproc") {
  36. &parse_2P_write_preproc($label);
  37. } elsif ($mode eq "write" && $numparties eq "2P" && $phase eq "online") {
  38. &parse_2P_write_online($label);
  39. } elsif ($numparties eq "3P" && $phase eq "preproc") {
  40. &parse_3P_preproc("$depth $netsetup$numops");
  41. } elsif ($numparties eq "3P" && $phase eq "online") {
  42. &parse_3P_online("$depth $netsetup$numops");
  43. }
  44. @seconds = (0,0);
  45. $what = '';
  46. $setupsize = 0;
  47. $opsize = 0;
  48. next;
  49. }
  50. }
  51. # Convert the data (in the form [n, sum, sum_squares]) to statistics (in
  52. # the form [mean, variance])
  53. my %preproc_s_stats = ();
  54. my %preproc_kib_stats = ();
  55. my %online_s_stats = ();
  56. my %online_kib_stats = ();
  57. &statsify(\%preproc_s_stats, \%preproc_s_data);
  58. &statsify(\%preproc_kib_stats, \%preproc_kib_data);
  59. &statsify(\%online_s_stats, \%online_s_data);
  60. &statsify(\%online_kib_stats, \%online_kib_data);
  61. # The 2P readwrite values are just the sums of the read and the write values
  62. &sum_readwrite_2P(\%preproc_s_stats);
  63. &sum_readwrite_2P(\%preproc_kib_stats);
  64. &sum_readwrite_2P(\%online_s_stats);
  65. &sum_readwrite_2P(\%online_kib_stats);
  66. # The total values are the sums of the preproc and online values
  67. my %total_s_stats = ();
  68. my %total_kib_stats = ();
  69. &sum_preproc_online(\%total_s_stats, \%preproc_s_stats, \%online_s_stats);
  70. &sum_preproc_online(\%total_kib_stats, \%preproc_kib_stats, \%online_kib_stats);
  71. # Output the data
  72. &output_stats(\%preproc_s_stats, "Preprc", "s");
  73. &output_stats(\%preproc_kib_stats, "Preprc", "KiB");
  74. &output_stats(\%online_s_stats, "Onln", "s");
  75. &output_stats(\%online_kib_stats, "Onln", "KiB");
  76. &output_stats(\%total_s_stats, "Totl", "s");
  77. &output_stats(\%total_kib_stats, "Totl", "KiB");
  78. # Subroutines
  79. sub parse_2P_read {
  80. my $label = $_[0];
  81. my $who = 0;
  82. my @preproc_s = ();
  83. my @preproc_kib = ();
  84. my @online_s = ();
  85. my @online_kib = ();
  86. while(<>) {
  87. last if /===== End/;
  88. # Try to recover from a malformed log
  89. last if /^Max GB:/;
  90. # It was too malformed
  91. die "Malformed log" if /===== Running/;
  92. if (/===== P([012]) output/) {
  93. $who = $1;
  94. next;
  95. }
  96. if (/Total preprocessing time: (\d+) µs/) {
  97. $preproc_s[$who] = $1 / 1000000;
  98. }
  99. if (/Total preprocessing bytes: (\d+)/) {
  100. $preproc_kib[$who] = $1 / 1024;
  101. }
  102. if (/Total query time: (\d+) µs/) {
  103. $online_s[$who] = $1 / 1000000;
  104. }
  105. if (/Total query bytes: (\d+)/) {
  106. $online_kib[$who] = $1 / 1024;
  107. }
  108. }
  109. return if $#preproc_s < 0;
  110. &accum_data(\%preproc_s_data, $label, &maxarray(@preproc_s));
  111. &accum_data(\%preproc_kib_data, $label, &avgarray(@preproc_kib));
  112. &accum_data(\%online_s_data, $label, &maxarray(@online_s));
  113. &accum_data(\%online_kib_data, $label, &avgarray(@online_kib));
  114. }
  115. sub parse_2P_write_preproc {
  116. my $label = $_[0];
  117. my $who = 0;
  118. my @preproc_s = ();
  119. my @preproc_kib = ();
  120. while(<>) {
  121. last if /===== End/;
  122. # Try to recover from a malformed log
  123. last if /^Max GB:/;
  124. # It was too malformed
  125. die "Malformed log" if /===== Running/;
  126. if (/===== P([012]) output/) {
  127. $who = $1;
  128. next;
  129. }
  130. if (/time to generate and evaluate \d+ OTs is: (\d+\.?\d*+)s/) {
  131. $preproc_s[$who] = $1;
  132. }
  133. if (/bytes transmitted for OT = (\d+) bytes/) {
  134. $preproc_kib[$who] = $1 / 1024;
  135. }
  136. if (/WallClockTime: (\d+\.?\d*) s/) {
  137. $preproc_s[$who] += $1;
  138. }
  139. if (/CommunicationCost: (\d+) bytes/) {
  140. $preproc_kib[$who] += $1 / 1024;
  141. }
  142. }
  143. return if $#preproc_s < 0;
  144. &accum_data(\%preproc_s_data, $label, &maxarray(@preproc_s));
  145. &accum_data(\%preproc_kib_data, $label, &avgarray(@preproc_kib));
  146. }
  147. sub parse_2P_write_online {
  148. my $label = $_[0];
  149. my $who = 0;
  150. my @online_s = ();
  151. my @online_kib = ();
  152. while(<>) {
  153. last if /===== End/;
  154. # Try to recover from a malformed log
  155. last if /^Max GB:/;
  156. # It was too malformed
  157. die "Malformed log" if /===== Running/;
  158. if (/===== P([012]) output/) {
  159. $who = $1;
  160. next;
  161. }
  162. if (/write_time = (\d+\.?\d*)/) {
  163. $online_s[$who] = $1;
  164. }
  165. if (/communication_cost_writes = (\d+) bytes/) {
  166. $online_kib[$who] = $1 / 1024;
  167. }
  168. }
  169. return if $#online_s < 0;
  170. &accum_data(\%online_s_data, $label, &maxarray(@online_s));
  171. &accum_data(\%online_kib_data, $label, &avgarray(@online_kib));
  172. }
  173. sub parse_3P_preproc {
  174. my $labelsuffix = $_[0];
  175. my $who = 0;
  176. my @preproc_s = ();
  177. my @preproc_kib = ();
  178. while(<>) {
  179. if (/===== P([012]) output/) {
  180. $who = $1;
  181. next;
  182. }
  183. last if /===== End/;
  184. # Try to recover from a malformed log
  185. last if /^Max GB:/;
  186. # It was too malformed
  187. die "Malformed log" if /===== Running/;
  188. if (/WallClockTime: (\d+\.?\d*)/) {
  189. $preproc_s[$who] = $1;
  190. }
  191. if (/CommunicationCost: (\d+) bytes/) {
  192. $preproc_kib[$who] = $1 / 1024;
  193. }
  194. }
  195. return if $#preproc_s < 0;
  196. &accum_data(\%preproc_s_data, "3PDuoram read $labelsuffix", &maxarray(@preproc_s));
  197. &accum_data(\%preproc_kib_data, "3PDuoram read $labelsuffix", &avgarray(@preproc_kib));
  198. &accum_data(\%preproc_s_data, "3PDuoram write $labelsuffix", &maxarray(@preproc_s));
  199. &accum_data(\%preproc_kib_data, "3PDuoram write $labelsuffix", &avgarray(@preproc_kib));
  200. &accum_data(\%preproc_s_data, "3PDuoram readwrite $labelsuffix", 2*&maxarray(@preproc_s));
  201. &accum_data(\%preproc_kib_data, "3PDuoram readwrite $labelsuffix", 2*&avgarray(@preproc_kib));
  202. }
  203. sub parse_3P_online {
  204. my $labelsuffix = $_[0];
  205. my $who = 0;
  206. my @read_s = ();
  207. my @read_kib = ();
  208. my @write_s = ();
  209. my @write_kib = ();
  210. my @readwrite_s = ();
  211. my @readwrite_kib = ();
  212. while(<>) {
  213. last if /===== End/;
  214. # Try to recover from a malformed log
  215. last if /^Max GB:/;
  216. # It was too malformed
  217. die "Malformed log" if /===== Running/;
  218. if (/===== P([012]) output/) {
  219. $who = $1;
  220. next;
  221. }
  222. if (/write_time =\s+(\d+\.?\d*)/) {
  223. $write_s[$who] = $1;
  224. }
  225. if (/communication_cost_writes = (\d+) bytes/) {
  226. $write_kib[$who] = $1 / 1024;
  227. }
  228. if (/dependent_read_time =\s+(\d+\.?\d*)/) {
  229. $read_s[$who] = $1;
  230. }
  231. if (/communication_cost_dep_read = (\d+) bytes/) {
  232. $read_kib[$who] = $1 / 1024;
  233. }
  234. if (/interleaved_time =\s+(\d+\.?\d*)/) {
  235. $readwrite_s[$who] = $1;
  236. }
  237. if (/communication_cost_interleaved = (\d+) bytes/) {
  238. $readwrite_kib[$who] = $1 / 1024;
  239. }
  240. }
  241. return if $#read_s < 0;
  242. &accum_data(\%online_s_data, "3PDuoram read $labelsuffix", &maxarray(@read_s));
  243. &accum_data(\%online_kib_data, "3PDuoram read $labelsuffix", &avgarray(@read_kib));
  244. &accum_data(\%online_s_data, "3PDuoram write $labelsuffix", &maxarray(@write_s));
  245. &accum_data(\%online_kib_data, "3PDuoram write $labelsuffix", &avgarray(@write_kib));
  246. &accum_data(\%online_s_data, "3PDuoram readwrite $labelsuffix", &maxarray(@readwrite_s));
  247. &accum_data(\%online_kib_data, "3PDuoram readwrite $labelsuffix", &avgarray(@readwrite_kib));
  248. }
  249. sub maxarray {
  250. my $max = $_[0];
  251. foreach (@_) {
  252. $max = $_ if $_ > $max;
  253. }
  254. $max;
  255. }
  256. sub avgarray {
  257. my $sum = 0;
  258. my $n = 0;
  259. foreach (@_) {
  260. $sum += $_;
  261. $n += 1;
  262. }
  263. $sum / $n;
  264. }
  265. # Pass:
  266. # - a reference to a dictionary
  267. # - the key into that dictionary
  268. # - the new data point
  269. # Data is stored in the dictionary as a triple (n, sum, sum_squares)
  270. sub accum_data {
  271. my ($dict, $key, $data) = @_;
  272. $dict->{$key} = [0, 0, 0] unless defined $dict->{$key};
  273. $dict->{$key}->[0] += 1;
  274. $dict->{$key}->[1] += $data;
  275. $dict->{$key}->[2] += ($data * $data);
  276. }
  277. # Convert data (in the form [n, sum, sum_squares]) to statistics (in
  278. # the form [mean, variance])
  279. sub statsify {
  280. my ($sdict, $ddict) = @_;
  281. my $key;
  282. foreach $key (keys %$ddict) {
  283. my $data = $ddict->{$key};
  284. my $n = $data->[0];
  285. my $sum = $data->[1];
  286. my $sumsq = $data->[2];
  287. if ($n == 0) {
  288. $sdict->{$key} = [undef, undef];
  289. } elsif ($n == 1) {
  290. $sdict->{$key} = [$sum, undef];
  291. } else {
  292. $sdict->{$key} = [$sum/$n, ($sumsq - ($sum*$sum/$n))/($n-1)];
  293. }
  294. }
  295. }
  296. # Turn a stat array [mean, variance] into a string to display
  297. sub statstr {
  298. my $data = $_[0];
  299. if (defined $data->[1]) {
  300. my $mean = $data->[0];
  301. my $stddev = $data->[1] > 0 ? sqrt($data->[1]) : 0;
  302. return "$mean ± $stddev";
  303. } elsif (defined $data->[0]) {
  304. return $data->[0];
  305. } else {
  306. return "none"
  307. }
  308. }
  309. # Sum two stat arrays
  310. sub statsum {
  311. my ($data0, $data1) = @_;
  312. if (defined $data0->[1] && defined $data1->[1]) {
  313. return [$data0->[0] + $data1->[0], $data0->[1] + $data1->[1]];
  314. } else {
  315. return [$data0->[0] + $data1->[0], undef];
  316. }
  317. }
  318. # Sum two stat arrays, scaling the second by the given factor
  319. sub statscalesum {
  320. my ($data0, $data1, $scale) = @_;
  321. if (defined $data0->[1] && defined $data1->[1]) {
  322. return [$data0->[0] + $data1->[0]*$scale, $data0->[1] + $data1->[1]*$scale];
  323. } else {
  324. return [$data0->[0] + $data1->[0]*$scale, undef];
  325. }
  326. }
  327. # The 2P readwrite values are just the sums of the read and the write values
  328. sub sum_readwrite_2P {
  329. my $dict = $_[0];
  330. my $key;
  331. foreach $key (keys %$dict) {
  332. if ($key =~ /^2PDuoram read /) {
  333. my $writekey = $key;
  334. my $readwritekey = $key;
  335. $writekey =~ s/^2PDuoram read /2PDuoram write /;
  336. $readwritekey =~ s/^2PDuoram read /2PDuoram readwrite /;
  337. if (defined $dict->{$writekey}) {
  338. $dict->{$readwritekey} = &statsum($dict->{$key}, $dict->{$writekey});
  339. } else {
  340. # It's OK if we're missing the data point, since we
  341. # don't necessary parse all the data at once.
  342. # print "Missing data point for $writekey\n";
  343. }
  344. }
  345. }
  346. }
  347. # Add the preproc and online stats to get the total stats
  348. sub sum_preproc_online {
  349. my ($tdict, $pdict, $odict) = @_;
  350. my $key;
  351. foreach $key (keys %$odict) {
  352. if (defined $pdict->{$key}) {
  353. $tdict->{$key} = &statsum($pdict->{$key}, $odict->{$key});
  354. } else {
  355. # We were able to do the online phase of a given
  356. # configuration, but not the preprocessing phase. That's
  357. # possibly, OK, since to preprocess k DPFs of a given size,
  358. # you can always just preprocess k/2 DPFs twice. (If you're
  359. # _able_ to do them in parallel, you'll probably get better
  360. # results, but worst case, just find the largest set of this
  361. # configuration we were able to preprocess in parallel, and
  362. # multiply the results by how many times we would have to
  363. # repeat it.)
  364. # The key will end with k (the number of read (or whatever)
  365. # operations we're making DPFs for. Replace that number
  366. # with the literal regexp "(\d+)".
  367. my $config = $key;
  368. $config =~ s/\d+$/\(\\d\+\)/;
  369. # How many did we try and fail to preprocess
  370. $key =~ $config;
  371. my $triednum = $1;
  372. # Find the largest number we were able to preprocess
  373. my $pkey;
  374. my $maxnum = 0;
  375. foreach $pkey (keys %$pdict) {
  376. if ($pkey =~ /$config/) {
  377. $maxnum = $1 if $1 > $maxnum;
  378. }
  379. }
  380. if ($maxnum > 0) {
  381. $pkey = $key;
  382. $pkey =~ s/\d+$/$maxnum/;
  383. my $scale = int(($triednum+$maxnum-1)/$maxnum);
  384. $tdict->{$key} = &statscalesum($odict->{$key}, $pdict->{$pkey}, $scale);
  385. }
  386. }
  387. }
  388. }
  389. # Output the stats in the given dictionary. Append $phase to the
  390. # protocol name, and add $units to the end.
  391. sub output_stats {
  392. my ($dict, $phase, $units) = @_;
  393. my $label;
  394. foreach $label (sort keys %$dict) {
  395. my $printlabel = $label;
  396. $printlabel =~ s/PDuoram/PDuoram$phase/;
  397. print $printlabel, " ", &statstr($dict->{$label}), " $units\n";
  398. }
  399. }