Skip to content

Moving build system to pixi#2037

Open
MJohnson459 wants to merge 75 commits into
masterfrom
pixi
Open

Moving build system to pixi#2037
MJohnson459 wants to merge 75 commits into
masterfrom
pixi

Conversation

@MJohnson459

@MJohnson459 MJohnson459 commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

This moves the entire ODM buildsystem to pixi. This allows us to use prebuild binaries for our libraries massively cutting down the build time, while also introducing a single pixi.toml file to store dependencies.

With this change, anyone should be able to build and run ODM like this:

pixi run build
pixi run odm -- --project-path ~/Projects/datasets/ Block-Michenzani   # e.g.

This should work on Linux (x86, aarch64), Windows, Mac. GPU support is also available by adding a -e gpu argument to the commands.

Changes

  • All non-forked dependencies that are on conda-forge we now use. As much as possible I have pinned the exact version we used before, although that wasn't always possible. GDAL, PDAL, Ceres, and OpenCV are the main ones.
  • In order to preserve versions, there are a few .patch files introduced in SuperBuild. These are mostly lifted from upstream where available or the minimal change I could make to get it working. If we update versions, most of these would go away. I chose to have the patch files here rather than in our forks just to keep this PR consistent and stand-alone. In the future we may prefer to move these patches to our forks.
  • I've updated the github actions to primarily use pixi and added a matrix to test different platforms - Linux (x86, aarch64), Windows, OSX.
  • The Dockerfiles have changed substantially however the final image should be very close to what they were before.
  • The GPU feature enables GPU acceleration for any library that has the option (libarrow, onnxruntime, etc). This might affect behaviour but it definitely affects the size of the installer. There is a trade-off to be made - if the performance difference is worth the size.
  • I've used Ninja on both Linux and Windows to have a single build tool. This works, but I'm not sure if it has a performance impact on Windows. It should give a big speedup to iterative build times as well.

Testing

To ensure this doesn't cause any major regressions, I've been keeping an eye on the following canaries:

  1. Build time from cold - my last test had this go from 40 minutes to 7m on my machine. CI it still takes 20m to 30m depending on the platform.
  2. Checked the output from two datasets, Block-Michenzani and odm_data_aukerman. I have been running these with no additional flags and to my untrained eye the results look pretty consistent.
  3. To maintain feature parity, I've been testing on Linux and Windows with MacOS and ARM64 builds tested in CI. The GPU image I've tested on Windows both natively and in Docker.
  4. The Docker image size has been mostly stable. They have increased slightly but not to a worrying degree.

Missing testing

While I have tested the basics, there are some areas I'm aware I haven't tested enough yet:

  • Various flags and arguments - i.e. non-default features
  • Complicated and larger datasets
  • An experts view on differences on output
  • Mac runtime
  • Arm runtime
  • Runtime performance on all platforms
  • Windows installer

Future work

  • Conda creates portable binaries by default which is good in one sense but will have a performance cost. We could do a pass to improve this using optimized packages if its an issue.
  • For every dependency we had prior, I have tried to tag that exact version in the pixi file. This works but we lose some benefits of pixi such as dependency resolution. We should go through each dependency and bump it as much as we can. We should also loosen the version range as we do this and rely on the pixi.lock file to lock the exact versions.
  • Create and upload ODM to a prefix.dev channel - this would make it a one liner to install and run on any platform.

MJohnson459 added 30 commits May 6, 2026 13:11
A devcontainer is a small wrapper around Docker to make it easy to set
up a clean development environment. Most IDE's and code editors support
these now as well as many cloud environments.

I've included a very simple environment to start with which we can
extend as necessary later to streamline the build process.
This diff adds the pixi file and updates some SuperBuild scripts to
compile. With this we can run `pixi install` and `pixi run build` and
the compilation works.
Output report from before and after pixi are almost identical.
roughly a 6 minute build now
PoissonRecon builds from a hand-written Makefile via `make`, which the
minimal pixi container image does not provide (unlike the CI runners,
which have a system make on PATH). Without it the Docker build failed at
the poissonrecon step with 'make: command not found'.
@smathermather

Copy link
Copy Markdown
Contributor

Related:
OpenDroneMap/oats#8

This is a clunky solution but give we will want to upstream all of these
patches anyway it seems ok for now. It means we can keep them as .patch
files making that transition easier.

In the future, we probably want to relook at how we handle these
external cmake projects but for now I'm avoiding changing too much.
@MJohnson459

Copy link
Copy Markdown
Contributor Author

The patches were trying to apply every time which as they weren't idempotent meant the build failed. Instead I added a small cmake wrapper which checks if the patch was already applied so repeated builds should now work.

@spwoodcock

spwoodcock commented Jul 2, 2026

Copy link
Copy Markdown
Member

Before this PR, I had never heard of pixi.

I'm using uv exclusively for application and library development in Python.

This article gives a good breakdown of the evolution of Python package management, and how to choose between the latest tools uv & pixi: https://jacobtomlinson.dev/posts/2025/python-package-managers-uv-vs-pixi/

Pretty much:
pip --> uv
conda --> pixi

Overall, seems like pixi is a great fit for ODM, requiring both compiled / native dependencies, C++ libs, and CUDA for GPU acceleration - kudos @MJohnson459!

Shapely 2 no longer has `__getitem__` for MultiPolygon, so unary_union
results were written whole instead of picking the largest polygon.
Commit 75a1e1f only fixed one half of that mismatch by changing the
schema to MultiPolygon; Fiona 1.9+ still rejects Polygon records against
a MultiPolygon schema. Use .geoms to select the largest polygon and
declare the GPKG layer as Polygon again.
@MJohnson459
MJohnson459 requested review from DodgySpaniard and smathermather and removed request for smathermather July 2, 2026 14:52
@smathermather

smathermather commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Instructions for installing pixi on mac use curl, but that fails due to some issue with default ssl / curl / mac os x (I think -- will dig in later). So, I installed pixi using Homebrew, and all was pretty smooth until what I think is a memory issue:

2026-07-02 21:18:30,023 DEBUG: Undistorting image DJI_0024.JPG
2026-07-02 21:18:30,160 DEBUG: Undistorting image DJI_0033.JPG
[INFO]    running "/Users/user01/Documents/git/ODM/SuperBuild/install/bin/opensfm/bin/opensfm" export_visualsfm --points "/Users/user01/Desktop/odm_test/drone_dataset_brighton_beach/opensfm"
[INFO]    Finished opensfm stage
[INFO]    Running openmvs stage
[INFO]    running "/Users/user01/Documents/git/ODM/SuperBuild/install/bin/opensfm/bin/opensfm" export_openmvs "/Users/user01/Desktop/odm_test/drone_dataset_brighton_beach/opensfm"
[INFO]    Depthmap resolution set to: 500px
[INFO]    Running dense reconstruction. This might take a while.
[INFO]    Estimating depthmaps
[INFO]    No nvidia-smi detected
[INFO]    running "/Users/user01/Documents/git/ODM/SuperBuild/install/bin/OpenMVS/DensifyPointCloud" "/Users/user01/Desktop/odm_test/drone_dataset_brighton_beach/opensfm/undistorted/openmvs/scene.mvs" --resolution-level 2 --dense-config-file "/Users/user01/Desktop/odm_test/drone_dataset_brighton_beach/opensfm/undistorted/openmvs/Densify.ini" --max-resolution 2000 --min-resolution 640 --max-threads 10 --number-views-fuse 2 --sub-resolution-levels 2 --archive-type 3 -w "/Users/user01/Desktop/odm_test/drone_dataset_brighton_beach/opensfm/undistorted/openmvs/depthmaps" -v 0 --cuda-device -2
dyld[57270]: Library not loaded: @rpath/libboost_iostreams.dylib
  Referenced from: <254CEE38-96AE-3994-A254-3C5BDA650E59> /Users/user01/Documents/git/ODM/SuperBuild/install/bin/OpenMVS/DensifyPointCloud
  Reason: tried: '/libboost_iostreams.dylib' (no such file)
/bin/sh: line 1: 57270 Abort trap: 6           "/Users/user01/Documents/git/ODM/SuperBuild/install/bin/OpenMVS/DensifyPointCloud" "/Users/user01/Desktop/odm_test/drone_dataset_brighton_beach/opensfm/undistorted/openmvs/scene.mvs" --resolution-level 2 --dense-config-file "/Users/user01/Desktop/odm_test/drone_dataset_brighton_beach/opensfm/undistorted/openmvs/Densify.ini" --max-resolution 2000 --min-resolution 640 --max-threads 10 --number-views-fuse 2 --sub-resolution-levels 2 --archive-type 3 -w "/Users/user01/Desktop/odm_test/drone_dataset_brighton_beach/opensfm/undistorted/openmvs/depthmaps" -v 0 --cuda-device -2

===== Dumping Info for Geeks (developers need this to fix bugs) =====
Child returned 134
Traceback (most recent call last):
  File "/Users/user01/Documents/git/ODM/stages/odm_app.py", line 82, in execute
    self.first_stage.run()
  File "/Users/user01/Documents/git/ODM/opendm/types.py", line 465, in run
    self.next_stage.run(outputs)
  File "/Users/user01/Documents/git/ODM/opendm/types.py", line 465, in run
    self.next_stage.run(outputs)
  File "/Users/user01/Documents/git/ODM/opendm/types.py", line 465, in run
    self.next_stage.run(outputs)
  [Previous line repeated 1 more time]
  File "/Users/user01/Documents/git/ODM/opendm/types.py", line 444, in run
    self.process(self.args, outputs)
  File "/Users/user01/Documents/git/ODM/stages/openmvs.py", line 121, in process
    raise e
  File "/Users/user01/Documents/git/ODM/stages/openmvs.py", line 107, in process
    run_densify()
  File "/Users/user01/Documents/git/ODM/stages/openmvs.py", line 102, in run_densify
    system.run('"%s" "%s" %s' % (context.omvs_densify_path,
  File "/Users/user01/Documents/git/ODM/opendm/system.py", line 112, in run
    raise SubprocessException("Child returned {}".format(retcode), retcode)
opendm.system.SubprocessException: Child returned 134

===== Done, human-readable information to follow... =====

[ERROR]   Uh oh! Processing stopped because of strange values in the reconstruction. This is often a sign that the input data has some issues or the software cannot deal with it. Have you followed best practices for data acquisition? See https://docs.opendronemap.org/flying/

@MJohnson459

Copy link
Copy Markdown
Contributor Author

So I ran the full OATS suite overnight just on my dev machine (no GPU, Linux) and the results were fairly promising at least on a pass/fail basis - 48 tests, 11 failures, (attached pic of results to preserve colours). Summarising the failures, there were 3 real bugs.

Screenshot_2026-07-03_10-42-17

Cause A - the latest image has a broken NumPy (6 failures). All of the tests that use --dsm or --dtm failed on the latest image. These passed on the pixi branch. I either fixed this when sorting out dependencies or its fixed in master but not released yet.

Cause B - codem alignment produces no registration.json file (3 failures). This applies to both pixi and latest. For some reason at this step we detect 0 ICP points and don't do the alignment. This seems to apply for both GeoTIFF and LAZ alignment. Note that OATS doesn't clean up properly yet so I think this should really be 4 failures as it affects both tags equally.

Cause C - odm_boruszyn_kap segfaults in both latest and pixi (2 failures). This seems like an outstanding bug:

error: no valid point-cloud for the ROI estimation
Segmentation fault (core dumped)
→ Child returned 139

So in summary, we have at least 2 outstanding bugs before we even look at the output files although neither of these are exclusive to the pixi change. And the latest image is broken for DEM generation.

@MJohnson459 MJohnson459 linked an issue Jul 3, 2026 that may be closed by this pull request
@spwoodcock

spwoodcock commented Jul 3, 2026

Copy link
Copy Markdown
Member

Instructions for installing pixi on mac use curl, but that fails due to some issue with default ssl / curl / mac os x (I think -- will dig in later). So, I installed pixi using Homebrew, and all was pretty smooth until what I think is a memory issue:

dyld[57270]: Library not loaded: @rpath/libboost_iostreams.dylib
  Referenced from: <254CEE38-96AE-3994-A254-3C5BDA650E59> /Users/user01/Documents/git/ODM/SuperBuild/install/bin/OpenMVS/DensifyPointCloud
  Reason: tried: '/libboost_iostreams.dylib' (no such file)
/bin/sh: line 1: 57270 Abort trap: 6

@smathermather
Looks like a missing lib for OpenMVS:
@rpath/libboost_iostreams.dylib

So next step would be to find:

  1. If the lib exists. Something like this:
cd /Users/user01/Documents/git/ODM
pixi shell
find .pixi -name "libboost_iostreams*.dylib"
  1. If yes, find why it's not read. If not, find why its not installed on Mac.

It seems like we weren't setting the RPATH on MacOS correctly. This
change should bake it into the binary matching how it works on Linux.
@MJohnson459

Copy link
Copy Markdown
Contributor Author

@smathermather Looks like a missing lib for OpenMVS: @rpath/libboost_iostreams.dylib

So next step would be to find:

  1. If the lib exists. Something like this:
cd /Users/user01/Documents/git/ODM
pixi shell
find .pixi -name "libboost_iostreams*.dylib"
  1. If yes, find why it's not read. If not, find why its not installed on Mac.

Yea this was it. I don't have a way to test on Mac easily so I was relying on the smoke test which basically just does ./run.py --help. I've extended it a little to also check OpenMVS binaries.

As a fix, the MacOS binaries should now include the RPATH similar to how Linux does it. Please let me know if this helped.

Windows uses a fundamentally different kind of dynamic library loading
so we can't easily check it in smoke.py. Instead lets drop it for now.
@smathermather

Copy link
Copy Markdown
Contributor

As a fix, the MacOS binaries should now include the RPATH similar to how Linux does it. Please let me know if this helped.

Further along:


[INFO]    Finished odm_filterpoints stage
[INFO]    Running odm_meshing stage
[INFO]    Writing ODM Mesh file in: /Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_meshing/odm_mesh.ply
[INFO]    running "/Users/bobbobberson/Documents/git/ODM/SuperBuild/install/bin/PoissonRecon" --in "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_filterpoints/point_cloud.ply" --out "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_meshing/odm_mesh.dirty.ply" --depth 11 --pointWeight 4.0 --samplesPerNode 1.0 --threads 9 --bType 2 --linearFit 
dyld[94363]: Library not loaded: @rpath/libomp.dylib
  Referenced from: <49A3DD28-A115-34E3-A1CA-8904E5979FE4> /Users/bobbobberson/Documents/git/ODM/SuperBuild/install/bin/PoissonRecon
  Reason: tried: '/libomp.dylib' (no such file)
/bin/sh: line 1: 94363 Abort trap: 6           "/Users/bobbobberson/Documents/git/ODM/SuperBuild/install/bin/PoissonRecon" --in "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_filterpoints/point_cloud.ply" --out "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_meshing/odm_mesh.dirty.ply" --depth 11 --pointWeight 4.0 --samplesPerNode 1.0 --threads 9 --bType 2 --linearFit
[WARNING] Child returned 134
[WARNING] PoissonRecon failed with 8 threads, let's retry with 4...
[INFO]    running "/Users/bobbobberson/Documents/git/ODM/SuperBuild/install/bin/PoissonRecon" --in "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_filterpoints/point_cloud.ply" --out "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_meshing/odm_mesh.dirty.ply" --depth 11 --pointWeight 4.0 --samplesPerNode 1.0 --threads 4 --bType 2 --linearFit 
dyld[94366]: Library not loaded: @rpath/libomp.dylib
  Referenced from: <49A3DD28-A115-34E3-A1CA-8904E5979FE4> /Users/bobbobberson/Documents/git/ODM/SuperBuild/install/bin/PoissonRecon
  Reason: tried: '/libomp.dylib' (no such file)
/bin/sh: line 1: 94366 Abort trap: 6           "/Users/bobbobberson/Documents/git/ODM/SuperBuild/install/bin/PoissonRecon" --in "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_filterpoints/point_cloud.ply" --out "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_meshing/odm_mesh.dirty.ply" --depth 11 --pointWeight 4.0 --samplesPerNode 1.0 --threads 4 --bType 2 --linearFit
[WARNING] Child returned 134
[WARNING] PoissonRecon failed with 4 threads, let's retry with 2...
[INFO]    running "/Users/bobbobberson/Documents/git/ODM/SuperBuild/install/bin/PoissonRecon" --in "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_filterpoints/point_cloud.ply" --out "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_meshing/odm_mesh.dirty.ply" --depth 11 --pointWeight 4.0 --samplesPerNode 1.0 --threads 2 --bType 2 --linearFit 
dyld[94368]: Library not loaded: @rpath/libomp.dylib
  Referenced from: <49A3DD28-A115-34E3-A1CA-8904E5979FE4> /Users/bobbobberson/Documents/git/ODM/SuperBuild/install/bin/PoissonRecon
  Reason: tried: '/libomp.dylib' (no such file)
/bin/sh: line 1: 94368 Abort trap: 6           "/Users/bobbobberson/Documents/git/ODM/SuperBuild/install/bin/PoissonRecon" --in "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_filterpoints/point_cloud.ply" --out "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_meshing/odm_mesh.dirty.ply" --depth 11 --pointWeight 4.0 --samplesPerNode 1.0 --threads 2 --bType 2 --linearFit
[WARNING] Child returned 134
[WARNING] PoissonRecon failed with 2 threads, let's retry with 1...
[INFO]    running "/Users/bobbobberson/Documents/git/ODM/SuperBuild/install/bin/PoissonRecon" --in "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_filterpoints/point_cloud.ply" --out "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_meshing/odm_mesh.dirty.ply" --depth 11 --pointWeight 4.0 --samplesPerNode 1.0 --threads 1 --bType 2 --linearFit 
dyld[94370]: Library not loaded: @rpath/libomp.dylib
  Referenced from: <49A3DD28-A115-34E3-A1CA-8904E5979FE4> /Users/bobbobberson/Documents/git/ODM/SuperBuild/install/bin/PoissonRecon
  Reason: tried: '/libomp.dylib' (no such file)
/bin/sh: line 1: 94370 Abort trap: 6           "/Users/bobbobberson/Documents/git/ODM/SuperBuild/install/bin/PoissonRecon" --in "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_filterpoints/point_cloud.ply" --out "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_meshing/odm_mesh.dirty.ply" --depth 11 --pointWeight 4.0 --samplesPerNode 1.0 --threads 1 --bType 2 --linearFit
[WARNING] Child returned 134
[INFO]    running "/Users/bobbobberson/Documents/git/ODM/SuperBuild/install/bin/OpenMVS/ReconstructMesh" -i "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_meshing/odm_mesh.dirty.ply" -o "/Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_meshing/odm_mesh.ply" --archive-type 3 --remove-spikes 0 --remove-spurious 20 --smooth 0 --target-face-num 400000 -v 0
13:54:27 [App     ] OpenMVS x32 v2.2.0
13:54:27 [App     ] Build date: Jul  2 2026, 21:07:54
13:54:27 [App     ] CPU:  (10 cores)
13:54:27 [App     ] RAM: 16.00GB Physical Memory 16.00GB Virtual Memory
13:54:27 [App     ] OS: Darwin 25.5.0 (arm64)
13:54:27 [App     ] Disk: 
13:54:27 [App     ] warning: no SSE compatible CPU or OS detected
13:54:27 [App     ] Command line: ReconstructMesh -i /Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_meshing/odm_mesh.dirty.ply -o /Users/bobbobberson/Desktop/odm_test/drone_dataset_brighton_beach/odm_meshing/odm_mesh.ply --archive-type 3 --remove-spikes 0 --remove-spurious 20 --smooth 0 --target-face-num 400000 -v 0

===== Dumping Info for Geeks (developers need this to fix bugs) =====
Child returned 1
Traceback (most recent call last):
  File "/Users/bobbobberson/Documents/git/ODM/stages/odm_app.py", line 82, in execute
    self.first_stage.run()
  File "/Users/bobbobberson/Documents/git/ODM/opendm/types.py", line 465, in run
    self.next_stage.run(outputs)
  File "/Users/bobbobberson/Documents/git/ODM/opendm/types.py", line 465, in run
    self.next_stage.run(outputs)
  File "/Users/bobbobberson/Documents/git/ODM/opendm/types.py", line 465, in run
    self.next_stage.run(outputs)
  [Previous line repeated 3 more times]
  File "/Users/bobbobberson/Documents/git/ODM/opendm/types.py", line 444, in run
    self.process(self.args, outputs)
  File "/Users/bobbobberson/Documents/git/ODM/stages/odm_meshing.py", line 25, in process
    mesh.screened_poisson_reconstruction(tree.filtered_point_cloud,
  File "/Users/bobbobberson/Documents/git/ODM/opendm/mesh.py", line 201, in screened_poisson_reconstruction
    system.run('"{reconstructmesh}" -i "{infile}" '
  File "/Users/bobbobberson/Documents/git/ODM/opendm/system.py", line 112, in run
    raise SubprocessException("Child returned {}".format(retcode), retcode)
opendm.system.SubprocessException: Child returned 1

===== Done, human-readable information to follow... =====

[ERROR]   Uh oh! Processing stopped because of strange values in the reconstruction. This is often a sign that the input data has some issues or the software cannot deal with it. Have you followed best practices for data acquisition? See https://docs.opendronemap.org/flying/

bobbobberson% pixi shell
 WARN Encountered 1 warning while parsing the manifest:
  ⚠ the `[system-requirements]` table is deprecated in favor of virtual packages on `platforms`
    ╭─[/Users/bobbobberson/Documents/git/ODM/pixi.toml:70:1]
 69 │     
 70 │ ╭─▶ [feature.gpu.system-requirements]
 71 │ ├─▶ cuda = "12.0"
    · ╰──── declare these on the `platforms` entries instead
 72 │     
    ╰────
  help: e.g. platforms = [{ platform = "linux-64", cuda = "12" }]


(odm) bobbobberson% find .pixi -name "libomp.dylib"
.pixi/envs/default/lib/libomp.dylib

Declare the standard OCI labels (revision, source, version, created) in the
runtime stage of Dockerfile and gpu.Dockerfile via build args defaulting to
unknown, and inject the values from the publish workflows so published images
can be mapped back to their source commit.
Add the static title, description, url, documentation, licenses and vendor
OCI image labels to the runtime stage of Dockerfile and gpu.Dockerfile.
Add a docker-build pixi task and scripts/docker-build.py that builds the runtime
image with the GIT_COMMIT, BUILD_DATE and IMAGE_VERSION build args derived from
the working tree, so local images carry the same OCI labels as CI. Point the
README build instructions at the task.
Default the docker-build image tag to opendronemap/odm:<branch> when building
off master (sanitising the branch name for Docker), keeping :latest and :gpu on
master, so local branch builds don't clobber the latest tag.
@spwoodcock

Copy link
Copy Markdown
Member

Oh one other thing to note: I think this PR answers the question in #1960

If we use pre-built packages, then we don't run the build through the ODM build wrapper with -march=nehalem every time.

This would mean we likely drop support for very old CPUs without AVX / AVX2 (as the prebuilt packages will likely include optimised versions for newer architectures).

What do you think @MJohnson459?

@MJohnson459

Copy link
Copy Markdown
Contributor Author

@spwoodcock It's a good point, there's a lot going on in this PR so thanks for bringing it up. I'll try to explain what I've done and you can check me, I spent a bit of time trying to work this out myself.

Conda

For the first piece of the puzzle, Conda compiles any C++ on Linux with these flags (trimmed down for clarity):

CXXFLAGS=-std=c++17 -march=nocona -mtune=haswell -O2

(I will note the documentation on this is lacking right now)

The -march=nocona is circa 2004 CPU which I believe is actually even older than the nehalem one ODM used. This means the pre-compiled libs won't use AVX, etc.

However, unlike the previous ODM build it specifies the -mtune flag which allows certain optimisations for a haswell to be used, without breaking backwards compatibility. This combined with -O2 means I don't really know how the performance compares - I've at least run it locally and the difference isn't noticeable but I haven't measured the performance yet (I'm extending oats to capture more info for this).

Finally, this applies to the generic conda-forge build farm. It's not clear to me if individual libraries can override this or how strict they are about enforcing these defaults.

Superbuild

For the second piece, there are still a few libraries we compile because we have forks. Two of these have -march=native set in their cmake files which overrides anything we do - openmvs and OpenPointClass. The former we patch out in SuperBuild/cmake/mvstexturing.patch. The latter has a PORTABLE_BUILD flag we set in SuperBuild/cmake/External-OpenPointClass.cmake.

I've not explicitly set an -march or -mtune for our Superbuild yet (default for gcc is normally x86-64 on ubuntu) but with OpenPointClass setting nehalem that becomes our effective base.

Summary

The best-practice for C++/cmake libraries is to omit -march entirely and leave it up to the end application to supply flags. I've tried to catch the ones that don't do that and patch them where I can.

Conda sets -march=nocona, Superbuild sets -march=nehalem at most. Overall that means nehalem is likely our baseline, the same as it was before.

It also means we are likely missing some optimisations, but its not as clear cut how much the -mtune makes up for the older instruction set. I mentioned as a next step but there is a way for conda-forge libs to be optimised for architecture but I haven't looked into it much yet. I was holding off until we have a way to measure it.

Does that all make (some) sense?

@spwoodcock

Copy link
Copy Markdown
Member

@spwoodcock It's a good point, there's a lot going on in this PR so thanks for bringing it up. I'll try to explain what I've done and you can check me, I spent a bit of time trying to work this out myself.

Conda

For the first piece of the puzzle, Conda compiles any C++ on Linux with these flags (trimmed down for clarity):

CXXFLAGS=-std=c++17 -march=nocona -mtune=haswell -O2

(I will note the documentation on this is lacking right now)

The -march=nocona is circa 2004 CPU which I believe is actually even older than the nehalem one ODM used. This means the pre-compiled libs won't use AVX, etc.

However, unlike the previous ODM build it specifies the -mtune flag which allows certain optimisations for a haswell to be used, without breaking backwards compatibility. This combined with -O2 means I don't really know how the performance compares - I've at least run it locally and the difference isn't noticeable but I haven't measured the performance yet (I'm extending oats to capture more info for this).

Finally, this applies to the generic conda-forge build farm. It's not clear to me if individual libraries can override this or how strict they are about enforcing these defaults.

Superbuild

For the second piece, there are still a few libraries we compile because we have forks. Two of these have -march=native set in their cmake files which overrides anything we do - openmvs and OpenPointClass. The former we patch out in SuperBuild/cmake/mvstexturing.patch. The latter has a PORTABLE_BUILD flag we set in SuperBuild/cmake/External-OpenPointClass.cmake.

I've not explicitly set an -march or -mtune for our Superbuild yet (default for gcc is normally x86-64 on ubuntu) but with OpenPointClass setting nehalem that becomes our effective base.

Summary

The best-practice for C++/cmake libraries is to omit -march entirely and leave it up to the end application to supply flags. I've tried to catch the ones that don't do that and patch them where I can.

Conda sets -march=nocona, Superbuild sets -march=nehalem at most. Overall that means nehalem is likely our baseline, the same as it was before.

It also means we are likely missing some optimisations, but its not as clear cut how much the -mtune makes up for the older instruction set. I mentioned as a next step but there is a way for conda-forge libs to be optimised for architecture but I haven't looked into it much yet. I was holding off until we have a way to measure it.

Does that all make (some) sense?

It certainly does! That's much clearer 😄 Thank you - I should probably close the linked issue then, as I think it's handled well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Modernise Python setup for repo

3 participants