rlm@23
|
1 #!/usr/bin/env perl
|
rlm@23
|
2 # -*- perl -*-
|
rlm@23
|
3
|
rlm@23
|
4 use strict;
|
rlm@23
|
5 use warnings;
|
rlm@23
|
6 use Getopt::Long qw(:config no_auto_abbrev no_ignore_case pass_through);
|
rlm@23
|
7 use IO::Pty;
|
rlm@23
|
8
|
rlm@23
|
9 #
|
rlm@23
|
10 # Turn on warnings
|
rlm@23
|
11 #
|
rlm@23
|
12 $^W = 1;
|
rlm@23
|
13
|
rlm@23
|
14 ##
|
rlm@23
|
15 ## Benchmark run script
|
rlm@23
|
16 ##
|
rlm@23
|
17
|
rlm@23
|
18 sub ExecModel($);
|
rlm@23
|
19 sub Exec($$);
|
rlm@23
|
20 sub CompareOutput();
|
rlm@23
|
21 sub ReadConfig($$);
|
rlm@23
|
22
|
rlm@23
|
23
|
rlm@23
|
24 #############################################################################
|
rlm@23
|
25 #############################################################################
|
rlm@23
|
26 ##
|
rlm@23
|
27 ## Start by figuring out the model location and type.
|
rlm@23
|
28 ##
|
rlm@23
|
29 #############################################################################
|
rlm@23
|
30 #############################################################################
|
rlm@23
|
31
|
rlm@23
|
32 my %config;
|
rlm@23
|
33
|
rlm@23
|
34 ReadConfig("config/env.sh", 1);
|
rlm@23
|
35 ReadConfig("$config{modelDir}/config/env.sh", 1);
|
rlm@23
|
36 ReadConfig("$config{modelDir}/config/signature.sh", 0);
|
rlm@23
|
37
|
rlm@23
|
38 ##
|
rlm@23
|
39 ## Pseudo-enumeration of possible model types
|
rlm@23
|
40 ##
|
rlm@23
|
41 my $MODEL_NONE = 0;
|
rlm@23
|
42 my $MODEL_FPGA = 1; # Model runs on FPGA hardware
|
rlm@23
|
43 my $MODEL_BLUESIM = 2; # Bluesim
|
rlm@23
|
44 my $MODEL_VSIM = 3; # Verilog simulator
|
rlm@23
|
45
|
rlm@23
|
46 my $mType = $MODEL_NONE;
|
rlm@23
|
47
|
rlm@23
|
48
|
rlm@23
|
49 #############################################################################
|
rlm@23
|
50 #############################################################################
|
rlm@23
|
51 ##
|
rlm@23
|
52 ## Process command line arguments
|
rlm@23
|
53 ##
|
rlm@23
|
54 #############################################################################
|
rlm@23
|
55 #############################################################################
|
rlm@23
|
56
|
rlm@23
|
57 my $help = 0;
|
rlm@23
|
58 my $onlyCompare = 0;
|
rlm@23
|
59 my $noCompare = 0;
|
rlm@23
|
60 my $forceLoad = 0;
|
rlm@23
|
61 my $gdb = 0;
|
rlm@23
|
62 my $noProgram = 0;
|
rlm@23
|
63 my $noReserve = 0;
|
rlm@23
|
64 my $funcpPrefix = "";
|
rlm@23
|
65 my $funcpSuffix = "";
|
rlm@23
|
66 my $printCycle = undef;
|
rlm@23
|
67 my $bluesimCmd = undef;
|
rlm@23
|
68 my $vcdStart = undef;
|
rlm@23
|
69 my $vcdCycles = 20000;
|
rlm@23
|
70 my $m5run = 0;
|
rlm@23
|
71
|
rlm@23
|
72 my $status = GetOptions("help!" => \$help,
|
rlm@23
|
73 "gdb!" => \$gdb,
|
rlm@23
|
74 "noprogram!" => \$noProgram,
|
rlm@23
|
75 "noreserve!" => \$noReserve,
|
rlm@23
|
76 "force-load!" => \$forceLoad,
|
rlm@23
|
77 "funcp-prefix=s" => \$funcpPrefix,
|
rlm@23
|
78 "funcp-suffix=s" => \$funcpSuffix,
|
rlm@23
|
79 "onlycompare!" => \$onlyCompare,
|
rlm@23
|
80 "nocompare!" => \$noCompare,
|
rlm@23
|
81 "pc=s" => \$printCycle,
|
rlm@23
|
82 "bluesim=s" => \$bluesimCmd,
|
rlm@23
|
83 "vcdstart=i" => \$vcdStart,
|
rlm@23
|
84 "vcdcycles=i" => \$vcdCycles,
|
rlm@23
|
85 "m5!" => \$m5run,
|
rlm@23
|
86 );
|
rlm@23
|
87
|
rlm@23
|
88 # Put quotation marks back on arguments that have spaces since they will be
|
rlm@23
|
89 # passed through a shell once more.
|
rlm@23
|
90 foreach my $i ( 0 .. $#ARGV ) {
|
rlm@23
|
91 if (($ARGV[$i] =~ /\s/) && ! ($ARGV[$i] =~ /['"]$/)) {
|
rlm@23
|
92 $ARGV[$i] = '"' . $ARGV[$i] . '"';
|
rlm@23
|
93 }
|
rlm@23
|
94 }
|
rlm@23
|
95
|
rlm@23
|
96 if ($onlyCompare != 0) {
|
rlm@23
|
97 exit(CompareOutput());
|
rlm@23
|
98 }
|
rlm@23
|
99
|
rlm@23
|
100 if ($m5run != 0) {
|
rlm@23
|
101 $mType = $MODEL_NONE;
|
rlm@23
|
102 }
|
rlm@23
|
103 elsif (-f "$config{modelDir}/$config{model}_hw.errinfo") {
|
rlm@23
|
104 $mType = $MODEL_FPGA;
|
rlm@23
|
105 }
|
rlm@23
|
106 elsif (-f "$config{modelDir}/$config{model}_hw.exe") {
|
rlm@23
|
107 $mType = $MODEL_BLUESIM;
|
rlm@23
|
108 }
|
rlm@23
|
109 elsif (-f "$config{modelDir}/$config{model}_hw.vexe") {
|
rlm@23
|
110 $mType = $MODEL_VSIM;
|
rlm@23
|
111 }
|
rlm@23
|
112 else {
|
rlm@23
|
113 die("Can't determine model type");
|
rlm@23
|
114 }
|
rlm@23
|
115
|
rlm@23
|
116 if ($help || ! $status) {
|
rlm@23
|
117 print STDERR "\nArguments:\n";
|
rlm@23
|
118 print STDERR " [--gdb] Invokes the software side in gdb\n";
|
rlm@23
|
119 print STDERR " [--noprogram] Skips the FPGA load and reservation steps\n";
|
rlm@23
|
120 print STDERR " [--noreserve] Skips the FPGA reservation steps\n";
|
rlm@23
|
121 print STDERR " [--funcp-prefix=\"<prefix>\"]\n";
|
rlm@23
|
122 print STDERR " Prepend prefix to HAsim's --funcp argument\n";
|
rlm@23
|
123 print STDERR " [--funcp-suffix=\"<suffix>\"]\n";
|
rlm@23
|
124 print STDERR " Append suffix to HAsim's --funcp argument\n";
|
rlm@23
|
125 print STDERR " [--onlycompare] Only compare output files (without running)\n";
|
rlm@23
|
126 print STDERR " [--nocompare] Skip comparison of output files\n";
|
rlm@23
|
127 print STDERR " [--m5] Run workload in m5 without HAsim\n";
|
rlm@23
|
128
|
rlm@23
|
129 if ($mType == $MODEL_FPGA) {
|
rlm@23
|
130 print STDERR " [--force-load] Load a bitfile to the FPGA even if it has errors\n";
|
rlm@23
|
131 }
|
rlm@23
|
132
|
rlm@23
|
133 if ($mType == $MODEL_BLUESIM) {
|
rlm@23
|
134 print STDERR " [--vcdstart=<cycle>] Generate VCD dump for wave viewer (e.g. gtkwave)\n";
|
rlm@23
|
135 print STDERR " [--vcdcycles=<cycles>] VCD dump length (default = 20000)\n";
|
rlm@23
|
136 }
|
rlm@23
|
137
|
rlm@23
|
138 if ($config{isHybridModel}) {
|
rlm@23
|
139 my $cmd = "$config{modelDir}/$config{model} --help-run-append";
|
rlm@23
|
140 system($cmd);
|
rlm@23
|
141 }
|
rlm@23
|
142
|
rlm@23
|
143 exit(1);
|
rlm@23
|
144 }
|
rlm@23
|
145
|
rlm@23
|
146 #############################################################################
|
rlm@23
|
147 #############################################################################
|
rlm@23
|
148 ##
|
rlm@23
|
149 ## Adjust model arguments
|
rlm@23
|
150 ##
|
rlm@23
|
151 #############################################################################
|
rlm@23
|
152 #############################################################################
|
rlm@23
|
153
|
rlm@23
|
154 my $feedFlags = "${funcpPrefix} $config{feedFlags} ${funcpSuffix}";
|
rlm@23
|
155
|
rlm@23
|
156 if ($config{feeder} eq 'm5') {
|
rlm@23
|
157 # Tell m5 to be quiet and not to enable the remote gdb port. Under netbatch
|
rlm@23
|
158 # it appears there are sometimes attempts to connect to the port, which
|
rlm@23
|
159 # stops simulation.
|
rlm@23
|
160 $feedFlags = "--quiet --remote-gdb-port=0 ${feedFlags}";
|
rlm@23
|
161 }
|
rlm@23
|
162
|
rlm@23
|
163 my $cmd;
|
rlm@23
|
164
|
rlm@23
|
165 if ($m5run == 0) {
|
rlm@23
|
166 # Normal run
|
rlm@23
|
167 $cmd = "$config{modelDir}/$config{model} --modeldir=$config{modelDir} --workload=$config{workload} --funcp=\"${feedFlags}\" $config{genFlags}";
|
rlm@23
|
168 foreach my $c (@ARGV) {
|
rlm@23
|
169 $cmd .= " $c";
|
rlm@23
|
170 }
|
rlm@23
|
171
|
rlm@23
|
172 if (defined($printCycle)) {
|
rlm@23
|
173 $cmd .= " --pc=${printCycle}";
|
rlm@23
|
174 }
|
rlm@23
|
175 }
|
rlm@23
|
176 else {
|
rlm@23
|
177 if ($config{feeder} ne 'm5') {
|
rlm@23
|
178 die("This workload does not use m5");
|
rlm@23
|
179 }
|
rlm@23
|
180
|
rlm@23
|
181 # Running inside m5 without HAsim
|
rlm@23
|
182 my $m5cmd;
|
rlm@23
|
183 if (exists($ENV{M5BIN})) {
|
rlm@23
|
184 $m5cmd = $ENV{M5BIN};
|
rlm@23
|
185 }
|
rlm@23
|
186 else {
|
rlm@23
|
187 my $m5bin = "platform/m5/build/ALPHA_SE/m5." . ($gdb ? "debug" : "opt");
|
rlm@23
|
188 $m5cmd = `awb-resolver ${m5bin}`;
|
rlm@23
|
189 chomp($m5cmd);
|
rlm@23
|
190 die("Failed to find $m5bin") if ($m5cmd eq '');
|
rlm@23
|
191 }
|
rlm@23
|
192
|
rlm@23
|
193 $cmd = "${m5cmd} ${feedFlags}";
|
rlm@23
|
194
|
rlm@23
|
195 # Drop --hasim-sim
|
rlm@23
|
196 $cmd =~ s/--hasim-sim //;
|
rlm@23
|
197 # Drop escaping of quotes
|
rlm@23
|
198 $cmd =~ s/\\"/"/g;
|
rlm@23
|
199
|
rlm@23
|
200 $noProgram = 1;
|
rlm@23
|
201 }
|
rlm@23
|
202
|
rlm@23
|
203 #
|
rlm@23
|
204 # Bluesim arguments
|
rlm@23
|
205 #
|
rlm@23
|
206
|
rlm@23
|
207 # Generate dump.vcd for wave viewer (e.g. gtkwave)?
|
rlm@23
|
208 if (defined($vcdStart)) {
|
rlm@23
|
209 my $vcdCmd = "sim vcd on; sim step $vcdCycles; sim stop";
|
rlm@23
|
210 if ($vcdStart > 0) {
|
rlm@23
|
211 $vcdCmd = "sim step ${vcdStart}; ${vcdCmd}";
|
rlm@23
|
212 }
|
rlm@23
|
213
|
rlm@23
|
214 if (defined($bluesimCmd)) {
|
rlm@23
|
215 $bluesimCmd .= " ";
|
rlm@23
|
216 }
|
rlm@23
|
217 else {
|
rlm@23
|
218 $bluesimCmd = "";
|
rlm@23
|
219 }
|
rlm@23
|
220 $bluesimCmd .= "-c \"$vcdCmd\"";
|
rlm@23
|
221 }
|
rlm@23
|
222
|
rlm@23
|
223 if (defined($bluesimCmd)) {
|
rlm@23
|
224 $cmd .= " --bluesim=\'$bluesimCmd\'";
|
rlm@23
|
225 }
|
rlm@23
|
226
|
rlm@23
|
227 # Adjust the arguments for Bluesim if it is being invoked directly
|
rlm@23
|
228 if (! $config{isHybridModel} && ($mType == $MODEL_BLUESIM)) {
|
rlm@23
|
229 $cmd =~ s/\s--/ +--/g;
|
rlm@23
|
230
|
rlm@23
|
231 # Bluesim may expect to load a program from a well known file
|
rlm@23
|
232 unlink('program.vmh');
|
rlm@23
|
233 link("program/$config{workload}.$config{ISA}.vmh", 'program.vmh');
|
rlm@23
|
234 }
|
rlm@23
|
235
|
rlm@23
|
236
|
rlm@23
|
237 #############################################################################
|
rlm@23
|
238 #############################################################################
|
rlm@23
|
239 ##
|
rlm@23
|
240 ## Load the FPGA and run the model
|
rlm@23
|
241 ##
|
rlm@23
|
242 #############################################################################
|
rlm@23
|
243 #############################################################################
|
rlm@23
|
244
|
rlm@23
|
245 #
|
rlm@23
|
246 # Move old stats file so we are sure statistics come from this run
|
rlm@23
|
247 #
|
rlm@23
|
248 if (-f "$config{workload}.stats") {
|
rlm@23
|
249 rename("$config{workload}.stats", "$config{workload}.stats.old");
|
rlm@23
|
250 }
|
rlm@23
|
251
|
rlm@23
|
252 if ($mType == $MODEL_FPGA) {
|
rlm@23
|
253 if (! defined($printCycle)) {
|
rlm@23
|
254 # User didn't specify a cycle printing interval. Pick one more reasonable
|
rlm@23
|
255 # for HW.
|
rlm@23
|
256 #$cmd .= " --pc=10000000";
|
rlm@23
|
257 }
|
rlm@23
|
258
|
rlm@23
|
259 # Load FPGA
|
rlm@23
|
260 $ENV{FPGA_BIT_FILE} = "$config{modelDir}/.xilinx/$config{model}_par.bit";
|
rlm@23
|
261
|
rlm@23
|
262 if (! $noProgram) {
|
rlm@23
|
263 if (! $forceLoad && -s "$config{modelDir}/$config{model}_hw.errinfo") {
|
rlm@23
|
264 print STDERR "FPGA bit file has errors:\n\n";
|
rlm@23
|
265 system("cat $config{modelDir}/$config{model}_hw.errinfo > /dev/stderr");
|
rlm@23
|
266 print STDERR "\nUse --force-load to ignore the error.\n";
|
rlm@23
|
267 exit(1);
|
rlm@23
|
268 }
|
rlm@23
|
269
|
rlm@23
|
270 if (! $noReserve) {
|
rlm@23
|
271 Exec("hasim-fpga-ctrl --reserve", "Failed to reserve FPGA");
|
rlm@23
|
272 }
|
rlm@23
|
273
|
rlm@23
|
274 # Does a download script exist to program the FPGA?
|
rlm@23
|
275 my $needProgram = (-f "$config{modelDir}/config/$config{model}.download");
|
rlm@23
|
276
|
rlm@23
|
277 $needProgram = 1;
|
rlm@23
|
278
|
rlm@23
|
279 # Is the FPGA already programmed with the correct bit file?
|
rlm@23
|
280 if (exists($config{signature})) {
|
rlm@23
|
281 my $curSignature = `hasim-fpga-ctrl --getsignature`;
|
rlm@23
|
282 chomp($curSignature);
|
rlm@23
|
283 if ($curSignature eq $config{signature}) {
|
rlm@23
|
284 print "FPGA is already programmed (signature match)...\n";
|
rlm@23
|
285 #$needProgram = 0;
|
rlm@23
|
286 }
|
rlm@23
|
287 }
|
rlm@23
|
288
|
rlm@23
|
289 if ($needProgram) {
|
rlm@23
|
290 Exec("hasim-fpga-ctrl --program", "Failed to enter FPGA programming mode");
|
rlm@23
|
291
|
rlm@23
|
292 my $dir = `pwd`;
|
rlm@23
|
293 chomp($dir);
|
rlm@23
|
294 Exec("(cd $config{modelDir}; ./config/$config{model}.download ${dir}/FPGA_programming.log)", "Failed to program FPGA");
|
rlm@23
|
295
|
rlm@23
|
296 if (exists($config{signature})) {
|
rlm@23
|
297 Exec("hasim-fpga-ctrl --setsignature=$config{signature}", "Failed to set FPGA bit image signature");
|
rlm@23
|
298 }
|
rlm@23
|
299 }
|
rlm@23
|
300
|
rlm@23
|
301 Exec("hasim-fpga-ctrl --activate", "Failed to activate FPGA or driver");
|
rlm@23
|
302 }
|
rlm@23
|
303 }
|
rlm@23
|
304
|
rlm@23
|
305 # Run the software side or a hardware simulator
|
rlm@23
|
306 my $run_status = 0;
|
rlm@23
|
307 if ($config{isHybridModel} || ($mType != $MODEL_FPGA)) {
|
rlm@23
|
308 $run_status = ExecModel($cmd);
|
rlm@23
|
309 }
|
rlm@23
|
310
|
rlm@23
|
311 # Create a stats file for null workloads to make regression.launcher happy (HACK)
|
rlm@23
|
312 if ( $config{workload} eq "null" ) {
|
rlm@23
|
313 system("touch null.stats");
|
rlm@23
|
314 }
|
rlm@23
|
315
|
rlm@23
|
316 if (-f "hasim_events.out") {
|
rlm@23
|
317 system("sort hasim_events.out -o hasim_events.out.$$; mv -f hasim_events.out.$$ hasim_events.out");
|
rlm@23
|
318 }
|
rlm@23
|
319 if (-f "$config{workload}.stats") {
|
rlm@23
|
320 system("sort $config{workload}.stats -o $config{workload}.stats.$$; mv -f $config{workload}.stats.$$ $config{workload}.stats");
|
rlm@23
|
321 }
|
rlm@23
|
322
|
rlm@23
|
323 if (($mType == $MODEL_FPGA) && ! $noProgram && ! $noReserve) {
|
rlm@23
|
324 Exec("hasim-fpga-ctrl --drop-reservation", "Failed to drop FPGA reservation");
|
rlm@23
|
325 }
|
rlm@23
|
326
|
rlm@23
|
327 if ($run_status != 0) {
|
rlm@23
|
328 exit($run_status);
|
rlm@23
|
329 }
|
rlm@23
|
330 else {
|
rlm@23
|
331 exit(CompareOutput());
|
rlm@23
|
332 }
|
rlm@23
|
333
|
rlm@23
|
334
|
rlm@23
|
335 sub ErrorExit($) {
|
rlm@23
|
336 my $msg = shift;
|
rlm@23
|
337
|
rlm@23
|
338 print STDERR "${msg}\n";
|
rlm@23
|
339
|
rlm@23
|
340 if (($mType == $MODEL_FPGA) && ! $noProgram && ! $noReserve) {
|
rlm@23
|
341 system("hasim-fpga-ctrl --drop-reservation");
|
rlm@23
|
342 }
|
rlm@23
|
343
|
rlm@23
|
344 exit(1);
|
rlm@23
|
345 }
|
rlm@23
|
346
|
rlm@23
|
347
|
rlm@23
|
348 ##
|
rlm@23
|
349 ## ExecModel --
|
rlm@23
|
350 ## This is the routine that actually invokes the model. stdout and stderr
|
rlm@23
|
351 ## are logged in a file. The return value is the exit status of the model.
|
rlm@23
|
352 ##
|
rlm@23
|
353 sub ExecModel($) {
|
rlm@23
|
354 my $cmd = shift;
|
rlm@23
|
355
|
rlm@23
|
356 if ($gdb) {
|
rlm@23
|
357 ## gdb needs stdin. Just use system() and don't do logging.
|
rlm@23
|
358 system("gdb -args " . $cmd);
|
rlm@23
|
359 return 0;
|
rlm@23
|
360 }
|
rlm@23
|
361
|
rlm@23
|
362 ##
|
rlm@23
|
363 ## Invoke the model, but log its output both to stdout and to a file.
|
rlm@23
|
364 ## Use a pty so the invoked program will use line buffering instead
|
rlm@23
|
365 ## of fully buffered writes. (Libc sets up stdout line buffered when
|
rlm@23
|
366 ## it thinks it is writing to a terminal. It uses fully buffered
|
rlm@23
|
367 ## writing to a pipe.)
|
rlm@23
|
368 ##
|
rlm@23
|
369
|
rlm@23
|
370 my $pty = new IO::Pty;
|
rlm@23
|
371 my $slave = $pty->slave();
|
rlm@23
|
372
|
rlm@23
|
373 my $pid = fork();
|
rlm@23
|
374 die "Couldn't fork: $!" unless defined $pid;
|
rlm@23
|
375
|
rlm@23
|
376 if (! $pid) {
|
rlm@23
|
377 # Child process is the monitoring process
|
rlm@23
|
378 $pty->make_slave_controlling_terminal();
|
rlm@23
|
379
|
rlm@23
|
380 my $output = "$config{workload}.$config{ISA}.out";
|
rlm@23
|
381 if(exists($config{silent})) {
|
rlm@23
|
382 $output = "/dev/null";
|
rlm@23
|
383 }
|
rlm@23
|
384
|
rlm@23
|
385 if (! open(LOG, ">$output")) {
|
rlm@23
|
386 print STDERR "Error opening log file $output\n";
|
rlm@23
|
387 }
|
rlm@23
|
388
|
rlm@23
|
389 # Unbuffered I/O loop
|
rlm@23
|
390 while (1) {
|
rlm@23
|
391 my $buf;
|
rlm@23
|
392 my $n = sysread($slave, $buf, 4096);
|
rlm@23
|
393
|
rlm@23
|
394 last if ($n == 0);
|
rlm@23
|
395
|
rlm@23
|
396 syswrite(STDOUT, $buf);
|
rlm@23
|
397 syswrite(LOG, $buf);
|
rlm@23
|
398 }
|
rlm@23
|
399
|
rlm@23
|
400 close(LOG);
|
rlm@23
|
401 exit(0);
|
rlm@23
|
402 }
|
rlm@23
|
403
|
rlm@23
|
404 # Bind new PTY to STDOUT (but save old STDOUT)
|
rlm@23
|
405 $pty->close_slave();
|
rlm@23
|
406 open(my $oldOut, ">&", STDOUT) or die $!;
|
rlm@23
|
407 open(STDOUT, ">&", $pty) or die $!;
|
rlm@23
|
408
|
rlm@23
|
409 # Run model
|
rlm@23
|
410 my $result = system("${cmd} 2>&1");
|
rlm@23
|
411
|
rlm@23
|
412 # Send ^d to end child logging thread
|
rlm@23
|
413 print "\cD";
|
rlm@23
|
414
|
rlm@23
|
415 # Return to normal STDOUT
|
rlm@23
|
416 close(STDOUT);
|
rlm@23
|
417 open(STDOUT, ">&", $oldOut) or die $!;
|
rlm@23
|
418 close($oldOut);
|
rlm@23
|
419
|
rlm@23
|
420 # Compute exit status of model
|
rlm@23
|
421 my $status = 0;
|
rlm@23
|
422 if ($result == -1) {
|
rlm@23
|
423 print STDERR "Model execution failed\n";
|
rlm@23
|
424 $status = 1;
|
rlm@23
|
425 }
|
rlm@23
|
426 elsif ($result & 127) {
|
rlm@23
|
427 print STDERR "Child died with signal " . ($result & 127) . ", " . (($result & 128) ? 'with' : 'without') . " coredump\n";
|
rlm@23
|
428 $status = 1;
|
rlm@23
|
429 }
|
rlm@23
|
430 elsif (($result >> 8) != 0) {
|
rlm@23
|
431 $status = $result >> 8;
|
rlm@23
|
432 print "Model exited with status $status\n";
|
rlm@23
|
433 }
|
rlm@23
|
434
|
rlm@23
|
435 return $status;
|
rlm@23
|
436 }
|
rlm@23
|
437
|
rlm@23
|
438
|
rlm@23
|
439 sub Exec($$) {
|
rlm@23
|
440 my $cmd = shift;
|
rlm@23
|
441 my $errmsg = shift;
|
rlm@23
|
442
|
rlm@23
|
443 system($cmd);
|
rlm@23
|
444 if ($? == -1) {
|
rlm@23
|
445 ErrorExit("Failed to execute $cmd: $!");
|
rlm@23
|
446 }
|
rlm@23
|
447 elsif ($? & 127) {
|
rlm@23
|
448 ErrorExit("Child died with signal " . ($? & 127) . ", " . (($? & 128) ? 'with' : 'without') . " coredump");
|
rlm@23
|
449 }
|
rlm@23
|
450 elsif (($? >> 8) != 0) {
|
rlm@23
|
451 ErrorExit("${errmsg}");
|
rlm@23
|
452 }
|
rlm@23
|
453 }
|
rlm@23
|
454
|
rlm@23
|
455
|
rlm@23
|
456 sub CompareOutput() {
|
rlm@23
|
457 return 0 if ($noCompare != 0);
|
rlm@23
|
458 return 0 if (! exists($config{compare}) || ($config{compare} eq ''));
|
rlm@23
|
459
|
rlm@23
|
460 }
|
rlm@23
|
461
|
rlm@23
|
462
|
rlm@23
|
463 #
|
rlm@23
|
464 # Read the configuration file
|
rlm@23
|
465 #
|
rlm@23
|
466 sub ReadConfig($$) {
|
rlm@23
|
467 my $conf = shift;
|
rlm@23
|
468 my $required = shift;
|
rlm@23
|
469
|
rlm@23
|
470 my $status = open(CONFIG, "< $conf");
|
rlm@23
|
471 if (! $status) {
|
rlm@23
|
472 return if (! $required);
|
rlm@23
|
473 die("Failed to open $conf");
|
rlm@23
|
474 }
|
rlm@23
|
475
|
rlm@23
|
476 while (<CONFIG>) {
|
rlm@23
|
477 chomp;
|
rlm@23
|
478 my $t = $_;
|
rlm@23
|
479 $t =~ s/#.*//;
|
rlm@23
|
480 if ($t =~ /^\s*([^\s]+)\s*=\s*"(.*)"\s*$/) {
|
rlm@23
|
481 my $c = $1;
|
rlm@23
|
482 my $v = $2;
|
rlm@23
|
483 $v =~ s/^["'](.*)["']$/$1/; # Drop quotation marks
|
rlm@23
|
484 $config{$c} = $v;
|
rlm@23
|
485 }
|
rlm@23
|
486 elsif ($t =~ /^\s*([^\s]+)\s*=\s*([^\s]+)\s*$/) {
|
rlm@23
|
487 my $c = $1;
|
rlm@23
|
488 my $v = $2;
|
rlm@23
|
489 $config{$c} = $v;
|
rlm@23
|
490 }
|
rlm@23
|
491 }
|
rlm@23
|
492 }
|