Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:17:40

0001 // $Id$
0002 //
0003 //    File: JEventProcessor_janaview.cc
0004 // Created: Fri Oct  3 08:14:14 EDT 2014
0005 // Creator: davidl (on Darwin harriet.jlab.org 13.4.0 i386)
0006 //
0007 
0008 #include <unistd.h>
0009 #include <set>
0010 using namespace std;
0011 
0012 #include "JEventProcessor_janaview.h"
0013 #include <JANA/JEventSource.h>
0014 
0015 #include <TLatex.h>
0016 #include <TArrow.h>
0017 #include <TBox.h>
0018 
0019 jv_mainframe *JVMF = NULL;
0020 JEventProcessor_janaview *JEP=NULL;
0021 
0022 
0023 // Routine used to create our JEventProcessor
0024 #include <JANA/JApplication.h>
0025 #include <JANA/JFactory.h>
0026 
0027 extern "C"{
0028 void InitPlugin(JApplication *app){
0029     InitJANAPlugin(app);
0030     app->Add(new JEventProcessor_janaview());
0031     
0032     // Some event sources don't maintain call stack info
0033     // unless told to do so via environment variable.
0034     app->SetParameterValue("RECORD_CALL_STACK", 1);
0035     
0036 }
0037 } // "C"
0038 
0039 //==============================================================================
0040 
0041 
0042 //.....................................
0043 // FactoryNameSort
0044 //.....................................
0045 bool FactoryNameSort(JFactory *a,JFactory *b){
0046   if (a->GetObjectName()==b->GetObjectName()) return string(a->GetTag()) < string(b->GetTag());
0047   return a->GetObjectName() < b->GetObjectName();
0048 }
0049 
0050 //==============================================================================
0051 
0052 //-------------------
0053 // JanaViewRootGUIThread
0054 //
0055 // C-callable routine that can be used with pthread_create to launch
0056 // a thread that creates the ROOT GUI and handles all ROOT GUI interactions
0057 //-------------------
0058 void* JanaViewRootGUIThread(void */*arg*/)
0059 {
0060 //  JEventProcessor_janaview *jproc = (JEventProcessor_janaview*)arg;
0061 
0062     // Create a ROOT TApplication object
0063     int narg = 0;
0064     TApplication app("JANA Viewer", &narg, NULL);
0065     app.SetReturnFromRun(true);
0066     JVMF = new jv_mainframe(gClient->GetRoot(), 600, 600, true);
0067     
0068     try{
0069         app.Run();
0070     }catch(std::exception &e){
0071         _DBG_ << "Exception: " << e.what() << endl;
0072     }
0073 
0074     return NULL;
0075 }
0076 
0077 //==============================================================================
0078 
0079 
0080 //------------------
0081 // JEventProcessor_janaview (Constructor)
0082 //------------------
0083 JEventProcessor_janaview::JEventProcessor_janaview()
0084 {
0085     eventnumber = 0;
0086 
0087     pthread_mutex_init(&mutex, NULL);
0088     pthread_cond_init(&cond, NULL);
0089 
0090     pthread_t root_thread;
0091     pthread_create(&root_thread, NULL, JanaViewRootGUIThread, this);
0092     
0093     while(!JVMF) usleep(100000);
0094 
0095     JEP = this;
0096 }
0097 
0098 //------------------
0099 // ~JEventProcessor_janaview (Destructor)
0100 //------------------
0101 JEventProcessor_janaview::~JEventProcessor_janaview()
0102 {
0103 
0104 }
0105 
0106 //------------------
0107 // init
0108 //------------------
0109 void JEventProcessor_janaview::Init()
0110 {
0111 }
0112 
0113 //------------------
0114 // brun
0115 //------------------
0116 void JEventProcessor_janaview::BeginRun(const std::shared_ptr<const JEvent>& event)
0117 {
0118     this->loop = event;
0119     loop->GetJCallGraphRecorder()->SetEnabled(true);
0120 }
0121 
0122 //------------------
0123 // evnt
0124 //------------------
0125 void JEventProcessor_janaview::Process(const std::shared_ptr<const JEvent>& event)
0126 {
0127     // We need to wait here in order to allow the GUI to control when to
0128     // go to the next event. Lock the mutex and wait for the GUI to wake us
0129     auto app = event->GetJApplication();
0130     app->SetTicker(false);
0131     // app->monitor_heartbeat = false;  // TODO: Re-add this when I cycle back to the heartbeat stuff
0132 
0133     pthread_mutex_lock(&mutex);
0134 
0135     // static bool processed_first_event = false;
0136 
0137     this->loop = event;
0138     this->eventnumber = event->GetEventNumber();
0139     
0140     JEventSource *source = event->GetJEventSource();
0141     JVMF->UpdateInfo(source->GetResourceName(), event->GetRunNumber(), event->GetEventNumber());
0142 
0143     vector<JVFactoryInfo> facinfo;
0144     GetObjectTypes(facinfo);
0145     JVMF->UpdateObjectTypeList(facinfo);
0146     
0147     MakeCallGraph();
0148 
0149     pthread_cond_wait(&cond, &mutex);
0150     
0151     // processed_first_event = true;
0152     
0153     pthread_mutex_unlock(&mutex);
0154 }
0155 
0156 //------------------
0157 // NextEvent
0158 //------------------
0159 void JEventProcessor_janaview::NextEvent(void)
0160 {
0161     // This just unblocks the pthread_cond_wait() call in evnt(). 
0162     pthread_cond_signal(&cond);
0163 }
0164 
0165 //------------------
0166 // erun
0167 //------------------
0168 void JEventProcessor_janaview::EndRun()
0169 {
0170     // This is called whenever the run number changes, before it is
0171     // changed to give you a chance to clean up before processing
0172     // events from the next run number.
0173 }
0174 
0175 //------------------
0176 // fini
0177 //------------------
0178 void JEventProcessor_janaview::Finish(void)
0179 {
0180     // Called before program exit after event processing is finished.
0181 }
0182 
0183 //------------------------------------------------------------------
0184 // MakeNametag
0185 //------------------------------------------------------------------
0186 string JEventProcessor_janaview::MakeNametag(const string &name, const string &tag)
0187 {
0188     string nametag = name;
0189     if(tag.size()>0)nametag += ":"+tag;
0190 
0191     return nametag;
0192 }
0193 
0194 //------------------
0195 // GetObjectTypes
0196 //------------------
0197 void JEventProcessor_janaview::GetObjectTypes(vector<JVFactoryInfo> &facinfo)
0198 {
0199     if(!loop) return;
0200 
0201     // Get factory pointers and sort them by factory name
0202     vector<JFactory*> factories = loop->GetAllFactories();
0203     sort(factories.begin(), factories.end(), FactoryNameSort);
0204     
0205     // Copy factory info into JVFactoryInfo structures
0206     for(uint32_t i=0; i<factories.size(); i++){
0207         JVFactoryInfo finfo;
0208         finfo.name = factories[i]->GetObjectName();
0209         finfo.tag = factories[i]->GetTag();
0210         finfo.nametag = MakeNametag(finfo.name, finfo.tag);
0211         facinfo.push_back(finfo);
0212     }
0213 }
0214 
0215 //------------------
0216 // GetAssociatedTo
0217 //------------------
0218 void JEventProcessor_janaview::GetAssociatedTo(JObject *jobj, vector<const JObject*> &associatedTo)
0219 {
0220     if(!loop) return;
0221 
0222     vector<JFactory*> factories = loop->GetAllFactories();
0223     for(uint32_t i=0; i<factories.size(); i++){
0224         
0225         // Do not activate factories that have not yet been activated
0226             if(factories[i]->GetCreationStatus() == JFactory::CreationStatus::NotCreatedYet) continue;
0227 
0228         // Get objects for this factory and associated objects for each of those
0229         vector<JObject*> vobjs = factories[i]->GetAs<JObject>();
0230         for(uint32_t i=0; i<vobjs.size(); i++){
0231             JObject *obj = vobjs[i];
0232             
0233             vector<const JObject*> associated;
0234             obj->GetT(associated);
0235             
0236             for(uint32_t j=0; j<associated.size(); j++){
0237                 if(associated[j] == jobj) associatedTo.push_back(obj);
0238             }
0239         }
0240     }
0241 }
0242 
0243 //------------------
0244 // MakeCallGraph
0245 //------------------
0246 void JEventProcessor_janaview::MakeCallGraph(string nametag)
0247 {
0248     if(nametag=="") nametag = JVMF->GetSelectedObjectType();
0249 
0250     // Clear canvas
0251     TCanvas *c = JVMF->canvas->GetCanvas();
0252     c->cd();
0253     c->Clear();
0254     c->Update();
0255     
0256     // Delete any existing callgraph objects
0257     for(auto it : cgobjs) if(it.second) delete it.second;
0258     cgobjs.clear();
0259 
0260     // Make list of all factories and their callees
0261     auto stack = loop->GetJCallGraphRecorder()->GetCallGraph();
0262     if(stack.empty()) return;
0263     for(auto &cs : stack){
0264         string caller = MakeNametag(cs.caller_name, cs.caller_tag);
0265         string callee = MakeNametag(cs.callee_name, cs.callee_tag);
0266 
0267         if(caller == "<ignore>") continue;
0268         
0269         CGobj *caller_obj = cgobjs[caller];
0270         CGobj *callee_obj = cgobjs[callee];
0271         if( caller_obj==NULL ) caller_obj = cgobjs[caller] = new CGobj(caller);
0272         if( callee_obj==NULL ) callee_obj = cgobjs[callee] = new CGobj(callee);
0273         
0274         caller_obj->callees.insert(callee_obj);
0275     }
0276 
0277     // Continually loop, promoting all callers to be higher in rank than all
0278     // of their callees
0279     do{
0280         bool nothing_changed = true;
0281         // map<string, CGobj*>::iterator iter = cgobjs.begin();
0282 
0283         for(auto p : cgobjs){   
0284             CGobj *caller_obj = p.second;
0285             for(auto callee_obj : caller_obj->callees){
0286                 if(caller_obj == callee_obj) break; // in case we are listed as our own callee!
0287                 if( callee_obj->rank >= caller_obj->rank){
0288                     caller_obj->rank = callee_obj->rank + 1;
0289                     nothing_changed = false;
0290                 }
0291             }
0292         }
0293 
0294         if(nothing_changed) break;
0295     }while(true);
0296 
0297     // Determine overall rank properties (widths, heights, members)
0298     map<Int_t, CGrankprop > rankprops;
0299     map<string, CGobj*>::iterator iter;
0300     for(auto p : cgobjs){   
0301         CGobj *cgobj = p.second;
0302         CGrankprop &rankprop = rankprops[cgobj->rank];
0303         
0304         rankprop.cgobjs.push_back(cgobj);
0305         rankprop.totheight += cgobj->h;
0306         if((int32_t)cgobj->w > rankprop.totwidth) rankprop.totwidth = cgobj->w;
0307     }
0308     
0309     // Get minimum width and height of canvas needed to display everything
0310     Int_t totwidth  = 0; // left edge gap in pixels
0311     Int_t totheight = 0;
0312     Int_t Nx = rankprops.size(); // number of columns (ranks)
0313     Int_t Ny = 0; // number of rows in tallest rank
0314     map<Int_t, CGrankprop >::iterator itrp;
0315     for(itrp=rankprops.begin(); itrp!=rankprops.end(); itrp++){
0316     
0317         CGrankprop &rprop = itrp->second;
0318         totwidth += rprop.totwidth;
0319         Int_t height = rprop.totheight;
0320         if(totheight < height){
0321             totheight = height;
0322             Ny = rprop.cgobjs.size();
0323         }
0324     }
0325     Int_t xspace = 50; // minimum number of pixels between columns
0326     Int_t yspace = 10; // minimum number of pixels between rows
0327     Int_t minwidth  = totwidth  + (Nx+1)*xspace;
0328     Int_t minheight = totheight + (Ny+1)*yspace;
0329     
0330     // Get actual height and width of canvas so we can either make it
0331     // bigger or increase our spacing.
0332     // Note that I spent a LOT of time trying to get this to work right.
0333     // In the end, I never could. I'm going to have punt now and call it 
0334     // "somewhat usable".
0335     Int_t cwidth  = JVMF->fTab->GetWidth();
0336     Int_t cheight = JVMF->fTab->GetHeight();
0337     if( cwidth  < minwidth  ) cwidth  = minwidth;
0338     if( cheight < minheight ) cheight = minheight;
0339     
0340     // Loop over all ranks again, setting x and y spacing and
0341     // using them to calculate the box coordinates for each factory
0342     xspace = (cwidth - totwidth)/(Nx+1);
0343     Int_t xpos = xspace/2;
0344     for(itrp=rankprops.begin(); itrp!=rankprops.end(); itrp++){
0345     
0346         CGrankprop &rprop = itrp->second;
0347         yspace = (cheight - rprop.totheight)/(rprop.cgobjs.size()+1);
0348         Int_t ypos = yspace;
0349         for(uint32_t i=0; i<rprop.cgobjs.size(); i++){
0350             CGobj *cgobj = rprop.cgobjs[i];
0351             
0352             Int_t pad = 4;
0353             cgobj->x1 = xpos - pad;
0354             cgobj->x2 = xpos + cgobj->w + pad;
0355             cgobj->y1 = ypos - pad;
0356             cgobj->y2 = ypos + cgobj->h + pad;
0357             cgobj->ymid = (cgobj->y2 + cgobj->y1)/2;
0358             
0359             ypos += cgobj->h + yspace;
0360         }
0361 
0362         xpos += rprop.totwidth + xspace;
0363     }
0364     
0365     // Fill decendants and ancestors fields for all cgobjs. This will
0366     // allow us to draw the "primary path" i.e. links that would be a 
0367     // direct result of the specified nametag being called
0368     for(auto it=rankprops.rbegin(); it!=rankprops.rend(); it++){
0369         CGrankprop &rprop = it->second;
0370         for(auto cgobj : rprop.cgobjs){
0371             for(auto callee_obj : cgobj->callees){
0372                 callee_obj->ancestors.insert(cgobj);
0373                 callee_obj->ancestors.insert(cgobj->ancestors.begin(), cgobj->ancestors.end());
0374             }
0375         }
0376     }
0377     for(auto it : rankprops){
0378         CGrankprop &rprop = it.second;
0379         for(auto cgobj : rprop.cgobjs){
0380             cgobj->decendants.insert(cgobj->callees.begin(), cgobj->callees.end());
0381             for(auto callee_obj : cgobj->callees){
0382                 cgobj->decendants.insert(callee_obj->decendants.begin(), callee_obj->decendants.end());
0383             }
0384         }
0385     }
0386 
0387     // Clear canvas
0388     JVMF->canvas->SetWidth(  cwidth  );
0389     JVMF->canvas->SetHeight( cheight );
0390     c->SetCanvasSize( cwidth, cheight );
0391     c->SetMargin(0.0, 0.0, 0.0, 0.0);
0392     c->Clear();
0393     c->Update();
0394     
0395     // Draw links first
0396     for(iter=cgobjs.begin(); iter != cgobjs.end(); iter++){
0397         CGobj *cgobj1 = iter->second;
0398         double x1 = cgobj1->x1/(double)cwidth;
0399         double y1 = cgobj1->ymid/(double)cheight;
0400         for(auto cgobj2 : cgobj1->callees){ 
0401             double x2 = cgobj2->x2/(double)cwidth;
0402             double y2 = cgobj2->ymid/(double)cheight;
0403             
0404             bool is_ancestor   = cgobj1->ancestors.count(cgobjs[nametag]) || cgobj1->nametag==nametag;
0405             bool is_descendant = cgobj2->decendants.count(cgobjs[nametag]) || cgobj2->nametag==nametag;
0406             
0407             TLine *lin = new TLine(x1,y1,x2,y2);
0408             if(is_ancestor){
0409                 lin->SetLineColor(kGreen+2);
0410                 lin->SetLineWidth(4.0);
0411             }else if(is_descendant){
0412                 lin->SetLineColor(kBlue);
0413                 lin->SetLineWidth(4.0);
0414             }else{
0415                 lin->SetLineColor(kBlack);
0416                 lin->SetLineWidth(1.0);
0417             }
0418             lin->Draw();
0419         }
0420     }
0421 
0422     // Draw boxes with factory names
0423     TLatex latex;
0424     latex.SetTextSizePixels(20);
0425     latex.SetTextAlign(22);
0426     TBox *border = new TBox();
0427     for(iter=cgobjs.begin(); iter != cgobjs.end(); iter++){
0428         CGobj *cgobj = iter->second;
0429         if(!cgobj) continue; // NULL may be inserted above while looking for nametag
0430         double x1 = cgobj->x1/(double)cwidth;
0431         double x2 = cgobj->x2/(double)cwidth;
0432         double y1 = cgobj->y1/(double)cheight;
0433         double y2 = cgobj->y2/(double)cheight;
0434         double padx = 4.0/(double)cwidth;
0435         double pady = 4.0/(double)cheight;
0436 
0437         TBox *box = new TBox(x1, y1, x2, y2);
0438         latex.SetTextColor(kWhite);
0439         if(cgobj->nametag == nametag){
0440             latex.SetTextColor(kBlack);
0441             box->SetFillColor(TColor::GetColor( (Float_t)1.0, 0.3, 1.0));
0442             border->SetFillColor(kGreen+1);
0443             border->DrawBox(x1-padx, y1-pady, (x1+x2)/2.0, y2+pady);
0444             border->SetFillColor(kBlue);
0445             border->DrawBox((x1+x2)/2.0, y1-pady, x2+padx, y2+pady);
0446         }else if(cgobj->ancestors.count(cgobjs[nametag])){
0447             box->SetFillColor(kGreen+3);
0448             border->SetFillColor(kGreen);
0449             border->DrawBox(x1-padx, y1-pady, x2+padx, y2+pady);
0450         }else if(cgobj->decendants.count(cgobjs[nametag])){
0451             box->SetFillColor(kBlue);
0452             border->SetFillColor(kCyan);
0453             border->DrawBox(x1-padx, y1-pady, x2+padx, y2+pady);
0454         }else{
0455             box->SetFillColor(TColor::GetColor( (Float_t)0.4, 0.4, 0.4));
0456         }
0457         box->Draw();
0458         latex.DrawLatex((x1+x2)/2.0, (y1+y2)/2.0, cgobj->nametag.c_str());
0459     }
0460     
0461     TBox *box = new TBox(0.0, 0.0, 1.0, 1.0);
0462     box->SetFillStyle(0);
0463     box->SetLineWidth(4);
0464     box->SetLineColor(kRed);
0465     box->Draw();
0466 
0467     c->Update();
0468 
0469     // This is needed to force the scrollbars to redraw with the
0470     // proper parameters if the canvas size has changed (which
0471     // it almost always has!)
0472     JVMF->Redraw(JVMF->gcanvas);
0473 }
0474