Salome HOME
a1b0dafbe9ec6350f55cb9dbda81274097640806
[tools/libbatch.git] / src / LSF / BatchManager_LSF.cxx
1 //  Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 /*
23  * BatchManager_LSF.cxx : emulation of LSF client
24  *
25  * Auteur : Bernard SECHER - CEA DEN
26  * Mail   : mailto:bernard.secher@cea.fr
27  * Date   : Thu Apr 24 10:17:22 2008
28  * Projet : PAL Salome
29  *
30  */
31
32 #include <cstdlib>
33 #include <fstream>
34 #include <sstream>
35
36 #include <Constants.hxx>
37 #include <Utils.hxx>
38 #include <NotYetImplementedException.hxx>
39 #include "BatchManager_LSF.hxx"
40 #include "JobInfo_LSF.hxx"
41 #include "Log.hxx"
42
43 using namespace std;
44
45 namespace Batch {
46
47   BatchManager_LSF::BatchManager_LSF(const FactBatchManager * parent, const char * host,
48                                        const char * username,
49                                        CommunicationProtocolType protocolType, const char * mpiImpl)
50   : BatchManager(parent, host, username, protocolType, mpiImpl)
51   {
52     // Nothing to do
53   }
54
55   // Destructeur
56   BatchManager_LSF::~BatchManager_LSF()
57   {
58     // Nothing to do
59   }
60
61   // Methode pour le controle des jobs : soumet un job au gestionnaire
62   const JobId BatchManager_LSF::submitJob(const Job & job)
63   {
64     Parametre params = job.getParametre();
65     const std::string workDir = params[WORKDIR];
66
67     // export input files on cluster
68     LOG("Export des fichiers en entree");
69     exportInputFiles(job);
70
71     // build batch script for job
72     LOG("Construction du script de batch");
73     string scriptFile = buildSubmissionScript(job);
74     LOG("Script envoye");
75
76     // define command to submit batch
77     string subCommand = string("cd ") + workDir + "; bsub < " + scriptFile;
78     string command = _protocol.getExecCommand(subCommand, _hostname, _username);
79     command += " 2>&1";
80     LOG(command);
81
82     string output;
83     int status = Utils::getCommandOutput(command, output);
84     LOG(output);
85     if (status != 0) throw RunTimeException("Can't submit job, error was: " + output);
86
87     // read id of submitted job in output
88     int p10 = output.find("<");
89     int p20 = output.find(">");
90     string strjob = output.substr(p10+1,p20-p10-1);
91
92     JobId id(this, strjob);
93     return id;
94   }
95
96   // Methode pour le controle des jobs : retire un job du gestionnaire
97   void BatchManager_LSF::deleteJob(const JobId & jobid)
98   {
99     int status;
100     int ref;
101     istringstream iss(jobid.getReference());
102     iss >> ref;
103
104     // define command to delete batch
105     string subCommand = string("bkill ") + iss.str();
106     string command = _protocol.getExecCommand(subCommand, _hostname, _username);
107     LOG(command);
108     status = system(command.c_str());
109     if (status)
110       throw RunTimeException("Error of connection on remote host");
111
112     LOG("jobId = " << ref << "killed");
113   }
114
115   // Methode pour le controle des jobs : renvoie l'etat du job
116   JobInfo BatchManager_LSF::queryJob(const JobId & jobid)
117   {
118     int id;
119     istringstream iss(jobid.getReference());
120     iss >> id;
121
122     // define command to query batch
123     string subCommand = string("bjobs ") + iss.str();
124     string command = _protocol.getExecCommand(subCommand, _hostname, _username);
125     LOG(command);
126
127     string output;
128     int status = Utils::getCommandOutput(command, output);
129     if (status) throw RunTimeException("Error of connection on remote host");
130
131     JobInfo_LSF ji = JobInfo_LSF(id, output);
132     return ji;
133   }
134
135
136
137   // Methode pour le controle des jobs : teste si un job est present en machine
138   bool BatchManager_LSF::isRunning(const JobId & jobid)
139   {
140     throw NotYetImplementedException("BatchManager_LSF::isRunning");
141   }
142
143   std::string BatchManager_LSF::buildSubmissionScript(const Job & job)
144   {
145     Parametre params = job.getParametre();
146
147     // Job Parameters
148     string workDir       = "";
149     string fileToExecute = "";
150     int nbproc           = 0;
151     int edt              = 0;
152     int mem              = 0;
153     string queue         = "";
154
155     // Mandatory parameters
156     if (params.find(WORKDIR) != params.end()) 
157       workDir = params[WORKDIR].str();
158     else 
159       throw RunTimeException("params[WORKDIR] is not defined ! Please defined it, cannot submit this job");
160     if (params.find(EXECUTABLE) != params.end()) 
161       fileToExecute = params[EXECUTABLE].str();
162     else 
163       throw RunTimeException("params[EXECUTABLE] is not defined ! Please defined it, cannot submit this job");
164
165     // Optional parameters
166     if (params.find(NBPROC) != params.end()) 
167       nbproc = params[NBPROC];
168     if (params.find(MAXWALLTIME) != params.end()) 
169       edt = params[MAXWALLTIME];
170     if (params.find(MAXRAMSIZE) != params.end()) 
171       mem = params[MAXRAMSIZE];
172     if (params.find(QUEUE) != params.end()) 
173       queue = params[QUEUE].str();
174
175     string::size_type p1 = fileToExecute.find_last_of("/");
176     string::size_type p2 = fileToExecute.find_last_of(".");
177     string rootNameToExecute = fileToExecute.substr(p1+1,p2-p1-1);
178     string fileNameToExecute = fileToExecute.substr(p1+1);
179  
180     // Create batch submit file
181     ofstream tempOutputFile;
182     std::string TmpFileName = Utils::createAndOpenTemporaryFile("LSF-script", tempOutputFile);
183
184     tempOutputFile << "#! /bin/sh -f" << endl ;
185     if (params.find(NAME) != params.end())
186       tempOutputFile << "#BSUB -J " << params[NAME] << endl;
187     if (queue != "")
188       tempOutputFile << "#BSUB -q " << queue << endl;
189     if( edt > 0 )
190       tempOutputFile << "#BSUB -W " << getWallTime(edt) << endl ;
191     if( mem > 0 )
192       tempOutputFile << "#BSUB -M " << mem*1024 << endl ;
193     tempOutputFile << "#BSUB -n " << nbproc << endl ;
194
195     if (params.find(EXCLUSIVE) != params.end() && params[EXCLUSIVE]) {
196       tempOutputFile << "#BSUB -x" << endl ;
197     }
198
199     size_t pos = workDir.find("$HOME");
200     string baseDir;
201     if( pos != string::npos )
202       baseDir = getHomeDir(workDir) + workDir.substr(pos+5,workDir.length()-5);
203     else{
204       pos = workDir.find("~");
205       if( pos != string::npos )
206         baseDir = getHomeDir(workDir) + workDir.substr(pos+1,workDir.length()-1);
207       else
208         baseDir = workDir;
209     }
210     tempOutputFile << "#BSUB -o " << baseDir << "/logs/output.log." << rootNameToExecute << endl ;
211     tempOutputFile << "#BSUB -e " << baseDir << "/logs/error.log." << rootNameToExecute << endl ;
212
213     // Define environment for the job
214     Environnement env = job.getEnvironnement();
215     for (Environnement::const_iterator iter = env.begin() ; iter != env.end() ; ++iter) {
216       tempOutputFile << "export " << iter->first << "=" << iter->second << endl;
217     }
218
219     tempOutputFile << "cd " << workDir << endl ;
220
221     // generate nodes file
222     tempOutputFile << "LIBBATCH_NODEFILE=`mktemp nodefile-XXXXXXXXXX` || exit 1" << endl;
223     tempOutputFile << "bool=0" << endl;
224     tempOutputFile << "for i in $LSB_MCPU_HOSTS; do" << endl;
225     tempOutputFile << "  if test $bool = 0; then" << endl;
226     tempOutputFile << "    n=$i" << endl;
227     tempOutputFile << "    bool=1" << endl;
228     tempOutputFile << "  else" << endl;
229     tempOutputFile << "    for ((j=0;j<$i;j++)); do" << endl;
230     tempOutputFile << "      echo $n >> $LIBBATCH_NODEFILE" << endl;
231     tempOutputFile << "    done" << endl;
232     tempOutputFile << "    bool=0" << endl;
233     tempOutputFile << "  fi" << endl;
234     tempOutputFile << "done" << endl;
235     tempOutputFile << "export LIBBATCH_NODEFILE" << endl;
236
237     // Launch the executable
238     tempOutputFile << "./" + fileNameToExecute;
239     if (params.find(ARGUMENTS) != params.end()) {
240       Versatile V = params[ARGUMENTS];
241       for(Versatile::const_iterator it=V.begin(); it!=V.end(); it++) {
242         StringType argt = * static_cast<StringType *>(*it);
243         string     arg  = argt;
244         tempOutputFile << " " << arg;
245       }
246     }
247     tempOutputFile << endl;
248
249     // Remove the node file
250     tempOutputFile << "rm $LIBBATCH_NODEFILE" << endl;
251
252     tempOutputFile.flush();
253     tempOutputFile.close();
254
255     LOG("Batch script file generated is: " << TmpFileName.c_str());
256
257     string remoteFileName = rootNameToExecute + "_Batch.sh";
258     int status = _protocol.copyFile(TmpFileName, "", "",
259                                     workDir + "/" + remoteFileName,
260                                     _hostname, _username);
261     if (status)
262       throw RunTimeException("Error of connection on remote host");
263     return remoteFileName;
264   }
265
266   std::string BatchManager_LSF::getWallTime(const long edt)
267   {
268     long h, m;
269     h = edt / 60;
270     m = edt - h*60;
271     ostringstream oss;
272     if( m >= 10 )
273       oss << h << ":" << m;
274     else
275       oss << h << ":0" << m;
276     return oss.str();
277   }
278
279   std::string BatchManager_LSF::getHomeDir(std::string tmpdir)
280   {
281     std::string home;
282     int idx = tmpdir.find("Batch/");
283     std::string filelogtemp = tmpdir.substr(idx+6, tmpdir.length());
284     filelogtemp = "/tmp/logs" + filelogtemp + "_home";
285
286     string subCommand = string("echo $HOME");
287     string command = _protocol.getExecCommand(subCommand, _hostname, _username) + " > " + filelogtemp;
288     LOG(command);
289     int status = system(command.c_str());
290     if (status)
291       throw RunTimeException("Error of launching home command on remote host");
292
293     std::ifstream file_home(filelogtemp.c_str());
294     std::getline(file_home, home);
295     file_home.close();
296     return home;
297   }
298
299 }