You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
exercise_2/3rdparty/colmap-dev/lib/VLFeat/generic.c

1680 lines
55 KiB

/** @file generic.c
** @brief Generic - Definition
** @author Andrea Vedaldi
**/
/*
Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson.
Copyright (C) 2013 Andrea Vedaldi.
All rights reserved.
This file is part of the VLFeat library and is made available under
the terms of the BSD license (see the COPYING file).
*/
/**
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@mainpage Vision Lab Features Library (VLFeat)
@version __VLFEAT_VERSION__
@author The VLFeat Team
@par Copyright &copy; 2012-14 The VLFeat Authors
@par Copyright &copy; 2007-11 Andrea Vedaldi and Brian Fulkerson
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
The VLFeat C library implements common computer
vision algorithms, with a special focus on visual features, as used
in state-of-the-art object recognition and image
matching applications.
VLFeat strives to be clutter-free, simple, portable, and well documented.
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@section main-contents Contents
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
- **Visual feature detectors and descriptors**
- @subpage sift
- @subpage dsift
- @subpage mser
- @subpage covdet
- @subpage scalespace
- @subpage hog
- @subpage fisher
- @subpage vlad
- @subpage liop
- @subpage lbp
- **Clustering and indexing**
- @subpage kmeans
- @subpage ikmeans.h "Integer K-means (IKM)"
- @subpage hikmeans.h "Hierarchical Integer K-means (HIKM)"
- @subpage gmm
- @subpage aib
- @subpage kdtree
- **Segmentation**
- @subpage slic
- @subpage quickshift
- **Statistical methods**
- @subpage aib
- @subpage homkermap
- @subpage svm
- **Utilities**
- @subpage random
- @subpage mathop
- @subpage stringop.h "String operations"
- @subpage imopv.h "Image operations"
- @subpage pgm.h "PGM image format"
- @subpage heap-def.h "Generic heap object (priority queue)"
- @subpage rodrigues.h "Rodrigues formula"
- @subpage mexutils.h "MATLAB MEX helper functions"
- @subpage getopt_long.h "Drop-in @c getopt_long replacement"
- **General information**
- @subpage conventions
- @subpage generic
- @subpage portability
- @ref resources
- @subpage objects
- @ref threads
- @subpage matlab
- @subpage metaprogram
- @subpage dev
- @subpage glossary
**/
/**
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@page resources Memory and resource handling
@author Andrea Vedaldi
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
Some VLFeat functions return pointers to memory blocks or
objects. Only ::vl_malloc, ::vl_calloc, ::vl_realloc and functions
whose name contains either the keywords @c new or @c copy transfer the
ownership of the memory block or object to the caller. The caller must
dispose explicitly of all the resources it owns (by calling ::vl_free
for a memory block, or the appropriate deletion function for an
object).
The memory allocation functions can be customized by
::vl_set_alloc_func (which sets the implementations of ::vl_malloc,
::vl_realloc, ::vl_calloc and ::vl_free). Remapping the memory
allocation functions can be done only if there are no currently
allocated VLFeat memory blocks or objects -- thus typically at the
very beginning of a program. The memory allocation functions are a
global property, shared by all threads.
VLFeat uses three rules that simplify handling exceptions when used in
combination which certain environment such as MATLAB.
- The library allocates local memory only through the re-programmable
::vl_malloc, ::vl_calloc, and ::vl_realloc functions.
- The only resource referenced by VLFeat objects is memory (for
instance, it is illegal for an object to reference an open file).
Other resources such as files or threads may be allocated within a
VLFeat function call, but they are all released before the function
ends, or their ownership is directly transferred to the caller.
- The global library state is an exception. It cannot reference any
local object created by the caller and uses the standard C memory
allocation functions.
In this way, the VLFeat local state can be reset at any time simply by
disposing of all the memory allocated by the library so far. The
latter can be done easily by mapping the memory allocation functions
to implementations that track the memory blocks allocated, and then
disposing of all such blocks. Since the global state does not
reference any local object nor uses the remapped memory functions, it
is unaffected by such an operation; conversely, since no VLFeat object
references anything but memory, this guarantees that all allocated
resources are properly disposed (avoiding leaking resource). This is
used extensively in the design of MATLAB MEX files (see @ref
matlab).
**/
/**
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@page conventions Conventions
@author Andrea Vedaldi
@tableofcontents
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
This page summarizes some of the conventions used by the library.
@section conventions-storage Matrix and image storage conventions
If not otherwise specified, matrices in VLFeat are stored in memory in
<em>column major</em> order. Given a matrix $[A_{ij}] \in \real^{m
\times n}$, this amounts of enumerating the elements one column per
time: $A_{11}, A_{21}, \dots, A_{m1}, A_{12}, \dots, A_{mn}$. This
convention is compatible with Fortran, MATLAB, and popular numerical
libraries.
Matrices are often used in the library to pack a number data vectors
$\bx_1,\dots,\bx_n \in \real^m$ of equal dimension together. These are
normally stored as the columns of the matrix:
\[
X = \begin{bmatrix} \bx_1, \dots, \bx_n \end{bmatrix},
\qquad
X \in \real_{m\times n}
\]
In this manner, consecutive elements of each data vector $\bx_i$ is
stored in consecutive memory locations, improving memory access
locality in most algorithms.
Images $I(x,y)$ are stored instead in <em>row-major</em> order,
i.e. one row after the other. Note that an image can be naturally
identified as a matrix $I_{yx}$, where the vertical coordinate $y$
indexes the rows and the horizontal coordinate $x$ the columns. The
image convention amounts to storing this matrix in row-major rather
than column-major order, which is in conflict with the rule given
above. The reason for this choice is that most image processing and
graphical libraries assume this convention; it is, however,
<em>not</em> the same as MATLAB's.
**/
/**
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@page objects Objects
@author Andrea Vedaldi
@tableofcontents
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
Many VLFeat algorithms are available in the form of *objects*. The C
language, used by VLFeat, does not support objects explicitly. Here an
object is intended a C structure along with a number of functions (the
object member functions or methods) operating on it. Ideally, the
object data structure is kept opaque to the user, for example by
defining it in the @c .c implementation files which are not accessible
to the library user.
Object names are capitalized and start with the <code>Vl</code> prefix
(for example @c VlExampleObject). Object methods are lowercase and
start with the <code>vl_<object_name>_</code> suffix
(e.g. @c vl_example_object_new).
<!-- ------------------------------------------------------------ -->
@section objects-lifecycle Object lifecycle
<!-- ------------------------------------------------------------ -->
Conceptually, an object undergoes four phases during its lifecycle:
allocation, initialization, finalization, and deallocation:
- **Allocation.** The memory to hold the object structure is allocated.
This is usually done by calling a memory allocation function such as
::vl_calloc to reserve an object of the required size @c
sizeof(VlExampleObject). Alternatively, the object can simply by
allocated on the stack by declaring a local variable of type
VlExampleObject.
- **Initialization.** The object is initialized by assigning a value to
its data members and potentially allocating a number of resources,
including other objects or memory buffers. Initialization is
done by methods containing the @c init keyword, e.g. @c
vl_example_object_init. Several such methods may be provided.
- **Finalization.** Initialization is undone by finalization, whose main
purpose is to release any resource allocated and still owned by the
object. Finalization is done by the @c vl_example_object_finalize
method.
- **Deallocation.** The memory holding the object structure is
disposed of, for example by calling ::vl_free or automatically when
the corresponding local variable is popped from the stack.
In practice, most VlFeat object are supposed to be created on the
heap. To this end, allocation/initialization and
finalization/deallocation are combined into two operations:
- **Creating a new object.** This allocates a new object on the heap
and initializes it, combining allocation and initialization in a
single operation. It is done by methods containing the @c new keyword,
e.g. @c vl_example_object_new.
- **Deleting an object.** This disposes of an object created by a @c
new method, combining finalization and deallocation, for example
@c vl_example_object_delete.
<!-- ------------------------------------------------------------ -->
@section objects-getters-setters Getters and setters
<!-- ------------------------------------------------------------ -->
Most objects contain a number of methods to get (getters) and set
(setters) properties. These should contain the @c get and @c set
keywords in their name, for example
@code
double x = vl_example_object_get_property () ;
vl_example_object_set_property(x) ;
@endcode
**/
/**
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@page matlab MATLAB integration
@author Andrea Vedaldi
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
The VLFeat C library is designed to integrate seamlessly with MATLAB.
Binary compatibility is simplified by the use of the C language
(rather than C++). In addition, the library design follows certain
restrictions that make it compatible with the MATLAB MEX interface.
The main issue in calling a library function from a MATLAB MEX
function is that MATLAB can abort the execution of the MEX function
at any point, either due to an error, or directly upon a user request
(Ctrl-C) (empirically, however, a MEX function seems to be
incorruptible only during the invocation of certain functions of the
MEX API such as @c mexErrMsgTxt).
When a MEX function is interrupted, resources (memory blocks or
objects) whose ownership was transferred from VLFeat to the MEX
function may be leaked. Notice that interrupting a MEX function would
similarly leak any memory block allocated within the MEX function. To
solve this issue, MATLAB provides his own memory manager (@c
mxMalloc, @c mxRealloc, ...). When a MEX file is interrupted or ends,
all memory blocks allocated by using one of such functions are
released, preventing leakage.
In order to integrate VLFeat with this model in the most seamless
way, VLFeat memory allocation functions (::vl_malloc, ::vl_realloc,
::vl_calloc) are mapped to the corresponding MEX memory allocation
functions. Such functions automatically dispose of all the memory
allocated by a MEX function when the function ends (even because of
an exception). Because of the restrictions of the library design
illustrated in @ref resources, this operation is safe and
correctly dispose of VLFeat local state. As a consequence, it is
possible to call @c mexErrMsgTxt at any point in the MEX function
without worrying about leaking resources.
This however comes at the price of some limitations. Beyond the
restrictions illustrated in @ref resources, here we note that no
VLFeat local resource (memory blocks or objects) can persist across
MEX file invocations. This implies that any result produced by a
VLFeat MEX function must be converted back to a MATLAB object such as
a vector or a structure. In particular, there is no direct way of
creating an object within a MEX file, returning it to MATLAB, and
passing it again to another MEX file.
**/
/**
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@page metaprogram Preprocessor metaprogramming
@author Andrea Vedaldi
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
Part of VLFeat code uses a simple form of preprocessor metaprogramming.
This technique is used, similarly to C++ templates, to instantiate
multiple version of a given algorithm for different data types
(e.g. @c float and @c double).
In most cases preprocessor metaprogramming is invisible to the library
user, as it is used only internally.
**/
/**
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@page glossary Glossary
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
- <b>Column-major.</b> A <em>M x N </em> matrix <em>A</em> is
stacked with column-major order as the sequence \f$(A_{11}, A_{21},
\dots, A_{12}, \dots)\f$. More in general, when stacking a multi
dimensional array this indicates that the first index is the one
varying most quickly, with the other followed in the natural order.
- <b>Opaque structure.</b> A structure is opaque if the user is not supposed
to access its member directly, but through appropriate interface functions.
Opaque structures are commonly used to define objects.
- <b>Row-major.</b> A <em>M x N </em> matrix <em>A</em> is
stacked with row-major order as the sequence \f$(A_{11}, A_{12},
\dots, A_{21}, \dots)\f$. More in general, when stacking a multi
dimensional array this indicates that the last index is the one
varying most quickly, with the other followed in reverse order.
- <b>Feature frame.</b> A <em>feature frame</em> is the geometrical
description of a visual features. For instance, the frame of
a @ref sift.h "SIFT feature" is oriented disk and the frame of
@ref mser.h "MSER feature" is either a compact and connected set or
a disk.
- <b>Feature descriptor.</b> A <em>feature descriptor</em> is a quantity
(usually a vector) which describes compactly the appearance of an
image region (usually corresponding to a feature frame).
**/
/**
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@page dev Developing the library
@tableofcontents
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
This page contains information useful to the developer of VLFeat.
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@section dev-copy Copyright
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
A short copyright notice is added at the beginning of each file. For
example:
<pre>
Copyright (C) 2013 Milan Sulc
Copyright (C) 2012 Daniele Perrone.
Copyright (C) 2011-13 Andrea Vedaldi.
All rights reserved.
This file is part of the VLFeat library and is made available under
the terms of the BSD license (see the COPYING file).
</pre>
The copyright of each file is assigned to the authors of the file.
Every author making a substantial contribution to a file should
note its copyright by adding a line to the copyright list with the year
of the modification. Year ranges are acceptable. Lines are never
deleted, only appended, or potentially modified to list
more years.
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@section dev-style Coding style
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<ul>
<li><b>Look at existing code before you start.</b> The general rule
is: try to match the style of the existing code as much as
possible.</li>
<li><b>No white spaces at the end of lines.</b> White spaces introduce
invisible changes in the code that are however picked up by control
version systems such as Git.</li>
<li><b>Descriptive variable names.</b> Most variable names start with
a lower case letter and are capitalized, e.g., @c numElements. Only
the following abbreviations are considered acceptable: @c num. The @c
dimension of a vector is the number of elements it contains (for other
objects that could be a @c size, a @c length, or a @c
numElements). For multi-dimensional arrays, @c dimensions could
indicate the array with each of the @c numDimensions dimensions.</li>
<li><b>Short variable names.</b> For indexes in short for loops it is
fine to use short index names such as @c i, @c j, and @c k. For example:
<pre>
for (i = 0 ; i < numEntries ; ++i) values[i] ++ ;
</pre>
is considered acceptable.</li>
<li><b>Function arguments.</b> VLFeat functions that operate on an
object (member functions) should be passed the object address as first
argument; this argument should be called @c self. For example:
<pre>
void vl_object_do_something(VlObject *self) ;
</pre>
Multi-dimensional arrays should be specified first by their address,
and then by their dimensions. For example
<pre>
void vl_use_array (float * array, vl_size numColumns, vl_size numRows) ; // good
void vl_use_array (vl_size numColumns, vl_size numRows, float * array) ; // bad
</pre>
Arguments that are used as outputs should be specified first (closer to
the left-hand side of an expression). For example
<pre>
void vl_sum_numbers (float * output, float input1, float input2) ; // good
void vl_sum_numbers (float input1, float input2, float * output) ; // bad
</pre>
These rules can be combined. For example
<pre>
void vl_object_sum_to_array (VlObject * self, float * outArray,
vl_size numColumns, vl_size numRows, float * inArray) ; // good
</pre>
Note that in this case no dimension for @c inArray is specified as it
is assumed that @c numColumns and @c numRows are the dimensions of
both arrays.
</li>
</ul>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@subsection dev-style-matlab MATLAB coding style
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<ul>
<li><b>Help messages.</b> Each @c .m file should include a standard
help comment block (accessible from MATLAB @c help() command).
The first line of the block has a space, the name of the function,
4 spaces, and a brief command description. The body of the help
message is indented with 4 spaces. For example
@code
% VL_FUNCTION An example function
% VL_FUNCTION() does nothing.
@endcode
The content HELP message itself should follow MATLAB default style.
For example, rather than giving a list of formal input and output
arguments as often done, one simply shows how to use the function, explaining
along the way the different ways the function can be called and
the format of the parameters.
</li>
</ul>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@section dev-doc Documenting the code
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
The VLFeat C library code contains its own in documentation <a
href='http://www.stack.nl/~dimitri/doxygen/'>Doxygen</a> format. The
documentation consists in generic pages, such as the @ref index
"index" and the page you are reading, and documentations for each
library module, usually corresponding to a certain header file.
- **Inline comments.** Inline Doxygen comments are discouraged except
in the documentation of data members of structures. They start with
a capital letter and end with a period. For example:
@code
struct VlExampleStructure {
int aMember ; /\*\*< A useful data member.
}
@endcode
- **Brief comments.** Brief Doxygen comments starts by a capital
and end with a period. The documentation of all functions start
with a brief comment.
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@subsection devl-doc-modules Documenting the library modules
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
A library module groups a number of data types and functions that
implement a certain functionality of VLFeat. The documentation of a
library module is generally organized as follows:
1. A page introducing the module and including a getting started
section (3.g. @ref svm-starting) containing a short tutorial to
quickly familiarize the user with the module (e.g. @ref svm).
2. One or more pages of detailed technical background discussing the
algorithms implemented. These sections are used not just as part of
the C API, but also as documentation for other APIs such as MATLAB
(e.g. @ref svm-fundamentals).
3. One or more pages with the structure and function documentation
(e.g. @ref svm.h).
More in detail, consider a module called <em>Example Module</em>. Then one would
typically have:
<ul>
<li>A header or declaration file @c example-module.h. Such a file has an
heading of the type:
@verbinclude example-module-doc.h
This comment block contains a file directive, causing the file to be
included in the documentation, a brief directive, specifying a short
description of what the file is, and a list of authors. A
(non-Doxygen) comment block with a short the copyright notice follows.
The brief directive should include a <code>@@ref</code> directive to point
to the main documentation page describing the module, if there is one.
</li>
<li> An implementation or definition file @c example-module.c. This file
has an heading of the type:
@verbinclude example-module-doc.c
This is similar to the declaration file, except for the content of the
brief comment.
</li>
</ul>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@subsection devl-doc-functions Documenting functions
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@subsection devl-doc-structures Documenting structures
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@subsection devl-doc-structures Documenting objects
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
As seen in @ref objects, VLFeat treats certain structures with
an object-like semantics. Usually, a module defines exactly one such
objects. In this case, the object member functions should be grouped
(by using Doxygen grouping functionality) as
- **Construct and destroy** for the @c vl_object_new, @c
vl_object_delete and similar member functions.
- **Set parameters** for setter functions.
- **Retrieve parameters and data** for getter functions.
- **Process data** for functions processing data.
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@subsection devl-doc-bib Bibliographic references
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
Since version 0.9.14, the VLFeat C library documentation makes use of
a proper bibliographic reference in BibTeX format (see the file @c
docsrc/vlfeat.bib). Doxygen uses this file when it sees instances of
the <code>@@cite{xyz}</code> command. Here @c xyz is a BibTeX
key. For example, @c vlfeat.bib file contains the entry:
<pre>
@@inproceedings{martin97the-det-curve,
Author = {A. Martin and G. Doddington and T. Kamm and M. Ordowski and M. Przybocki},
Booktitle = {Proc. Conf. on Speech Communication and Technology},
Title = {The {DET} curve in assessment of detection task performance},
Year = {1997}}
</pre>
For example, the Doxygen directive
<code>@@cite{martin97the-det-curve}</code> generates the output
@cite{martin97the-det-curve}, which is a link to the corresponding
entry in the bibliography.
**/
/**
@file generic.h
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@page generic General support functionalities
@author Andrea Vedaldi
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
VLFeat contains several support functionalities addressing the C
preprocessors, using multiple threads (including parallel computations),
handling errors, allocating memory, etc. These are described in
the following pages:
- @subpage resources
- @subpage threads
- @subpage misc
**/
/**
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@page misc Preprocssor, library state, etc.
@author Andrea Vedaldi
@tableofcontents
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@section misc-preproc C preprocessor helpers
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
VLFeat provides a few C preprocessor macros of general
utility. These include stringification (::VL_STRINGIFY,
::VL_XSTRINGIFY) and concatenation (::VL_CAT, ::VL_XCAT) of symbols.
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@section misc-state VLFeat state and configuration parameters
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
VLFeat has some global configuration parameters that can
changed. Changing the configuration is thread unsave
(@ref threads). Use ::vl_set_simd_enabled to toggle the use of
a SIMD unit (Intel SSE code), ::vl_set_alloc_func to change
the memory allocation functions, and ::vl_set_printf_func
to change the logging function.
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@section misc-error Error handling
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
Some VLFeat functions signal errors in a way similar to the
standard C library. In case of error, a VLFeat function
may return an error code directly,
or an invalid result (for instance a negative file descriptor or a null
pointer). Then ::vl_get_last_error and ::vl_get_last_error_message can be used
to retrieve further details about the error (these functions should be
used right after an error has occurred, before any other VLFeat call).
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@section misc-memory Memory allocation
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
VLFeat uses the ::vl_malloc, ::vl_realloc, ::vl_calloc and ::vl_free
functions to allocate memory. Normally these functions are mapped to
the underlying standard C library implementations. However
::vl_set_alloc_func can be used to map them to other
implementations. For instance, in MATALB MEX files these functions
are mapped to the MATLAB equivalent which has a garbage collection
mechanism to cope with interruptions during execution.
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@section misc-logging Logging
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
VLFeat uses the macros ::VL_PRINT and ::VL_PRINTF to print progress
or debug informations. These functions are normally mapped to the @c
printf function of the underlying standard C library. However
::vl_set_printf_func can be used to map it to a different
implementation. For instance, in MATLAB MEX files this function is
mapped to @c mexPrintf. Setting the function to @c NULL disables
logging.
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@section misc-time Measuring time
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
VLFeat provides ::vl_tic and ::vl_toc as an easy way of measuring
elapsed time.
**/
/**
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@page threads Threading
@tableofcontents
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
VLFeat supports for threaded computations can be used to take advantage
of multi-core architectures. Threading support includes:
- Supporting using VLFeat functions and objects from multiple threads
simultaneously. This is discussed in @ref threads-multiple.
- Using multiple cores to accelerate computations. This is
discussed in @ref threads-parallel.
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@section threads-multiple Using VLFeat from multiple threads
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
VLFeat can be used from multiple threads simultaneously if proper
rules are followed.
- <b>A VLFeat object instance is accessed only from one thread at any
given time.</b> Functions operating on objects (member functions)
are conditionally thread safe: the same function may be called
simultaneously from multiple threads provided that it operates on
different, independent objects. However, modifying the same object
from multiple threads (using the same or different member functions)
is possible only from one thread at any given time, and should
therefore be synchronized. Certain VLFeat objects may contain
features specific to simplify multi-threaded operations
(e.g. ::VlKDForest).
- <b>Thread-safe global functions are used.</b> These include
thread-specific operations such as retrieving the last error by
::vl_get_last_error and obtaining the thread-specific random number
generator instance by ::vl_get_rand. In these cases, the functions
operate on thread-specific data that VLFeat creates and
maintains. Note in particular that each thread has an independent
default random number generator (as returned by
::vl_get_rand). VLFeat objects that involve using random numbers
will typically use the random number generator of the thread
currently accessing the object (although an object-specific
generator can be often be specified instead).
- <b>Any other global function is considered non-thread safe and is
accessed exclusively by one thread at a time.</b> A small number of
operations are non-reentrant <em>and</em> affect all threads
simultaneously. These are restricted to changing certain global
configuration parameters, such as the memory allocation functions by
::vl_set_alloc_func. These operations are <em>not</em> thread safe
and are preferably executed before multiple threads start to operate
with the library.
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
@section threads-parallel Parallel computations
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
VLFeat uses OpenMP to implement parallel computations. Generally, this
means that multiple cores are uses appropriately and transparently,
provided that other multi-threaded parts of the application use OpenMP
and that VLFeat and the application link to the same OpenMP library.
If finer control is required, read on.
VLFeat functions avoids affecting OpenMP global state, including the
desired number of computational threads, in order to minimize side
effects to the linked application (e.g. MATLAB). Instead, VLFeat
duplicates a few OpenMP control parameters when needed (this approach
is similar to the method used by other libraries such as Intel MKL).
The maximum number of threads available to the application can be
obtained by ::vl_get_thread_limit (for OpenMP version 3.0 and
greater). This limit is controlled by the OpenMP library (the function
is a wrapper around @c omp_get_thread_limit), which in turn may
determined that based on the number of computational cores or the
value of the @c OMP_THREAD_LIMIT variable when the program is
launched. This value is an upper bound on the number of computation
threads that can be used at any time.
The maximum number of computational thread that VLFeat should use is
set by ::vl_set_num_threads() and retrieved by ::vl_get_max_threads().
This number is a target value as well as an upper bound to the number
of threads used by VLFeat. This value is stored in the VLFeat private
state and is not necessarily equal to the corresponding OpenMP state
variable retrieved by calling @c omp_get_max_threads(). @c
vl_set_num_threads(1) disables the use of multiple threads and @c
vl_set_num_threads(0) uses the value returned by the OpenMP call @c
omp_get_max_threads(). The latter value is controlled, for example, by
calling @c omp_set_num_threads() in the application. Note that:
- @c vl_set_num_threads(0) determines the number of treads using @c
omp_get_max_threads() *when it is called*. Subsequent calls to @c
omp_set_num_threads() will therefore *not* affect the number of
threads used by VLFeat.
- @c vl_set_num_threads(vl_get_thread_limit()) causes VLFeat use all
the available threads, regardless on the number of threads set
within the application by calls to @c omp_set_num_threads().
- OpenMP may still dynamically decide to use a smaller number of
threads in any specific parallel computation.
@sa http://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_userguide_win/GUID-C2295BC8-DD22-466B-94C9-5FAA79D4F56D.htm
http://software.intel.com/sites/products/documentation/doclib/mkl_sa/11/mkl_userguide_win/index.htm#GUID-DEEF0363-2B34-4BAB-87FA-A75DBE842040.htm
http://software.intel.com/sites/products/documentation/hpc/mkl/lin/MKL_UG_managing_performance/Using_Additional_Threading_Control.htm
**/
#include "generic.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
#if defined(VL_OS_WIN)
#include <Windows.h>
#else
#include <unistd.h>
#endif
#if ! defined(VL_DISABLE_THREADS) && defined(VL_THREADS_POSIX)
#include <pthread.h>
#endif
#if defined(_OPENMP)
#include <omp.h>
#endif
/* ---------------------------------------------------------------- */
/* Global and thread states */
/* ---------------------------------------------------------------- */
/* Thread state */
typedef struct _VlThreadState
{
/* errors */
int lastError ;
char lastErrorMessage [VL_ERR_MSG_LEN] ;
/* random number generator */
VlRand rand ;
/* time */
#if defined(VL_OS_WIN)
LARGE_INTEGER ticFreq ;
LARGE_INTEGER ticMark ;
#else
clock_t ticMark ;
#endif
} VlThreadState ;
/* Gobal state */
typedef struct _VlState
{
/* The thread state uses either a mutex (POSIX)
or a critical section (Win) */
#if defined(VL_DISABLE_THREADS)
VlThreadState * threadState ;
#else
#if defined(VL_THREADS_POSIX)
pthread_key_t threadKey ;
pthread_mutex_t mutex ;
pthread_t mutexOwner ;
pthread_cond_t mutexCondition ;
size_t mutexCount ;
#elif defined(VL_THREADS_WIN)
DWORD tlsIndex ;
CRITICAL_SECTION mutex ;
#endif
#endif /* VL_DISABLE_THREADS */
/* Configurable functions */
int (*printf_func) (char const * format, ...) ;
void *(*malloc_func) (size_t) ;
void *(*realloc_func) (void*,size_t) ;
void *(*calloc_func) (size_t, size_t) ;
void (*free_func) (void*) ;
#if defined(VL_ARCH_IX86) || defined(VL_ARCH_X64) || defined(VL_ARCH_IA64)
VlX86CpuInfo cpuInfo ;
#endif
vl_size numCPUs ;
vl_bool simdEnabled ;
vl_size numThreads ;
} VlState ;
/* Global state instance */
VlState _vl_state ;
/* ----------------------------------------------------------------- */
VL_INLINE VlState * vl_get_state () ;
VL_INLINE VlThreadState * vl_get_thread_specific_state () ;
static void vl_lock_state (void) ;
static void vl_unlock_state (void) ;
static VlThreadState * vl_thread_specific_state_new (void) ;
static void vl_thread_specific_state_delete (VlThreadState * self) ;
/** @brief Get VLFeat version string
** @return the library version string.
**/
char const *
vl_get_version_string ()
{
return VL_VERSION_STRING ;
}
/** @brief Get VLFeat configuration string.
** @return a new configuration string.
**
** The function returns a new string containing a human readable
** description of the library configuration.
**/
char *
vl_configuration_to_string_copy ()
{
char * string = 0 ;
int length = 0 ;
char * staticString = vl_static_configuration_to_string_copy() ;
char * cpuString =
#if defined(VL_ARCH_IX86) || defined(VL_ARCH_X64) || defined(VL_ARCH_IA64)
_vl_x86cpu_info_to_string_copy(&vl_get_state()->cpuInfo) ;
#else
"Generic CPU" ;
#endif
#if defined(DEBUG)
int const debug = 1 ;
#else
int const debug = 0 ;
#endif
while (string == 0) {
if (length > 0) {
string = vl_malloc(sizeof(char) * length) ;
if (string == NULL) break ;
}
length = snprintf(string, length,
"VLFeat version %s\n"
" Static config: %s\n"
" %" VL_FMT_SIZE " CPU(s): %s\n"
#if defined(_OPENMP)
" OpenMP: max threads: %d (library: %" VL_FMT_SIZE ")\n"
#endif
" Debug: %s\n",
vl_get_version_string (),
staticString,
vl_get_num_cpus(), cpuString,
#if defined(_OPENMP)
omp_get_max_threads(), vl_get_max_threads(),
#endif
VL_YESNO(debug)) ;
length += 1 ;
}
if (staticString) vl_free(staticString) ;
if (cpuString) vl_free(cpuString) ;
return string ;
}
/** @internal @brief A printf that does not do anything */
static int
do_nothing_printf (char const* format VL_UNUSED, ...)
{
return 0 ;
}
/** @internal
** @brief Lock VLFeat state
**
** The function locks VLFeat global state mutex.
**
** The mutex is recursive: locking multiple times from the same thread
** is a valid operations, but requires an equivalent number
** of calls to ::vl_unlock_state.
**
** @sa ::vl_unlock_state
**/
static void
vl_lock_state (void)
{
#if ! defined(VL_DISABLE_THREADS)
#if defined(VL_THREADS_POSIX)
VlState * state = vl_get_state () ;
pthread_t thisThread = pthread_self () ;
pthread_mutex_lock (&state->mutex) ;
if (state->mutexCount >= 1 &&
pthread_equal (state->mutexOwner, thisThread)) {
state->mutexCount ++ ;
} else {
while (state->mutexCount >= 1) {
pthread_cond_wait (&state->mutexCondition, &state->mutex) ;
}
state->mutexOwner = thisThread ;
state->mutexCount = 1 ;
}
pthread_mutex_unlock (&state->mutex) ;
#elif defined(VL_THREADS_WIN)
EnterCriticalSection (&vl_get_state()->mutex) ;
#endif
#endif
}
/** @internal
** @brief Unlock VLFeat state
**
** The function unlocks VLFeat global state mutex.
**
** @sa ::vl_lock_state
**/
static void
vl_unlock_state (void)
{
#if ! defined(VL_DISABLE_THREADS)
#if defined(VL_THREADS_POSIX)
VlState * state = vl_get_state () ;
pthread_mutex_lock (&state->mutex) ;
-- state->mutexCount ;
if (state->mutexCount == 0) {
pthread_cond_signal (&state->mutexCondition) ;
}
pthread_mutex_unlock (&state->mutex) ;
#elif defined(VL_THREADS_WIN)
LeaveCriticalSection (&vl_get_state()->mutex) ;
#endif
#endif
}
/** @internal
** @brief Return VLFeat global state
**
** The function returns a pointer to VLFeat global state.
**
** @return pointer to the global state structure.
**/
VL_INLINE VlState *
vl_get_state (void)
{
return &_vl_state ;
}
/** @internal@brief Get VLFeat thread state
** @return pointer to the thread state structure.
**
** The function returns a pointer to VLFeat thread state.
**/
VL_INLINE VlThreadState *
vl_get_thread_specific_state (void)
{
#ifdef VL_DISABLE_THREADS
return vl_get_state()->threadState ;
#else
VlState * state ;
VlThreadState * threadState ;
vl_lock_state() ;
state = vl_get_state() ;
#if defined(VL_THREADS_POSIX)
threadState = (VlThreadState *) pthread_getspecific(state->threadKey) ;
#elif defined(VL_THREADS_WIN)
threadState = (VlThreadState *) TlsGetValue(state->tlsIndex) ;
#endif
if (! threadState) {
threadState = vl_thread_specific_state_new () ;
}
#if defined(VL_THREADS_POSIX)
pthread_setspecific(state->threadKey, threadState) ;
#elif defined(VL_THREADS_WIN)
TlsSetValue(state->tlsIndex, threadState) ;
#endif
vl_unlock_state() ;
return threadState ;
#endif
}
/* ---------------------------------------------------------------- */
/** @brief Get the number of CPU cores of the host
** @return number of CPU cores.
**/
vl_size
vl_get_num_cpus (void)
{
return vl_get_state()->numCPUs ;
}
/** @fn ::vl_set_simd_enabled(vl_bool)
** @brief Toggle usage of SIMD instructions
** @param x @c true if SIMD instructions are used.
**
** Notice that SIMD instructions are used only if the CPU model
** supports them. Note also that data alignment may restrict the use
** of such instructions.
**
** @see ::vl_cpu_has_sse2(), ::vl_cpu_has_sse3(), etc.
**/
void
vl_set_simd_enabled (vl_bool x)
{
vl_get_state()->simdEnabled = x ;
}
/** @brief Are SIMD instructons enabled?
** @return @c true if SIMD instructions are enabled.
**/
vl_bool
vl_get_simd_enabled (void)
{
return vl_get_state()->simdEnabled ;
}
/** @brief Check for AVX instruction set
** @return @c true if AVX is present.
**/
vl_bool
vl_cpu_has_avx (void)
{
#if defined(VL_ARCH_IX86) || defined(VL_ARCH_X64) || defined(VL_ARCH_IA64)
return vl_get_state()->cpuInfo.hasAVX ;
#else
return VL_FALSE ;
#endif
}
/** @brief Check for SSE3 instruction set
** @return @c true if SSE3 is present.
**/
vl_bool
vl_cpu_has_sse3 (void)
{
#if defined(VL_ARCH_IX86) || defined(VL_ARCH_X64) || defined(VL_ARCH_IA64)
return vl_get_state()->cpuInfo.hasSSE3 ;
#else
return VL_FALSE ;
#endif
}
/** @brief Check for SSE2 instruction set
** @return @c true if SSE2 is present.
**/
vl_bool
vl_cpu_has_sse2 (void)
{
#if defined(VL_ARCH_IX86) || defined(VL_ARCH_X64) || defined(VL_ARCH_IA64)
return vl_get_state()->cpuInfo.hasSSE2 ;
#else
return VL_FALSE ;
#endif
}
/* ---------------------------------------------------------------- */
/** @brief Get the number of computational threads available to the application
** @return number of threads.
**
** This function wraps the OpenMP function @c
** omp_get_thread_limit(). If VLFeat was compiled without OpenMP
** support, this function returns 1. If VLFeat was compiled with
** OpenMP prior to version 3.0 (2008/05), it returns 0.
**
** @sa @ref threads-parallel
**/
vl_size
vl_get_thread_limit (void)
{
#if defined(_OPENMP)
#if _OPENMP >= 200805
/* OpenMP version >= 3.0 */
return omp_get_thread_limit() ;
#else
return 0 ;
#endif
#else
return 1 ;
#endif
}
/** @brief Get the maximum number of computational threads used by VLFeat.
** @return number of threads.
**
** This function returns the maximum number of thread used by
** VLFeat. VLFeat will try to use this number of computational
** threads and never exceed it.
**
** This is similar to the OpenMP function @c omp_get_max_threads();
** however, it reads a parameter private to VLFeat which is
** independent of the value used by the OpenMP library.
**
** If VLFeat was compiled without OpenMP support, this function
** returns 1.
**
** @sa vl_set_num_threads(), @ref threads-parallel
**/
vl_size
vl_get_max_threads (void)
{
#if defined(_OPENMP)
return vl_get_state()->numThreads ;
#else
return 1 ;
#endif
}
/** @brief Set the maximum number of threads used by VLFeat.
** @param numThreads number of threads to use.
**
** This function sets the maximum number of computational threads
** that will be used by VLFeat. VLFeat may in practice use fewer
** threads (for example because @a numThreads is larger than the
** number of computational cores in the host, or because the number
** of threads exceeds the limit available to the application).
**
** If @c numThreads is set to 0, then VLFeat sets the number of
** threads to the OpenMP current maximum, obtained by calling @c
** omp_get_max_threads().
**
** This function is similar to @c omp_set_num_threads() but changes a
** parameter internal to VLFeat rather than affecting OpenMP global
** state.
**
** If VLFeat was compiled without, this function does nothing.
**
** @sa vl_get_max_threads(), @ref threads-parallel
**/
#if defined(_OPENMP)
void
vl_set_num_threads (vl_size numThreads)
{
if (numThreads == 0) {
numThreads = omp_get_max_threads() ;
}
vl_get_state()->numThreads = numThreads ;
}
#else
void
vl_set_num_threads (vl_size numThreads VL_UNUSED) { }
#endif
/* ---------------------------------------------------------------- */
/** @brief Set last VLFeat error
** @param error error code.
** @param errorMessage error message format string.
** @param ... format string arguments.
** @return error code.
**
** The function sets the code and optionally the error message
** of the last encountered error. @a errorMessage is the message
** format. It uses the @c printf convention and is followed by
** the format arguments. The maximum length of the error message is
** given by ::VL_ERR_MSG_LEN (longer messages are truncated).
**
** Passing @c NULL as @a errorMessage
** sets the error message to the empty string.
**/
int
vl_set_last_error (int error, char const * errorMessage, ...)
{
VlThreadState * state = vl_get_thread_specific_state() ;
va_list args;
va_start(args, errorMessage) ;
if (errorMessage) {
#ifdef VL_COMPILER_LCC
vsprintf(state->lastErrorMessage, errorMessage, args) ;
#else
vsnprintf(state->lastErrorMessage,
sizeof(state->lastErrorMessage)/sizeof(char),
errorMessage, args) ;
#endif
} else {
state->lastErrorMessage[0] = 0 ;
}
state->lastError = error ;
va_end(args) ;
return error ;
}
/** @brief Get the code of the last error
** @return error code.
** @sa ::vl_get_last_error_message.
**/
int
vl_get_last_error (void) {
return vl_get_thread_specific_state()->lastError ;
}
/** @brief Get the last error message
** @return pointer to the error message.
** @sa ::vl_get_last_error.
**/
char const *
vl_get_last_error_message (void)
{
return vl_get_thread_specific_state()->lastErrorMessage ;
}
/* ---------------------------------------------------------------- */
/** @brief Set memory allocation functions
** @param malloc_func pointer to @c malloc.
** @param realloc_func pointer to @c realloc.
** @param calloc_func pointer to @c calloc.
** @param free_func pointer to @c free.
**/
void
vl_set_alloc_func (void *(*malloc_func) (size_t),
void *(*realloc_func) (void*, size_t),
void *(*calloc_func) (size_t, size_t),
void (*free_func) (void*))
{
VlState * state ;
vl_lock_state () ;
state = vl_get_state() ;
state->malloc_func = malloc_func ;
state->realloc_func = realloc_func ;
state->calloc_func = calloc_func ;
state->free_func = free_func ;
vl_unlock_state () ;
}
/** @brief Allocate a memory block
** @param n size in bytes of the new block.
** @return pointer to the allocated block.
**
** This function allocates a memory block of the specified size.
** The synopsis is the same as the POSIX @c malloc function.
**/
void *
vl_malloc (size_t n)
{
return (vl_get_state()->malloc_func)(n) ;
//return (memalign)(32,n) ;
}
/** @brief Reallocate a memory block
** @param ptr pointer to a memory block previously allocated.
** @param n size in bytes of the new block.
** @return pointer to the new block.
**
** This function reallocates a memory block to change its size.
** The synopsis is the same as the POSIX @c realloc function.
**/
void *
vl_realloc (void* ptr, size_t n)
{
return (vl_get_state()->realloc_func)(ptr, n) ;
}
/** @brief Free and clear a memory block
** @param n number of items to allocate.
** @param size size in bytes of an item.
** @return pointer to the new block.
**
** This function allocates and clears a memory block.
** The synopsis is the same as the POSIX @c calloc function.
**/
void *
vl_calloc (size_t n, size_t size)
{
return (vl_get_state()->calloc_func)(n, size) ;
}
/** @brief Free a memory block
** @param ptr pointer to the memory block.
**
** This function frees a memory block allocated by ::vl_malloc,
** ::vl_calloc, or ::vl_realloc. The synopsis is the same as the POSIX
** @c malloc function.
**/
void
vl_free (void *ptr)
{
(vl_get_state()->free_func)(ptr) ;
}
/* ---------------------------------------------------------------- */
/** @brief Set the printf function
** @param printf_func pointer to a @c printf implementation.
** Set @c print_func to NULL to disable printf.
**/
void
vl_set_printf_func (printf_func_t printf_func)
{
vl_get_state()->printf_func = printf_func ? printf_func : do_nothing_printf ;
}
/** @brief Get the printf function
** @return printf_func pointer to the @c printf implementation.
** @sa ::vl_set_printf_func.
**/
printf_func_t
vl_get_printf_func (void) {
return vl_get_state()->printf_func ;
}
/* ---------------------------------------------------------------- */
/** @brief Get processor time
** @return processor time in seconds.
** @sa ::vl_tic, ::vl_toc
**/
double
vl_get_cpu_time ()
{
#ifdef VL_OS_WIN
VlThreadState * threadState = vl_get_thread_specific_state() ;
LARGE_INTEGER mark ;
QueryPerformanceCounter (&mark) ;
return (double)mark.QuadPart / (double)threadState->ticFreq.QuadPart ;
#else
return (double)clock() / (double)CLOCKS_PER_SEC ;
#endif
}
/** @brief Reset processor time reference
** The function resets VLFeat TIC/TOC time reference. There is one
** such reference per thread.
** @sa ::vl_get_cpu_time, ::vl_toc.
**/
void
vl_tic (void)
{
VlThreadState * threadState = vl_get_thread_specific_state() ;
#ifdef VL_OS_WIN
QueryPerformanceCounter (&threadState->ticMark) ;
#else
threadState->ticMark = clock() ;
#endif
}
/** @brief Get elapsed time since tic
** @return elapsed time in seconds.
**
** The function
** returns the processor time elapsed since ::vl_tic was called last.
**
** @remark In multi-threaded applications, there is an independent
** timer for each execution thread.
**
** @remark On UNIX, this function uses the @c clock() system call.
** On Windows, it uses the @c QueryPerformanceCounter() system call,
** which is more accurate than @c clock() on this platform.
**/
double
vl_toc (void)
{
VlThreadState * threadState = vl_get_thread_specific_state() ;
#ifdef VL_OS_WIN
LARGE_INTEGER tocMark ;
QueryPerformanceCounter(&tocMark) ;
return (double) (tocMark.QuadPart - threadState->ticMark.QuadPart) /
threadState->ticFreq.QuadPart ;
#else
return (double) (clock() - threadState->ticMark) / CLOCKS_PER_SEC ;
#endif
}
/* ---------------------------------------------------------------- */
/** @brief Get the default random number generator.
** @return random number generator.
**
** The function returns a pointer to the default
** random number generator.
** There is one such generator per thread.
**/
VL_EXPORT VlRand *
vl_get_rand (void)
{
return &vl_get_thread_specific_state()->rand ;
}
/* ---------------------------------------------------------------- */
/* Library construction and destruction routines */
/* --------------------------------------------------------------- */
/** @internal@brief Construct a new thread state object
** @return new state structure.
**/
static VlThreadState *
vl_thread_specific_state_new (void)
{
VlThreadState * self ;
#if defined(DEBUG)
printf("VLFeat DEBUG: thread constructor begins.\n") ;
#endif
self = malloc(sizeof(VlThreadState)) ;
self->lastError = 0 ;
self->lastErrorMessage[0] = 0 ;
#if defined(VL_OS_WIN)
QueryPerformanceFrequency (&self->ticFreq) ;
self->ticMark.QuadPart = 0 ;
#else
self->ticMark = 0 ;
#endif
vl_rand_init (&self->rand) ;
return self ;
}
/** @internal@brief Delete a thread state structure
** @param self thread state object.
**/
static void
vl_thread_specific_state_delete (VlThreadState * self)
{
#if defined(DEBUG)
printf("VLFeat DEBUG: thread destructor begins.\n") ;
#endif
free (self) ;
}
/* ---------------------------------------------------------------- */
/* Library constructor and destructor */
/* ---------------------------------------------------------------- */
/** @internal @brief Initialize VLFeat state */
void
vl_constructor (void)
{
VlState * state ;
#if defined(DEBUG)
printf("VLFeat DEBUG: constructor begins.\n") ;
#endif
state = vl_get_state() ;
#if ! defined(VL_DISABLE_THREADS)
#if defined(DEBUG)
printf("VLFeat DEBUG: constructing thread specific state.\n") ;
#endif
#if defined(VL_THREADS_POSIX)
{
typedef void (*destructorType)(void * );
pthread_key_create (&state->threadKey,
(destructorType)
vl_thread_specific_state_delete) ;
pthread_mutex_init (&state->mutex, NULL) ;
pthread_cond_init (&state->mutexCondition, NULL) ;
}
#elif defined(VL_THREADS_WIN)
InitializeCriticalSection (&state->mutex) ;
state->tlsIndex = TlsAlloc () ;
#endif
#else
/* threading support disabled */
#if defined(DEBUG)
printf("VLFeat DEBUG: constructing the generic thread state instance (threading support disabled).\n") ;
#endif
vl_get_state()->threadState = vl_thread_specific_state_new() ;
#endif
state->malloc_func = malloc ;
state->realloc_func = realloc ;
state->calloc_func = calloc ;
state->free_func = free ;
state->printf_func = printf ;
/* on x86 platforms read the CPUID register */
#if defined(VL_ARCH_IX86) || defined(VL_ARCH_X64) || defined(VL_ARCH_IA64)
_vl_x86cpu_info_init (&state->cpuInfo) ;
#endif
/* get the number of CPUs */
#if defined(VL_OS_WIN)
{
SYSTEM_INFO info;
GetSystemInfo (&info) ;
state->numCPUs = info.dwNumberOfProcessors ;
}
#elif defined(_SC_NPROCESSORS_ONLN)
state->numCPUs = sysconf(_SC_NPROCESSORS_ONLN) ;
#else
state->numCPUs = 1 ;
#endif
state->simdEnabled = VL_TRUE ;
/* get the number of (OpenMP) threads used by the library */
#if defined(_OPENMP)
state->numThreads = omp_get_max_threads() ;
#else
state->numThreads = 1 ;
#endif
#if defined(DEBUG)
printf("VLFeat DEBUG: constructor ends.\n") ;
#endif
}
/** @internal @brief Destruct VLFeat */
void
vl_destructor ()
{
VlState * state ;
#if defined(DEBUG)
printf("VLFeat DEBUG: destructor begins.\n") ;
#endif
state = vl_get_state() ;
#if ! defined(VL_DISABLE_THREADS)
#if defined(DEBUG)
printf("VLFeat DEBUG: destroying a thread specific state instance.\n") ;
#endif
#if defined(VL_THREADS_POSIX)
{
/* Delete the thread state of this thread as the
destructor is not called by pthread_key_delete or after
the key is deleted. When the library
is unloaded, this thread should also be the last one
using the library, so this is fine.
*/
VlThreadState * threadState =
pthread_getspecific(state->threadKey) ;
if (threadState) {
vl_thread_specific_state_delete (threadState) ;
pthread_setspecific(state->threadKey, NULL) ;
}
}
pthread_cond_destroy (&state->mutexCondition) ;
pthread_mutex_destroy (&state->mutex) ;
pthread_key_delete (state->threadKey) ;
#elif defined(VL_THREADS_WIN)
{
/* Delete the thread state of this thread as the
destructor is not called by pthread_key_delete or after
the key is deleted. When the library
is unloaded, this thread should also be the last one
using the library, so this is fine.
*/
VlThreadState * threadState =
TlsGetValue(state->tlsIndex) ;
if (threadState) {
vl_thread_specific_state_delete (threadState) ;
TlsSetValue(state->tlsIndex, NULL) ;
}
}
TlsFree (state->tlsIndex) ;
DeleteCriticalSection (&state->mutex) ;
#endif
#else
#if defined(DEBUG)
printf("VLFeat DEBUG: destroying the generic thread state instance (threading support disabled).\n") ;
#endif
vl_thread_specific_state_delete(vl_get_state()->threadState) ;
#endif
#if defined(DEBUG)
printf("VLFeat DEBUG: destructor ends.\n") ;
#endif
}
/* ---------------------------------------------------------------- */
/* Cross-platform call to constructor/destructor */
/* ---------------------------------------------------------------- */
#ifdef __cplusplus
#define INITIALIZER(f) \
static void f(void); \
struct f##_t_ { f##_t_(void) { f(); } }; static f##_t_ f##_; \
static void f(void)
#elif defined(_MSC_VER)
#pragma section(".CRT$XCU",read)
#define INITIALIZER2_(f,p) \
static void f(void); \
__declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \
__pragma(comment(linker,"/include:" p #f "_")) \
static void f(void)
#ifdef _WIN64
#define INITIALIZER(f) INITIALIZER2_(f,"")
#else
#define INITIALIZER(f) INITIALIZER2_(f,"_")
#endif
#else
#define INITIALIZER(f) \
static void f(void) __attribute__((constructor)); \
static void f(void)
#endif
INITIALIZER(vl_initialize)
{
vl_constructor();
atexit(vl_destructor);
}