plugins_manager.cpp 12.4 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
#include <list>
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 44
//! 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;
}

45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
void get_library_dirs(std::list<std::string>& dirs)
{
	dirs.push_back("");

#ifndef _WIN32
	std::string obj_str ;
	const char *env_str = getenv("ALTA_LIB") ;

	if(env_str == NULL) {
		obj_str = "" ;
	} else {
		obj_str = std::string(env_str)+":" ;
	}

	while(true)	{
		int lb = obj_str.find_first_not_of(":",0) ;
		int le = obj_str.find_first_of(":",lb) ;

		if(lb < le)	{
			dirs.push_back(obj_str.substr(lb,le-lb)) ;
			obj_str = obj_str.substr(le+1,obj_str.size()) ;
		} else {
			break ;
		}
	}
#endif
}

73 74 75 76 77
//! \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)
{
78 79 80 81 82 83 84 85 86
	std::list<std::string> basename;
	get_library_dirs(basename);

	std::list<std::string>::iterator iter;
	for(iter = basename.begin(); iter != basename.end(); ++iter)
	{
	std::string libname = *iter;
	libname.append(library_name(filename));

87

pacanows's avatar
pacanows committed
88
#ifdef _WIN32
89
    HINSTANCE handle = LoadLibraryA(libname.c_str());
90 91 92 93 94 95 96
    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;
97
            continue;
98 99 100 101 102 103 104 105
        }
#ifdef DEBUG_CORE
        std::cout << "<<DEBUG>> will provide a " << function << " for library \"" << filename << "\"" << std::endl;
#endif
        return res;
    }
    else
    {
106
        std::cerr << "<<ERROR>> unable to load the dynamic library file \"" << libname << "\"" << std::endl;
107
        std::cerr << "          cause: \"" << GetLastError() << "\"" << std::endl;
108
        continue;
109
    }
110
#else
111
    void* handle = dlopen(libname.c_str(), RTLD_GLOBAL | RTLD_LAZY);
112

113
	 if(handle != NULL)
114 115 116
	 {
		 void (*res)();
		 *(void **)(&res) = dlsym(handle, function);
117 118 119

        if(dlerror() != NULL)
        {
120
            std::cerr << "<<ERROR>> unable to load the symbol \"" << function << "\" from " << libname << std::endl;
121
            continue;
122 123
        }
#ifdef DEBUG_CORE
124
        std::cout << "<<DEBUG>> will provide a " << function << " for library \"" << libname << "\"" << std::endl;
125 126 127 128 129
#endif
        return (T)res;
    }
    else
    {
130
        std::cerr << "<<ERROR>> unable to load the dynamic library file \"" << libname << "\"" << std::endl;
131
		  std::cerr << "          cause: \"" << dlerror() << "\"" << std::endl;
132
        continue;
133 134
    }
#endif
135 136
	}
return NULL;
137 138
}

139 140 141 142 143 144 145 146
//! \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 ;
147
		return NULL;
148 149
	}

150 151 152
	// Set the precision of the input
	file.precision(10);

153 154
	// Parameters of the function object
	int nX, nY;
155
	params::input param_in   = params::UNKNOWN_INPUT;
156
	params::output param_out = params::UNKNOWN_OUTPUT;
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
	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 ;
182 183 184 185 186 187 188 189 190 191 192 193 194
		}
		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);
195 196
		}
		else if(comment == std::string("CMD"))
197
      {
198 199 200 201 202 203 204 205
			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
206 207 208 209
    if(f->input_parametrization() == params::UNKNOWN_INPUT)
    {
        f->setParametrization(param_in);
    }
210
	f->setParametrization(param_out);
211 212

	// Load the function part from the file object
213
    f->load(file);
214 215 216 217

	return f;
}

218 219 220
//! 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)
221
{
222
    if(!args.is_defined("func"))
223 224 225 226 227 228 229
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> no function plugin specified, returning a rational function" << std::endl;
#endif
        return new rational_function();
    }

230 231
    // The function to be returned.
    function* func = NULL;
Laurent Belcour's avatar
Laurent Belcour committed
232

233
    if(args.is_vec("func"))
234
    {
235 236 237 238 239 240 241 242
        std::vector<std::string> args_vec = args.get_vec("func");

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

243
        //! create a <em>compound</em> class to store multiple
244
        //! functions in it.
245
		  compound_function* compound = new compound_function();
246

247 248 249 250 251 252
          //! 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]);
253 254 255
#ifdef DEBUG
              std::cout << "<<DEBUG>> load function with args: " << n << std::endl;
#endif
256 257 258 259 260 261 262 263
              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
              {
264
                  compound->push_back(dynamic_cast<nonlinear_function*>(f), temp_args);
265 266
              }
          }
267

268 269
		  //! return the compound class
		  func = compound;
270 271 272
    }
    else
    {
273
        const std::string filename = args["func"];
274 275 276 277 278
        FunctionPrototype myFunction = open_library<FunctionPrototype>(filename, "provide_function");
        if(myFunction != NULL)
        {
#ifdef DEBUG
            std::cout << "<<DEBUG>> using function provider in file \"" << filename << "\"" << std::endl;
279
#endif
280
            func =  myFunction();
281 282 283 284 285 286
        }
        else
        {
            std::cerr << "<<ERROR>> no function provider found in file \"" << filename << "\"" << std::endl;
            return new rational_function() ;
        }
287 288
    }

289 290 291
    // Treat the case of the Fresnel
    if(args.is_defined("fresnel"))
    {
292 293 294 295 296 297 298 299
		 // 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;
		 }
300

301
		 std::cout << "<<DEBUG>> multiplying by a Fresnel term" << std::endl;
302

303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
		 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);
			 }
		 }

324
		 nonlinear_function* func_fres = dynamic_cast<nonlinear_function*>(get_function(arguments::create_arguments(n)));
325 326 327 328 329 330 331 332 333
		 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;
		 }
334

335
	 }
336
/*
337 338 339 340 341 342 343
	 // 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
344
*/
345
    return func;
346
}
347
ptr<data> plugins_manager::get_data(const std::string& n)
348
{
349 350
    if(n.empty())
    {
351
#ifdef DEBUG
352
        std::cout << "<<DEBUG>> no data plugin specified, returning a vertial_segment loader" << std::endl;
353
#endif
354 355 356
        return new vertical_segment();
    }

357
	 DataPrototype myData = open_library<DataPrototype>(n, "provide_data");
358 359
    if(myData != NULL)
    {
360
#ifdef DEBUG
361 362 363 364 365 366 367 368 369
        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() ;
    }
370
}
371
ptr<fitter> plugins_manager::get_fitter(const std::string& n)
372
{
Laurent Belcour's avatar
Laurent Belcour committed
373 374 375 376 377
    if(n.empty())
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> no fitter plugin specified, returning null" << std::endl;
#endif
378
        return NULL;
Laurent Belcour's avatar
Laurent Belcour committed
379 380
    }

381
    FitterPrototype myFitter = open_library<FitterPrototype>(n, "provide_fitter");
Laurent Belcour's avatar
Laurent Belcour committed
382 383 384 385 386
    if(myFitter != NULL)
    {
#ifdef DEBUG
        std::cout << "<<DEBUG>> using function provider in file \"" << n << "\"" << std::endl;
#endif
387
        return myFitter();
Laurent Belcour's avatar
Laurent Belcour committed
388 389 390
    }
    else
    {
391
        std::cerr << "<<ERROR>> no fitter provider found in file \"" << n << "\"" << std::endl;
392
        return NULL ;
Laurent Belcour's avatar
Laurent Belcour committed
393
    }
394
}
395

396
void plugins_manager::check_compatibility(ptr<data>& d, const ptr<function>& f,
397
                                          const arguments& args)
Laurent Belcour's avatar
Laurent Belcour committed
398
{
399 400
	if(d->input_parametrization() == params::UNKNOWN_INPUT &&
		f->input_parametrization() == params::UNKNOWN_INPUT)
Laurent Belcour's avatar
Laurent Belcour committed
401
	{
402
		std::cout << "<<WARNING>> both function and data objects have no parametrization" << std::endl;
Laurent Belcour's avatar
Laurent Belcour committed
403 404 405
	}
	else
	{
406 407 408 409 410 411 412 413 414 415
		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());
		}
416
		else if(d->input_parametrization() != f->input_parametrization() && args.is_defined("change-param"))
417
		{
418
			std::cout << "<<INFO>> has to change the parametrization of the input data " << params::get_name(d->input_parametrization()) << std::endl;
419
            std::cout << "<<INFO>> to " << params::get_name(f->input_parametrization()) << std::endl;
420 421
			ptr<data_params> dd = new data_params(d, f->input_parametrization());
			d = dynamic_pointer_cast<data>(dd) ;
422 423 424 425 426
		}
		else
		{
			std::cout << "<<DEBUG>> no change was made to the parametrization" << std::endl;
		}
Laurent Belcour's avatar
Laurent Belcour committed
427 428 429 430
	}

	if(f->dimY() != d->dimY())
	{
Laurent Belcour's avatar
Laurent Belcour committed
431
        f->setDimY(d->dimY());
Laurent Belcour's avatar
Laurent Belcour committed
432 433 434 435 436 437 438 439 440 441 442
	}

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

444 445 446
// \todo implement the Darwin (MACOS) version.
#ifdef WIN32
#include <windows.h>
447
size_t plugins_manager::get_system_memory()
448 449 450 451 452 453
{
	MEMORYSTATUSEX status;
	status.dwLength = sizeof(status);
	GlobalMemoryStatusEx(&status);
	return status.ullTotalPhys;
}
454 455 456 457 458
#elif __APPLE__
size_t plugins_manager::get_system_memory()
{
	return 0;
}
459 460
#else
#include <unistd.h>
461
size_t plugins_manager::get_system_memory()
462 463 464 465 466 467
{
	long pages = sysconf(_SC_PHYS_PAGES);
	long page_size = sysconf(_SC_PAGE_SIZE);
	return pages * page_size;
}
#endif