source: trunk/Mars/mbase/MTask.cc@ 20107

Last change on this file since 20107 was 19345, checked in by tbretz, 6 years ago
Improves the behaviour with RecursiveRemove. Strictly speaking this change might only be necessary if a class contains more than one member which is bound to recursive remove. Onth other hand setting all members to NULL which might be affected by RecursiveRemove is not wrong either.
File size: 16.8 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 12/2000 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2007
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MTask
28//
29// Base class for all tasks which can perfomed in a tasklist
30// For each event processed in the eventloop all the different
31// tasks in the tasklist will be processed.
32//
33// So all tasks must inherit from this baseclass.
34//
35// The inheritance from MInputStreamID is used to indicate the
36// type of event that this task is for. If it is "All" it is executed
37// independantly of the actual ID of the task list.
38//
39// Inside this abstract class, there are three fundamental function:
40//
41// - PreProcess(): executed before the eventloop starts. Here you
42// can initiate different things, open files, etc.
43// As an argument this function gets a pointer to the
44// parameter list. You can stop the execution by
45// returning kFALSE instead of kTRUE. If an error
46// occured and you return kFALSE make sure, that
47// any action is closed correctly and all newly
48// created object are deleted. The PostProcess in
49// such a case won't be executed by the Tasklist or
50// Eventloop.
51//
52// - Process(): executed for each event in the eventloop. Do it
53// one task after the other (as they occur in the
54// tasklist). Only the tasks with a Stream ID
55// which matches the actual ID of the tasklist
56// are executed. A task can return kFALSE to
57// stop the execuition of the tasklist or
58// kCONTINUE to skip the pending tasks. If you want
59// to stop the eventloop and wants the eventloop to
60// return the status 'failed' return kERROR.
61//
62// - ReInit() The idea is, that
63// a) we have one file per run
64// b) each file contains so called run-headers which
65// stores information 'per run', eg MRawRunHeader
66// or the bad pixels
67// c) this information must be evaluated somehow each
68// time a new file is opened.
69//
70// If you use MReadMarsFile or MCT1ReadPreProc it is
71// called each time a new file has been opened and the
72// new run headers have been read before the first
73// event of these file is preprocessed.
74//
75// - PostProcess(): executed after the eventloop. Here you can close
76// output files, start display of the run parameter,
77// etc. PostProcess is only executed in case of
78// PreProcess was successfull (returned kTRUE)
79//
80//
81// Remark: Using a MTask in your tasklist doesn't make much sense,
82// because it is doing nothing. However it is a nice tool
83// to count something (exspecially if used together with a
84// filter)
85//
86//
87// Version 1:
88// ----------
89// - first version
90//
91// Version 2:
92// ----------
93// - added fSerialNumber
94//
95/////////////////////////////////////////////////////////////////////////////
96#include "MTask.h"
97
98#include <fstream>
99
100#include <TClass.h>
101#include <TBaseClass.h> // OverwritesProcess
102#include <TStopwatch.h> // TStopwatch
103
104#include "MString.h"
105
106#include "MLog.h"
107#include "MLogManip.h"
108
109#include "MFilter.h"
110#include "MStatusDisplay.h"
111
112#undef DEBUG_PROCESS
113//#define DEBUG_PROCESS
114
115ClassImp(MTask);
116
117using namespace std;
118
119MTask::MTask(const char *name, const char *title)
120 : fFilter(NULL), fSerialNumber(0), fIsPreprocessed(kFALSE),
121 fStopwatch(0), fNumExecutions(0), fNumExec0(0), fAccelerator(0)
122{
123 fName = name ? name : "MTask";
124 fTitle = title ? title : "Base class for all tasks (dummy task).";
125
126 fListOfBranches = new TList;
127 fListOfBranches->SetOwner();
128
129 fStopwatch = new TStopwatch;
130}
131
132// --------------------------------------------------------------------------
133//
134// Destructor. Delete fStopwatch and fListOfBranches
135//
136MTask::~MTask()
137{
138 delete fStopwatch;
139 fStopwatch = 0;
140
141 delete fListOfBranches;
142 fListOfBranches = 0;
143}
144
145// --------------------------------------------------------------------------
146//
147// Initialize fFilter with filter and if not null add the result of
148// GetDataMember from the filter to the branch list.
149//
150void MTask::SetFilter(MFilter *filter)
151{
152 fFilter=filter;
153 if (!filter)
154 return;
155
156 fFilter->SetBit(kMustCleanup); // Better is better ;-)
157 AddToBranchList(filter->GetDataMember());
158}
159
160// --------------------------------------------------------------------------
161//
162// This adds a branch to the list for the auto enabeling schmeme.
163// This makes it possible for MReadTree to decide which branches
164// are really needed for the eventloop. Only the necessary branches
165// are read from disk which speeds up the calculation enormously.
166//
167// You can use TRegExp expressions like "*.fEnergy", but the
168// recommended method is to call this function for exactly all
169// branches you want to have, eg:
170// AddToBranchList("MMcTrig.fNumFirstLevel");
171// AddToBranchList("MMcTrig;1.fNumFirstLevel");
172// AddToBranchList("MMcTrig;2.fNumFirstLevel");
173//
174// We agreed on the convetion, that all branches are stored with
175// a trailing dot '.' so that always the Master Branch name
176// (eg. MMcTrig) is part of the branch name.
177//
178// Remark: The common place to call AddToBranchList is the
179// constructor of the derived classes (tasks)
180//
181void MTask::AddToBranchList(const char *b)
182{
183 if (fListOfBranches->FindObject(b))
184 return;
185
186 fListOfBranches->Add(new TNamed(b, ""));
187}
188
189// --------------------------------------------------------------------------
190//
191// Using this overloaded member function you may cascade several branches
192// in acomma seperated list, eg: "MMcEvt.fTheta,MMcEvt.fEnergy"
193//
194// For moredetailed information see AddToBranchList(const char *b);
195//
196void MTask::AddToBranchList(const TString &str)
197{
198 TString s = str;
199
200 while (!s.IsNull())
201 {
202 Int_t fst = s.First(',');
203
204 if (fst<0)
205 fst = s.Length();
206
207 AddToBranchList((const char*)TString(s(0, fst)));
208
209 s.Remove(0, fst+1);
210 }
211}
212
213// --------------------------------------------------------------------------
214//
215// Copy constructor. Reset MInputStreamID, copy pointer to fFilter and
216// copy the contents of fListOfBranches
217//
218MTask::MTask(MTask &t) : MInputStreamID()
219{
220 fFilter = t.fFilter;
221 fListOfBranches->AddAll(t.fListOfBranches);
222}
223
224// --------------------------------------------------------------------------
225//
226// Mapper function for PreProcess.
227// Sets the preprocessed flag dependend on the return value of PreProcess.
228// Resets number of executions and cpu consumtion timer.
229// If task has already been preprocessed return kTRUE.
230//
231Int_t MTask::CallPreProcess(MParList *plist)
232{
233 if (fIsPreprocessed)
234 return kTRUE;
235
236 // This does not reset the counter!
237 fStopwatch->Reset();
238 fNumExec0 = fNumExecutions;
239
240 *fLog << all << GetDescriptor() << "... " << flush;
241 if (fDisplay)
242 fDisplay->SetStatusLine2(*this);
243
244 switch (PreProcess(plist))
245 {
246 case kFALSE:
247 return kFALSE;
248
249 case kTRUE:
250 fIsPreprocessed = kTRUE;
251 return kTRUE;
252
253 case kSKIP:
254 return kSKIP;
255 }
256
257 *fLog << err << dbginf << "PreProcess of " << GetDescriptor();
258 *fLog << " returned an unknown value... aborting." << endl;
259
260 return kFALSE;
261}
262
263// --------------------------------------------------------------------------
264//
265// Mapper function for Process.
266// Executes Process dependent on the existance of a filter and its possible
267// return value.
268// If Process is executed, the execution counter is increased.
269// Count cpu consumption time.
270//
271Int_t MTask::CallProcess()
272{
273 //
274 // Check for the existance of a filter. If a filter is existing
275 // check for its value. If the value is kFALSE don't execute
276 // this task.
277 //
278 if (fFilter && !fFilter->IsConditionTrue())
279 return kTRUE;
280
281 if (!HasAccelerator(kAccDontTime))
282 fStopwatch->Start(kFALSE);
283
284 fNumExecutions++;
285
286#ifdef DEBUG_PROCESS
287 *fLog << all << flush << GetName() << "..." << flush;
288#endif
289
290 const Int_t rc = Process();
291
292#ifdef DEBUG_PROCESS
293 *fLog << all << flush << "done." << endl;
294#endif
295
296 if (!HasAccelerator(kAccDontTime))
297 fStopwatch->Stop();
298
299 return rc;
300}
301
302// --------------------------------------------------------------------------
303//
304// Mapper function for PreProcess.
305// Calls Postprocess dependent on the state of the preprocessed flag,
306// resets this flag.
307//
308Int_t MTask::CallPostProcess()
309{
310 if (!fIsPreprocessed)
311 return kTRUE;
312
313 fIsPreprocessed = kFALSE;
314
315 *fLog << all << GetDescriptor() << "... " << flush;
316 if (fDisplay)
317 fDisplay->SetStatusLine2(*this);
318
319 return PostProcess();
320}
321
322// --------------------------------------------------------------------------
323//
324// This is reinit function
325//
326// This function is called asynchronously if the tasks in the tasklist need
327// reinitialization. This for example happens when the eventloop switches
328// from one group of events to another one (eg. switching between events
329// of different runs means reading a new run header and a new run header
330// may mean that some value must be reinitialized)
331//
332// the virtual implementation returns kTRUE
333//
334Bool_t MTask::ReInit(MParList *)
335{
336 return kTRUE;
337}
338
339// --------------------------------------------------------------------------
340//
341// This is processed before the eventloop starts
342//
343// It is the job of the PreProcess to connect the tasks
344// with the right container in the parameter list.
345//
346// the virtual implementation returns kTRUE
347//
348Int_t MTask::PreProcess(MParList *)
349{
350 return kTRUE;
351}
352
353// --------------------------------------------------------------------------
354//
355// This is processed for every event in the eventloop
356//
357// the virtual implementation returns kTRUE
358//
359Int_t MTask::Process()
360{
361 return kTRUE;
362}
363
364// --------------------------------------------------------------------------
365//
366// This is processed after the eventloop starts
367//
368// the virtual implementation returns kTRUE
369//
370Int_t MTask::PostProcess()
371{
372 return kTRUE;
373}
374
375// --------------------------------------------------------------------------
376//
377// Returns the name of the object. If the name of the object is not the
378// class name it returns the object name and in []-brackets the class name.
379// If a serial number is set (!=0) the serial number is added to the
380// name (eg. ;1)
381//
382const TString MTask::GetDescriptor() const
383{
384 //
385 // Because it returns a (const char*) we cannot return a casted
386 // local TString. The pointer would - immediatly after return -
387 // point to a random memory segment, because the TString has gone.
388 //
389 if (fName==ClassName())
390 return fSerialNumber==0 ? (TString)ClassName() : MString::Format("%s;%d", ClassName(), fSerialNumber);
391
392 return fSerialNumber>0 ?
393 MString::Format("%s;%d [%s]", fName.Data(), fSerialNumber, ClassName()) :
394 MString::Format("%s [%s]", fName.Data(), ClassName());
395}
396
397// --------------------------------------------------------------------------
398//
399// Return the total number of calls to since PreProcess(). If Process() was
400// not called due to a set filter this is not counted.
401//
402UInt_t MTask::GetNumExecutions() const
403{
404 return fNumExecutions-fNumExec0;
405}
406
407// --------------------------------------------------------------------------
408//
409// Return the total number of calls to Process() ever. If Process() was not
410// called due to a set filter this is not counted.
411//
412UInt_t MTask::GetNumExecutionsTotal() const
413{
414 return fNumExecutions;
415}
416
417// --------------------------------------------------------------------------
418//
419// Return total CPU execution time in seconds of calls to Process().
420// If Process() was not called due to a set filter this is not counted.
421//
422Double_t MTask::GetCpuTime() const
423{
424 return fStopwatch->CpuTime();
425}
426
427// --------------------------------------------------------------------------
428//
429// Return total real execution time in seconds of calls to Process().
430// If Process() was not called due to a set filter this is not counted.
431//
432Double_t MTask::GetRealTime() const
433{
434 return fStopwatch->RealTime();
435}
436
437// --------------------------------------------------------------------------
438//
439// Prints the relative time spent in Process() (relative means relative to
440// its parent Tasklist) and the number of times Process() was executed.
441// Don't wonder if the sum of the tasks in a tasklist is not 100%,
442// because only the call to Process() of the task is measured. The
443// time of the support structure is ignored. The faster your analysis is
444// the more time is 'wasted' in the support structure.
445// Only the CPU time is displayed. This means that exspecially task
446// which have a huge part of file i/o will be underestimated in their
447// relative wasted time.
448// For convinience the lvl argument results in a number of spaces at the
449// beginning of the line. So that the structur of a tasklist can be
450// identified. If a Tasklist or task has filter applied the name of the
451// filter is printer in <>-brackets behind the number of executions.
452// Use MTaskList::PrintStatistics without an argument.
453// For tasks which don't overwrite Process() no action is perfomed.
454//
455void MTask::PrintStatistics(const Int_t lvl, Bool_t title, Double_t time) const
456{
457 if (!Overwrites("Process") && IsA()!=MTask::Class())
458 return;
459
460 *fLog << all << setfill(' ') << setw(lvl) << " ";
461
462 if (GetCpuTime()>0 && time>0 && GetCpuTime()>=0.001*time && !HasAccelerator(kAccDontTime))
463 *fLog << Form("%5.1f", GetCpuTime()/time*100) << "% ";
464 else
465 *fLog << " ";
466
467 if (HasStreamId())
468 *fLog << GetStreamId() << ":";
469 *fLog << GetDescriptor();
470
471 if (GetNumExecutions()>0)
472 *fLog << "\t" << dec << GetNumExecutions();
473
474 if (fFilter)
475 *fLog << " <" << fFilter->GetName() << ">";
476 if (title)
477 *fLog << "\t" << fTitle;
478 *fLog << endl;
479}
480
481// --------------------------------------------------------------------------
482//
483// First call MParContainer::SavePrimitive which should stream the primitive
484// to the output stream. Then, if a filter is set, stream first the filter
485// and afterwards set the filter for this task.
486//
487void MTask::SavePrimitive(ostream &out, Option_t *)
488{
489 MParContainer::SavePrimitive(out);
490 if (!fFilter)
491 return;
492
493 /*
494 If we don't stream filter which are not in the task list itself
495 (which means: already streamed) we may be able to use
496 SavePrimitive as some kind of validity check for the macros
497
498 fFilter->SavePrimitive(out);
499 */
500 out << " " << GetUniqueName() << ".SetFilter(&" << fFilter->GetUniqueName() <<");" << endl;
501 if (fSerialNumber>0)
502 out << " " << GetUniqueName() << ".SetSerialNumber(" << fSerialNumber <<");" << endl;
503}
504
505void MTask::SavePrimitive(ofstream &out, Option_t *o)
506{
507 SavePrimitive(static_cast<ostream&>(out), o);
508}
509
510void MTask::SetDisplay(MStatusDisplay *d)
511{
512 if (fFilter)
513 fFilter->SetDisplay(d);
514 MParContainer::SetDisplay(d);
515}
516
517// --------------------------------------------------------------------------
518//
519// This is used to print the output in the PostProcess/Finalize.
520// Or everywhere else in a nice fashioned and unified way.
521//
522void MTask::PrintSkipped(UInt_t n, const char *str)
523{
524 *fLog << " " << setw(7) << n << " (";
525 *fLog << Form("%5.1f", 100.*n/GetNumExecutions());
526 *fLog << "%) Evts skipped: " << str << endl;
527}
528
529// --------------------------------------------------------------------------
530//
531// If obj==fFilter set fFilter to NULL
532// Call MParcontainer::RecursiveRemove
533//
534void MTask::RecursiveRemove(TObject *obj)
535{
536 if (obj==fFilter)
537 fFilter=NULL;
538
539 if (fFilter)
540 fFilter->RecursiveRemove(obj);
541
542 MParContainer::RecursiveRemove(obj);
543}
Note: See TracBrowser for help on using the repository browser.