As pointed out by several users, introduction of parallel operations on
vectors severely impacts solver performance on small problems, with time
consumption increasing with the number of threads.
In order to minimize overhead of trying to execute small tasks using a
large number of threads, task scheduling mechanism was changed to avoid
scheduling all tasks at once.
However, there is still a large difference in exectuion time because the
main thread always launches the next thread before starting doing the
work. This leads to several orders of magnitude slowdown when going from
a single-threaded execution (which follows a fast-forward path to a
single loop over all indices, without any synchronization involved)
to a two-thread execution:
/bin/parallel_vector_operations_benchmark
-------------------------------------------
Benchmark Time
-------------------------------------------
SetZero/128 12.8 ns
SetZeroParallel/128/1 16.6 ns
SetZeroParallel/128/2 2211 ns
In order to eliminate this effect, we limit the block-size of parallel
execution of vector operations to 2^16 elements (thus, starting parallel
execution only for vectors of at least 2^17 elements).
Threshold of 2^16 elements was choosen by evaluating thresholds from
2^10 to 2^20 (only powers of 2), with 2^14..2^20 significantly reducing
worst-case runtime degradation.
Details can be found in discussion of the issue at
https://github.com/ceres-solver/ceres-solver/issues/1016
Change-Id: I555c882d63ee53323ceb426743b970f989b65503
Parallelization of remaining block-diagonal matrix-vector product and
vector operations makes parallel execution slightly faster
Before (Intel 8176 CPU, 10 iterations):
-----------------------------------------------------------------------
Benchmark Time
-----------------------------------------------------------------------
PSEPreconditioner...<problem-13682-4456117-pre.txt>/1_median 26677 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/1_stddev 26.6 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/2_median 31037 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/2_stddev 191 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/4_median 16915 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/4_stddev 98.0 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/8_median 9175 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/8_stddev 44.1 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/16_median 4974 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/16_stddev 11.5 ms
After:
-----------------------------------------------------------------------
Benchmark Time
-----------------------------------------------------------------------
PSEPreconditioner...<problem-13682-4456117-pre.txt>/1_median 26609 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/1_stddev 69.4 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/2_median 29178 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/2_stddev 367 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/4_median 16152 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/4_stddev 106 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/8_median 8773 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/8_stddev 41.5 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/16_median 4800 ms
PSEPreconditioner...<problem-13682-4456117-pre.txt>/16_stddev 14.7 ms
Change-Id: Ib1d1b0c4edf9c556a9e996c49486d2726efcc558
1. Add a version history
2. Update copyright years across the code base
3. Run format_all.sh
4. Update version strings from 2.1.0 to 2.2.0 in the docs and
elsewhere.
Change-Id: I46d8d479d54bd6002d532785e67342106e73c9ac
Main focus of this change is to parallelize remaining operations (most of them
are operations on vectors) in code-path utilized with iterative Schur
complement.
Parallelization is handled using lazy evaluation of Eigen expressions.
On linux pc with intel 8176 processor parallelization of vector operations has
the following effect:
Running ./bin/parallel_vector_operations_benchmark
Run on (112 X 3200.32 MHz CPU s)
CPU Caches:
L1 Data 32 KiB (x56)
L1 Instruction 32 KiB (x56)
L2 Unified 1024 KiB (x56)
L3 Unified 39424 KiB (x2)
Load Average: 3.30, 8.41, 11.82
-----------------------------------
Benchmark Time
-----------------------------------
SetZero 10009532 ns
SetZeroParallel/1 10024139 ns
...
SetZeroParallel/16 877606 ns
Negate 4978856 ns
NegateParallel/1 5145413 ns
...
NegateParallel/16 721823 ns
Assign 10731408 ns
AssignParallel/1 10749944 ns
...
AssignParallel/16 1829381 ns
D2X 15214399 ns
D2XParallel/1 15623245 ns
...
D2XParallel/16 2687060 ns
DivideSqrt 8220050 ns
DivideSqrtParallel/1 9088467 ns
...
DivideSqrtParallel/16 905569 ns
Clamp 3502010 ns
ClampParallel/1 4507897 ns
...
ClampParallel/16 759576 ns
Norm 4426782 ns
NormParallel/1 4442805 ns
...
NormParallel/16 430290 ns
Dot 9023276 ns
DotParallel/1 9031304 ns
...
DotParallel/16 1157267 ns
Axpby 14608289 ns
AxpbyParallel/1 14570825 ns
...
AxpbyParallel/16 2672220 ns
-----------------------------------
Multi-threading of vector operations in ISC and program evaluation results into
the following improvement:
Running ./bin/evaluation_benchmark
--------------------------------------------------------------------------------------
Benchmark this 2fd81de
--------------------------------------------------------------------------------------
Residuals<problem-13682-4456117-pre.txt>/1 4136 ms 4292 ms
Residuals<problem-13682-4456117-pre.txt>/2 2919 ms 2670 ms
Residuals<problem-13682-4456117-pre.txt>/4 2065 ms 2198 ms
Residuals<problem-13682-4456117-pre.txt>/8 1458 ms 1609 ms
Residuals<problem-13682-4456117-pre.txt>/16 1152 ms 1227 ms
ResidualsAndJacobian<problem-13682-4456117-pre.txt>/1 19759 ms 20084 ms
ResidualsAndJacobian<problem-13682-4456117-pre.txt>/2 10921 ms 10977 ms
ResidualsAndJacobian<problem-13682-4456117-pre.txt>/4 6220 ms 6941 ms
ResidualsAndJacobian<problem-13682-4456117-pre.txt>/8 3490 ms 4398 ms
ResidualsAndJacobian<problem-13682-4456117-pre.txt>/16 2277 ms 3172 ms
Plus<problem-13682-4456117-pre.txt>/1 339 ms 322 ms
Plus<problem-13682-4456117-pre.txt>/2 220 ms
Plus<problem-13682-4456117-pre.txt>/4 128 ms
Plus<problem-13682-4456117-pre.txt>/8 78.0 ms
Plus<problem-13682-4456117-pre.txt>/16 49.8 ms
ISCRightMultiplyAndAccumulate<problem-13682-4456117-pre.txt>/1 2434 ms 2478 ms
ISCRightMultiplyAndAccumulate<problem-13682-4456117-pre.txt>/2 2706 ms 2688 ms
ISCRightMultiplyAndAccumulate<problem-13682-4456117-pre.txt>/4 1430 ms 1548 ms
ISCRightMultiplyAndAccumulate<problem-13682-4456117-pre.txt>/8 742 ms 883 ms
ISCRightMultiplyAndAccumulate<problem-13682-4456117-pre.txt>/16 438 ms 555 ms
ISCRightMultiplyAndAccumulateDiag<problem-13682-4456117-pre.txt>/1 2438 ms 2481 ms
ISCRightMultiplyAndAccumulateDiag<problem-13682-4456117-pre.txt>/2 2565 ms 2790 ms
ISCRightMultiplyAndAccumulateDiag<problem-13682-4456117-pre.txt>/4 1434 ms 1551 ms
ISCRightMultiplyAndAccumulateDiag<problem-13682-4456117-pre.txt>/8 765 ms 892 ms
ISCRightMultiplyAndAccumulateDiag<problem-13682-4456117-pre.txt>/16 435 ms 559 ms
JacobianSquaredColumnNorm<problem-13682-4456117-pre.txt>/1 1278 ms
JacobianSquaredColumnNorm<problem-13682-4456117-pre.txt>/2 1555 ms
JacobianSquaredColumnNorm<problem-13682-4456117-pre.txt>/4 833 ms
JacobianSquaredColumnNorm<problem-13682-4456117-pre.txt>/8 459 ms
JacobianSquaredColumnNorm<problem-13682-4456117-pre.txt>/16 250 ms
JacobianScaleColumns<problem-13682-4456117-pre.txt>/1 1468 ms
JacobianScaleColumns<problem-13682-4456117-pre.txt>/2 1871 ms
JacobianScaleColumns<problem-13682-4456117-pre.txt>/4 957 ms
JacobianScaleColumns<problem-13682-4456117-pre.txt>/8 528 ms
JacobianScaleColumns<problem-13682-4456117-pre.txt>/16 294 ms
End-to-end improvements with bundle_adjuster invoked with
./bin/bundle_adjuster --num_threads 28 --num_iterations 40 \
--linear_solver iterative_schur \
--preconditioner jacobi --input
---------------------------------------------
Problem this 2fd81de
---------------------------------------------
problem-13682-4456117-pre.txt 508.6 892.7
problem-1778-993923-pre.txt 763.8 1129.9
problem-1723-156502-pre.txt 6.3 14.4
problem-356-226730-pre.txt 76.3 116.2
problem-257-65132-pre.txt 38.6 52.0
Change-Id: Ie31cc5015f13fa479c16ffb5ce48c9b880990d49
1. Convert it from a class to a template function. Where the
template parameter is "DenseVectorType". This allows us
to have a single implementation of Conjugate Gradients
without worrying about where the matrix and the vectors
are stored or what their internal representation is.
For the case of CPU based vectors, we abstract operations
on Eigen vectors using eigen_vector_ops.
2. Introduce ConjugateGradientsLinearOperator which is
templated on DenseVectorType. It is the matrix vector
multiplication abstraction.
3. Port the tests and all usages of ConjugateGradientsSolver
to this new implementation.
4. Introduce Eigen::Vector based RightMultiply and LeftMultiply
methods into LinearOperator which by default delete to the
bare pointer based interfaces.
5. Add an identity preconditioner.
These changes are being made in preparation for adding a CUDA
based CGNR solver.
Change-Id: I9da36dc6c131856dd1a4aa7e645aaf12d25dd79b