JeffersonLab / hcana

Hall C++ Analyzer
7 stars 118 forks source link

Bug with basic post process usage #375

Closed whit2333 closed 6 years ago

whit2333 commented 6 years ago

Below is my replay script. There is a segfault (see stacktrace below). I think this is likely a design flaw associated with the podd's use of static for the list of "post processes". If std::cout isn't used, then there is no problem.

In addition to the class SimplePostProcess, the only other change from the source adopted from is adding the post process via

  auto* pp = new SimplePostProcess([](){ std::cout << "qwerty\n"; return 0;});
  analyzer->AddPostProcess(pp);
#include "THttpServer.h"
#include <functional>
#include <iostream>
#include <string>

class SimplePostProcess : public THaPostProcess {
public:
  using Function_t = std::function<int()>;
  Function_t flambda;
  SimplePostProcess(Function_t&& f) : flambda(std::forward<Function_t>(f)) { }
  //SimplePostProcess()  { }
  virtual ~SimplePostProcess(){ }

  virtual Int_t Init(const TDatime& ) {
    //std::cout << derp;
    return 0;
  }
  virtual Int_t Process( const THaEvData*, const THaRunBase*, Int_t code ){ 
    printf("asdf\n");
    flambda();
    return 0;
  }
  virtual Int_t Close(){ return 0; }
};

#if defined(__ROOTCLING__)
#pragma link C++ class SimplePostProcess+;
#pragma link C++ class std::vector<SimplePostProcess*>+;
#endif

void replay_production_all_shms (Int_t RunNumber = 0, Int_t MaxEvent = 0) {

  // Get RunNumber and MaxEvent if not provided.
  if(RunNumber == 0) {
    cout << "Enter a Run Number (-1 to exit): ";
    cin >> RunNumber;
    if( RunNumber<=0 ) return;
  }
  if(MaxEvent == 0) {
    cout << "\nNumber of Events to analyze: ";
    cin >> MaxEvent;
    if(MaxEvent == 0) {
      cerr << "...Invalid entry\n";
      exit;
    }
  }

  // Create file name patterns.
  const char* RunFileNamePattern = "shms_all_%05d.dat";
  vector<TString> pathList;
  pathList.push_back(".");
  pathList.push_back("./raw");
  pathList.push_back("./raw/../raw.copiedtotape");
  pathList.push_back("./cache");

  const char* ROOTFileNamePattern = "ROOTfiles/shms_replay_production_all_%d_%d.root";

  // Load global parameters
  gHcParms->Define("gen_run_number", "Run Number", RunNumber);
  gHcParms->AddString("g_ctp_database_filename", "DBASE/SHMS/standard.database");
  gHcParms->Load(gHcParms->GetString("g_ctp_database_filename"), RunNumber);
  gHcParms->Load(gHcParms->GetString("g_ctp_parm_filename"));
  gHcParms->Load(gHcParms->GetString("g_ctp_kinematics_filename"), RunNumber);
  // Load parameters for SHMS trigger configuration
  gHcParms->Load("PARAM/TRIG/tshms.param");
  // Load fadc debug parameters
  gHcParms->Load("PARAM/SHMS/GEN/p_fadc_debug.param");

  // Load the Hall C detector map
  gHcDetectorMap = new THcDetectorMap();
  gHcDetectorMap->Load("MAPS/SHMS/DETEC/STACK/shms_stack.map");

  // Add trigger apparatus
  THaApparatus* TRG = new THcTrigApp("T", "TRG");
  gHaApps->Add(TRG);
  // Add trigger detector to trigger apparatus
  THcTrigDet* shms = new THcTrigDet("shms", "SHMS Trigger Information");
  TRG->AddDetector(shms);

  // Set up the equipment to be analyzed
  THcHallCSpectrometer* SHMS = new THcHallCSpectrometer("P", "SHMS");
  gHaApps->Add(SHMS);
  // Add Noble Gas Cherenkov to SHMS apparatus
  THcCherenkov* ngcer = new THcCherenkov("ngcer", "Noble Gas Cherenkov");
  SHMS->AddDetector(ngcer);
  // Add drift chambers to SHMS apparatus
  THcDC* dc = new THcDC("dc", "Drift Chambers");
  SHMS->AddDetector(dc);
  // Add hodoscope to SHMS apparatus
  THcHodoscope* hod = new THcHodoscope("hod", "Hodoscope");
  SHMS->AddDetector(hod);
  // Add Heavy Gas Cherenkov to SHMS apparatus
  THcCherenkov* hgcer = new THcCherenkov("hgcer", "Heavy Gas Cherenkov");
  SHMS->AddDetector(hgcer);
  // Add Aerogel Cherenkov to SHMS apparatus
  THcAerogel* aero = new THcAerogel("aero", "Aerogel");
  SHMS->AddDetector(aero);
  // Add calorimeter to SHMS apparatus
  THcShower* cal = new THcShower("cal", "Calorimeter");
  SHMS->AddDetector(cal);

  // Add rastered beam apparatus
  THaApparatus* beam = new THcRasteredBeam("P.rb", "Rastered Beamline");
  gHaApps->Add(beam);
  // Add physics modules
  // Calculate reaction point
  THaReactionPoint* prp = new THaReactionPoint("P.react", "SHMS reaction point", "P", "P.rb");
  gHaPhysics->Add(prp);
  // Calculate extended target corrections
  THcExtTarCor* pext = new THcExtTarCor("P.extcor", "HMS extended target corrections", "P", "P.react");
  gHaPhysics->Add(pext);
  // Calculate golden track quantites
  THaGoldenTrack* gtr = new THaGoldenTrack("P.gtr", "SHMS Golden Track", "P");
  gHaPhysics->Add(gtr);
  // Calculate primary (scattered beam - usually electrons) kinematics
  THcPrimaryKine* kin = new THcPrimaryKine("P.kin", "SHMS Single Arm Kinematics", "P", "P.rb");
  gHaPhysics->Add(kin);
  // Calculate the hodoscope efficiencies
  THcHodoEff* peff = new THcHodoEff("phodeff", "SHMS hodo efficiency", "P.hod");
  gHaPhysics->Add(peff);

  // Add event handler for prestart event 125.
  THcConfigEvtHandler* ev125 = new THcConfigEvtHandler("HC", "Config Event type 125");
  gHaEvtHandlers->Add(ev125);
  // Add event handler for EPICS events
  THaEpicsEvtHandler* hcepics = new THaEpicsEvtHandler("epics", "HC EPICS event type 180");
  gHaEvtHandlers->Add(hcepics);
  // Add event handler for scaler events
  THcScalerEvtHandler* pscaler = new THcScalerEvtHandler("P", "Hall C scaler event type 1");
  pscaler->AddEvtType(1);
  pscaler->AddEvtType(129);
  pscaler->SetDelayedType(129);
  pscaler->SetUseFirstEvent(kTRUE);
  gHaEvtHandlers->Add(pscaler);
  // Add event handler for DAQ configuration event
  THcConfigEvtHandler *pconfig = new THcConfigEvtHandler("pconfig", "Hall C configuration event handler");
  gHaEvtHandlers->Add(pconfig);

  // Set up the analyzer - we use the standard one,
  // but this could be an experiment-specific one as well.
  // The Analyzer controls the reading of the data, executes
  // tests/cuts, loops over Acpparatus's and PhysicsModules,
  // and executes the output routines.
  THcAnalyzer* analyzer = new THcAnalyzer;

  auto* pp = new SimplePostProcess([](){ std::cout << "qwerty\n"; return 0;});
  analyzer->AddPostProcess(pp);

  // A simple event class to be output to the resulting tree.
  // Creating your own descendant of THaEvent is one way of
  // defining and controlling the output.
  THaEvent* event = new THaEvent;

  // Define the run(s) that we want to analyze.
  // We just set up one, but this could be many.
  THcRun* run = new THcRun( pathList, Form(RunFileNamePattern, RunNumber) );

  // Set to read in Hall C run database parameters
  run->SetRunParamClass("THcRunParameters");

  // Eventually need to learn to skip over, or properly analyze the pedestal events
  run->SetEventRange(1, MaxEvent); // Physics Event number, does not include scaler or control events.
  run->SetNscan(1);
  run->SetDataRequired(0x7);
  run->Print();

  // Define the analysis parameters
  TString ROOTFileName = Form(ROOTFileNamePattern, RunNumber, MaxEvent);
  analyzer->SetCountMode(2);  // 0 = counter is # of physics triggers
                              // 1 = counter is # of all decode reads
                              // 2 = counter is event number
  analyzer->SetEvent(event);
  // Set EPICS event type
  analyzer->SetEpicsEvtType(180);
  // Define crate map
  analyzer->SetCrateMapFileName("MAPS/db_cratemap.dat");
  // Define output ROOT file
  analyzer->SetOutFile(ROOTFileName.Data());
  // Define DEF-file
  analyzer->SetOdefFile("DEF-files/SHMS/PRODUCTION/pstackana_production_all.def");
  // Define cuts file
  analyzer->SetCutFile("DEF-files/SHMS/PRODUCTION/CUTS/pstackana_production_cuts.def");  // optional
  // File to record accounting information for cuts
  analyzer->SetSummaryFile(Form("REPORT_OUTPUT/SHMS/PRODUCTION/summary_all_production_%d_%d.report", RunNumber, MaxEvent));  // optional
  // Start the actual analysis.
  analyzer->Process(run);
  // Create report file from template
  analyzer->PrintReport("TEMPLATES/SHMS/PRODUCTION/pstackana_production.template",
            Form("REPORT_OUTPUT/SHMS/PRODUCTION/replay_shms_all_production_%d_%d.report", RunNumber, MaxEvent));  // optional

}
Starting analysis
asdf

 *** Break *** segmentation violation

===========================================================
There was a crash.
This is the entire stack trace of all threads:
===========================================================
#0  0x00007ff9142b68fa in __GI___waitpid (pid=1286, stat_loc=stat_loc
entry=0x7ffcd4073358, options=options
entry=0) at ../sysdeps/unix/sysv/linux/waitpid.c:29
#1  0x00007ff9142259cb in do_system (line=<optimized out>) at ../sysdeps/posix/system.c:148
#2  0x00007ff919552173 in TUnixSystem::Exec (shellcmd=<optimized out>, this=0x1a297c0) at /opt/software/sources/root/core/unix/src/TUnixSystem.cxx:2119
#3  TUnixSystem::StackTrace() () at /opt/software/sources/root/core/unix/src/TUnixSystem.cxx:2413
#4  0x00007ff919554a44 in TUnixSystem::DispatchSignals (this=0x1a297c0, sig=kSigSegmentationViolation) at /opt/software/sources/root/core/unix/src/TUnixSystem.cxx:3644
#5  <signal handler called>
#6  0x00007ff914c38616 in std::ostream::sentry::sentry (this=0x7ffcd4075ad0, __os=...) at /opt/software/builds/gcc_8.1.0_build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/ostream.tcc:46
#7  0x00007ff914c38c28 in std::__ostream_insert<char, std::char_traits<char> > (__out=..., __s=__s
entry=0x7ff919eb2d7e "qwerty\n", __n=7) at /opt/software/builds/gcc_8.1.0_build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/ostream_insert.h:76
#8  0x00007ff914c39037 in std::operator<< <std::char_traits<char> > (__out=..., __s=0x7ff919eb2d7e "qwerty\n") at /opt/software/builds/gcc_8.1.0_build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/char_traits.h:320
#9  0x00007ff919eb7a7c in ?? ()
#10 0x0000000006d8e238 in ?? ()
#11 0x0000000006d8e238 in ?? ()
#12 0x00007ffcd4075b70 in ?? ()
#13 0x00007ff919eb78e3 in ?? ()
#14 0x00007ff919eb7a50 in ?? ()
#15 0x0000000006d8e238 in ?? ()
#16 0x00007ffcd4075b90 in ?? ()
#17 0x00007ff919eb7f15 in ?? ()
#18 0x0000000006d8e238 in ?? ()
#19 0x0000000006d8e238 in ?? ()
#20 0x00007ffcd4075bd0 in ?? ()
#21 0x00007ff919eb7d33 in ?? ()
#22 0x0000000500000000 in ?? ()
#23 0x0000000006d8e220 in ?? ()
#24 0x00000000d4075bd0 in ?? ()
#25 0x000000000728bb00 in ?? ()
#26 0x0000000006dfea10 in ?? ()
#27 0x0000000006d8e220 in ?? ()
#28 0x00007ffcd4075c20 in ?? ()
#29 0x00007ff915b680b0 in THaAnalyzer::PostProcess(int) () from /home/whit/lib/libHallA.so
===========================================================
hansenjo commented 6 years ago

It works fine for me, both in interpreted and compiled mode.

I put your class definition in a separate file, which I include at the top of an existing replay script (the one from the Workshop2017 tutorial). It runs fine, happily printing out your "querty":

Starting analysis
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
SPP: event = 0, code = 0
qwerty
Warning::GenScaler:: (10,1) using default num 32 channels
SPP: event = 1, code = 0
qwerty
SPP: event = 2, code = 1
qwerty
SPP: event = 3, code = 1
qwerty
SPP: event = 4, code = 1
qwerty
SPP: event = 5, code = 1
qwerty
SPP: event = 6, code = 0
qwerty
SPP: event = 7, code = 1
qwerty
.....

(I modified the code slightly to print out the event number and analysis status code. It also works when just printing out "asdf" or whatever.)

I don't understand what you mean by "Podd's use of static or the list of "post processes"". Do you mean the static_cast<THaPostProcess*>? We could add a check to ensure that only objects inheriting from THaPostProcess can be added to the list; that would be a good safety check. But the static_cast is not the problem here; you class does inherit from the proper base class.

The only significant design flaw that one could argue about is that the return code of the Process function is ignored by THaAnalyzer::PostProcess, so PostProcess modules are currently not suitable as event filters for the standard ROOT file. But this is actually by design; the purpose of the PostProcess modules is that each module could open its own output file (whichever format) for writing event data (raw or somehow processed), using the analysis status code as a hint. Or to serve event data up to the web, or similar things.

In any case, I don't know why your code crashes; maybe there's a different problem in your setup? How about compiling everything for debugging (scons -jN debug=1) and running the analyzer under gdb? That's usually the fastest way to the root cause of segfaults.

hansenjo commented 6 years ago

Possibly related analyzer commit:

commit 20cf746a6e78acef372711711b64f764bc144e28 Author: Ole Hansen ole@jlab.org Date: Mon Oct 2 18:05:44 2017 -0400

From Ed Brash: SCons fixes for interactive interpreter segfaults
...
- Add -fPIC to g++ command line flags specifically for the
  compilation of src/main.C ... this was not done before, and
  appears to have been the source of the segfault issue.

Closes #141

Like SCons, CMake does not add -fPIC to the compile options of src/main.cxx. I can readily reproduce the crash reported in JeffersonLab/analyzer#141 with your CMake build.

whit2333 commented 6 years ago

Yep. That fixed it. Thanks!