plugins_manager.cpp 11.7 KB
Newer Older
1
#include "plugins_manager.h"
2 3
#include "rational_function.h"
#include "vertical_segment.h"
4

pacanows's avatar
pacanows committed
5
#ifdef _WIN32
6
    #include <windows.h>
7 8 9
#else
    #include <dlfcn.h>
#endif
10
#include <stdio.h>
11

12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
//! Add dynamic library extension (.so or .dll) to a dynamic object as well as
//! prepending 'lib' depending on the plateform.
std::string library_name(const std::string name) 
{
	std::string filename;

	const int n = name.length();
#if defined( _WIN32)
	if(name.substr(n-4, n) != std::string("dll")) {
		filename.append(name);
		filename.append(".dll");
	}
#elif defined(__APPLE__)
	if(name.substr(n-5, n) != std::string("dylib")) {
		filename.append("lib");
		filename.append(name);
		filename.append(".dylib");
	}
#else
	if(name.substr(n-2, n) != std::string("so")) {
		filename.append("lib");
		filename.append(name);
		filename.append(".so");
	}
#endif
	else {
		filename.append(name);
	}

	return filename;
}

44 45 46 47 48
//! \brief Open a dynamic library file (.so or .dll) and extract the associated
//! provide function. The template argument is used to cast the library to a
//! specific type.
template<typename T> T open_library(const std::string& filename, const char* function)
{
49 50
	std::string libname = library_name(filename);

pacanows's avatar
pacanows committed
51
#ifdef _WIN32
52
    HINSTANCE handle = LoadLibraryA(libname.c_str());
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
    if(handle != NULL)
    {
        T res = (T)GetProcAddress(handle, function);

        if(res == NULL)
        {
            std::cerr << "<<ERROR>> unable to load the symbol \"" << function << "\" from " << filename << std::endl;
            return NULL;
        }
#ifdef DEBUG_CORE
        std::cout << "<<DEBUG>> will provide a " << function << " for library \"" << filename << "\"" << std::endl;
#endif
        return res;
    }
    else
    {
69
        std::cerr << "<<ERROR>> unable to load the dynamic library file \"" << libname << "\"" << std::endl;
70 71 72
        std::cerr << "          cause: \"" << GetLastError() << "\"" << std::endl;
        return NULL;
    }
73
#else
74
    void* handle = dlopen(libname.c_str(), RTLD_GLOBAL | RTLD_LAZY);
75

76
	 if(handle != NULL)
77 78 79
	 {
		 void (*res)();
		 *(void **)(&res) = dlsym(handle, function);
80 81 82

        if(dlerror() != NULL)
        {
83
            std::cerr << "<<ERROR>> unable to load the symbol \"" << function << "\" from " << libname << std::endl;
84 85 86
            return NULL;
        }
#ifdef DEBUG_CORE
87
        std::cout << "<<DEBUG>> will provide a " << function << " for library \"" << libname << "\"" << std::endl;
88 89 90 91 92
#endif
        return (T)res;
    }
    else
    {
93
        std::cerr << "<<ERROR>> unable to load the dynamic library file \"" << libname << "\"" << std::endl;
94
		  std::cerr << "          cause: \"" << dlerror() << "\"" << std::endl;
95 96 97 98 99
        return NULL;
    }
#endif
}

100 101 102 103 104 105 106 107
//! \brief load a function from the ALTA input file.
function* plugins_manager::get_function(const std::string& filename)
{
	std::ifstream file;
	file.open(filename.c_str()) ;
	if(!file.is_open())
	{
		std::cerr << "<<ERROR>> unable to open file \"" << filename << "\"" << std::endl ;
108
		return NULL;
109 110
	}

111 112 113
	// Set the precision of the input
	file.precision(10);

114 115
	// Parameters of the function object
	int nX, nY;
116
	params::input param_in   = params::UNKNOWN_INPUT;
117
	params::output param_out = params::UNKNOWN_OUTPUT;
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
	arguments args;

	// Test for the first line of the file. Should be a ALTA FUNC HEADER
	std::string line ;
	std::getline(file, line) ;
	if(line != "#ALTA FUNC HEADER")
	{
		std::cerr << "<<ERROR>> this is not a function file" << std::endl;
	}

	// Parse the header for the function command line and the dimension
	// of the function
	while(line != "#ALTA HEADER END")
	{
		std::getline(file, line) ;
		std::stringstream linestream(line) ;

		linestream.ignore(1) ;

		std::string comment ;
		linestream >> comment ;

		if(comment == std::string("DIM"))
		{
			linestream >> nX >> nY ;
143 144 145 146 147 148 149 150 151 152 153 154 155
		}
		else if(comment == std::string("PARAM_IN"))
		{
			std::string name;
			linestream >> name;
			std::cout << "<<DEBUG>> parsed input parametrization: " << name << std::endl;
			param_in = params::parse_input(name);
		}
		else if(comment == std::string("PARAM_OUT"))
		{
			std::string name;
			linestream >> name;
			param_out = params::parse_output(name);
156 157
		}
		else if(comment == std::string("CMD"))
158
      {
159 160 161 162 163 164 165 166
			args = arguments::create_arguments(line.substr(4, std::string::npos));
		}
	}

	// Create the function from the command line
	function* f = get_function(args);
	f->setDimX(nX);
	f->setDimY(nY);
Laurent Belcour's avatar
Laurent Belcour committed
167 168 169 170
    if(f->input_parametrization() == params::UNKNOWN_INPUT)
    {
        f->setParametrization(param_in);
    }
171
	f->setParametrization(param_out);
172 173

	// Load the function part from the file object
174
    f->load(file);
175 176 177 178

	return f;
}

179 180 181
//! Get an instance of the function selected based on the name <em>n</em>.
//! Return NULL if no one exist.
function* plugins_manager::get_function(const arguments& args)
182
{
183
    if(!args.is_defined("func"))
184 185 186 187 188 189 190
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> no function plugin specified, returning a rational function" << std::endl;
#endif
        return new rational_function();
    }

191 192
    // The function to be returned.
    function* func = NULL;
Laurent Belcour's avatar
Laurent Belcour committed
193

194
    if(args.is_vec("func"))
195
    {
196 197 198 199 200 201 202 203
        std::vector<std::string> args_vec = args.get_vec("func");

        // Treating the case []
        if(args_vec.size() == 0)
        {
            return NULL;
        }

204
        //! create a <em>compound</em> class to store multiple
205
        //! functions in it.
206
		  compound_function* compound = new compound_function();
207

208 209 210 211 212 213
          //! For each args_vec element, create a function object and add
          //! it to the compound one.
          for(unsigned int i=0; i<args_vec.size(); ++i)
          {
              std::string n("--func ");
              n.append(args_vec[i]);
214 215 216
#ifdef DEBUG
              std::cout << "<<DEBUG>> load function with args: " << n << std::endl;
#endif
217 218 219 220 221 222 223 224
              arguments temp_args = arguments::create_arguments(n);
              function* f = get_function(temp_args);
              if(dynamic_cast<nonlinear_function*>(f) == NULL)
              {
                  std::cerr << "<<ERROR>> only non-linear function care compatible with a compound" << std::endl;
              }
              else
              {
225
                  compound->push_back(dynamic_cast<nonlinear_function*>(f), temp_args);
226 227
              }
          }
228

229 230
		  //! return the compound class
		  func = compound;
231 232 233
    }
    else
    {
234
        const std::string filename = args["func"];
235 236 237 238 239
        FunctionPrototype myFunction = open_library<FunctionPrototype>(filename, "provide_function");
        if(myFunction != NULL)
        {
#ifdef DEBUG
            std::cout << "<<DEBUG>> using function provider in file \"" << filename << "\"" << std::endl;
240
#endif
241
            func =  myFunction();
242 243 244 245 246 247
        }
        else
        {
            std::cerr << "<<ERROR>> no function provider found in file \"" << filename << "\"" << std::endl;
            return new rational_function() ;
        }
248 249
    }

250 251 252
    // Treat the case of the Fresnel
    if(args.is_defined("fresnel"))
    {
253 254 255 256 257 258 259 260
		 // Cast into a non linear function, only those are permitted to use
		 // a Fresnel term.
		 nonlinear_function* nl_func = dynamic_cast<nonlinear_function*>(func);
		 if(nl_func == NULL)
		 {
			 std::cerr << "<<ERROR>> only non-linear function are permitted to use Fresnel" << std::endl;
			 return func;
		 }
261

262
		 std::cout << "<<DEBUG>> multiplying by a Fresnel term" << std::endl;
263

264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
		 std::string n("--func ");
		 if(args.is_vec("fresnel"))
		 {
			 std::string temp = args["fresnel"];
			 n.append(temp.substr(1, temp.size()-2));
		 }
		 else
		 {
			 std::string fname = args["fresnel"];
			 if(fname.empty()) // Nothing to do except print error, no plugin defined
			 {
				 std::cerr << "<<ERROR>> Fresnel plugin not defined" << std::endl;
				 std::cerr << "<<ERROR>> using --fresnel alone is not permitted" << std::endl;
				 return func;
			 }
			 else // Case where the fresnel parameters is only the plugin filename
			 {
				 n.append(fname);
			 }
		 }

285
		 nonlinear_function* func_fres = dynamic_cast<nonlinear_function*>(get_function(arguments::create_arguments(n)));
286 287 288 289 290 291 292 293 294
		 if(func_fres != NULL)
		 {
			return new product_function(nl_func, func_fres);
		 }
		 else
		 {
			 std::cerr << "<<ERROR>> the right part of the product is not a nonlinear function. Will use only the left part." << std::endl;
			 return func;
		 }
295

296
	 }
297
/*
298 299 300 301 302 303 304
	 // Correction of the data by 1/cosine(theta_L)
	 if(args.is_defined("data-correct-cosine"))
	 {
		 nonlinear_function* cosine = new cosine_function();
		 func = new product_function(cosine, dynamic_cast<nonlinear_function*>(func));
	 }
	 // End of correction
305
*/
306
    return func;
307
}
308
ptr<data> plugins_manager::get_data(const std::string& n)
309
{
310 311
    if(n.empty())
    {
312
#ifdef DEBUG
313
        std::cout << "<<DEBUG>> no data plugin specified, returning a vertial_segment loader" << std::endl;
314
#endif
315 316 317
        return new vertical_segment();
    }

318
	 DataPrototype myData = open_library<DataPrototype>(n, "provide_data");
319 320
    if(myData != NULL)
    {
321
#ifdef DEBUG
322 323 324 325 326 327 328 329 330
        std::cout << "<<DEBUG>> using function provider in file \"" << n << "\"" << std::endl;
#endif
        return myData();
    }
    else
    {
        std::cerr << "<<ERROR>> no data provider found in file \"" << n << "\"" << std::endl;
        return new vertical_segment() ;
    }
331
}
332
ptr<fitter> plugins_manager::get_fitter(const std::string& n)
333
{
Laurent Belcour's avatar
Laurent Belcour committed
334 335 336 337 338
    if(n.empty())
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> no fitter plugin specified, returning null" << std::endl;
#endif
339
        return NULL;
Laurent Belcour's avatar
Laurent Belcour committed
340 341
    }

342
    FitterPrototype myFitter = open_library<FitterPrototype>(n, "provide_fitter");
Laurent Belcour's avatar
Laurent Belcour committed
343 344 345 346 347
    if(myFitter != NULL)
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> using function provider in file \"" << n << "\"" << std::endl;
#endif
348
        return myFitter();
Laurent Belcour's avatar
Laurent Belcour committed
349 350 351
    }
    else
    {
352
        std::cerr << "<<ERROR>> no fitter provider found in file \"" << n << "\"" << std::endl;
353
        return NULL ;
Laurent Belcour's avatar
Laurent Belcour committed
354
    }
355
}
356

357
void plugins_manager::check_compatibility(ptr<data>& d, const ptr<function>& f,
358
                                          const arguments& args)
Laurent Belcour's avatar
Laurent Belcour committed
359
{
360 361
	if(d->input_parametrization() == params::UNKNOWN_INPUT &&
		f->input_parametrization() == params::UNKNOWN_INPUT)
Laurent Belcour's avatar
Laurent Belcour committed
362
	{
363
		std::cout << "<<WARNING>> both function and data objects have no parametrization" << std::endl;
Laurent Belcour's avatar
Laurent Belcour committed
364 365 366
	}
	else
	{
367 368 369 370 371 372 373 374 375 376
		if(d->input_parametrization() == params::UNKNOWN_INPUT)
		{
			std::cout << "<<WARNING>> unknown parametrization for data" << std::endl;
		}

		if(f->input_parametrization() == params::UNKNOWN_INPUT)
		{
			std::cout << "<<DEBUG>> function will take the parametrization of the data" << std::endl;
			f->setParametrization(d->input_parametrization());
		}
377
		else if(d->input_parametrization() != f->input_parametrization() && args.is_defined("change-param"))
378
		{
379
			std::cout << "<<INFO>> has to change the parametrization of the input data " << params::get_name(d->input_parametrization()) << std::endl;
380
            std::cout << "<<INFO>> to " << params::get_name(f->input_parametrization()) << std::endl;
381 382
			ptr<data_params> dd = new data_params(d, f->input_parametrization());
			d = dynamic_pointer_cast<data>(dd) ;
383 384 385 386 387
		}
		else
		{
			std::cout << "<<DEBUG>> no change was made to the parametrization" << std::endl;
		}
Laurent Belcour's avatar
Laurent Belcour committed
388 389 390 391
	}

	if(f->dimY() != d->dimY())
	{
Laurent Belcour's avatar
Laurent Belcour committed
392
        f->setDimY(d->dimY());
Laurent Belcour's avatar
Laurent Belcour committed
393 394 395 396 397 398 399 400 401 402 403
	}

	/*
	// Check is the data has to be clusterized
	if(args.is_defined("cluster-dim"))
	{
	clustering* cluster = new clustering(d, args);
	d = cluster;
	}
	*/
}
404

405 406 407
// \todo implement the Darwin (MACOS) version.
#ifdef WIN32
#include <windows.h>
408
size_t plugins_manager::get_system_memory()
409 410 411 412 413 414
{
	MEMORYSTATUSEX status;
	status.dwLength = sizeof(status);
	GlobalMemoryStatusEx(&status);
	return status.ullTotalPhys;
}
415 416 417 418 419
#elif __APPLE__
size_t plugins_manager::get_system_memory()
{
	return 0;
}
420 421
#else
#include <unistd.h>
422
size_t plugins_manager::get_system_memory()
423 424 425 426 427 428
{
	long pages = sysconf(_SC_PHYS_PAGES);
	long page_size = sysconf(_SC_PAGE_SIZE);
	return pages * page_size;
}
#endif