1/*M///////////////////////////////////////////////////////////////////////////////////////
2//
3//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4//
5//  By downloading, copying, installing or using the software you agree to this license.
6//  If you do not agree to this license, do not download, install,
7//  copy or use the software.
8//
9//
10//                        Intel License Agreement
11//                For Open Source Computer Vision Library
12//
13// Copyright (C) 2000, Intel Corporation, all rights reserved.
14// Third party copyrights are property of their respective owners.
15//
16// Redistribution and use in source and binary forms, with or without modification,
17// are permitted provided that the following conditions are met:
18//
19//   * Redistribution's of source code must retain the above copyright notice,
20//     this list of conditions and the following disclaimer.
21//
22//   * Redistribution's in binary form must reproduce the above copyright notice,
23//     this list of conditions and the following disclaimer in the documentation
24//     and/or other materials provided with the distribution.
25//
26//   * The name of Intel Corporation may not be used to endorse or promote products
27//     derived from this software without specific prior written permission.
28//
29// This software is provided by the copyright holders and contributors "as is" and
30// any express or implied warranties, including, but not limited to, the implied
31// warranties of merchantability and fitness for a particular purpose are disclaimed.
32// In no event shall the Intel Corporation or contributors be liable for any direct,
33// indirect, incidental, special, exemplary, or consequential damages
34// (including, but not limited to, procurement of substitute goods or services;
35// loss of use, data, or profits; or business interruption) however caused
36// and on any theory of liability, whether in contract, strict liability,
37// or tort (including negligence or otherwise) arising in any way out of
38// the use of this software, even if advised of the possibility of such damage.
39//
40//M*/
41
42
43/****************************************************************************************/
44/*                         Dynamic detection and loading of IPP modules                 */
45/****************************************************************************************/
46
47#include "_cxcore.h"
48
49#if defined _MSC_VER && _MSC_VER >= 1200
50#pragma warning( disable: 4115 )        /* type definition in () */
51#endif
52
53#if defined _MSC_VER && defined WIN64 && !defined EM64T
54#pragma optimize( "", off )
55#endif
56
57#if defined WIN32 || defined WIN64
58#include <windows.h>
59#else
60#include <dlfcn.h>
61#include <sys/time.h>
62#endif
63
64#include <string.h>
65#include <stdio.h>
66#include <ctype.h>
67
68#define CV_PROC_GENERIC             0
69#define CV_PROC_SHIFT               10
70#define CV_PROC_ARCH_MASK           ((1 << CV_PROC_SHIFT) - 1)
71#define CV_PROC_IA32_GENERIC        1
72#define CV_PROC_IA32_WITH_MMX       (CV_PROC_IA32_GENERIC|(2 << CV_PROC_SHIFT))
73#define CV_PROC_IA32_WITH_SSE       (CV_PROC_IA32_GENERIC|(3 << CV_PROC_SHIFT))
74#define CV_PROC_IA32_WITH_SSE2      (CV_PROC_IA32_GENERIC|(4 << CV_PROC_SHIFT))
75#define CV_PROC_IA64                2
76#define CV_PROC_EM64T               3
77#define CV_GET_PROC_ARCH(model)     ((model) & CV_PROC_ARCH_MASK)
78
79typedef struct CvProcessorInfo
80{
81    int model;
82    int count;
83    double frequency; // clocks per microsecond
84}
85CvProcessorInfo;
86
87#undef MASM_INLINE_ASSEMBLY
88
89#if defined WIN32 && !defined  WIN64
90
91#if defined _MSC_VER
92#define MASM_INLINE_ASSEMBLY 1
93#elif defined __BORLANDC__
94
95#if __BORLANDC__ >= 0x560
96#define MASM_INLINE_ASSEMBLY 1
97#endif
98
99#endif
100
101#endif
102
103/*
104   determine processor type
105*/
106static void
107icvInitProcessorInfo( CvProcessorInfo* cpu_info )
108{
109    memset( cpu_info, 0, sizeof(*cpu_info) );
110    cpu_info->model = CV_PROC_GENERIC;
111
112#if defined WIN32 || defined WIN64
113
114#ifndef PROCESSOR_ARCHITECTURE_AMD64
115#define PROCESSOR_ARCHITECTURE_AMD64 9
116#endif
117
118#ifndef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
119#define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10
120#endif
121
122    SYSTEM_INFO sys;
123    LARGE_INTEGER freq;
124
125    GetSystemInfo( &sys );
126
127    if( sys.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL &&
128        sys.dwProcessorType == PROCESSOR_INTEL_PENTIUM && sys.wProcessorLevel >= 6 )
129    {
130        int version = 0, features = 0, family = 0;
131        int id = 0;
132        HKEY key = 0;
133
134        cpu_info->count = (int)sys.dwNumberOfProcessors;
135        unsigned long val = 0, sz = sizeof(val);
136
137        if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\SYSTEM\\CentralProcessor\\0\\",
138            0, KEY_QUERY_VALUE, &key ) >= 0 )
139        {
140            if( RegQueryValueEx( key, "~MHz", 0, 0, (uchar*)&val, &sz ) >= 0 )
141                cpu_info->frequency = (double)val;
142            RegCloseKey( key );
143        }
144
145#ifdef MASM_INLINE_ASSEMBLY
146        __asm
147        {
148            /* use CPUID to determine the features supported */
149            pushfd
150            mov   eax, 1
151            push  ebx
152            push  esi
153            push  edi
154#ifdef __BORLANDC__
155            db 0fh
156            db 0a2h
157#else
158            _emit 0x0f
159            _emit 0xa2
160#endif
161            pop   edi
162            pop   esi
163            pop   ebx
164            mov   version, eax
165            mov   features, edx
166            popfd
167        }
168#elif defined WIN32 && __GNUC__ > 2
169        asm volatile
170        (
171            "movl $1,%%eax\n\t"
172            ".byte 0x0f; .byte 0xa2\n\t"
173            "movl %%eax, %0\n\t"
174            "movl %%edx, %1\n\t"
175            : "=r"(version), "=r" (features)
176            :
177            : "%ebx", "%esi", "%edi"
178        );
179#else
180        {
181            static const char cpuid_code[] =
182                "\x53\x56\x57\xb8\x01\x00\x00\x00\x0f\xa2\x5f\x5e\x5b\xc3";
183            typedef int64 (CV_CDECL * func_ptr)(void);
184            func_ptr cpuid = (func_ptr)(void*)cpuid_code;
185            int64 cpuid_val = cpuid();
186            version = (int)cpuid_val;
187            features = (int)(cpuid_val >> 32);
188        }
189#endif
190
191        #define ICV_CPUID_M6     ((1<<15)|(1<<23))  /* cmov + MMX */
192        #define ICV_CPUID_A6     ((1<<25)|ICV_CPUID_M6) /* <all above> + SSE */
193        #define ICV_CPUID_W7     ((1<<26)|ICV_CPUID_A6) /* <all above> + SSE2 */
194
195        family = (version >> 8) & 15;
196        if( family >= 6 && (features & ICV_CPUID_M6) != 0 ) /* Pentium II or higher */
197            id = features & ICV_CPUID_W7;
198
199        cpu_info->model = id == ICV_CPUID_W7 ? CV_PROC_IA32_WITH_SSE2 :
200                          id == ICV_CPUID_A6 ? CV_PROC_IA32_WITH_SSE :
201                          id == ICV_CPUID_M6 ? CV_PROC_IA32_WITH_MMX :
202                          CV_PROC_IA32_GENERIC;
203    }
204    else
205    {
206#if defined EM64T
207        if( sys.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 )
208            cpu_info->model = CV_PROC_EM64T;
209#elif defined WIN64
210        if( sys.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 )
211            cpu_info->model = CV_PROC_IA64;
212#endif
213        if( QueryPerformanceFrequency( &freq ) )
214            cpu_info->frequency = (double)freq.QuadPart;
215    }
216#else
217    cpu_info->frequency = 1;
218
219#ifdef __x86_64__
220    cpu_info->model = CV_PROC_EM64T;
221#elif defined __ia64__
222    cpu_info->model = CV_PROC_IA64;
223#elif !defined __i386__
224    cpu_info->model = CV_PROC_GENERIC;
225#else
226    cpu_info->model = CV_PROC_IA32_GENERIC;
227
228    // reading /proc/cpuinfo file (proc file system must be supported)
229    FILE *file = fopen( "/proc/cpuinfo", "r" );
230
231    if( file )
232    {
233        char buffer[1024];
234        int max_size = sizeof(buffer)-1;
235
236        for(;;)
237        {
238            const char* ptr = fgets( buffer, max_size, file );
239            if( !ptr )
240                break;
241            if( strncmp( buffer, "flags", 5 ) == 0 )
242            {
243                if( strstr( buffer, "mmx" ) && strstr( buffer, "cmov" ))
244                {
245                    cpu_info->model = CV_PROC_IA32_WITH_MMX;
246                    if( strstr( buffer, "xmm" ) || strstr( buffer, "sse" ))
247                    {
248                        cpu_info->model = CV_PROC_IA32_WITH_SSE;
249                        if( strstr( buffer, "emm" ))
250                            cpu_info->model = CV_PROC_IA32_WITH_SSE2;
251                    }
252                }
253            }
254            else if( strncmp( buffer, "cpu MHz", 7 ) == 0 )
255            {
256                char* pos = strchr( buffer, ':' );
257                if( pos )
258                    cpu_info->frequency = strtod( pos + 1, &pos );
259            }
260        }
261
262        fclose( file );
263        if( CV_GET_PROC_ARCH(cpu_info->model) != CV_PROC_IA32_GENERIC )
264            cpu_info->frequency = 1;
265        else
266            assert( cpu_info->frequency > 1 );
267    }
268#endif
269#endif
270}
271
272
273CV_INLINE const CvProcessorInfo*
274icvGetProcessorInfo()
275{
276    static CvProcessorInfo cpu_info;
277    static int init_cpu_info = 0;
278    if( !init_cpu_info )
279    {
280        icvInitProcessorInfo( &cpu_info );
281        init_cpu_info = 1;
282    }
283    return &cpu_info;
284}
285
286
287/****************************************************************************************/
288/*                               Make functions descriptions                            */
289/****************************************************************************************/
290
291#undef IPCVAPI_EX
292#define IPCVAPI_EX(type,func_name,names,modules,arg) \
293    { (void**)&func_name##_p, (void*)(size_t)-1, names, modules, 0 },
294
295#undef IPCVAPI_C_EX
296#define IPCVAPI_C_EX(type,func_name,names,modules,arg) \
297    { (void**)&func_name##_p, (void*)(size_t)-1, names, modules, 0 },
298
299static CvPluginFuncInfo cxcore_ipp_tab[] =
300{
301#undef _CXCORE_IPP_H_
302#include "_cxipp.h"
303#undef _CXCORE_IPP_H_
304    {0, 0, 0, 0, 0}
305};
306
307
308/*
309   determine processor type, load appropriate dll and
310   initialize all function pointers
311*/
312#if defined WIN32 || defined WIN64
313#define DLL_PREFIX ""
314#define DLL_SUFFIX ".dll"
315#else
316#define DLL_PREFIX "lib"
317#define DLL_SUFFIX ".so"
318#define LoadLibrary(name) dlopen(name, RTLD_LAZY)
319#define FreeLibrary(name) dlclose(name)
320#define GetProcAddress dlsym
321typedef void* HMODULE;
322#endif
323
324#if 0 /*def _DEBUG*/
325#define DLL_DEBUG_FLAG "d"
326#else
327#define DLL_DEBUG_FLAG ""
328#endif
329
330#define VERBOSE_LOADING 0
331
332#if VERBOSE_LOADING
333#define ICV_PRINTF(args)  printf args; fflush(stdout)
334#else
335#define ICV_PRINTF(args)
336#endif
337
338typedef struct CvPluginInfo
339{
340    const char* basename;
341    HMODULE handle;
342    char name[100];
343}
344CvPluginInfo;
345
346static CvPluginInfo plugins[CV_PLUGIN_MAX];
347static CvModuleInfo cxcore_info = { 0, "cxcore", CV_VERSION, cxcore_ipp_tab };
348
349CvModuleInfo *CvModule::first = 0, *CvModule::last = 0;
350
351CvModule::CvModule( CvModuleInfo* _info )
352{
353    cvRegisterModule( _info );
354    info = last;
355}
356
357CvModule::~CvModule()
358{
359    if( info )
360    {
361        CvModuleInfo* p = first;
362        for( ; p != 0 && p->next != info; p = p->next )
363            ;
364        if( p )
365            p->next = info->next;
366        if( first == info )
367            first = info->next;
368        if( last == info )
369            last = p;
370        cvFree( &info );
371        info = 0;
372    }
373}
374
375static int
376icvUpdatePluginFuncTab( CvPluginFuncInfo* func_tab )
377{
378    int i, loaded_functions = 0;
379
380    // 1. reset pointers
381    for( i = 0; func_tab[i].func_addr != 0; i++ )
382    {
383        if( func_tab[i].default_func_addr == (void*)(size_t)-1 )
384            func_tab[i].default_func_addr = *func_tab[i].func_addr;
385        else
386            *func_tab[i].func_addr = func_tab[i].default_func_addr;
387        func_tab[i].loaded_from = 0;
388    }
389
390    // ippopencv substitutes all the other IPP modules
391    if( plugins[CV_PLUGIN_OPTCV].handle != 0 )
392    {
393        for( i = 2; i < CV_PLUGIN_MKL; i++ )
394        {
395            assert( plugins[i].handle == 0 );
396            plugins[i].handle = plugins[CV_PLUGIN_OPTCV].handle;
397        }
398    }
399
400    // 2. try to find corresponding functions in ipp* and reassign pointers to them
401    for( i = 0; func_tab[i].func_addr != 0; i++ )
402    {
403    #if defined _MSC_VER && _MSC_VER >= 1200
404        #pragma warning( disable: 4054 4055 ) /* converting pointers to code<->data */
405    #endif
406        char name[100];
407        int j = 0, idx = 0;
408
409        assert( func_tab[i].loaded_from == 0 );
410
411        if( func_tab[i].search_modules )
412        {
413            uchar* addr = 0;
414            const char* name_ptr = func_tab[i].func_names;
415
416            for( ; j < 10 && name_ptr; j++ )
417            {
418                const char* name_start = name_ptr;
419                const char* name_end;
420                while( !isalpha(name_start[0]) && name_start[0] != '\0' )
421                    name_start++;
422                if( !name_start[0] )
423                    name_start = 0;
424                name_end = name_start ? strchr( name_start, ',' ) : 0;
425                idx = (func_tab[i].search_modules / (1<<j*4)) % CV_PLUGIN_MAX;
426
427                if( plugins[idx].handle != 0 && name_start )
428                {
429                    if( name_end != 0 )
430                    {
431                        strncpy( name, name_start, name_end - name_start );
432                        name[name_end - name_start] = '\0';
433                    }
434                    else
435                        strcpy( name, name_start );
436
437                    addr = (uchar*)GetProcAddress( plugins[idx].handle, name );
438                    if( addr )
439                        break;
440                }
441                name_ptr = name_end;
442            }
443
444            if( addr )
445            {
446            /*#ifdef WIN32
447                while( *addr == 0xE9 )
448                    addr += 5 + *((int*)(addr + 1));
449            #endif*/
450                *func_tab[i].func_addr = addr;
451                func_tab[i].loaded_from = idx; // store index of the module
452                                                   // that contain the loaded function
453                loaded_functions++;
454                ICV_PRINTF(("%s: \t%s\n", name, plugins[idx].name ));
455            }
456
457            #if defined _MSC_VER && _MSC_VER >= 1200
458                #pragma warning( default: 4054 4055 )
459            #endif
460        }
461    }
462
463#if VERBOSE_LOADING
464    {
465    int not_loaded = 0;
466    ICV_PRINTF(("\nTotal loaded: %d\n\n", loaded_functions ));
467    printf( "***************************************************\nNot loaded ...\n\n" );
468    for( i = 0; func_tab[i].func_addr != 0; i++ )
469        if( !func_tab[i].loaded_from )
470        {
471            ICV_PRINTF(( "%s\n", func_tab[i].func_names ));
472            not_loaded++;
473        }
474
475    ICV_PRINTF(("\nTotal: %d\n", not_loaded ));
476    }
477#endif
478
479    if( plugins[CV_PLUGIN_OPTCV].handle != 0 )
480    {
481        for( i = 2; i < CV_PLUGIN_MKL; i++ )
482            plugins[i].handle = 0;
483    }
484
485    return loaded_functions;
486}
487
488
489CV_IMPL int
490cvRegisterModule( const CvModuleInfo* module )
491{
492    CvModuleInfo* module_copy = 0;
493
494    CV_FUNCNAME( "cvRegisterModule" );
495
496    __BEGIN__;
497
498    size_t name_len, version_len;
499
500    CV_ASSERT( module != 0 && module->name != 0 && module->version != 0 );
501
502    name_len = strlen(module->name);
503    version_len = strlen(module->version);
504
505    CV_CALL( module_copy = (CvModuleInfo*)cvAlloc( sizeof(*module_copy) +
506                                        name_len + 1 + version_len + 1 ));
507
508    *module_copy = *module;
509    module_copy->name = (char*)(module_copy + 1);
510    module_copy->version = (char*)(module_copy + 1) + name_len + 1;
511
512    memcpy( (void*)module_copy->name, module->name, name_len + 1 );
513    memcpy( (void*)module_copy->version, module->version, version_len + 1 );
514    module_copy->next = 0;
515
516    if( CvModule::first == 0 )
517        CvModule::first = module_copy;
518    else
519        CvModule::last->next = module_copy;
520    CvModule::last = module_copy;
521
522    if( CvModule::first == CvModule::last )
523    {
524        CV_CALL( cvUseOptimized(1));
525    }
526    else
527    {
528        CV_CALL( icvUpdatePluginFuncTab( module_copy->func_tab ));
529    }
530
531    __END__;
532
533    if( cvGetErrStatus() < 0 && module_copy )
534        cvFree( &module_copy );
535
536    return module_copy ? 0 : -1;
537}
538
539
540CV_IMPL int
541cvUseOptimized( int load_flag )
542{
543    int i, loaded_modules = 0, loaded_functions = 0;
544    CvModuleInfo* module;
545    const CvProcessorInfo* cpu_info = icvGetProcessorInfo();
546    int arch = CV_GET_PROC_ARCH(cpu_info->model);
547
548    // TODO: implement some more elegant way
549    // to find the latest and the greatest IPP/MKL libraries
550    static const char* opencv_sfx[] = { "100", "099", "097", 0 };
551    static const char* ipp_sfx_ia32[] = { "-6.1", "-6.0", "-5.3", "-5.2", "-5.1", "", 0 };
552    static const char* ipp_sfx_ia64[] = { "64-6.1", "64-6.0", "64-5.3", "64-5.2", "64-5.1", "64", 0 };
553    static const char* ipp_sfx_em64t[] = { "em64t-6.1", "em64t-6.0", "em64t-5.3", "em64t-5.2", "em64t-5.1", "em64t", 0 };
554    static const char* mkl_sfx_ia32[] = { "p4", "p3", "def", 0 };
555    static const char* mkl_sfx_ia64[] = { "i2p", "itp", 0 };
556    static const char* mkl_sfx_em64t[] = { "def", 0 };
557    const char** ipp_suffix = arch == CV_PROC_IA64 ? ipp_sfx_ia64 :
558                              arch == CV_PROC_EM64T ? ipp_sfx_em64t : ipp_sfx_ia32;
559    const char** mkl_suffix = arch == CV_PROC_IA64 ? mkl_sfx_ia64 :
560                              arch == CV_PROC_EM64T ? mkl_sfx_em64t : mkl_sfx_ia32;
561
562    for( i = 0; i < CV_PLUGIN_MAX; i++ )
563        plugins[i].basename = 0;
564    plugins[CV_PLUGIN_NONE].basename = 0;
565    plugins[CV_PLUGIN_NONE].name[0] = '\0';
566    plugins[CV_PLUGIN_OPTCV].basename = "ippopencv";
567    plugins[CV_PLUGIN_IPPCV].basename = "ippcv";
568    plugins[CV_PLUGIN_IPPI].basename = "ippi";
569    plugins[CV_PLUGIN_IPPS].basename = "ipps";
570    plugins[CV_PLUGIN_IPPVM].basename = "ippvm";
571    plugins[CV_PLUGIN_IPPCC].basename = "ippcc";
572    plugins[CV_PLUGIN_MKL].basename = "mkl_";
573
574    // try to load optimized dlls
575    for( i = 1; i < CV_PLUGIN_MAX; i++ )
576    {
577        // unload previously loaded optimized modules
578        if( plugins[i].handle )
579        {
580            FreeLibrary( plugins[i].handle );
581            plugins[i].handle = 0;
582        }
583
584        // do not load regular IPP modules if the custom merged IPP module is already found.
585        if( i < CV_PLUGIN_MKL && load_flag && plugins[CV_PLUGIN_OPTCV].handle != 0 )
586            continue;
587
588        if( load_flag && plugins[i].basename &&
589            (arch == CV_PROC_IA32_GENERIC || arch == CV_PROC_IA64 || arch == CV_PROC_EM64T) )
590        {
591            const char** suffix = i == CV_PLUGIN_OPTCV ? opencv_sfx :
592                            i < CV_PLUGIN_MKL ? ipp_suffix : mkl_suffix;
593            if( suffix == mkl_sfx_ia32 )
594            {
595                if( !(cpu_info->model & CV_PROC_IA32_WITH_SSE2) )
596                    suffix++;
597                if( !(cpu_info->model & CV_PROC_IA32_WITH_SSE) )
598                    suffix++;
599            }
600
601            for( ; *suffix != 0; suffix++ )
602            {
603                sprintf( plugins[i].name, DLL_PREFIX "%s%s" DLL_DEBUG_FLAG DLL_SUFFIX,
604                    plugins[i].basename, *suffix );
605
606                ICV_PRINTF(("loading %s...\n", plugins[i].name ));
607                plugins[i].handle = LoadLibrary( plugins[i].name );
608                if( plugins[i].handle != 0 )
609                {
610                    ICV_PRINTF(("%s loaded\n", plugins[i].name ));
611                    loaded_modules++;
612                    break;
613                }
614                #ifndef WIN32
615                // temporary workaround for MacOSX
616                sprintf( plugins[i].name, DLL_PREFIX "%s%s" DLL_DEBUG_FLAG ".dylib",
617                    plugins[i].basename, *suffix );
618
619                ICV_PRINTF(("loading %s...\n", plugins[i].name ));
620                plugins[i].handle = LoadLibrary( plugins[i].name );
621                if( plugins[i].handle != 0 )
622                {
623                    ICV_PRINTF(("%s loaded\n", plugins[i].name ));
624                    loaded_modules++;
625                    break;
626                }
627                #endif
628            }
629        }
630    }
631
632    for( module = CvModule::first; module != 0; module = module->next )
633        loaded_functions += icvUpdatePluginFuncTab( module->func_tab );
634
635    return loaded_functions;
636}
637
638CvModule cxcore_module( &cxcore_info );
639
640CV_IMPL void
641cvGetModuleInfo( const char* name, const char **version, const char **plugin_list )
642{
643    static char joint_verinfo[1024] = "";
644    static char plugin_list_buf[1024] = "";
645
646    CV_FUNCNAME( "cvGetLibraryInfo" );
647
648    if( version )
649        *version = 0;
650
651    if( plugin_list )
652        *plugin_list = 0;
653
654    __BEGIN__;
655
656    CvModuleInfo* module;
657
658    if( version )
659    {
660        if( name )
661        {
662            size_t i, name_len = strlen(name);
663
664            for( module = CvModule::first; module != 0; module = module->next )
665            {
666                if( strlen(module->name) == name_len )
667                {
668                    for( i = 0; i < name_len; i++ )
669                    {
670                        int c0 = toupper(module->name[i]), c1 = toupper(name[i]);
671                        if( c0 != c1 )
672                            break;
673                    }
674                    if( i == name_len )
675                        break;
676                }
677            }
678            if( !module )
679                CV_ERROR( CV_StsObjectNotFound, "The module is not found" );
680
681            *version = module->version;
682        }
683        else
684        {
685            char* ptr = joint_verinfo;
686
687            for( module = CvModule::first; module != 0; module = module->next )
688            {
689                sprintf( ptr, "%s: %s%s", module->name, module->version, module->next ? ", " : "" );
690                ptr += strlen(ptr);
691            }
692
693            *version = joint_verinfo;
694        }
695    }
696
697    if( plugin_list )
698    {
699        char* ptr = plugin_list_buf;
700        int i;
701
702        for( i = 0; i < CV_PLUGIN_MAX; i++ )
703            if( plugins[i].handle != 0 )
704            {
705                sprintf( ptr, "%s, ", plugins[i].name );
706                ptr += strlen(ptr);
707            }
708
709        if( ptr > plugin_list_buf )
710        {
711            ptr[-2] = '\0';
712            *plugin_list = plugin_list_buf;
713        }
714        else
715            *plugin_list = "";
716    }
717
718    __END__;
719}
720
721
722typedef int64 (CV_CDECL * rdtsc_func)(void);
723
724/* helper functions for RNG initialization and accurate time measurement */
725CV_IMPL  int64  cvGetTickCount( void )
726{
727    const CvProcessorInfo* cpu_info = icvGetProcessorInfo();
728
729    if( cpu_info->frequency > 1 &&
730        CV_GET_PROC_ARCH(cpu_info->model) == CV_PROC_IA32_GENERIC )
731    {
732#ifdef MASM_INLINE_ASSEMBLY
733    #ifdef __BORLANDC__
734        __asm db 0fh
735        __asm db 31h
736    #else
737        __asm _emit 0x0f;
738        __asm _emit 0x31;
739    #endif
740#elif (defined __GNUC__ || defined CV_ICC) && defined __i386__
741        int64 t;
742        asm volatile (".byte 0xf; .byte 0x31" /* "rdtsc" */ : "=A" (t));
743        return t;
744#else
745        static const char code[] = "\x0f\x31\xc3";
746        rdtsc_func func = (rdtsc_func)(void*)code;
747        return func();
748#endif
749    }
750    else
751    {
752#if defined WIN32 || defined WIN64
753        LARGE_INTEGER counter;
754        QueryPerformanceCounter( &counter );
755        return (int64)counter.QuadPart;
756#else
757        struct timeval tv;
758        struct timezone tz;
759        gettimeofday( &tv, &tz );
760        return (int64)tv.tv_sec*1000000 + tv.tv_usec;
761#endif
762    }
763}
764
765CV_IMPL  double  cvGetTickFrequency()
766{
767    return icvGetProcessorInfo()->frequency;
768}
769
770
771static int icvNumThreads = 0;
772static int icvNumProcs = 0;
773
774CV_IMPL int cvGetNumThreads(void)
775{
776    if( !icvNumProcs )
777        cvSetNumThreads(0);
778    return icvNumThreads;
779}
780
781CV_IMPL void cvSetNumThreads( int threads )
782{
783    if( !icvNumProcs )
784    {
785#ifdef _OPENMP
786        icvNumProcs = omp_get_num_procs();
787        icvNumProcs = MIN( icvNumProcs, CV_MAX_THREADS );
788#else
789        icvNumProcs = 1;
790#endif
791    }
792
793#ifdef _OPENMP
794    if( threads <= 0 )
795        threads = icvNumProcs;
796    //else
797    //    threads = MIN( threads, icvNumProcs );
798
799    icvNumThreads = threads;
800#else
801    icvNumThreads = 1;
802#endif
803}
804
805
806CV_IMPL int cvGetThreadNum(void)
807{
808#ifdef _OPENMP
809    return omp_get_thread_num();
810#else
811    return 0;
812#endif
813}
814
815
816/* End of file. */
817