3 /**************************************************************************
4 * This file is property of and copyright by the ALICE HLT Project *
5 * ALICE Experiment at CERN, All rights reserved. *
7 * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no> *
8 * for The ALICE HLT Project. *
10 * Permission to use, copy, modify and distribute this software and its *
11 * documentation strictly for non-commercial purposes is hereby granted *
12 * without fee, provided that the above copyright notice appears in all *
13 * copies and that both the copyright notice and this permission notice *
14 * appear in the supporting documentation. The authors make no claims *
15 * about the suitability of this software for any purpose. It is *
16 * provided "as is" without express or implied warranty. *
17 **************************************************************************/
19 /** @file AliHLTSystem.cxx
20 @author Matthias Richter
22 @brief Implementation of HLT module management.
29 #include "AliHLTStdIncludes.h"
30 #include "AliHLTSystem.h"
31 #include "AliHLTComponentHandler.h"
32 #include "AliHLTComponent.h"
33 #include "AliHLTConfiguration.h"
34 #include "AliHLTConfigurationHandler.h"
35 #include "AliHLTTask.h"
36 #include "AliHLTModuleAgent.h"
37 #include "AliHLTOfflineInterface.h"
38 #include <TObjArray.h>
39 #include <TObjString.h>
40 #include <TStopwatch.h>
42 #include <TInterpreter.h>
44 /** HLT default component libraries */
45 const char* kHLTDefaultLibs[]= {
48 // "libAliHLTSample.so",
55 /** ROOT macro for the implementation of ROOT specific class methods */
56 ClassImp(AliHLTSystem)
58 AliHLTSystem::AliHLTSystem()
60 fpComponentHandler(new AliHLTComponentHandler()),
61 fpConfigurationHandler(new AliHLTConfigurationHandler()),
65 fStopwatches(new TObjArray),
69 // see header file for class documentation
71 // refer to README to build package
73 // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
75 if (fgNofInstances++>0)
76 HLTWarning("multiple instances of AliHLTSystem, you should not use more than one at a time");
78 SetGlobalLoggingLevel(kHLTLogDefault);
79 if (fpComponentHandler) {
80 AliHLTComponentEnvironment env;
81 memset(&env, 0, sizeof(AliHLTComponentEnvironment));
82 env.fAllocMemoryFunc=AliHLTSystem::AllocMemory;
83 env.fLoggingFunc=NULL;
84 AliHLTComponentLogSeverity loglevel=fpComponentHandler->GetLocalLoggingLevel();
85 fpComponentHandler->SetLocalLoggingLevel(kHLTLogError);
86 fpComponentHandler->SetEnvironment(&env);
87 fpComponentHandler->LoadLibrary("libAliHLTUtil.so");
88 fgAliLoggingFunc=(AliHLTLogging::AliHLTDynamicMessage)fpComponentHandler->FindSymbol("libAliHLTUtil.so", "AliDynamicMessage");
89 fpComponentHandler->SetLocalLoggingLevel(loglevel);
90 if (fgAliLoggingFunc==NULL) {
91 HLTError("symbol lookp failure: can not find AliDynamicMessage, switching to HLT logging system");
93 fpComponentHandler->AnnounceVersion();
95 HLTFatal("can not create Component Handler");
97 if (fpConfigurationHandler) {
98 AliHLTConfiguration::GlobalInit(fpConfigurationHandler);
100 HLTFatal("can not create Configuration Handler");
104 AliHLTSystem::~AliHLTSystem()
106 // see header file for class documentation
109 AliHLTConfiguration::GlobalDeinit(fpConfigurationHandler);
110 if (fpConfigurationHandler) {
111 delete fpConfigurationHandler;
113 fpConfigurationHandler=NULL;
115 if (fpComponentHandler) {
116 delete fpComponentHandler;
118 fpComponentHandler=NULL;
121 int AliHLTSystem::fgNofInstances=0;
123 int AliHLTSystem::AddConfiguration(AliHLTConfiguration* pConf)
125 // see header file for class documentation
134 int AliHLTSystem::InsertConfiguration(AliHLTConfiguration* pConf, AliHLTConfiguration* pPrec)
136 // see header file for class documentation
148 int AliHLTSystem::DeleteConfiguration(AliHLTConfiguration* pConf)
150 // see header file for class documentation
159 int AliHLTSystem::BuildTaskList(const char* id)
161 // see header file for class documentation
164 if (fpConfigurationHandler) {
165 AliHLTConfiguration* pConf=fpConfigurationHandler->FindConfiguration(id);
167 iResult=BuildTaskList(pConf);
169 HLTError("unknown configuration \"%s\"", id);
181 int AliHLTSystem::BuildTaskList(AliHLTConfiguration* pConf)
183 // see header file for class documentation
186 AliHLTTask* pTask=NULL;
187 if ((pTask=FindTask(pConf->GetName()))!=NULL) {
188 if (pTask->GetConf()!=pConf) {
189 HLTError("configuration missmatch, there is already a task with configuration name \"%s\", but it is different. Most likely configuration %p is not registered properly", pConf->GetName(), pConf);
192 // task for this configuration exists, terminate
194 } else if (pConf->SourcesResolved(1)!=1) {
195 HLTError("configuration \"%s\" has unresolved sources, aborting ...", pConf->GetName());
198 pTask=new AliHLTTask(pConf);
203 static int iterationLevel=0;
204 if (pTask && iResult>=0) {
205 // check for circular dependencies
206 if ((iResult=pConf->FollowDependency(pConf->GetName()))>0) {
207 HLTError("detected circular dependency for configuration \"%s\"", pTask->GetName());
208 pTask->PrintDependencyTree(pTask->GetName(), 1/*use the configuration list*/);
209 HLTError("aborted ...");
213 // check whether all dependencies are already in the task list
214 // create the missing ones
215 // this step is an iterative process which calls this function again for the missing
216 // configurations, in order to avoid the currently processed task to be created
217 // again it is added to the list temporarily and removed afterwards
218 // This is of high importance to preserve the order of the tasks. Furthermore, the
219 // InsertTask method has to be used in order to set all the cross links right
220 fTaskList.Add(pTask);
221 AliHLTConfiguration* pDep=pConf->GetFirstSource();
222 while (pDep!=NULL && iResult>=0) {
223 HLTDebug("iteration %d: checking dependency %s (%p)", iterationLevel, pDep->GetName(), pDep);
224 if (FindTask(pDep->GetName())==NULL) {
225 HLTDebug("iteration %d: building task list for configuration %s (%p)", iterationLevel, pDep->GetName(), pDep);
227 iResult=BuildTaskList(pDep);
230 pDep=pConf->GetNextSource();
232 // remove the temporarily added task
233 fTaskList.Remove(pTask);
235 // insert the task and set the cross-links
237 HLTDebug("iteration %d: inserting task %s (%p)", iterationLevel, pTask->GetName(), pTask);
238 iResult=InsertTask(pTask);
251 int AliHLTSystem::CleanTaskList()
253 // see header file for class documentation
256 while ((lnk=fTaskList.LastLink())!=NULL) {
257 delete (lnk->GetObject());
258 fTaskList.Remove(lnk);
263 int AliHLTSystem::InsertTask(AliHLTTask* pTask)
265 // see header file for class documentation
267 TObjLink *lnk = NULL;
268 if ((iResult=pTask->CheckDependencies())>0)
269 lnk=fTaskList.FirstLink();
270 while (lnk && iResult>0) {
271 AliHLTTask* pCurr = (AliHLTTask*)lnk->GetObject();
272 //HLTDebug("checking \"%s\"", pCurr->GetName());
273 iResult=pTask->Depends(pCurr);
275 iResult=pTask->SetDependency(pCurr);
276 pCurr->SetTarget(pTask);
277 HLTDebug("set dependency \"%s\" for configuration \"%s\"", pCurr->GetName(), pTask->GetName());
279 if (pCurr->Depends(pTask)) {
280 // circular dependency
281 HLTError("circular dependency: can not resolve dependencies for configuration \"%s\"", pTask->GetName());
283 } else if ((iResult=pTask->CheckDependencies())>0) {
289 fTaskList.AddAfter(lnk, pTask);
291 fTaskList.AddFirst(pTask);
293 HLTDebug("task \"%s\" (%p) inserted (size %d)", pTask->GetName(), pTask, sizeof(AliHLTTask));
294 } else if (iResult>0) {
295 HLTError("can not resolve dependencies for configuration \"%s\" (%d unresolved)", pTask->GetName(), iResult);
301 AliHLTTask* AliHLTSystem::FindTask(const char* id)
303 // see header file for class documentation
304 AliHLTTask* pTask=NULL;
306 pTask=(AliHLTTask*)fTaskList.FindObject(id);
311 void AliHLTSystem::PrintTaskList()
313 // see header file for class documentation
314 HLTLogKeyword("task list");
315 TObjLink *lnk = NULL;
316 HLTMessage("Task List");
317 lnk=fTaskList.FirstLink();
319 TObject* obj=lnk->GetObject();
321 HLTMessage(" %s - status:", obj->GetName());
322 AliHLTTask* pTask=(AliHLTTask*)obj;
323 pTask->PrintStatus();
330 int AliHLTSystem::Run(Int_t iNofEvents, int bStop)
332 // see header file for class documentation
335 SetStatusFlags(kRunning);
336 if (fEventCount>=0 || (iResult=InitTasks())>=0) {
337 if (fEventCount>=0 || (iResult=StartTasks())>=0) {
338 if (fEventCount==0) {
339 InitBenchmarking(fStopwatches);
341 //ResumeBenchmarking(fStopwatches);
343 for (int i=fEventCount; i<fEventCount+iNofEvents && iResult>=0; i++) {
344 if ((iResult=ProcessTasks(i))>=0) {
348 // TODO: define different running modes to either ignore errors in
349 // event processing or not
354 fEventCount+=iNofEvents;
355 if (bStop) StopTasks();
356 //else PauseBenchmarking(fStopwatches);
358 if (bStop) DeinitTasks();
362 } else if (iResult==-ENOENT) {
363 iResult=0; // do not propagate the error
365 ClearStatusFlags(kRunning);
369 int AliHLTSystem::InitTasks()
371 // see header file for class documentation
373 TObjLink *lnk=fTaskList.FirstLink();
376 HLTWarning("Task list is empty, aborting ...");
379 while (lnk && iResult>=0) {
380 TObject* obj=lnk->GetObject();
382 AliHLTTask* pTask=(AliHLTTask*)obj;
383 iResult=pTask->Init(NULL, fpComponentHandler);
389 HLTError("can not initialize task list, error %d", iResult);
395 int AliHLTSystem::InitBenchmarking(TObjArray* pStopwatches)
397 // see header file for class documentation
399 if (pStopwatches==NULL) return 0;
401 for (int i=0; i<(int)AliHLTComponent::kSWTypeCount; i++) {
402 TStopwatch* pStopwatch= new TStopwatch;
405 pStopwatches->AddAt(pStopwatch, i);
412 TObjLink *lnk=fTaskList.FirstLink();
413 while (lnk && iResult>=0) {
414 TObject* obj=lnk->GetObject();
416 AliHLTTask* pTask=(AliHLTTask*)obj;
417 AliHLTComponent* pComp=NULL;
418 if (iResult>=0 && (pComp=pTask->GetComponent())!=NULL) {
419 switch (pComp->GetComponentType()) {
420 case AliHLTComponent::kProcessor:
421 pComp->SetStopwatches(pStopwatches);
423 case AliHLTComponent::kSource:
425 // this switch determines whether the time consumption of the
426 // AliHLTComponent base methods should be counted to the input
427 // stopwatch or base stopwatch.
428 //int inputBase=(int)AliHLTComponent::kSWBase;
429 int inputBase=(int)AliHLTComponent::kSWInput;
430 pComp->SetStopwatch(pStopwatches->At(inputBase), AliHLTComponent::kSWBase);
431 pComp->SetStopwatch(pStopwatches->At((int)AliHLTComponent::kSWInput), AliHLTComponent::kSWDA);
434 case AliHLTComponent::kSink:
436 // this switch determines whether the time consumption of the
437 // AliHLTComponent base methods should be counted to the output
438 // stopwatch or base stopwatch.
439 //int outputBase=(int)AliHLTComponent::kSWBase;
440 int outputBase=(int)AliHLTComponent::kSWOutput;
441 pComp->SetStopwatch(pStopwatches->At(outputBase), AliHLTComponent::kSWBase);
442 pComp->SetStopwatch(pStopwatches->At((int)AliHLTComponent::kSWOutput), AliHLTComponent::kSWDA);
446 HLTWarning("unknown component type %d", (int)pComp->GetComponentType());
456 int AliHLTSystem::PrintBenchmarking(TObjArray* pStopwatches, int bClean)
458 // see header file for class documentation
460 if (pStopwatches==NULL) return 0;
462 for (int i=0; i<(int)AliHLTComponent::kSWTypeCount; i++) {
463 if (!dynamic_cast<TStopwatch*>(pStopwatches->At(i))) {
469 if (iInitialized!=0) {
470 HLTInfo("HLT statistics:\n"
471 " base: R:%.3fs C:%.3fs\n"
472 " input: R:%.3fs C:%.3fs\n"
473 " output: R:%.3fs C:%.3fs\n"
474 " event processing : R:%.3fs C:%.3fs"
475 , dynamic_cast<TStopwatch*>(pStopwatches->At(AliHLTComponent::kSWBase))->RealTime()
476 , dynamic_cast<TStopwatch*>(pStopwatches->At(AliHLTComponent::kSWBase))->CpuTime()
477 , dynamic_cast<TStopwatch*>(pStopwatches->At(AliHLTComponent::kSWInput))->RealTime()
478 , dynamic_cast<TStopwatch*>(pStopwatches->At(AliHLTComponent::kSWInput))->CpuTime()
479 , dynamic_cast<TStopwatch*>(pStopwatches->At(AliHLTComponent::kSWOutput))->RealTime()
480 , dynamic_cast<TStopwatch*>(pStopwatches->At(AliHLTComponent::kSWOutput))->CpuTime()
481 , dynamic_cast<TStopwatch*>(pStopwatches->At(AliHLTComponent::kSWDA))->RealTime()
482 , dynamic_cast<TStopwatch*>(pStopwatches->At(AliHLTComponent::kSWDA))->CpuTime()
487 for (int i=0; i<(int)AliHLTComponent::kSWTypeCount; i++) {
488 TObject* pObj=pStopwatches->RemoveAt(i);
489 if (pObj) delete pObj;
495 int AliHLTSystem::StartTasks()
497 // see header file for class documentation
499 TObjLink *lnk=fTaskList.FirstLink();
500 while (lnk && iResult>=0) {
501 TObject* obj=lnk->GetObject();
503 AliHLTTask* pTask=(AliHLTTask*)obj;
504 iResult=pTask->StartRun();
510 HLTError("can not start task list, error %d", iResult);
518 int AliHLTSystem::ProcessTasks(Int_t eventNo)
520 // see header file for class documentation
522 HLTDebug("processing event no %d", eventNo);
523 TObjLink *lnk=fTaskList.FirstLink();
524 while (lnk && iResult>=0) {
525 TObject* obj=lnk->GetObject();
527 AliHLTTask* pTask=(AliHLTTask*)obj;
528 iResult=pTask->ProcessTask(eventNo);
529 HLTDebug("task %s finnished (%d)", pTask->GetName(), iResult);
536 HLTInfo("Event %d successfully finished (%d)", eventNo, iResult);
539 HLTError("Processing of event %d failed (%d)", eventNo, iResult);
545 int AliHLTSystem::StopTasks()
547 // see header file for class documentation
549 TObjLink *lnk=fTaskList.FirstLink();
550 while (lnk && iResult>=0) {
551 TObject* obj=lnk->GetObject();
553 AliHLTTask* pTask=(AliHLTTask*)obj;
554 iResult=pTask->EndRun();
559 PrintBenchmarking(fStopwatches, 1 /*clean*/);
563 int AliHLTSystem::DeinitTasks()
565 // see header file for class documentation
567 TObjLink *lnk=fTaskList.FirstLink();
568 while (lnk && iResult>=0) {
569 TObject* obj=lnk->GetObject();
571 AliHLTTask* pTask=(AliHLTTask*)obj;
572 iResult=pTask->Deinit();
583 void* AliHLTSystem::AllocMemory( void* /*param*/, unsigned long size )
585 // see header file for class documentation
588 p=(void*)new char[size];
592 log.LoggingVarargs(kHLTLogError, "AliHLTSystem" , "AllocMemory" , __FILE__ , __LINE__ , "exeption during memory allocation" );
597 int AliHLTSystem::Reconstruct(int nofEvents, AliRunLoader* runLoader,
598 AliRawReader* rawReader)
600 // see header file for class documentation
602 if (runLoader || rawReader || nofEvents==0) {
603 if (nofEvents>0) {HLTInfo("Run Loader %p, Raw Reader %p , %d event(s)", runLoader, rawReader, nofEvents);}
604 if (CheckStatus(kReady)) {
606 // special case to close the reconstruction
610 if ((iResult=AliHLTOfflineInterface::SetParamsToComponents(runLoader, rawReader))>=0) {
611 // the system always remains started after event processing, a specific
612 // call with nofEvents==0 is neede to execute the stop sequence
613 iResult=Run(nofEvents, 0);
617 HLTError("wrong state %#x, required flags %#x", GetStatusFlags(), kReady);
620 HLTError("missing RunLoader (%p)/RawReader (%p) instance", runLoader, rawReader);
626 int AliHLTSystem::FillESD(int eventNo, AliRunLoader* runLoader, AliESDEvent* esd)
628 // see header file for class documentation
630 if (runLoader || esd) {
631 HLTInfo("Event %d: Run Loader %p, ESD %p", eventNo, runLoader, esd);
632 iResult=AliHLTOfflineInterface::FillComponentESDs(eventNo, runLoader, esd);
634 HLTError("missing run loader/ESD instance(s)");
640 int AliHLTSystem::LoadComponentLibraries(const char* libraries)
642 // see header file for class documentation
645 if (fpComponentHandler) {
646 TString libs(libraries);
647 TObjArray* pTokens=libs.Tokenize(" ");
649 int iEntries=pTokens->GetEntries();
650 for (int i=0; i<iEntries && iResult>=0; i++) {
651 iResult=fpComponentHandler->LoadLibrary((((TObjString*)pTokens->At(i))->GetString()).Data());
656 SetStatusFlags(kLibrariesLoaded);
658 // lets see if we need this, probably not
659 //fpComponentHandler->UnloadLibraries();
660 ClearStatusFlags(kLibrariesLoaded);
664 HLTFatal("no component handler available");
672 int AliHLTSystem::Configure(AliRunLoader* runloader)
674 // see header file for class documentation
675 Configure(NULL, runloader);
678 int AliHLTSystem::Configure(AliRawReader* rawReader, AliRunLoader* runloader)
680 // see header file for class documentation
682 if (CheckStatus(kRunning)) {
683 HLTError("HLT system in running state, can not configure");
686 ClearStatusFlags(kConfigurationLoaded|kTaskListCreated);
687 if (CheckFilter(kHLTLogDebug))
688 AliHLTModuleAgent::PrintStatus();
689 if (CheckStatus(kConfigurationLoaded)==0) {
690 iResult=LoadConfigurations(rawReader, runloader);
692 if (fChains.Length()==0) {
693 HLTError("custom configuration(s) specified, but no configuration to run in local reconstruction, use \'localrec=<conf>\' option");
698 SetStatusFlags(kConfigurationLoaded);
699 if (CheckFilter(kHLTLogDebug))
700 fpConfigurationHandler->PrintConfigurations();
701 iResult=BuildTaskListsFromTopConfigurations(rawReader, runloader);
703 SetStatusFlags(kTaskListCreated);
706 if (iResult<0) SetStatusFlags(kError);
711 int AliHLTSystem::ScanOptions(const char* options)
713 // see header file for class documentation
717 TString alloptions(options);
718 TObjArray* pTokens=alloptions.Tokenize(" ");
720 int iEntries=pTokens->GetEntries();
721 for (int i=0; i<iEntries; i++) {
722 TString token=(((TObjString*)pTokens->At(i))->GetString());
723 if (token.Contains("loglevel=")) {
724 TString param=token.ReplaceAll("loglevel=", "");
725 if (param.IsDigit()) {
726 SetGlobalLoggingLevel((AliHLTComponentLogSeverity)param.Atoi());
727 } else if (param.BeginsWith("0x") &&
728 param.Replace(0,2,"",0).IsHex()) {
730 sscanf(param.Data(),"%x", &severity);
731 SetGlobalLoggingLevel((AliHLTComponentLogSeverity)severity);
733 HLTWarning("wrong parameter for option \'loglevel=\', (hex) number expected");
735 } else if (token.Contains("alilog=off")) {
737 } else if (token.Contains("config=")) {
738 TString param=token.ReplaceAll("config=", "");
740 gROOT->Macro(param.Data(), &error);
742 SetStatusFlags(kConfigurationLoaded);
744 HLTError("can not execute macro \'%s\'", param.Data());
747 } else if (token.Contains("chains=")) {
748 TString param=token.ReplaceAll("chains=", "");
749 fChains=param.ReplaceAll(",", " ");
750 } else if (token.BeginsWith("lib") && token.EndsWith(".so")) {
754 HLTWarning("unknown option \'%s\'", token.Data());
762 const char** deflib=kHLTDefaultLibs;
768 if ((!CheckStatus(AliHLTSystem::kLibrariesLoaded)) &&
769 (LoadComponentLibraries(libs.Data())<0)) {
770 HLTError("error while loading HLT libraries");
778 int AliHLTSystem::Reset(int bForce)
780 // see header file for class documentation
782 if (!bForce && CheckStatus(kRunning)) {
783 HLTError("HLT system in running state, can not configure");
787 ClearStatusFlags(~kUninitialized);
791 int AliHLTSystem::LoadConfigurations(AliRawReader* rawReader, AliRunLoader* runloader)
793 // see header file for class documentation
794 if (CheckStatus(kRunning)) {
795 HLTError("HLT system in running state, can not configure");
799 AliHLTModuleAgent* pAgent=AliHLTModuleAgent::GetFirstAgent();
800 while (pAgent && iResult>=0) {
801 const char* deplibs=pAgent->GetRequiredComponentLibraries();
803 HLTDebug("load libraries \'%s\' for agent %s (%p)", deplibs, pAgent->GetName(), pAgent);
804 iResult=LoadComponentLibraries(deplibs);
807 HLTDebug("load configurations for agent %s (%p)", pAgent->GetName(), pAgent);
808 pAgent->CreateConfigurations(fpConfigurationHandler, rawReader, runloader);
809 pAgent=AliHLTModuleAgent::GetNextAgent();
815 int AliHLTSystem::BuildTaskListsFromTopConfigurations(AliRawReader* rawReader, AliRunLoader* runloader)
817 // see header file for class documentation
818 if (CheckStatus(kRunning)) {
819 HLTError("HLT system in running state, can not configure");
822 if (!CheckStatus(kConfigurationLoaded)) {
823 HLTWarning("configurations not yet loaded");
828 AliHLTModuleAgent* pAgent=AliHLTModuleAgent::GetFirstAgent();
829 while ((pAgent || fChains.Length()>0) && iResult>=0) {
831 if (fChains.Length()>0) {
833 HLTInfo("custom local reconstruction configurations: %s", tops.Data());
835 tops=pAgent->GetReconstructionChains(rawReader, runloader);
836 HLTInfo("local reconstruction configurations for agent %s (%p): %s", pAgent->GetName(), pAgent, tops.Data());
838 TObjArray* pTokens=tops.Tokenize(" ");
840 int iEntries=pTokens->GetEntries();
841 for (int i=0; i<iEntries && iResult>=0; i++) {
842 const char* pCID=((TObjString*)pTokens->At(i))->GetString().Data();
843 AliHLTConfiguration* pConf=fpConfigurationHandler->FindConfiguration(pCID);
845 iResult=BuildTaskList(pConf);
847 HLTWarning("can not find top configuration %s", pCID);
853 if (fChains.Length()>0) {
854 break; // ignore the agents
856 pAgent=AliHLTModuleAgent::GetNextAgent();
858 if (iResult>=0) SetStatusFlags(kTaskListCreated);
863 int AliHLTSystem::CheckStatus(int flag)
865 // see header file for class documentation
866 if (flag==kUninitialized && flag==fState) return 1;
867 if ((fState&flag)==flag) return 1;
871 int AliHLTSystem::GetStatusFlags()
873 // see header file for class documentation
877 int AliHLTSystem::SetStatusFlags(int flags)
879 // see header file for class documentation
884 int AliHLTSystem::ClearStatusFlags(int flags)
886 // see header file for class documentation
891 void* AliHLTSystem::FindDynamicSymbol(const char* library, const char* symbol)
893 // see header file for class documentation
894 if (fpComponentHandler==NULL) return NULL;
895 return fpComponentHandler->FindSymbol(library, symbol);