CMS 3D CMS Logo

Mpslibclass.py
Go to the documentation of this file.
1 from __future__ import print_function
2 # This Jobdatabas-Class interacts with the mps.db file.
3 # It's member-variables are often called in the mps_... scripts.
4 #
5 # Meaning of the database variables: (still need to work on these)
6 #
7 # (1) Header
8 # header - version information
9 # batchScript - base script for serial job
10 # cfgTemplate - template for cfg file
11 # infiList - list of input files to be serialized
12 # classInf - batch class information (might contain two ':'-separated)
13 # addFiles - job name for submission
14 # driver - specifies whether merge job is foreseen
15 # nJobs - number of serial jobs (not including merge job)
16 # mergeScript - base script for merge job
17 # mssDir - directory for mass storage (e.g. Castor)
18 # updateTime - time of last update (seconds since 1970)
19 # updateTimeHuman - time of last update (human readable)
20 # elapsedTime - seconds since last update
21 # mssDirPool - pool for $mssDir (e.g. cmscaf/cmscafuser)
22 # pedeMem - Memory allocated for pede
23 # spare1
24 # spare2
25 # spare3
26 
27 # (2) Job-level variables/lists
28 # JOBNUMBER - ADDED, selfexplanatory
29 # JOBDIR - name of job directory (not full path)
30 # JOBSTATUS - status of job
31 # JOBRUNTIME - present CPU time of job
32 # JOBNEVT - number of events processed by job
33 # JOBHOST - presently used to store remark
34 # JOBINCR - CPU increment since last check
35 # JOBREMARK - comment
36 # JOBSP1 - spare
37 # JOBSP2 - possible weight for pede
38 # JOBSP3 - possible name as given to mps_setup.pl -N <name> ...
39 # JOBID - ID of the LSF/HTCondor job
40 
41 from builtins import range
42 import datetime
43 import time
44 import os
45 import sys
46 
47 #-------------------------------------------------------------------------------
49 
50  JOBNUMBER, JOBDIR, JOBID, JOBSTATUS, JOBNTRY, JOBRUNTIME, JOBNEVT, JOBHOST, JOBINCR, \
51  JOBREMARK, JOBSP1, JOBSP2, JOBSP3 = ([] for i in range(13))
52 
53  header, batchScript, cfgTemplate, infiList, classInf, addFiles, driver, mergeScript, \
54  mssDir, updateTimeHuman, mssDirPool, spare1, spare2, spare3 = ('' for i in range(14))
55 
56  updateTime, elapsedTime, pedeMem , nJobs = -1, -1, -1, -1
57 
58  #-------------------------------------------------------------------------------
59  # parses the mps.db file into the member variables and arrays
60  __default_db_file_name = "mps.db"
61  def read_db(self, db_file_name = __default_db_file_name):
62  try:
63  DBFILE = open(db_file_name,'r')
64  except IOError as e:
65  if e.args != (2, 'No such file or directory'):
66  raise
67  else:
68  if db_file_name == jobdatabase.__default_db_file_name:
69  msg = ("No 'mps.db' found. Make sure you are in a campaign "
70  "directory and that the campaign is set up.")
71  else:
72  msg = "Database file '"+db_file_name+"' not found. Exiting."
73  print(msg)
74  sys.exit(1)
75 
76  #read infolines at the top, used rstrip to delete the '\n'
77  self.header = DBFILE.readline().strip()
78  self.batchScript = DBFILE.readline().rstrip('\n')
79  self.cfgTemplate = DBFILE.readline().rstrip('\n')
80  self.infiList = DBFILE.readline().rstrip('\n')
81  self.classInf = DBFILE.readline().rstrip('\n') #formerly named 'class' ->conflict
82  self.addFiles = DBFILE.readline().rstrip('\n')
83  self.driver = DBFILE.readline().rstrip('\n')
84  self.mergeScript = DBFILE.readline().rstrip('\n')
85  self.mssDir = DBFILE.readline().rstrip('\n')
86  self.updateTime = int(DBFILE.readline())
87  self.updateTimeHuman = DBFILE.readline().rstrip('\n')
88  self.elapsedTime = int(DBFILE.readline())
89  self.mssDirPool = DBFILE.readline().rstrip('\n')
90  self.pedeMem = int(DBFILE.readline())
91  self.spare1 = DBFILE.readline().rstrip('\n')
92  self.spare2 = DBFILE.readline().rstrip('\n')
93  self.spare3 = DBFILE.readline().rstrip('\n')
94 
95  #read actual jobinfo into arrays
96  self.nJobs = 0
97  milleJobs = 0
98 
99 
100  for line in DBFILE:
101  if line.strip() == "": continue # ignore empty lines
102  line = line.rstrip('\n') # removes the pesky \n from line
103  parts = line.split(":") # read each line and split into parts list
104  self.JOBNUMBER.append(int(parts[0]))
105  self.JOBDIR.append(parts[1].strip())
106  self.JOBID.append(parts[2])
107  self.JOBSTATUS.append(parts[3].strip())
108  self.JOBNTRY.append(int(parts[4]))
109  self.JOBRUNTIME.append(int(parts[5])) #int float?
110  self.JOBNEVT.append(int(parts[6]))
111  self.JOBHOST.append(parts[7].strip())
112  self.JOBINCR.append(int(parts[8]))
113  self.JOBREMARK.append(parts[9].strip())
114  self.JOBSP1.append(parts[10].strip())
115  self.JOBSP2.append(parts[11].strip())
116  self.JOBSP3.append(parts[12].strip())
117 
118  #count number of jobs
119  if not self.JOBDIR[self.nJobs].startswith("jobm"):
120  milleJobs += 1
121  self.nJobs += 1
122  self.nJobs = milleJobs
123 
124  DBFILE.close()
125 
126 
127 
128  #-------------------------------------------------------------------------------
129  # prints the member varaiables and arrays to the terminal
130  def print_memdb(self):
131  #print metainfo
132  print("\n=== mps database printout ===\n")
133  print(self.header)
134  print('Script:\t\t', self.batchScript)
135  print('cfg:\t\t', self.cfgTemplate)
136  print('files:\t\t', self.infiList)
137  print('class:\t\t', self.classInf)
138  print('name:\t\t', self.addFiles)
139  print('driver:\t\t', self.driver)
140  print('mergeScript:\t', self.mergeScript)
141  print('mssDir:\t\t', self.mssDir)
142  print('updateTime:\t', self.updateTimeHuman)
143  print('elapsed:\t', self.elapsedTime)
144  print('mssDirPool:\t', self.mssDirPool)
145  print('pedeMem:\t', self.pedeMem, '\n')
146 
147  #print interesting Job-level lists ---- to add: t/evt, fix remarks
148  print('### dir jobid stat try rtime nevt remark weight name')
149  print("------------------------------------------------------------------------------")
150  for i in range(self.nJobs):
151  print('%03d %6s %9s %6s %3d %5d %8d %8s %5s %s' % (
152  self.JOBNUMBER[i],
153  self.JOBDIR[i],
154  self.JOBID[i],
155  self.JOBSTATUS[i],
156  self.JOBNTRY[i],
157  self.JOBRUNTIME[i],
158  self.JOBNEVT[i],
159  self.JOBHOST[i],
160  self.JOBSP2[i],
161  self.JOBSP3[i]))
162 
163  #print merge Jobs if merge mode
164  if self.driver == 'merge':
165  for i in range(self.nJobs,len(self.JOBDIR)):
166  print('%s %6s %9s %6s %3d %5d %8d %8s %5s %s' % (
167  'MMM',
168  self.JOBDIR[i],
169  self.JOBID[i],
170  self.JOBSTATUS[i],
171  self.JOBNTRY[i],
172  self.JOBRUNTIME[i],
173  self.JOBNEVT[i],
174  self.JOBHOST[i],
175  self.JOBSP2[i],
176  self.JOBSP3[i]))
177 
178  #print summed info
179  totalEvents = sum(self.JOBNEVT[:self.nJobs])
180  totalCpu = sum(self.JOBRUNTIME[:self.nJobs])
181  meanCpuPerEvent = 0.
182  if totalEvents > 0:
183  meanCpuPerEvent = float(totalCpu)/totalEvents
184  print("------------------------------------------------------------------------------")
185  print("\t\t\t\t\tEvent total:\t", totalEvents)
186  print("\t\t\t\t\tCPU total:\t", totalCpu, 's')
187  print("\t\t\t\t\tMean CPU/event:\t",meanCpuPerEvent,'s')
188 
189 
190 
191 
192 
193  #-------------------------------------------------------------------------------
194  # writes a new mps.db file from the members. Replaces the old mps.db
195  def write_db(self):
196  self.header = "mps database schema 3.2"
197  self.currentTime = int(time.time())
198  self.elapsedTime = 0;
199  if self.updateTime != 0:
200  self.elapsedTime = self.currentTime - self.updateTime
201  self.updateTime = self.currentTime
202  self.updateTimeHuman = str(datetime.datetime.today()) #no timezone :(
203  self.spare1 = "-- unused --"
204  self.spare2 = "-- unused --"
205  self.spare3 = "-- unused --"
206 
207  #if mps.db already exists, backup as mps.db~ (in case of interupt during write)
208  os.system('[[ -a mps.db ]] && cp -p mps.db mps.db~')
209 
210  #write mps.db header
211  DBFILE = open ("mps.db", "w")
212  headData = [ self.header, self.batchScript, self.cfgTemplate, self.infiList,
213  self.classInf, self.addFiles, self.driver, self.mergeScript,
214  self.mssDir, self.updateTime, self.updateTimeHuman,
215  self.elapsedTime, self.mssDirPool, self.pedeMem,
216  self.spare1, self.spare2, self.spare3 ]
217  for item in headData:
218  DBFILE.write("%s\n" % item)
219 
220  #write mps.db jobinfo
221  for i in range(len(self.JOBID)):
222  DBFILE.write('%03d:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n' %
223  (i+1,
224  self.JOBDIR[i],
225  self.JOBID[i],
226  self.JOBSTATUS[i],
227  self.JOBNTRY[i],
228  self.JOBRUNTIME[i],
229  self.JOBNEVT[i],
230  self.JOBHOST[i],
231  self.JOBINCR[i],
232  self.JOBREMARK[i],
233  self.JOBSP1[i],
234  self.JOBSP2[i],
235  self.JOBSP3[i]))
236  DBFILE.close()
237 
238  #-------------------------------------------------------------------------------
239  # returns job class as stored in db
240  # one and only argument may be "mille" or "pede" for mille or pede jobs
241  def get_class(self, argument=''):
242  CLASSES = self.classInf.split(':')
243  if len(CLASSES)<1 or len(CLASSES)>2:
244  print('\nget_class():\n class must be of the form \'class\' or \'classMille:classPede\', but is \'%s\'!\n\n', classInf)
245  sys.exit(1)
246  elif argument == 'mille':
247  return CLASSES[0]
248  elif argument == 'pede':
249  if len(CLASSES) == 1:
250  return CLASSES[0]
251  elif len(CLASSES) == 2:
252  return CLASSES[1]
253  else:
254  print('\nget_class():\n Know class only for \'mille\' or \'pede\', not %s!\n\n' %argument)
255  sys.exit(1)
def read_db(self, db_file_name=__default_db_file_name)
Definition: Mpslibclass.py:61
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def get_class(self, argument='')
Definition: Mpslibclass.py:241
#define str(s)