Commit 74570540e3b3f5e6c3e89d481bbcb3d1215c0674

Authored by Luigi Tibaldo
1 parent adc857ac

cstsdist parallelized

cscripts/cstsdist.par
... ... @@ -38,6 +38,7 @@ statistic, s, h, DEFAULT,DEFAULT|CSTAT|WSTAT|CHI2,, "Optimization statistic"
38 38 #
39 39 # Standard parameters
40 40 #====================
  41 +nthreads, i, h, 0,0,1000, "Number of parallel processes (0=use all available CPUs)"
41 42 chatter, i, h, 2,0,4, "Chattiness of output"
42 43 clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
43 44 debug, b, h, no,,, "Activate debugging mode?"
... ...
cscripts/cstsdist.py
... ... @@ -24,6 +24,33 @@ import ctools
24 24 from cscripts import obsutils
25 25 from cscripts import modutils
26 26 from cscripts import ioutils
  27 +from cscripts import mputils
  28 +
  29 +# ============================================ #
  30 +# Global functions for multiprocessing support #
  31 +# ============================================ #
  32 +def _multiprocessing_func_wrapper(args):
  33 + return _multiprocessing_func(*args)
  34 +def _multiprocessing_func(cls, i):
  35 +
  36 + # Initialise thread logger
  37 + cls._log.clear()
  38 + cls._log.buffer_size(100000)
  39 +
  40 + # Compute light curve bin
  41 + cstart = cls.celapse()
  42 + result = cls._trial(i)
  43 + celapse = cls.celapse() - cstart
  44 + buffer = cls._log.buffer()
  45 +
  46 + # Close logger
  47 + cls._log.close()
  48 +
  49 + # Collect thread information
  50 + info = {'celapse': celapse, 'log': buffer}
  51 +
  52 + # Return light curve bin result and thread information
  53 + return result, info
27 54  
28 55  
29 56 # ============== #
... ... @@ -46,10 +73,48 @@ class cstsdist(ctools.csobservation):
46 73 self._srcname = ''
47 74 self._log_clients = False
48 75 self._model = None
  76 + self._nthreads = 0
49 77  
50 78 # Return
51 79 return
52 80  
  81 + # State methods por pickling
  82 + def __getstate__(self):
  83 + """
  84 + Extend ctools.csobservation getstate method to include some members
  85 +
  86 + Returns
  87 + -------
  88 + state : dict
  89 + Pickled instance
  90 + """
  91 + # Set pickled dictionary
  92 + state = {'base' : ctools.csobservation.__getstate__(self),
  93 + 'srcname' : self._srcname,
  94 + 'log_clients' : self._log_clients,
  95 + 'model' : self._model,
  96 + 'nthreads' : self._nthreads}
  97 +
  98 + # Return pickled dictionary
  99 + return state
  100 +
  101 + def __setstate__(self, state):
  102 + """
  103 + Extend ctools.csobservation setstate method to include some members
  104 +
  105 + Parameters
  106 + ----------
  107 + state : dict
  108 + Pickled instance
  109 + """
  110 + ctools.csobservation.__setstate__(self, state['base'])
  111 + self._srcname = state['srcname']
  112 + self._log_clients = state['log_clients']
  113 + self._model = state['model']
  114 + self._nthreads = state['nthreads']
  115 +
  116 + # Return
  117 + return
53 118  
54 119 # Private methods
55 120 def _get_parameters(self):
... ... @@ -79,6 +144,9 @@ class cstsdist(ctools.csobservation):
79 144 # Write input parameters into logger
80 145 self._log_parameters(gammalib.TERSE)
81 146  
  147 + # Set number of processes for multiprocessing
  148 + self._nthreads = mputils.nthreads(self)
  149 +
82 150 # Return
83 151 return
84 152  
... ... @@ -258,7 +326,29 @@ class cstsdist(ctools.csobservation):
258 326 # Write header
259 327 self._log_header1(gammalib.TERSE, 'Generate TS distribution')
260 328  
261   - # Loop over trials
  329 + # If using multiprocessing
  330 + if self._nthreads > 1:
  331 +
  332 + # Create pool of workers
  333 + from multiprocessing import Pool
  334 + pool = Pool(processes = self._nthreads)
  335 +
  336 + # Run time bin analysis in parallel with map
  337 + args = [(self, seed) for seed in range(self['ntrials'].integer())]
  338 + poolresults = pool.map(_multiprocessing_func_wrapper, args)
  339 +
  340 + # Close pool and join
  341 + pool.close()
  342 + pool.join()
  343 +
  344 + # Write results
  345 + for seed in range(self['ntrials'].integer()):
  346 + result = poolresults[seed][0]
  347 + ioutils.write_csv_row(self['outfile'].filename().url(), seed,
  348 + result['colnames'], result['values'])
  349 + self._log_string(gammalib.TERSE, poolresults[seed][1]['log'], False)
  350 +
  351 + # Otherwise, loop over trials
262 352 for seed in range(self['ntrials'].integer()):
263 353  
264 354 # Make a trial
... ...
test/test_cstsdist.py
... ... @@ -135,6 +135,27 @@ class Test(test):
135 135 # Check pull distribution file
136 136 self._check_result_file('cstsdist_py1.dat')
137 137  
  138 + # Set-up cstsdist without multiprocessing
  139 + tsdist = cscripts.cstsdist()
  140 + tsdist['inobs'] = self._events
  141 + tsdist['inmodel'] = self._model
  142 + tsdist['srcname'] = 'Crab'
  143 + tsdist['caldb'] = self._caldb
  144 + tsdist['irf'] = self._irf
  145 + tsdist['ntrials'] = 2
  146 + tsdist['outfile'] = 'cstsdist_py2.dat'
  147 + tsdist['logfile'] = 'cstsdist_py2.log'
  148 + tsdist['chatter'] = 3
  149 + tsdist['nthreads'] = 1
  150 +
  151 + # Run cstsdist script
  152 + tsdist.logFileOpen() # Make sure we get a log file
  153 + tsdist.run()
  154 + tsdist.save()
  155 +
  156 + # Check pull distribution file
  157 + self._check_result_file('cstsdist_py2.dat')
  158 +
138 159 # Return
139 160 return
140 161  
... ...