This file is indexed.

/usr/bin/tricensus-mpi-status is in regina-normal-mpi 4.95-1build1.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
#!/usr/bin/perl -w
#
# Regina - A Normal Surface Theory Calculator
# View a concise summary of events in a tricensus-mpi log file
#
# Copyright (c) 2005-2013, Ben Burton
# For further details contact Ben Burton (bab@debian.org).
#
# Usage: tricensus-mpi-status <log-file>
#
# See the manpage or users' handbook for full usage instructions.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# As an exception, when this program is distributed through (i) the
# App Store by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or
# (iii) Google Play by Google Inc., then that store may impose any
# digital rights management, device limits and/or redistribution
# restrictions that are required by its terms of service.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with this program; if not, write to the Free
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
# MA 02110-1301, USA.
#

use File::stat;
use IO::Uncompress::AnyUncompress qw(anyuncompress $AnyUncompressError);
use strict;

my $LOG;

# Display basic usage information.
#
sub usage {
    print STDERR "Usage: $0 <log-file>\n";
    exit(1);
}

# Quit with the given error message(s).
# Assumes that the log file is currently open (and closes it).
#
sub bail {
    foreach (@_) {
        print STDERR "ERROR: $_\n";
    }
    close($LOG);
    exit(1);
}

# --- Parse the command-line options. ---

usage unless @ARGV;
my $logFile = pop @ARGV;
usage if @ARGV;

$LOG = new IO::Uncompress::AnyUncompress $logFile;
if (! $LOG) {
    print STDERR "ERROR: Could not read the log file $logFile.\n";
    print STDERR "       ($AnyUncompressError)\n";
    exit(1);
}

# nPairings:
#   Total number of face pairings farmed out.
my $nPairings = 0;

# nTris:
#   Total number of triangulations found.
my $nTris = 0;

# searchType:
#   0     : not yet known
#   -1    : one pairing at a time
#   +1    : pairings split into subsearches
my $searchType = 0;

# pairingStatus:
#   undef : no such pairing
#   -1    : pairing processed on its own, still running
#   -2    : pairing processed on its own, finished
#   +1    : pairing split into subsearches, splitting still continuing
#   +2    : pairing split into subsearches, final # subsearches is known
my %pairingStatus = ();

# pairingSize:
#   undef : no such pairing
#   -1    : pairing processed on its own
#   >=0   : # subsearches currently farmed out
my %pairingSize = ();

# pairingDone:
#   undef : no such pairing
#   -1    : pairing processed on its own
#   >=0   : # subsearches finished
my %pairingDone = ();

# pairingProcHash:
#   Lists of precise subsearches that are currently being processed for
#   each face pairing (only relevant if subsearches are used).
my %pairingProcHash = ();

# pairingTris:
#   Total number of triangulations found for each face pairing.
my %pairingTris = ();

# donePairings:
#   Have we received a final pairings count?
my $donePairings = 0;

# doneTris:
#   Have we received a final triangulations count?
my $doneTris = 0;

my $lastDate = undef;
my $ref;
while (<$LOG>) {
    # Strip off the date and newline.
    chomp;
    s/^([A-Za-z0-9:\. ]{19} \d\d\d\d)  // and $lastDate = $1;

    if (/^Farmed pairing (\d+) -->/ or /^#(\d+): -->/) {
        $searchType > 0 and
            bail("Both subsearch and pairing-at-once search styles are used.");
        $searchType = -1;

        exists $pairingStatus{$1} and
            bail("Irregularity in farming order (pairing $1).");
        $1 == $nPairings + 1 or
            bail("Irregularity in farming order (pairing $1).");

        $pairingStatus{$1} = -1;
        $pairingSize{$1} = -1;
        $pairingDone{$1} = -1;
        $pairingTris{$1} = 0;
        $nPairings++;
    } elsif (/^Farmed subsearch (\d+)-(\d+) /) {
        $searchType < 0 and
            bail("Both subsearch and pairing-at-once search styles are used.");
        $searchType = 1;

        if (! exists $pairingStatus{$1}) {
            # First time we've seen this face pairing.

            $1 == $nPairings + 1 or
                bail("Irregularity in farming order ($1-$2).");
            $2 == 1 or
                bail("Irregularity in subsearch order ($1-$2).");

            $pairingStatus{$1} = 1;
            $pairingSize{$1} = 1;
            $pairingDone{$1} = 0;
            $pairingProcHash{$1} = { $2 => 1 };
            $pairingTris{$1} = 0;
            $nPairings++;
        } else {
            # A new subsearch for the face pairing that is currently being
            # processed.

            $1 == $nPairings or
                bail("Irregularity in farming order ($1-$2).");
            $2 == $pairingSize{$1} + 1 or
                bail("Irregularity in subsearch order ($1-$2).");
            $pairingStatus{$1} > 0 or
                bail("Subsearch farmed for standalone pairing ($1-$2).");
            $pairingStatus{$1} == 1 or
                bail("Subsearch farmed after pairing finalised ($1-$2).");

            $pairingSize{$1}++;
            $ref = $pairingProcHash{$1};
            $$ref{$2} = 1;
        }
    } elsif (/^Task \[(\d+) .+ (\d+) found/ or /^#(\d+): (\d+) triangulation/) {
        $searchType > 0 and
            bail("Both subsearch and pairing-at-once search styles are used.");
        $searchType = -1;

        exists $pairingStatus{$1} or
            bail("Results received for previously unseen pairing ($1).");
        $pairingStatus{$1} < 0 or
            bail("Results received for non-standalone pairing ($1).");
        $pairingStatus{$1} == -1 or
            bail("Results received after pairing finished ($1).");
        $pairingTris{$1} and
            bail("Unexpected triangulations already stored for pairing ($1).");

        $pairingStatus{$1} = -2;
        $pairingTris{$1} = $2;
        $nTris += $2;
    } elsif (/^Task \[(\d+)-(\d+) .+ (\d+) found/) {
        $searchType < 0 and
            bail("Both subsearch and pairing-at-once search styles are used.");
        $searchType = 1;

        exists $pairingStatus{$1} or
            bail("Subsearch received for previously unseen pairing ($1-$2).");
        $pairingStatus{$1} > 0 or
            bail("Subsearch received for standalone pairing ($1-$2).");
        $ref = $pairingProcHash{$1};
        # print join(' ', keys(%$ref))."\n";
        exists $$ref{$2} or
            bail("Subsearch received but not farmed ($1-$2).");
        delete $$ref{$2};

        $pairingDone{$1}++;
        $pairingTris{$1} += $3;
        $nTris += $3;
    } elsif (/^Pairing (\d+): Farmed (\d+) subsearch/) {
        $searchType < 0 and
            bail("Both subsearch and pairing-at-once search styles are used.");
        $searchType = 1;

        if (! exists $pairingStatus{$1}) {
            # First time we've seen this pairing.  There must have been
            # no subsearches.
            $1 == $nPairings + 1 or
                bail("Irregularity in farming order (pairing $1).");

            $pairingSize{$1} = 0;
            $pairingDone{$1} = 0;
            $pairingProcHash{$1} = { };
            $pairingTris{$1} = 0;
            $nPairings++;
        } elsif ($pairingStatus{$1} < 0) {
            bail("Final subsearch count received for standalone pairing ($1).");
        } elsif ($pairingStatus{$1} != 1) {
            bail("Pairing $1 finalised more than once.");
        }
        $pairingSize{$1} == $2 or
            bail("Mismatched subsearch count for pairing $1.");

        $pairingStatus{$1} = 2;
    } elsif (/^Slave \d+ stopped/) {
        # Winding to a close.  Ignore this line.
    } elsif (/^(Done:|\s+-) (\d+) pairing.* read$/) {
        # End of file.
        $donePairings and
            bail("Final pairing count appears more than once.");
        ($2 == $nPairings) or
            bail("Mismatched final pairing count ($2 != $nPairings).");
        $donePairings = 1;
    } elsif (/^(Done:|\s+-) (\d+) triangulation.* found$/) {
        # End of file.
        $doneTris and
            bail("Final triangulation count appears more than once.");
        ($2 == $nTris) or
            bail("Mismatched final triangulation count ($2 != $nTris).");
        $doneTris = 1;
    } elsif (/^Done:$/) {
        # Support for legacy log format.  Ignore this line.
    } else {
        bail('Unparseable line in log file:', $_);
    }
}

my $nDonePairings = 0;
my $hashRef;
for (my $i = 1; $i <= $nPairings; $i++) {
    print "Pairing $i: ";

    if ($pairingStatus{$i} == -1) {
        print "running";
    } elsif ($pairingStatus{$i} == -2) {
        print "done";
        $nDonePairings++;
    } elsif ($pairingStatus{$i} == 1) {
        print "$pairingDone{$i} / ($pairingSize{$i} + ...) done";
    } elsif ($pairingStatus{$i} == 2 and $pairingDone{$i} == $pairingSize{$i}) {
        print "all $pairingSize{$i} done";
        $nDonePairings++;
    } elsif ($pairingStatus{$i} == 2) {
        print "$pairingDone{$i} / $pairingSize{$i} done";
    } else {
        bail("Unknown status for pairing $i.");
    }

    print ", $pairingTris{$i} found" unless $pairingStatus{$i} == -1;
    print "\n";

    # More sanity checking.
    if ($pairingStatus{$i} > 0) {
        $hashRef = $pairingProcHash{$i};
        (scalar keys %$hashRef) == $pairingSize{$i} - $pairingDone{$i} or
            bail("Mismatched count of current subsearches for pairing $i.");
    }
}

if ($donePairings and $doneTris) {
    $nPairings == $nDonePairings or
        bail("Log finished but some pairings incomplete ".
            "($nDonePairings != $nPairings).");

    print "All done: $nPairings pairing(s), $nTris triangulation(s).\n";
} else {
    ($donePairings or $doneTris) and bail('Final tallies incomplete.');

    print "Still running, $nTris found";
    if ($lastDate) {
        print ", last activity: $lastDate";
    } else {
        # See when the log was last modified.
        my $st = stat($logFile);
        if ($st) {
            print ", log last updated: " . scalar localtime $st->mtime;
        } else {
            print ", no update time available.";
        }
    }
    print "\n";
}

close($LOG);
exit(0);