#!/usr/bin/perl # # pvrip: Takes a vrip file (output), conf file, bound mesh, res in # meters, max voxels per chunk, and loadlimit file. # # All of these are the same as vrip, except the loadlimit file, # which lists the desired load on the various parallel machines. # It looks something like: # radiance 4 # maglio 3 # cesello 2.2 # blackout 1.4 # lambert 7 # wavelet 1.2 # blueridge 1.4 # # You can edit the numbers while it's running, but you cannot # change the order of the list, or add/remove machines while # it's running. sub printUsage { print STDERR "\n"; print STDERR "Usage: pvrip \\\n". " [options]\n"; print STDERR "e.g.: pvrip v2mm.vri v2mm.ply v.conf v.bbox.ply 2.0 40M loadlimit\n"; print STDERR " or: pvrip v5mm.vri v5mm.ply v.conf v.conf 5.0 9500K ~/loadlimit \\\n"; print STDERR " -noxload -logdir logs -subvoldir subvols\n"; print STDERR "\n"; print STDERR "Options:\n"; print STDERR " -rampscale Where s is the scale-factor for the ramp in\n"; print STDERR " vrip. If you do not supply a rampscale,\n"; print STDERR " pvrip will use (2500*voxelsize) as the\n"; print STDERR " default rampscale.\n"; print STDERR " -norampscale Don't pass a rampscale to vrip. (By default,\n"; print STDERR " pvrip passes a rampscale that overrides .vriprc).\n"; print STDERR " -logdir Where dir is the directory to store all the\n"; print STDERR " log files (cmd, stdout, stderr for each chunk).\n"; print STDERR " default logdir is logs_PID (Process ID).\n"; print STDERR " -subvoldir Where dir is the directory to store all the\n"; print STDERR " subvol .conf/.vri/.ply files.\n"; print STDERR " default subvoldir is subvols_PID.\n"; print STDERR " -bboxesok Disables the check to see if bboxes are up to date.\n"; print STDERR " Normally, bboxes are updated if they are older than the\n"; print STDERR " conf file, since changing the conf transforms will outdate\n"; print STDERR " the bbox. But if you're *sure* your bboxes are ok, this\n"; print STDERR " will speed it up.\n"; print STDERR " -passtovrip \"X\" Will pass the string X to each vrip (at the end of the\n"; print STDERR " of the command line)\n"; print STDERR " -passtovripsurf \"X\" Will pass the string X to each vripsurf (at the end\n"; print STDERR " of the command line)\n"; print STDERR " -xload Will pop up xload windows for each host.\n"; print STDERR " -noxload Will not pop up xload windows for each host.\n"; print STDERR " (default)\n"; print STDERR " -merge Will run plymerge/plyshared at the end to merge\n"; print STDERR " subvols into a single mesh. (default)\n"; print STDERR " -nomerge Will not run plymerge/plyshared.\n"; print STDERR " -crunch Will run plycrunch on the subvols and final mesh,\n"; print STDERR " and generate .set files. (default)\n"; print STDERR " -nocrunch Will not run plycrunch.\n"; print STDERR " -clean Will run plyclean -defaults on the final shared mesh,\n"; print STDERR " to remove slivers (~37% less tris)\n"; print STDERR " -noclean Will not run plyclean.\n"; print STDERR "\n"; print STDERR "Notes:\n"; print STDERR " - max_voxels_per_chunk recognizes K and M, eg, 20K, 50M\n"; print STDERR " - The loadlimit file should look like this:\n"; print STDERR "radiance 6.5\n"; print STDERR "lambert 3.5\n"; print STDERR "phong 1.2\n"; print STDERR " - pvrip will not start a job on a machine unless\n"; print STDERR " the limit is larger than 1.\n"; print STDERR " - you can adjust the numbers in loadlimit while\n"; print STDERR " pvrip is running, but you cannot add, delete,\n"; print STDERR " or reorder the host lines.\n"; print STDERR "\n"; exit(-1); } if ($#ARGV < 6) { &printUsage(); } $VRIFILE = $ARGV[0]; $PLYFILE = $ARGV[1]; $CONFFILE = $ARGV[2]; $BOUNDFILE = $ARGV[3]; $RES = $ARGV[4]; $MAXVOX = $ARGV[5]; $LOADFILE = $ARGV[6]; # Default values $LOGDIR = "logs_$$"; $XLOADSTR = ""; $SUBVOLDIR = "subvols_$$"; $DOCRUNCH = 1; $DOCLEAN = 1; $DOMERGE = 1; $BBOXESOKSTR = ""; $RAMPSCALE = 2500 * $RES; $PASSTOVRIP = ""; $PASSTOVRIPSURF = ""; # Parse the -arguments $currarg = 7; while ($currarg <= $#ARGV) { if ($ARGV[$currarg] eq "-logdir" || $ARGV[$currarg] eq "-ld") { $LOGDIR = $ARGV[$currarg+1]; $currarg +=2; if ($LOGDIR eq "") { print STDERR "Error: no logdir???\n\n"; &printUsage(); } } elsif ($ARGV[$currarg] eq "-subvoldir" || $ARGV[$currarg] eq "-sd") { $SUBVOLDIR = $ARGV[$currarg+1]; $currarg +=2; if ($SUBVOLDIR eq "") { print STDERR "Error: no subvoldir???\n\n"; &printUsage(); } } elsif ($ARGV[$currarg] eq "-rampscale" || $ARGV[$currarg] eq "-rs") { $RAMPSCALE = $ARGV[$currarg+1]; $currarg +=2; if ($RAMPSCALE eq "") { print STDERR "Error: no rampscale???\n\n"; &printUsage; } } elsif ($ARGV[$currarg] eq "-passtovrip") { $PASSTOVRIP .= $ARGV[$currarg+1]; $currarg +=2; } elsif ($ARGV[$currarg] eq "-passtovripsurf") { $PASSTOVRIPSURF .= $ARGV[$currarg+1]; $currarg +=2; } elsif ($ARGV[$currarg] eq "-norampscale") { # Turn off the default rampscale undef($RAMPSCALE); $currarg++; } elsif ($ARGV[$currarg] eq "-bboxesok") { $BBOXESOKSTR = " -bboxesok "; $currarg++; } elsif ($ARGV[$currarg] eq "-noxload") { $XLOADSTR = " -noxload "; $currarg++; } elsif ($ARGV[$currarg] eq "-xload") { $XLOADSTR = " -xload "; $currarg++; } elsif ($ARGV[$currarg] eq "-crunch") { $DOCRUNCH = 1; $currarg++; } elsif ($ARGV[$currarg] eq "-nocrunch") { $DOCRUNCH = 0; $currarg++; } elsif ($ARGV[$currarg] eq "-clean") { $DOCLEAN = 1; $currarg++; } elsif ($ARGV[$currarg] eq "-noclean") { $DOCLEAN = 0; $currarg++; } elsif ($ARGV[$currarg] eq "-merge") { $DOMERGE = 1; $currarg++; } elsif ($ARGV[$currarg] eq "-nomerge") { $DOMERGE = 0; $currarg++; } else { print STDERR "Error: Unhandled arg $ARGV[$currarg].\n\n"; &printUsage(); } } # Allow k, K, m, M for MAXVOX (e.g. 40M) $MAXVOX =~ s/k/000/g; $MAXVOX =~ s/K/000/g; $MAXVOX =~ s/m/000000/g; $MAXVOX =~ s/M/000000/g; # Make sure subvoldir is usable, # And clean it out if it already exists if (-e $SUBVOLDIR) { if (-d $SUBVOLDIR) { -x $SUBVOLDIR || die "Error: subvoldir $SUBVOLDIR does not have execute permissions\n"; -w $SUBVOLDIR || die "Error: subvoldir $SUBVOLDIR does not have write permissions\n"; # print "Note, loadbalance using existing subvoldir $SUBVOLDIR...\n"; # Clear any old loadbalance logfiles $cmd = "cd $SUBVOLDIR; /bin/ls | /bin/grep 'subvol' | ". "/bin/xargs /bin/rm -f\n"; print "} Clearing old subvol files...."; system $cmd; print "Done.\n"; } else { print STDERR "Error: loadbalance: subvoldir $SUBVOLDIR exists, \n". "and is not a directory.\n"; printUsage(); } } else { # make subvoldir $errmsg = `mkdir $SUBVOLDIR\n`; if ($?) { die "Error: Could not mkdir $SUBVOLDIR\n"; } } # Run vripsplit $cmd = "vripsplit $CONFFILE $BOUNDFILE $RES $MAXVOX -subvoldir $SUBVOLDIR $BBOXESOKSTR\n"; $timecmd = &timecmd($cmd); print "} $cmd"; system $timecmd; !$? || die "Error: vripsplit returned an error. aborting.\n"; # Generate command list to vrip # First set a couple of options for vripsubvollist if ($DOCRUNCH) { $CRUNCHSTR = " -crunch "; } else {$CRUNCHSTR = "";} if (defined($RAMPSCALE)) { $RAMPSCALESTR = " -rampscale $RAMPSCALE "; } else { $RAMPSCALESTR = ""; } # Pass args blindly to vrip/vripsurf? $PASS_STR = ""; if ($PASSTOVRIP ne "") { $PASS_STR .= "-passtovrip \"$PASSTOVRIP\" "; } if ($PASSTOVRIPSURF ne "") { $PASS_STR .= "-passtovripsurf \"$PASSTOVRIPSURF\" "; } # Call vripsubvollist to actually generate the commands $cmd = "find $SUBVOLDIR | grep subvol | grep .conf | sort | ". "/bin/xargs vripsubvollist $CRUNCHSTR $RAMPSCALESTR $PASS_STR $RES > commands\n"; print "} $cmd"; system $cmd; !$? || die "Error: vripsubvollist returned an error. aborting.\n"; # Figure out how many subvol pieces there shall be $cmd = "wc -l commands\n"; $nsvs = int(`$cmd`); print "Number of subvolumes: $nsvs\n"; # Now execute the commands in parallel $cmd = "loadbalance $LOADFILE commands -logdir $LOGDIR $XLOADSTR\n"; $timecmd = &timecmd($cmd); print "} $cmd"; system $timecmd; !$? || die "Error: loadbalance returned an error. aborting.\n"; # Erase any subvolume .ply files with size 0 $cmd = "/bin/find $SUBVOLDIR | egrep \"subvol....\.ply\"\n"; @allplys = `$cmd`; for ($ii=0; $ii <= $#allplys; $ii++) { if (-z $allplys[$ii]) { # Zero size -- nuke $cmd = "/bin/rm $SUBVOLDIR/$allplys[$ii]\n"; print "} $cmd"; system $cmd; !$? || die "Error: removing zero-size .plys failed. aborting.\n"; } } # Merge all the ply files into a single ply file, # which has redundant vertices at the subvolume boundaries: if ($DOMERGE) { $cmd = "/bin/find $SUBVOLDIR | /bin/egrep \"subvol....\.ply\" | /bin/xargs plymerge > $PLYFILE.unshared\n"; $timecmd = &timecmd($cmd); print "} $cmd"; system $timecmd; !$? || die "Error: plymerge returned an error. aborting.\n"; # Remove redundant vertices $cmd = "plyshared < $PLYFILE.unshared > $PLYFILE\n"; $timecmd = &timecmd($cmd); print "} $cmd"; system $timecmd; !$? || die "Error: plyshared returned an error. aborting.\n"; # Plyclean it, to reduce slivers? if ($DOCLEAN) { $PLYCLEAN = $PLYFILE; $PLYCLEAN =~ s/.ply/_clean.ply/g; $cmd = "plyclean -defaults $PLYFILE > $PLYCLEAN\n"; $timecmd = &timecmd($cmd); print "} $cmd"; system $timecmd; !$? || die "Error: plyclean returned an error. aborting.\n"; # otherwise, mv plyclean into place $PLYRAW = $PLYFILE; $PLYRAW =~ s/.ply/_raw.ply/g; $cmd = "/bin/mv $PLYFILE $PLYRAW; /bin/mv $PLYCLEAN $PLYFILE\n"; $timecmd = &timecmd($cmd); print "} $cmd"; system $timecmd; !$? || die "Error: mv returned an error. aborting.\n"; } # Plycrunch it? if ($DOCRUNCH) { $cmd = "ply2crunchset -l 6 $PLYFILE\n"; $timecmd = &timecmd($cmd); print "} $cmd"; system $timecmd; !$? || die "Error: ply2crunchset returned an error. aborting.\n"; } } # Done print "pvrip finished successfully.\n"; ###################################################################### # helper subroutines ###################################################################### sub timecmd { $loccmd = $_[0]; # Extract program name from loccmd # strip args @words = split(' ', $loccmd); $locdescr = $words[0]; # strip path @words = split('/', $locdescr); $locdescr = $words[$#words]; $ltcmd = ("/usr/bin/time -f \"$locdescr time: user %U, system %S, elapsed %E, ". "%P CPU, page faults %F\" $loccmd"); return $ltcmd; }