mirror of
https://github.com/cmusphinx/sphinxtrain.git
synced 2026-06-16 13:14:30 +00:00
consistency with modern trends and other ASR frameworks. git-svn-id: svn+ssh://svn.code.sf.net/p/cmusphinx/code/trunk/SphinxTrain@11327 94700074-3cef-4d97-a70e-9c8c206c02f5
249 lines
6.7 KiB
Perl
249 lines
6.7 KiB
Perl
# -*- cperl -*-
|
|
## ====================================================================
|
|
##
|
|
## Copyright (c) 2006 Carnegie Mellon University. All rights
|
|
## reserved.
|
|
##
|
|
## Redistribution and use in source and binary forms, with or without
|
|
## modification, are permitted provided that the following conditions
|
|
## are met:
|
|
##
|
|
## 1. Redistributions of source code must retain the above copyright
|
|
## notice, this list of conditions and the following disclaimer.
|
|
##
|
|
## 2. Redistributions in binary form must reproduce the above copyright
|
|
## notice, this list of conditions and the following disclaimer in
|
|
## the documentation and/or other materials provided with the
|
|
## distribution.
|
|
##
|
|
## This work was supported in part by funding from the Defense Advanced
|
|
## Research Projects Agency and the National Science Foundation of the
|
|
## United States of America, and the CMU Sphinx Speech Consortium.
|
|
##
|
|
## THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
|
|
## ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
## THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
|
|
## NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
##
|
|
## ====================================================================
|
|
##
|
|
## Author: David Huggins-Daines
|
|
##
|
|
use strict;
|
|
|
|
package Queue::PBS;
|
|
use Fcntl;
|
|
use File::Temp qw(tempfile);
|
|
use B::Deparse;
|
|
use Data::Dumper;
|
|
use File::Spec::Functions;
|
|
use Queue::Job;
|
|
use Sys::Hostname;
|
|
|
|
sub new {
|
|
my $this = shift;
|
|
my $class = ref $this || $this;
|
|
|
|
if (-x '/usr/local/bin/qsub') {
|
|
unshift(@_, pbsbin => '/usr/local/bin');
|
|
}
|
|
my $self = {@_};
|
|
bless $self, $class;
|
|
}
|
|
|
|
sub network_path {
|
|
my ($host, $path) = @_;
|
|
$path = File::Spec->rel2abs($path);
|
|
$path =~ s,/.automount/([^/]+)/root,/net/$1,;
|
|
if ($path !~ m,^/net/,) {
|
|
$path = "/net/${host}$path";
|
|
}
|
|
return $path;
|
|
}
|
|
|
|
sub submit_job {
|
|
my $self = shift;
|
|
|
|
# Create a job object from arguments (not so elegant really)
|
|
my $job = Queue::Job->new(@_);
|
|
|
|
# Create a temporary script with no args to give to PBS
|
|
my ($tmpnam, $tmpfh);
|
|
if (defined($self->{tempfile})) {
|
|
$tmpnam = $self->{tempfile};
|
|
open $tmpfh, ">$tmpnam" or die "Failed to open $tmpnam: $!";
|
|
}
|
|
else {
|
|
($tmpfh, $tmpnam) = tempfile();
|
|
}
|
|
|
|
# Fix up some crucial paths (this is a HACK)
|
|
my $hostname = hostname();
|
|
$hostname =~ s/\..*$//;
|
|
if (defined($job->{command})) {
|
|
foreach my $arg (@{$job->{command}}) {
|
|
# Does it LOOK like an absolute path?
|
|
if (file_name_is_absolute($arg)) {
|
|
# Then try to network-ify it...
|
|
$arg = network_path($hostname, $arg);
|
|
}
|
|
}
|
|
}
|
|
|
|
# Use Data::Dumper to generate properly quoted arguments
|
|
local $Data::Dumper::Terse = 1;
|
|
print $tmpfh "#!/usr/bin/perl\n";
|
|
if (defined($job->{command})) {
|
|
# Carry over the PATH and PYTHONPATH envvars
|
|
foreach my $var (qw(PATH PYTHONPATH)) {
|
|
print $tmpfh "\$ENV{'$var'} = ", Dumper($ENV{$var}), ";\n";
|
|
}
|
|
print $tmpfh "exec(";
|
|
foreach (@{$job->{command}}) {
|
|
print $tmpfh Dumper($_), ",\n\t";
|
|
}
|
|
print $tmpfh ");\n";
|
|
}
|
|
elsif (defined($job->{coderef})) {
|
|
# Use B::Deparse to generate code
|
|
my $deparse = B::Deparse->new();
|
|
print $tmpfh "sub jobstuff ";
|
|
print $tmpfh $deparse->coderef2text($job->{coderef});
|
|
print $tmpfh "\nexit jobstuff(";
|
|
foreach (@{$job->{codeargs}}) {
|
|
print $tmpfh Dumper($_), ",\n\t";
|
|
}
|
|
print $tmpfh ");\n";
|
|
}
|
|
else {
|
|
die "Invalid Queue::Job object!\n";
|
|
}
|
|
close $tmpfh or die "Failed to close $tmpnam: $!";
|
|
|
|
my ($qsubbin, @pbsargs);
|
|
if (defined($self->{pbsbin})) {
|
|
$qsubbin = catfile($self->{pbsbin}, 'qsub');
|
|
}
|
|
else {
|
|
$qsubbin = 'qsub';
|
|
}
|
|
push @pbsargs, -q => $ST::CFG_QUEUE_NAME if defined $ST::CFG_QUEUE_NAME;
|
|
push @pbsargs, -e => $job->{errfile} if defined $job->{errfile};
|
|
push @pbsargs, -o => $job->{outfile} if defined $job->{outfile};
|
|
push @pbsargs, -N => substr($job->{name}, 0, 15) if defined $job->{name};
|
|
if (defined($job->{deps}) and @{$job->{deps}}) {
|
|
push @pbsargs, -W => ('depend=afterok:'
|
|
. join(':', @{$job->{deps}}));
|
|
}
|
|
if (defined($job->{resources})) {
|
|
foreach (@{$job->{resources}}) {
|
|
push @pbsargs, -l => $_;
|
|
}
|
|
}
|
|
if (defined($job->{variables})) {
|
|
foreach (@{$job->{variables}}) {
|
|
push @pbsargs, -v => $_;
|
|
}
|
|
}
|
|
|
|
# Call qsub to submit the script
|
|
die "Failed to fork: $!"
|
|
unless defined(my $pid = open QSUB, "-|");
|
|
if ($pid) {
|
|
my ($output, $jobid);
|
|
local $_;
|
|
while (<QSUB>) {
|
|
$output .= $_;
|
|
chomp;
|
|
if (/^(\d+)\./) {
|
|
$jobid = $1;
|
|
last;
|
|
}
|
|
}
|
|
die "Queue submission failed: no Job ID\n" unless defined($jobid);
|
|
close QSUB; # This does a waitpid($pid, 0) for us
|
|
die "Queue submission failed with status $?\n" if $?;
|
|
unlink $tmpnam;
|
|
return $jobid;
|
|
}
|
|
else {
|
|
open STDERR, ">&STDOUT";
|
|
exec $qsubbin, @pbsargs, $tmpnam or die "Failed to exec: $!";
|
|
}
|
|
}
|
|
|
|
sub query_job {
|
|
my ($self, $jobid) = @_;
|
|
|
|
my $qstatbin = catfile($self->{pbsbin}, 'qstat');
|
|
my $pid = open QSTAT, "-|";
|
|
die "Failed to fork: $!" unless defined $pid;
|
|
if ($pid) {
|
|
# FIXME: There is actually a way to get the exit status of a job
|
|
while (<QSTAT>) {
|
|
return 1 if /Unknown/;
|
|
return 1 if /\bC\b/;
|
|
return -1 if /\bE\b/;
|
|
}
|
|
close QSTAT;
|
|
}
|
|
else {
|
|
open STDERR, ">&STDOUT";
|
|
exec $qstatbin, $jobid or die "Failed to exec: $!";
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
sub waitfor_job {
|
|
my ($self, $jobid, $timeout, $interval) = @_;
|
|
|
|
my $elapsed = 0;
|
|
$interval = 5 unless defined($interval);
|
|
while (1) {
|
|
my $rv = $self->query_job($jobid);
|
|
# FIXME: There is actually a way to get the exit status of a job
|
|
return 0 if $rv == 1; # 0 = success
|
|
return 1 if $rv == -1; # 1 = failure
|
|
return -1 if defined($timeout) and $elapsed > $timeout;
|
|
sleep $interval;
|
|
$elapsed += $interval;
|
|
}
|
|
}
|
|
|
|
sub cancel_job {
|
|
my ($self, $jobid) = @_;
|
|
|
|
my $qdelbin = catfile($self->{pbsbin}, 'qdel');
|
|
system($qdelbin, $jobid) == 0;
|
|
}
|
|
|
|
1;
|
|
__END__
|
|
|
|
=head1 NAME
|
|
|
|
Queue::PBS - Access to the PBS queue.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
use Queue::PBS;
|
|
my $q = Queue::PBS->new();
|
|
my $id = $q->submit_job($cmd, @args);
|
|
waitfor_job($id);
|
|
cancel_job($id);
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
=head1 AUTHOR
|
|
|
|
David Huggins-Daines <dhuggins@cs.cmu.edu>
|
|
|
|
=cut
|