Skip to content

Commit ce485af

Browse files
authored
Merge pull request #1926 from alicevision/dev/parallelization
Add parallelization tool to optimize chunk computation distribution
2 parents 2528ea9 + 8e52faa commit ce485af

File tree

5 files changed

+89
-45
lines changed

5 files changed

+89
-45
lines changed

meshroom/aliceVision/RelativePoseEstimating.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class RelativePoseEstimating(desc.AVCommandLineNode):
88
size = desc.DynamicNodeSize("input")
99

1010
parallelization = desc.Parallelization(blockSize=25)
11-
commandLineRange = "--rangeStart {rangeStart} --rangeSize {rangeBlockSize}"
11+
commandLineRange = "--rangeIteration {rangeIteration} --rangeBlocksCount {rangeBlocksCount}"
1212

1313
category = "Sparse Reconstruction"
1414
documentation = """Estimate relative pose between each pair of views that share tracks."""

src/aliceVision/system/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ set(system_files_headers
99
ProgressDisplay.hpp
1010
nvtx.hpp
1111
hardwareContext.hpp
12+
Parallelization.hpp
1213
)
1314

1415
# Sources
@@ -20,6 +21,7 @@ set(system_files_sources
2021
ProgressDisplay.cpp
2122
nvtx.cpp
2223
hardwareContext.cpp
24+
Parallelization.cpp
2325
)
2426

2527
alicevision_add_library(aliceVision_system
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// This file is part of the AliceVision project.
2+
// Copyright (c) 2025 AliceVision contributors.
3+
// This Source Code Form is subject to the terms of the Mozilla Public License,
4+
// v. 2.0. If a copy of the MPL was not distributed with this file,
5+
// You can obtain one at https://mozilla.org/MPL/2.0/.
6+
7+
#pragma once
8+
9+
#include <aliceVision/system/Logger.hpp>
10+
#include <aliceVision/system/Parallelization.hpp>
11+
12+
namespace aliceVision {
13+
14+
bool rangeComputation(int & rangeStart, int & rangeEnd, int rangeIteration, int rangeBlocksCount, int itemsCount)
15+
{
16+
rangeIteration = std::max(0, rangeIteration);
17+
rangeBlocksCount = std::max(1, rangeBlocksCount);
18+
19+
if (itemsCount <= rangeBlocksCount)
20+
{
21+
//Just split 1 per iteration
22+
rangeStart = rangeIteration;
23+
rangeEnd = rangeStart + 1;
24+
}
25+
else
26+
{
27+
// Distribute data among available chunks
28+
const int chunkSize = itemsCount / rangeBlocksCount;
29+
const int reminder = itemsCount % rangeBlocksCount;
30+
31+
// Reminder is distributed among first iterations
32+
const int shift = std::min(rangeIteration, reminder);
33+
const int reminded = (rangeIteration < reminder)?1:0;
34+
35+
rangeStart = rangeIteration * chunkSize + shift;
36+
rangeEnd = rangeStart + chunkSize + reminded;
37+
}
38+
39+
rangeEnd = std::min(rangeEnd, itemsCount);
40+
41+
return (rangeStart < itemsCount);
42+
}
43+
44+
} // namespace aliceVision
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// This file is part of the AliceVision project.
2+
// Copyright (c) 2025 AliceVision contributors.
3+
// This Source Code Form is subject to the terms of the Mozilla Public License,
4+
// v. 2.0. If a copy of the MPL was not distributed with this file,
5+
// You can obtain one at https://mozilla.org/MPL/2.0/.
6+
7+
#pragma once
8+
9+
10+
namespace aliceVision {
11+
12+
/**
13+
* Utility function to compute range of values to process
14+
* Assuming we have itemsCount items in a container.
15+
* @param[out] rangeStart is the first element index to process
16+
* @param[out] rangeEnd is the last element index to process (non included)
17+
* @param rangeIteration is the iteration number
18+
* @param rangeBlocksCount is the number of iterations launched in parallel
19+
* @return false if nothing has to be processed in this iteration
20+
*/
21+
bool rangeComputation(int & rangeStart, int & rangeEnd, int rangeIteration, int rangeBlocksCount, int itemsCount);
22+
23+
} // namespace aliceVision

src/software/pipeline/main_relativePoseEstimating.cpp

Lines changed: 19 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <aliceVision/system/Timer.hpp>
1111
#include <aliceVision/system/Logger.hpp>
1212
#include <aliceVision/system/main.hpp>
13+
#include <aliceVision/system/Parallelization.hpp>
1314
#include <aliceVision/cmdline/cmdline.hpp>
1415

1516
#include <aliceVision/sfmData/SfMData.hpp>
@@ -140,8 +141,8 @@ int aliceVision_main(int argc, char** argv)
140141
std::string sfmDataFilename;
141142
std::string tracksFilename;
142143
std::string outputDirectory;
143-
int rangeStart = -1;
144-
int rangeSize = 1;
144+
int rangeIteration = 0;
145+
int rangeBlocksCount = 1;
145146
size_t minInliers = 35;
146147
bool enforcePureRotation = false;
147148
size_t countIterations = 1024;
@@ -166,8 +167,8 @@ int aliceVision_main(int argc, char** argv)
166167
("minInliers", po::value<size_t>(&minInliers)->default_value(minInliers), "Minimal number of inliers for a valid ransac.")
167168
("imagePairsList,l", po::value<std::vector<std::string>>(&predefinedPairList)->multitoken(),
168169
"Path(s) to one or more files which contain the list of image pairs to match.")
169-
("rangeStart", po::value<int>(&rangeStart)->default_value(rangeStart), "Range image index start.")
170-
("rangeSize", po::value<int>(&rangeSize)->default_value(rangeSize), "Range size.");
170+
("rangeIteration", po::value<int>(&rangeIteration)->default_value(rangeIteration), "Chunk id.")
171+
("rangeBlocksCount", po::value<int>(&rangeBlocksCount)->default_value(rangeBlocksCount), "Chunk count.");
171172
// clang-format on
172173

173174
CmdLine cmdline("AliceVision relativePoseEstimating");
@@ -193,33 +194,6 @@ int aliceVision_main(int argc, char** argv)
193194
return EXIT_FAILURE;
194195
}
195196

196-
// Define range to compute
197-
if(rangeStart != -1)
198-
{
199-
if(rangeStart < 0 || rangeSize < 0)
200-
{
201-
ALICEVISION_LOG_ERROR("Range is incorrect");
202-
return EXIT_FAILURE;
203-
}
204-
205-
if (rangeStart > sfmData.getViews().size())
206-
{
207-
ALICEVISION_LOG_INFO("Empty range to compute");
208-
return EXIT_SUCCESS;
209-
}
210-
211-
if(rangeStart + rangeSize > sfmData.getViews().size())
212-
{
213-
rangeSize = sfmData.getViews().size() - rangeStart;
214-
}
215-
}
216-
else
217-
{
218-
rangeStart = 0;
219-
rangeSize = sfmData.getViews().size();
220-
}
221-
ALICEVISION_LOG_DEBUG("Range to compute: rangeStart=" << rangeStart << ", rangeSize=" << rangeSize);
222-
223197

224198
// Load tracks
225199
ALICEVISION_LOG_INFO("Load tracks from " << tracksFilename << ".");
@@ -233,20 +207,14 @@ int aliceVision_main(int argc, char** argv)
233207
ALICEVISION_LOG_INFO("Compute co-visibility");
234208
std::map<Pair, unsigned int> covisibility;
235209

236-
int chunkStart = 0;
237-
int chunkEnd = 0;
210+
238211

239212
if (predefinedPairList.empty())
240213
{
241214
//Compute covisibility for tracks
242215
//This will get the list of pair of views which observe common features
243216
ALICEVISION_LOG_INFO("Automatically select pairs.");
244217
track::computeCovisibility(covisibility, tracksHandler.getAllTracks());
245-
246-
//Divide the work among chunks
247-
double ratioChunk = double(covisibility.size()) / double(sfmData.getViews().size());
248-
chunkStart = int(double(rangeStart) * ratioChunk);
249-
chunkEnd = int(double(rangeStart + rangeSize) * ratioChunk);
250218
}
251219
else
252220
{
@@ -256,7 +224,7 @@ int aliceVision_main(int argc, char** argv)
256224
PairSet pairs;
257225

258226
ALICEVISION_LOG_INFO("Load pair list from file: " << imagePairsFile);
259-
if (!matchingImageCollection::loadPairsFromFile(imagePairsFile, pairs, rangeStart, rangeSize))
227+
if (!matchingImageCollection::loadPairsFromFile(imagePairsFile, pairs, 0, -1))
260228
{
261229
return EXIT_FAILURE;
262230
}
@@ -273,10 +241,12 @@ int aliceVision_main(int argc, char** argv)
273241
covisibility[other] = 1;
274242
}
275243
}
244+
}
276245

277-
//Just process everything as it was already filtered during file loading
278-
chunkStart = 0;
279-
chunkEnd = covisibility.size();
246+
int chunkStart, chunkEnd;
247+
if (!rangeComputation(chunkStart, chunkEnd, rangeIteration, rangeBlocksCount, covisibility.size()))
248+
{
249+
ALICEVISION_LOG_INFO("Nothing to compute in this chunk");
280250
}
281251

282252
ALICEVISION_LOG_INFO("A total of " << covisibility.size() << " pairs has to be processed.");
@@ -287,11 +257,11 @@ int aliceVision_main(int argc, char** argv)
287257

288258
ALICEVISION_LOG_INFO("Process co-visibility");
289259
std::stringstream ss;
290-
ss << outputDirectory << "/pairs_" << rangeStart << ".json";
260+
ss << outputDirectory << "/pairs_" << rangeIteration << ".json";
291261
std::ofstream of(ss.str());
292262

293263
// For each covisible pair
294-
#pragma omp parallel for
264+
#pragma omp parallel for schedule(dynamic)
295265
for (int posPairs = chunkStart; posPairs < chunkEnd; posPairs++)
296266
{
297267
auto iterPairs = covisibility.begin();
@@ -311,6 +281,11 @@ int aliceVision_main(int argc, char** argv)
311281
aliceVision::track::TracksMap mapTracksCommon;
312282
track::getCommonTracksInImagesFast({refImage, nextImage}, tracksHandler.getAllTracks(), tracksHandler.getTracksPerView(), mapTracksCommon);
313283

284+
if (mapTracksCommon.size() == 0)
285+
{
286+
continue;
287+
}
288+
314289
// Build features coordinates matrices
315290
const std::size_t n = mapTracksCommon.size();
316291
std::vector<Eigen::Vector2d> refpts, nextpts;

0 commit comments

Comments
 (0)