Commit Graph

7 Commits

Author SHA1 Message Date
Sameer Agarwal 3c4f012606 ClangTidy fixes #2
Change-Id: Ib3baa62248342276d63b900b45561323fd81402d
2024-07-21 20:31:32 -07:00
Sameer Agarwal 0ca2db57c7 Fix a number of typos
Change-Id: I0038f9c91dc70c422c01305dc10fca5a22a2f0d0
2024-07-21 15:15:36 -07:00
Sameer Agarwal 68eeba2c2c Add a missing include
Change-Id: I3060e80a69374f7a2db31121715d0d892a54d311
2024-07-21 13:25:45 -07:00
Sameer Agarwal 57e26182f3 Add more missing headers
Change-Id: I35875ca856b7b80c622562a1c14b4c8ced10f740
2024-07-18 11:37:07 -07:00
Dmitriy Korchemkin dc7a859752 Single-threaded operations on small vectors
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
2023-10-09 13:55:30 +00:00
Dmitriy Korchemkin 354002f989 Schedule task in ParallerFor from the previous task
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.

The problem is two-fold:
 - Single-threaded execution is faster than multi-threaded
 - Overhead of multi-threaded execution increases dramaticaly when
   number of threads is increased

Supposedly, the second problem is due to ParallelInvoke scheduling
a task for each thread via ThreadPool.
When the time required to perform computations is smaller than costs of
scheduling task, runtime becomes linear in num_threads.
Moreover, main thread competes with working threads for mutex in
ConcurrentQueue.

In order to limit scheduling overhead and minimize lock contention,
each new task is scheduled from the previous one, if:
 - Number of scheduled tasks is less than num_threads
 - At the moment of creating the task not all work has been done

Correctness is granted by atomicity of thread_id counter.

SchedulerBenchmark mini-benchmark was added to illustrate the issue.
Each iteration of parallel loop performs change of a single value.

With the previous scheduling strategy, increasing number of threads
leads to significant increase of runtime:
-----------------------------------------------------
Benchmark                           Time   Iterations
-----------------------------------------------------
SchedulerBenchmark/128/1         14.1 ns     49496153
SchedulerBenchmark/128/2         3965 ns       240173
SchedulerBenchmark/128/4        13162 ns        71478
SchedulerBenchmark/128/8        30643 ns        29614
SchedulerBenchmark/128/16       63694 ns        10000
SchedulerBenchmark/256/1         24.1 ns     28943598
SchedulerBenchmark/256/2         3878 ns       227498
SchedulerBenchmark/256/4        13293 ns        69817
SchedulerBenchmark/256/8        31117 ns        32640
SchedulerBenchmark/256/16       59503 ns        14910
SchedulerBenchmark/1024/1        56.7 ns     12048398
SchedulerBenchmark/1024/2        4346 ns       203140
SchedulerBenchmark/1024/4       13487 ns        66736
SchedulerBenchmark/1024/8       30982 ns        33090
SchedulerBenchmark/1024/16      63199 ns        14762
SchedulerBenchmark/4096/1         189 ns      3633540
SchedulerBenchmark/4096/2        5932 ns       131884
SchedulerBenchmark/4096/4       14784 ns        61236
SchedulerBenchmark/4096/8       35857 ns        29276
SchedulerBenchmark/4096/16      63934 ns        10000

With new scheduling strategy, increasing requested number of threads
does not result in that high increase of runtime
-----------------------------------------------------
Benchmark                           Time   Iterations
-----------------------------------------------------
SchedulerBenchmark/128/1         14.1 ns     49323498
SchedulerBenchmark/128/2         2411 ns       362916
SchedulerBenchmark/128/4         3556 ns       243026
SchedulerBenchmark/128/8         4346 ns       200626
SchedulerBenchmark/128/16        5066 ns       169698
SchedulerBenchmark/256/1         24.2 ns     28960018
SchedulerBenchmark/256/2         2330 ns       388470
SchedulerBenchmark/256/4         3864 ns       219233
SchedulerBenchmark/256/8         4399 ns       195225
SchedulerBenchmark/256/16        5111 ns       161858
SchedulerBenchmark/1024/1        55.9 ns     12204777
SchedulerBenchmark/1024/2        2541 ns       329807
SchedulerBenchmark/1024/4        3977 ns       222628
SchedulerBenchmark/1024/8        4607 ns       193548
SchedulerBenchmark/1024/16       5031 ns       160285
SchedulerBenchmark/4096/1         188 ns      3714433
SchedulerBenchmark/4096/2        4203 ns       188284
SchedulerBenchmark/4096/4        4832 ns       171811
SchedulerBenchmark/4096/8        5605 ns       159093
SchedulerBenchmark/4096/16       6425 ns       126861

(both runs were executed on 28-core 56-thread cpu)

Change-Id: I91eca783280598997bfe6abd28019847731692e4
2023-10-06 20:25:16 +00:00
Dmitriy Korchemkin 54ad3dd03c Reorganize ParallelFor source files
Change-Id: Ic4941919e59210b48e447cbb61e539200c8c89df
2023-04-11 00:33:55 +03:00