Salome HOME
ee8c6245d2c087e448b529acbbbfc088a254cb37
[tools/libbatch.git] / src / PBS / Batch_BatchManager_ePBS.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_ePBS.cxx : emulation of PBS client
24  *
25  * Auteur : Bernard SECHER - CEA DEN, AndrĂ© RIBES - EDF R&D
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 <Batch_Constants.hxx>
37 #include <Batch_Utils.hxx>
38 #include <Batch_NotYetImplementedException.hxx>
39
40 #include "Batch_BatchManager_ePBS.hxx"
41 #include "Batch_JobInfo_ePBS.hxx"
42
43 using namespace std;
44
45 namespace Batch {
46
47   BatchManager_ePBS::BatchManager_ePBS(const FactBatchManager * parent, const char * host,
48                                        const char * username,
49                                        CommunicationProtocolType protocolType, const char * mpiImpl, 
50                                        int nb_proc_per_node)
51     : BatchManager(parent, host, username, protocolType, mpiImpl),
52       _nb_proc_per_node(nb_proc_per_node)
53   {
54     // Nothing to do
55   }
56
57   // Destructeur
58   BatchManager_ePBS::~BatchManager_ePBS()
59   {
60     // Nothing to do
61   }
62
63   // Methode pour le controle des jobs : soumet un job au gestionnaire
64   const JobId BatchManager_ePBS::submitJob(const Job & job)
65   {
66     Parametre params = job.getParametre();
67     const std::string workDir = params[WORKDIR];
68
69     // export input files on cluster
70     exportInputFiles(job);
71
72     // build batch script for job
73     string scriptFile = buildSubmissionScript(job);
74
75     // define command to submit batch
76     string subCommand = string("cd ") + workDir + "; qsub " + scriptFile;
77     string command = _protocol.getExecCommand(subCommand, _hostname, _username);
78     command += " 2>&1";
79     cerr << command.c_str() << endl;
80
81     // submit job
82     string output;
83     int status = Utils::getCommandOutput(command, output);
84     cout << output;
85     if (status != 0) throw RunTimeException("Can't submit job, error was: " + output);
86
87     // normally output contains only id of submitted job, we just need to remove the final \n
88     string jobref = output.substr(0, output.size() - 1);
89     JobId id(this, jobref);
90
91     return id;
92   }
93
94   // Ce manager permet de faire de la reprise
95   const Batch::JobId
96   BatchManager_ePBS::addJob(const Batch::Job & job, const std::string reference)
97   {
98     return JobId(this, reference);
99   }
100
101   // Methode pour le controle des jobs : retire un job du gestionnaire
102   void BatchManager_ePBS::deleteJob(const JobId & jobid)
103   {
104     int status;
105     int ref;
106     istringstream iss(jobid.getReference());
107     iss >> ref;
108
109     // define command to delete batch
110     string subCommand = string("qdel ") + iss.str();
111     string command = _protocol.getExecCommand(subCommand, _hostname, _username);
112     cerr << command.c_str() << endl;
113     status = system(command.c_str());
114     if (status)
115       throw RunTimeException("Error of connection on remote host");
116
117     cerr << "jobId = " << ref << "killed" << endl;
118   }
119
120   // Methode pour le controle des jobs : suspend un job en file d'attente
121   void BatchManager_ePBS::holdJob(const JobId & jobid)
122   {
123     throw NotYetImplementedException("BatchManager_ePBS::holdJob");
124   }
125
126   // Methode pour le controle des jobs : relache un job suspendu
127   void BatchManager_ePBS::releaseJob(const JobId & jobid)
128   {
129     throw NotYetImplementedException("BatchManager_ePBS::releaseJob");
130   }
131
132
133   // Methode pour le controle des jobs : modifie un job en file d'attente
134   void BatchManager_ePBS::alterJob(const JobId & jobid, const Parametre & param, const Environnement & env)
135   {
136     throw NotYetImplementedException("BatchManager_ePBS::alterJob");
137   }
138
139   // Methode pour le controle des jobs : modifie un job en file d'attente
140   void BatchManager_ePBS::alterJob(const JobId & jobid, const Parametre & param)
141   {
142     alterJob(jobid, param, Environnement());
143   }
144
145   // Methode pour le controle des jobs : modifie un job en file d'attente
146   void BatchManager_ePBS::alterJob(const JobId & jobid, const Environnement & env)
147   {
148     alterJob(jobid, Parametre(), env);
149   }
150
151   // Methode pour le controle des jobs : renvoie l'etat du job
152   JobInfo BatchManager_ePBS::queryJob(const JobId & jobid)
153   {
154     int id;
155     istringstream iss(jobid.getReference());
156     iss >> id;
157
158     // define command to query batch
159     string subCommand = string("qstat -f ") + iss.str();
160     string command = _protocol.getExecCommand(subCommand, _hostname, _username);
161     cerr << command.c_str() << endl;
162
163     string output;
164     int status = Utils::getCommandOutput(command, output);
165     if(status && status != 153 && status != 256*153)
166       throw RunTimeException("Error of connection on remote host");
167
168     JobInfo_ePBS ji = JobInfo_ePBS(id, output);
169     return ji;
170   }
171
172   // Methode pour le controle des jobs : teste si un job est present en machine
173   bool BatchManager_ePBS::isRunning(const JobId & jobid)
174   {
175     throw NotYetImplementedException("BatchManager_ePBS::isRunning");
176   }
177
178   std::string BatchManager_ePBS::buildSubmissionScript(const Job & job)
179   {
180     Parametre params = job.getParametre();
181     Environnement env = job.getEnvironnement();
182
183     // Job Parameters
184     string workDir       = "";
185     string fileToExecute = "";
186     int nbproc           = 0;
187     int edt              = 0;
188     int mem              = 0;
189     string queue         = "";
190
191     // Mandatory parameters
192     if (params.find(WORKDIR) != params.end()) 
193       workDir = params[WORKDIR].str();
194     else 
195       throw RunTimeException("params[WORKDIR] is not defined ! Please defined it, cannot submit this job");
196     if (params.find(EXECUTABLE) != params.end()) 
197       fileToExecute = params[EXECUTABLE].str();
198     else 
199       throw RunTimeException("params[EXECUTABLE] is not defined ! Please defined it, cannot submit this job");
200
201     // Optional parameters
202     if (params.find(NBPROC) != params.end()) 
203       nbproc = params[NBPROC];
204     if (params.find(MAXWALLTIME) != params.end()) 
205       edt = params[MAXWALLTIME];
206     if (params.find(MAXRAMSIZE) != params.end()) 
207       mem = params[MAXRAMSIZE];
208     if (params.find(QUEUE) != params.end()) 
209       queue = params[QUEUE].str();
210
211     string::size_type p1 = fileToExecute.find_last_of("/");
212     string::size_type p2 = fileToExecute.find_last_of(".");
213     string rootNameToExecute = fileToExecute.substr(p1+1,p2-p1-1);
214     string fileNameToExecute = fileToExecute.substr(p1+1);
215
216     // Create batch submit file
217     ofstream tempOutputFile;
218     std::string TmpFileName = Utils::createAndOpenTemporaryFile("PBS-script", tempOutputFile);
219
220     tempOutputFile << "#! /bin/sh -f" << endl;
221     if (params.find(NAME) != params.end()) {
222       tempOutputFile << "#PBS -N " << params[NAME] << endl;
223     }
224
225     if (nbproc > 0)
226     {
227       int nb_full_nodes = nbproc / _nb_proc_per_node;
228       int nb_proc_on_last_node = nbproc % _nb_proc_per_node;
229
230       // In exclusive mode, we reserve all procs on the nodes
231       if (params.find(EXCLUSIVE) != params.end() && params[EXCLUSIVE] && nb_proc_on_last_node > 0) {
232         nb_full_nodes += 1;
233         nb_proc_on_last_node = 0;
234       }
235
236       tempOutputFile << "#PBS -l nodes=";
237
238       // Full nodes
239       if (nb_full_nodes > 0) {
240         tempOutputFile << nb_full_nodes << ":ppn=" << _nb_proc_per_node;
241         if (nb_proc_on_last_node > 0) {
242           tempOutputFile << "+";
243         }
244       }
245
246       // Partly reserved node
247       if (nb_proc_on_last_node > 0) {
248         tempOutputFile << "1:ppn=" << nb_proc_on_last_node;
249       }
250
251       tempOutputFile << endl;
252     }
253     if (queue != "")
254       tempOutputFile << "#PBS -q " << queue << endl;
255     if( edt > 0 )
256       tempOutputFile << "#PBS -l walltime=" << edt*60 << endl;
257     if( mem > 0 )
258       tempOutputFile << "#PBS -l mem=" << mem << "MB" << endl;
259     tempOutputFile << "#PBS -o " << workDir << "/logs/output.log." << rootNameToExecute << endl;
260     tempOutputFile << "#PBS -e " << workDir << "/logs/error.log."  << rootNameToExecute << endl;
261
262     // Define environment for the job
263     if (!env.empty()) {
264       tempOutputFile << "#PBS -v ";
265       Environnement::const_iterator iter;
266       for (iter = env.begin() ; iter != env.end() ; ++iter) {
267         tempOutputFile << iter->first << "=" << iter->second << ",";
268       }
269       tempOutputFile << endl;
270     }
271
272     // Abstraction of PBS_NODEFILE - TODO
273     tempOutputFile << "export LIBBATCH_NODEFILE=$PBS_NODEFILE" << endl;
274
275     // Launch the executable
276     tempOutputFile << "cd " << workDir << endl;
277     tempOutputFile << "./" + fileNameToExecute << endl;
278     tempOutputFile.flush();
279     tempOutputFile.close();
280
281     cerr << "Batch script file generated is: " << TmpFileName.c_str() << endl;
282
283     string remoteFileName = rootNameToExecute + "_Batch.sh";
284     int status = _protocol.copyFile(TmpFileName, "", "",
285                                     workDir + "/" + remoteFileName,
286                                     _hostname, _username);
287     if (status)
288       throw RunTimeException("Error of connection on remote host, cannot copy batch submission file");
289     return remoteFileName;
290   }
291 }