Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Corryvreckan
Corryvreckan
Commits
9f72093a
Commit
9f72093a
authored
Oct 06, 2017
by
Simon Spannagel
Browse files
Implement dynamic library loading
parent
480a4b0f
Changes
2
Hide whitespace changes
Inline
Side-by-side
src/core/Analysis.C
View file @
9f72093a
// ROOT include files
#include
"TFile.h"
#include
<TSystem.h>
// Local include files
#include
"Analysis.h"
#include
"objects/Timepix3Track.h"
#include
"utils/log.h"
#include
<dlfcn.h>
#include
<fstream>
#define CORRYVRECKAN_ALGORITHM_PREFIX "libCorryvreckanAlgorithm"
#define CORRYVRECKAN_GENERATOR_FUNCTION "corryvreckan_module_generator"
using
namespace
corryvreckan
;
// Default constructor
...
...
@@ -72,6 +79,147 @@ void Analysis::add(Algorithm* algorithm){
m_algorithms
.
push_back
(
algorithm
);
}
void
Analysis
::
load
()
{
std
::
vector
<
Configuration
>
configs
=
conf_mgr_
->
getConfigurations
();
Configuration
global_config_
=
conf_mgr_
->
getGlobalConfiguration
();
// Create histogram output file
m_histogramFile
=
new
TFile
(
m_parameters
->
histogramFile
.
c_str
(),
"RECREATE"
);
m_directory
=
m_histogramFile
->
mkdir
(
"corryvreckan"
);
if
(
m_histogramFile
->
IsZombie
())
{
throw
RuntimeError
(
"Cannot create main ROOT file "
+
std
::
string
(
m_parameters
->
histogramFile
.
c_str
()));
}
// Loop through all non-global configurations
for
(
auto
&
config
:
configs
)
{
// Load library for each module. Libraries are named (by convention + CMAKE) libAllpixModule Name.suffix
std
::
string
lib_name
=
std
::
string
(
CORRYVRECKAN_ALGORITHM_PREFIX
).
append
(
config
.
getName
()).
append
(
SHARED_LIBRARY_SUFFIX
);
LOG_PROGRESS
(
STATUS
,
"LOAD_LOOP"
)
<<
"Loading algorithm "
<<
config
.
getName
();
void
*
lib
=
nullptr
;
bool
load_error
=
false
;
dlerror
();
if
(
loaded_libraries_
.
count
(
lib_name
)
==
0
)
{
// If library is not loaded then try to load it first from the config directories
if
(
global_config_
.
has
(
"library_directories"
))
{
std
::
vector
<
std
::
string
>
lib_paths
=
global_config_
.
getPathArray
(
"library_directories"
,
true
);
for
(
auto
&
lib_path
:
lib_paths
)
{
std
::
string
full_lib_path
=
lib_path
;
full_lib_path
+=
"/"
;
full_lib_path
+=
lib_name
;
// Check if the absolute file exists and try to load if it exists
std
::
ifstream
check_file
(
full_lib_path
);
if
(
check_file
.
good
())
{
lib
=
dlopen
(
full_lib_path
.
c_str
(),
RTLD_NOW
);
if
(
lib
!=
nullptr
)
{
LOG
(
DEBUG
)
<<
"Found library in configuration specified directory at "
<<
full_lib_path
;
}
else
{
load_error
=
true
;
}
break
;
}
}
}
// Otherwise try to load from the standard paths if not found already
if
(
!
load_error
&&
lib
==
nullptr
)
{
lib
=
dlopen
(
lib_name
.
c_str
(),
RTLD_NOW
);
if
(
lib
!=
nullptr
)
{
Dl_info
dl_info
;
dl_info
.
dli_fname
=
""
;
// workaround to get the location of the library
int
ret
=
dladdr
(
dlsym
(
lib
,
ALLPIX_UNIQUE_FUNCTION
),
&
dl_info
);
if
(
ret
!=
0
)
{
LOG
(
DEBUG
)
<<
"Found library during global search in runtime paths at "
<<
dl_info
.
dli_fname
;
}
else
{
LOG
(
WARNING
)
<<
"Found library during global search but could not deduce location, likely broken library"
;
}
}
else
{
load_error
=
true
;
}
}
}
else
{
// Otherwise just fetch it from the cache
lib
=
loaded_libraries_
[
lib_name
];
}
// If library did not load then throw exception
if
(
load_error
)
{
const
char
*
lib_error
=
dlerror
();
// Find the name of the loaded library if it exists
std
::
string
lib_error_str
=
lib_error
;
size_t
end_pos
=
lib_error_str
.
find
(
':'
);
std
::
string
problem_lib
;
if
(
end_pos
!=
std
::
string
::
npos
)
{
problem_lib
=
lib_error_str
.
substr
(
0
,
end_pos
);
}
// FIXME is checking the error in this way portable?
if
(
lib_error
!=
nullptr
&&
std
::
strstr
(
lib_error
,
"cannot allocate memory in static TLS block"
)
!=
nullptr
)
{
LOG
(
ERROR
)
<<
"Library could not be loaded: not enough thread local storage available"
<<
std
::
endl
<<
"Try one of below workarounds:"
<<
std
::
endl
<<
"- Rerun library with the environmental variable LD_PRELOAD='"
<<
problem_lib
<<
"'"
<<
std
::
endl
<<
"- Recompile the library "
<<
problem_lib
<<
" with tls-model=global-dynamic"
;
}
else
if
(
lib_error
!=
nullptr
&&
std
::
strstr
(
lib_error
,
"cannot open shared object file"
)
!=
nullptr
&&
problem_lib
.
find
(
ALLPIX_MODULE_PREFIX
)
==
std
::
string
::
npos
)
{
LOG
(
ERROR
)
<<
"Library could not be loaded: one of its dependencies is missing"
<<
std
::
endl
<<
"The name of the missing library is "
<<
problem_lib
<<
std
::
endl
<<
"Please make sure the library is properly initialized and try again"
;
}
else
{
LOG
(
ERROR
)
<<
"Library could not be loaded: it is not available"
<<
std
::
endl
<<
" - Did you enable the library during building? "
<<
std
::
endl
<<
" - Did you spell the library name correctly (case-sensitive)? "
;
if
(
lib_error
!=
nullptr
)
{
LOG
(
DEBUG
)
<<
"Detailed error: "
<<
lib_error
;
}
}
throw
corryvreckan
::
RuntimeError
(
"Error loading "
+
config
.
getName
());
}
// Remember that this library was loaded
loaded_libraries_
[
lib_name
]
=
lib
;
// Add the global internal parameters to the configuration
std
::
string
global_dir
=
gSystem
->
pwd
();
config
.
set
<
std
::
string
>
(
"_global_dir"
,
global_dir
);
// Create the algorithms from the library
m_algorithms
.
emplace_back
(
create_algorithm
(
loaded_libraries_
[
lib_name
],
config
,
m_clipboard
));
}
LOG_PROGRESS
(
STATUS
,
"LOAD_LOOP"
)
<<
"Loaded "
<<
configs
.
size
()
<<
" modules"
;
}
Algorithm
*
Analysis
::
create_algorithm
(
void
*
library
,
Configuration
config
,
Clipboard
*
clipboard
)
{
// Make the vector to return
std
::
string
algorithm_name
=
config
.
getName
();
// Get the generator function for this module
void
*
generator
=
dlsym
(
library
,
CORRYVRECKAN_GENERATOR_FUNCTION
);
// If the generator function was not found, throw an error
if
(
generator
==
nullptr
)
{
LOG
(
ERROR
)
<<
"Algorithm library is invalid or outdated: required interface function not found!"
;
throw
corryvreckan
::
RuntimeError
(
"Error instantiating algorithm from "
+
config
.
getName
());
}
// Convert to correct generator function
auto
algorithm_generator
=
reinterpret_cast
<
Algorithm
*
(
*
)(
std
::
string
,
Configuration
,
Clipboard
*
)
>
(
generator
);
// NOLINT
// Build algorithm
Algorithm
*
algorithm
=
algorithm_generator
(
config
.
getName
(),
config
,
clipboard
);
// Return the algorithm to the analysis
return
algorithm
;
}
// Run the analysis loop - this initialises, runs and finalises all algorithms
void
Analysis
::
run
(){
...
...
@@ -114,9 +262,6 @@ void Analysis::run(){
// Initalise all algorithms
void
Analysis
::
initialiseAll
(){
// Create histogram output file
m_histogramFile
=
new
TFile
(
m_parameters
->
histogramFile
.
c_str
(),
"RECREATE"
);
m_directory
=
m_histogramFile
->
mkdir
(
"corryvreckan"
);
int
nTracks
=
0
;
// Loop over all algorithms and initialise them
...
...
src/core/Analysis.h
View file @
9f72093a
...
...
@@ -33,7 +33,7 @@ public:
// Member functions
void
add
(
Algorithm
*
);
void
load
()
{}
;
void
load
();
void
run
();
void
timing
();
...
...
@@ -45,6 +45,7 @@ public:
TBrowser
*
browser
;
protected:
Algorithm
*
create_algorithm
(
void
*
library
,
corryvreckan
::
Configuration
config
,
Clipboard
*
clipboard
);
// Member variables
Parameters
*
m_parameters
;
...
...
@@ -53,6 +54,7 @@ protected:
vector
<
Algorithm
*>
m_algorithms
;
TFile
*
m_histogramFile
;
TDirectory
*
m_directory
;
std
::
map
<
std
::
string
,
void
*>
loaded_libraries_
;
int
m_events
;
};
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment