Skip to content

Fix the compiler warnings reported by CI, and build the examples - #742

Merged
DiamonDinoia merged 15 commits into
flatironinstitute:masterfrom
DiamonDinoia:fix/740
Aug 20, 2026
Merged

Fix the compiler warnings reported by CI, and build the examples#742
DiamonDinoia merged 15 commits into
flatironinstitute:masterfrom
DiamonDinoia:fix/740

Conversation

@DiamonDinoia

@DiamonDinoia DiamonDinoia commented Oct 24, 2025

Copy link
Copy Markdown
Collaborator

Supersedes the original contents of this PR (issue #740). The large example
modernization that was here has been split off into a separate branch; what is
left is the minimal set of changes that clears the warnings and stops the
examples from rotting again.

  • chore: fix all compiler warnings reported by CI - every warning in the
    GitHub and Jenkins logs, fixed at the source rather than suppressed: unused
    argc/argv, MSVC C4296 in interp.hpp, -Wshadow/-Wsign-compare/
    -Wunused-variable in the spread and interp headers. main is now spelled
    int main() everywhere it takes no arguments, C and C++ alike. The
    mwrap-generated mex gateways are generated code, so matlab/CMakeLists.txt
    drops the warning flags for those targets only.
  • refactor: drop the leftovers of the removed non-prolate kernels - three of
    the four guru_benchmark arms measured only SkipWithError since the ES and
    Kaiser-Bessel formulas started returning FINUFFT_ERR_KERFORMULA_NOTVALID.
  • chore: drop using-namespace-std from the library sources.
  • test: build and run the examples in CI - nothing built them, so they had
    rotted: three were missing from the CMake build, the single-precision ones
    asked for more modes than float can resolve and returned
    FINUFFT_ERR_EPS_TOO_SMALL, four leaked their finufft_opts, the CUDA ones
    ignored every return code, and threadsafe1d1 dropped ier so it could not
    fail as a test. The three guru examples now fill opts first and only touch a
    field inside the if, which deletes the else and, in the C one, a free()
    of a pointer that stays uninitialized whenever the demo is off.
  • chore: include what the library actually uses - include-what-you-use over
    the compile database, library sources only.

Verified: 0 warnings and a green ctest on both the dev (FFTW) and dev-ducc
presets with FINUFFT_BUILD_DEVEL=ON; the 16 CPU example tests pass under the
valgrind job's exact memcheck flags with no definite leaks; the CUDA build and
its 4 example tests pass on sm_89.

@mreineck

Copy link
Copy Markdown
Collaborator

This looks good, but I still think that using plain abs() in a C++ code (as is happening in other places of finufft) is an accident waiting to happen. Including <math.h> is archaic C++ for 27 years now, and if things go wrong, they tend to go wrong very subtly and require tedious debugging.
It's happened to me, and I've seen it happen to several other people ... but this can definitely wait for a follow-up patch.

@DiamonDinoia

Copy link
Copy Markdown
Collaborator Author

@mreineck I totally agree. We should not use abs in .cpp code. The issue with std::abs is when used on thrust::complex

@DiamonDinoia

Copy link
Copy Markdown
Collaborator Author

I turned that warning in an error. To mitigate the issue. Let me try having a go at fixing this.

@ahbarnett

Copy link
Copy Markdown
Collaborator

When I include std:: in testutils, as in this new version, tests pass fine on my linux machine with GCC 11.4.
So, I don't understand the CI "illegal" errors.

Note that in some sources in test/ I have using namespace std; which is probably bad practice but saved a lot of typing of std:: for math.
I also used fabs in many places.

Happy to insert std:: everywhere needed.

@mreineck

Copy link
Copy Markdown
Collaborator

The "illegal" errors are unrelated, I'm quite sure. I just have no idea what is causing them.

@lu1and10

Copy link
Copy Markdown
Member

the CI "illegal" errors.

@ahbarnett I'm not sure why CI breaks so often. One possible reason is, to accelerate the ci runs, @DiamonDinoia uses sccache in ci to cache the compiled object files(.o) from previous ci runs, if the previous ci run was ran on avx512 machine with flag -march=native, and the next ci run re-uses the cached object files and run on avx2 machine, there might be illegal instructions.

What is the "key" that sccache used to distinguish changes(currently how sccache decide to reuse .o files or not), besides the C++ flags, does sscache distinguish cpu instructions?

Currently, it seems with "-march=native", the ci may break with reused object files, I guess.

@mreineck

mreineck commented Oct 24, 2025

Copy link
Copy Markdown
Collaborator

Oh! If files compiled with -march=native are re-used on different hardware, the "illegal" makes perfect sense ... it's a cut-down "illegal instruction" error.

But CI should definitely never do this ...

And "illegal instruction" should not be truncated like this ... strange,

@lu1and10

Copy link
Copy Markdown
Member

But CI should definitely never do this ...

Yes, not sure if it's sccache problem. If it is, we should tell it, machine changed, with -march=native, please rerun no reuse...

@DiamonDinoia

DiamonDinoia commented Oct 24, 2025

Copy link
Copy Markdown
Collaborator Author

But CI should definitely never do this ...

Yes, not sure if it's sccache problem. If it is, we should tell it, machine changed, with -march=native, please rerun no reuse...

Worth opening a separate issue for it. We could add the instruction set from lscpu to the key. Or manually set the vector width. This allows to test different vectorizations same as xsimd does.

PS: @lu1and10 that's a very good guess! I was wondering what the problem was too.

@lu1and10

Copy link
Copy Markdown
Member

We could add the instruction set from lscpu to the key.

Good idea, we can retain the ci speedup from sccache and at the same time avoid illegal instructions.

@DiamonDinoia

Copy link
Copy Markdown
Collaborator Author

@mreineck I went ahead and remove using namespace std and fixed all the compiler warning/errors that originates from it (-werror has be incredibly useful).

I also fixed examples and one documentation file containing using namespace std. I don't think we should encourage bad practices.

I ran this though an LLM to tell me if I missed something and it says it is okay.

@mreineck, @lu1and10 what do you think?

@DiamonDinoia

Copy link
Copy Markdown
Collaborator Author

@blackwer I am a confused by examples/cuda/getting_started.cpp it seems to me a c file masquerading as cpp.

@mreineck

Copy link
Copy Markdown
Collaborator

Hi @DiamonDinoia, this is of course the cleanest approach to fix the issue (and also prevent it from happening again)!

I wouldn't say that using namespace std; is bad practice in general; it's only unconditionally bad if you "force" it onto users by putting it unprotected in a header file. Apart from that it can save a lot of typing; you only need to make sure that you are not using any "C-like" headers (like <math.h>).

That said, I like the change very much as it is, even though it touches a lot of files!

int m = 0;
for (int m2 = -(N2 / 2); m2 <= (N2 - 1) / 2; ++m2) // loop in correct order over F
for (int m1 = -(N1 / 2); m1 <= (N1 - 1) / 2; ++m1)
ct += fkstart[m++] * exp(J * (m1 * x[jt] + m2 * y[jt])); // crude direct

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, the exp seems to be missing a std::. Don't put too much trust in LLMs :)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

grep was my best friend here...

@blackwer

Copy link
Copy Markdown
Member

@blackwer I am a confused by examples/cuda/getting_started.cpp it seems to me a c file masquerading as cpp.

This whole package was written with as C plus some stuff. It's fine to update it to a more proper C++ style. It was just consistent with the way everything else was written.

@ahbarnett ahbarnett left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this. It's good you enforced the correct abs and exp etc in the library source and tests.

I feel that it makes the example codes much less readable. I would prefer the examples to simply using namespace std; because they are so limited, short, and designed for humans to read (Would it be a pain to just git checkout the examples from master, and fix the header from math.h to cmath ?). Ie, I think the PR got a little too big in scope, beyond just making sure the src/tests were secure.

In fact the whole thing makes me depressed about C++ ... what's the point of a language where you have to write std:: in front of every other function? Declaring complex vectors is particularly ugly now, as is any stdio stuff. It's not like we are inserting using namespace std; into a header file that affects other people here. It is just there to make clean, short, source codes for testing and examples.

Thoughts?

Comment thread examples/guru1d1.cpp Outdated
c[j] =
2 * ((double)rand() / RAND_MAX) - 1 + 1i * (2 * ((double)rand() / RAND_MAX) - 1);
c[j] = 2 * ((double)std::rand() / RAND_MAX) - 1 +
std::complex<double>(0.0, 1.0) *

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use I which was defined above for a reason? I must say this std:: everywhere is highly unpleasant! I'm not sure why in our example codes we're killing using namespace std; ....

Comment thread examples/guru1d1.cpp Outdated
c[j] =
2 * ((double)rand() / RAND_MAX) - 1 + 1i * (2 * ((double)rand() / RAND_MAX) - 1);
c[j] = 2 * ((double)std::rand() / RAND_MAX) - 1 +
std::complex<double>(0.0, 1.0) *

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I

Comment thread examples/guru1d1.cpp
x[j] = PI * (2 * ((double)rand() / RAND_MAX) - 1); // uniform random in [-pi,pi)
x[j] = PI * (2 * ((double)std::rand() / RAND_MAX) - 1); // uniform random in [-pi,pi)
// note FINUFFT doesn't use std::vector types, so we need to make a pointer...
finufft_setpts(plan, M, x.data(), NULL, NULL, 0, NULL, NULL, NULL);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nullptr ? Surely it doesn't matter since setpts ignores them.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed it. I'll fix it.

Comment thread examples/guru1d1f.cpp Outdated
x[j] = PI * (2 * ((float)std::rand() / RAND_MAX) - 1); // uniform random in [-pi,pi)
// note FINUFFT doesn't use std::vector types, so we need to make a pointer...
finufftf_setpts(plan, M, &x[0], NULL, NULL, 0, NULL, NULL, NULL);
finufftf_setpts(plan, M, &x[0], nullptr, nullptr, 0, nullptr, nullptr, nullptr);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

x.data()

Comment thread examples/guru2d1.cpp Outdated
int ier = finufft_makeplan(type, dim, Ns, +1, ntrans, tol, &plan, nullptr);
// step 2: send in M nonuniform points (just x, y in this case)...
finufft_setpts(plan, M, &x[0], &y[0], NULL, 0, NULL, NULL, NULL);
finufft_setpts(plan, M, &x[0], &y[0], nullptr, 0, nullptr, nullptr, nullptr);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

x.data() etc

Comment thread perftest/spreadtestnd.cpp Outdated
@@ -2,25 +2,20 @@
#include <finufft/spreadinterp.h>
#include <finufft/test_defs.h>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like adding using namespace std::printf etc to test_defs.h would make this a whole lot less ugly...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea! We can also add I to test_defs.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and rand

Comment thread src/c_interface.cpp Outdated

#include <finufft_common/common.h>
#include <cufinufft.h>
#include <finufft_common/common.h>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this header ordering is important, please add a comment...

Comment thread test/dumbinputs.cpp
F[k] = std::sin((FLT)0.7 * k) + IMA * std::cos((FLT)0.3 * k); // set F for t2
ier = FINUFFT1D2(M, x, c, +1, 0, N, F, &opts);
if (ier != FINUFFT_WARN_EPS_TOO_SMALL) {
printf("1d2 tol=0:\twrong err code %d\n", ier);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming printf is fine here, thank god! Not sure why it wasn't fine earlier...

Comment thread test/finufft3d_test.cpp
free(u);
if (isnan(errmax) || (errmax > errfail)) {
if (std::isnan(errmax) || (errmax > errfail)) {
printf("\tfailed! err %.3g > errfail %.3g\n", errmax, errfail);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hoping printf is fine here... please :)

@DiamonDinoia

DiamonDinoia commented Oct 28, 2025

Copy link
Copy Markdown
Collaborator Author

In general I do not like using exp in c++ or abs without std:: because I never know if I am calling a compiler builtin with implicit conversion or an actual function. One way to make is safer is to use -Wconversion

@ahbarnett

Copy link
Copy Markdown
Collaborator

Once kerformdef is in master, we should tweak this PR on enforcing std:: and bring in. I think it's easy enough for v2.5 inclusion... thoughts?

@DiamonDinoia

Copy link
Copy Markdown
Collaborator Author

I will have a look after kerformdef is merged and propose a plan.

DiamonDinoia added a commit that referenced this pull request Aug 12, 2026
…native

The step branched on 'avx512 in /proc/cpuinfo' and otherwise fell through to
-march=native, so the ISA the job built for depended on which runner it drew.
That is the same shape as the stale-object bug lu1and10 diagnosed in #742: an
arch flag that is not an explicit, stable string. c23a132 removed native from
the two sccache-backed workflows; this is the last one left.

Walk the x86-64 psABI levels against lscpu's flag list and pass the highest one
the runner actually supports, capped at v3 because valgrind's JIT does not cover
all of AVX-512 (which is what the old avx512 branch was really guarding against).
A v2-only runner now gets -march=x86-64-v2 instead of a native string nobody can
reproduce.

Verified by extracting the step's run body from the parsed YAML and executing it
under bash -e (GitHub's default shell) with cmake stubbed: v3 on this AVX2 host,
and v2 / x86-64 on simulated flag sets.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
@DiamonDinoia DiamonDinoia changed the title Fix 740 Fix the compiler warnings reported by CI, and build the examples Aug 12, 2026
@DiamonDinoia
DiamonDinoia changed the base branch from master to jenkins-cuda-matrix August 12, 2026 21:23
github-actions Bot added a commit that referenced this pull request Aug 14, 2026
github-actions Bot added a commit that referenced this pull request Aug 14, 2026
github-actions Bot added a commit that referenced this pull request Aug 14, 2026
github-actions Bot added a commit that referenced this pull request Aug 14, 2026
@DiamonDinoia
DiamonDinoia marked this pull request as ready for review August 15, 2026 00:26
@DiamonDinoia

Copy link
Copy Markdown
Collaborator Author

I finally had time to look at this and now I fixed (with @claude) all the compiler warnings. I tried to keep the changes minimal. Bundled with a small other issues that emerged while going at this.

@DiamonDinoia

Copy link
Copy Markdown
Collaborator Author

@ahbarnett or @lu1and10 if you are happy with the result we can merge, otherwise let me know what to change.

The tree aligns consecutive `=` and trailing comments by hand, but
`AlignConsecutiveAssignments: None` and `AlignTrailingComments: Leave`
let clang-format flatten that alignment on every file it touches.
Turning both on makes the formatter reproduce the existing style
instead of fighting it.

`AcrossEmptyLinesAndComments` matches the `AlignConsecutiveMacros`
setting already in the file, and keeps blocks such as
`finufft_default_opts` in one column across their blank lines.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Walked every warning in the GitHub and Jenkins logs and fixed it at the source
rather than suppressing it. The recurring ones:

* unused parameters: examples, tests and perftests declared `int main(int argc,
  char *argv[])` without reading either. `main` is now spelled `int main()`
  everywhere it takes no arguments, C and C++ alike; the ones that genuinely
  parse argv are untouched. `int main()` in C is only diagnosed under
  -Wpedantic, which the build applies to the library targets in src/ and
  nothing else.
* MSVC C4296 in interp.hpp: an `if constexpr` comparison that is always true for
  the instantiated widths. Guarded, with a static_assert next to it so the
  tail-handling stays provably complete.
* -Wshadow / -Wsign-compare / -Wunused-variable in the spread and interp
  headers, foldrescale and binsort_bench.
* the mwrap-generated mex gateways are generated code we do not edit, so
  matlab/CMakeLists.txt drops the warning flags for those targets only.

Also folds in the code-review findings on the first pass: round_down/round_up
gain runtime overloads so kernel_buffer_stride_runtime and its compile-time
mirror share one implementation and cannot drift, plus a static_assert that the
alignment fits in T before the mask is formed.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
80a7a49 made the PSWF the only kernel, so spread_kerformula 1-6 now return
FINUFFT_ERR_KERFORMULA_NOTVALID. Two things were left behind:

* nothing calls cyl_bessel_i any more, so the series implementation in
  src/common/utils.cpp, its __cpp_lib_math_special_functions feature detection,
  the two declarations in the header and the std-vs-series comparison in
  testutils all go.
* devel/guru_benchmark.cpp swept formulas 0, 1, 3 and 4, so three of its four
  arms only measured SkipWithError. It now sweeps the surviving PSWF shape
  choices 7, 8 and 9; checked against the library that 0/7/8/9 give ier=0 and
  1/3/4 give ier=24.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
Two .cpp files pulled the whole of std into the global namespace; fft.cpp then
needed a comment explaining that <algorithm> was included because the directive
hid std::min. Qualify the handful of uses instead and drop the note. The docs
snippet in opts.rst gets the same treatment so the documented example matches
the library's own style.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
include-what-you-use over the compile database, acting only on the library
(the ~46 remaining suggestions are std-header shuffling in examples, tests and
devel, which is churn for no gain):

* src/common/utils.cpp did not include its own header, so nothing checked its
  definitions against finufft_common/utils.h. It also reached PI and std::max
  transitively.
* kernel.cpp used MAX_AUTO_UPSAMPFAC/PI/PSWF0, std::min/max and std::function
  through other headers; pswf.cpp did the same for FINUFFT_ERR_PSWF_SETUP,
  std::fill and std::swap.
* pswf.h used an unqualified size_t with no <cstddef>.

Dependency headers were audited at the same time and are all the public entry
points already - <xsimd/xsimd.hpp>, <fftw3.h>, <cufft.h>, <cuComplex.h>,
<cuda_runtime.h>, <poet/poet.hpp>, thrust/*.h. Two look internal and are not:
xsimd/config/xsimd_config.hpp has to be read before xsimd.hpp to override
XSIMD_DEFAULT_ARCH when no architecture is supported, and ducc0's public fft.h
only *declares* c2c - the header-only definition is in fftnd_impl.h, so that
include stays, now with a comment saying why. IWYU's one opinion about a
dependency points the wrong way (it wants xsimd/types/xsimd_batch.hpp in place
of the umbrella header) and is rejected.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
The function takes an int debug it never reads (unlike its sibling
set_kernel_shape_given_ns, which reports on it), so -Wextra flags it in every
Debug build. Two of the three callers already passed a literal 0.
MAX_NF allows a fine-grid dimension up to 1e12, and set_nf_type12 hands one to
next235, whose long argument holds 32 bits on Windows. The wrapped value is
negative, the std::max(n, 1) inside clamps it to 1, and the call returns 2: a
silently tiny grid rather than a crash. good_size_235 already works in size_t,
so the narrow type only ever lived in the wrapper. fine_grid_len returns BIGINT
for the same reason.

testutils now rounds a dimension above 2^31, so the guard runs on the platform
that has the bug.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
CI compiled the examples already - cmake_ci, cmake_sanitizers, valgrind and
fortran all resolve to a preset inheriting dev, which sets
FINUFFT_BUILD_EXAMPLES=ON - but no job ever ran one, so nothing checked what
they compute, leak or return. Registering them as ctest tests turned up five
separate problems, all fixed here:

* three examples (simple2d1, gurumany1d1, spreadinterponly1d) were missing from
  examples/CMakeLists.txt entirely - the makefile globs, CMake enumerates.
* the single-precision examples asked for N=1e5 modes in float. Rounding in the
  deconvolve step floors the relative error near 0.5*FLT_EPSILON*N, which at
  N=1e5 is ~6e-3, so makeplan returned FINUFFT_ERR_EPS_TOO_SMALL and the math
  check was meaningless. N drops to 1e4 (and tol to 1e-3 in guru1d1f); they now
  return ier=0 at 3.2e-4, 3.2e-4 and 8.7e-5.
* four examples never deleted their `new finufft_opts`, a definite leak under
  ctest -T memcheck. The struct has no reason to be on the heap; many1d1 did not
  even pass it to the transform.
* the CUDA examples discarded every cufinufft return value, so they exited 0
  whatever failed. They now bail on ier > 1 (0 is success, 1 a usable warning).
* threadsafe1d1 dropped ier on the floor, so as a ctest test it could not fail;
  it now reports like threadsafe2d2f already did, both setting the flag inside an
  `omp critical` rather than racing on it. Not a `reduction(max:)`: MSVC defaults
  to OpenMP 2.0, which has no min/max reductions (error C7660).
* the three guru examples branched on `changeopts` to call makeplan with either
  &opts or NULL. Filling opts first and only touching a field inside the if
  deletes the else; in the C one it also deletes the malloc and the free() of a
  pointer that stays uninitialized whenever the demo is off, which is how it
  ships - undefined behaviour the memcheck job would eventually catch.

The GitHub jobs need no workflow change: the presets above already build the
examples, and powerpc sets the flag explicitly. Jenkins gets
-DFINUFFT_BUILD_EXAMPLES=ON and runs ctest from the build root rather than
build/test/cuda - the same tests plus the four CUDA examples, since perftest/cuda
registers none.

All 16 CPU examples pass in 2s and 132s at -j4 under the valgrind job's exact
memcheck flags, with no definite leaks; the four CUDA ones pass on sm_89.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
The fortran CI preset builds with DUCC0 (fortran inherits dev-ducc in
CMakePresets.json), and fortran/CMakeLists.txt drops guru1d1 from
FORTRAN_EXAMPLES when DUCC0 is on. Neither guru example is therefore built by
any CI job, and two defects sat there unnoticed.

guru1d1.f and guru1d1f.f include 'fftw3.f' for the FFTW plan-mode constants,
but the fortran targets never received FFTW's include directory, so the build
stopped with "Cannot open included file 'fftw3.f'". The two guru targets now
link finufft_fftlibs, which carries that directory in both FFTW
configurations; FFTW_INCLUDE_DIRS is populated only when a system FFTW is
found, not when CPM downloads one. The TARGET guard keeps the DUCC0 build
configuring, since guru1d1 is absent there.

guru1d1f.f then segfaulted. In single precision the rounding floor is
0.48 * eps_mach * gridlen, so tol=1e-5 at N=1e5 is unachievable: setpts
returns ier=26, and execute dereferences a plan that has no grid. The example
now asks for tol=1e-3 at N=1e4, matching its C++ twin.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
A warning nobody trips over is a warning that comes back: master had already
grown a fresh -Wunused-parameter since this branch fixed the last batch. The
COMPILE_WARNING_AS_ERROR property goes on the two library targets only, the same
ones finufft_apply_compile_settings gives the warning flags to, so no dependency
in the build tree is judged by our flags.

Errors then demand that every CI compiler agree on what a warning is:

- The library copies finufft_opts, and an implicit copy member reads every
  field, so clang reports the deprecated ones. Its own sources build with
  FINUFFT_NO_DEPRECATED_FIELDS, which drops the attribute. A pragma around the
  struct would not do: clang keys the diagnostic to the point where the implicit
  member is first required, and delayed template parsing, its default on Windows,
  moves that point out of any such region. The definition stays PRIVATE, so a
  user's call site still warns.
- -fno-semantic-interposition is an ELF flag. clang accepts it on Mach-O and on
  COFF, then warns that it went unused, which the try_compile filter cannot
  observe. Add the flag on ELF targets only.
- clang 18 reports a lone -fcx-limited-range as overriding the empty option it
  compares against, which clang 19 fixed, so clang builds disable that
  diagnostic. RelWithDebInfo also listed the Release flags twice; it now appends
  the Debug flags alone.
- MSVC reports narrowing conversions, shadowing and alignas padding, which GCC
  and clang leave to -Wconversion, -Wshadow and -Wpadded. This project asks for
  none of the three, so disable that set and hold every compiler to one level.
  C4702 joins it for xsimd, whose templates this library instantiates.

The MSVC set applies to every configuration, not only the ones that add /W4:
/W3 is CMake's default there, so a Release build reports C4244 as well.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
docs/opts.rst promises that showwarn=0 suppresses warnings, and makeplan.hpp
keeps that promise: nine error paths print unconditionally and then throw,
four showwarn gates guard a message that does not throw, and the two sets
never overlap.

check_sigma printed unconditionally. tolsweep already defaults showwarn=0 and
passes it to opts, yet contributed 849 of the test suite's 864 warning lines,
because it sweeps tol past the achievable floor on purpose.

The error still always speaks; only the warning now obeys showwarn. The suite
drops to 12 warning lines, all in tests where the warning is the assertion.

One warning still escapes the gate: the non-OpenMP branch of makeplan.hpp
warns that opts.nthreads>1 is ignored, without consulting showwarn. That
build is rare and the site is left untouched here.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
`run_tolsweep_double` takes 1353 s under valgrind in CI, against ctest's
1500 s default. Running the examples as tests raises the suite from 26
to 42 entries, and the valgrind workflow calls `ctest -j` with no bound,
so the extra contention pushes tolsweep past the default and the job
fails on a timeout rather than on a defect.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
@flatiron-jenkins

flatiron-jenkins commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

CPU

A band that brackets 1.00 resolved nothing; read the table, not the point estimate.

FFT backends: DUCC0. Intel(R) Xeon(R) Gold 6140 CPU @ 2.30GHz, 64 usable processors, 32 physical cores, x86-64-v4. Baseline master c3471b5.

perftest plot

FINUFFT perftest plot

how the benchmarks are measured

Ratio is master/PR-head time: >1 means the PR is faster. Time is makeplan plus setpts plus execute on both halves; the GPU host transfers stage the harness's own test data, so no library change moves them and they are left out. Each case runs 8 rounds with the two binaries interleaved and their order alternating; each arm is tabulated at its median round and the band spans the per-round ratios. A ratio is bold where the band excludes 1.00, which is where the run resolved a change; every other row resolved nothing. Every option a caller may leave alone is left alone (sorting, upsampling factor, kernel choice), so a change to one of finufft's heuristics shows up here as the change in time it causes. The thread count is the exception: a case is defined by the count it runs at.

per-case timings
case master (ms) PR head (ms) ratio band
fft:DUCC0 type:1 prec:f N1:1e4 N2:1 N3:1 ntransf:1 threads:1 M:1e7 tol:2e-3 341.37 340.97 1.00x 0.99-1.01
fft:DUCC0 type:2 prec:f N1:1e4 N2:1 N3:1 ntransf:1 threads:1 M:1e7 tol:2e-3 79.09 79.12 1.00x 0.97-1.07
fft:DUCC0 type:3 prec:f N1:1e4 N2:1 N3:1 ntransf:1 threads:1 M:1e7 tol:2e-3 564.90 561.65 1.01x 0.99-1.01
fft:DUCC0 type:1 prec:d N1:1e4 N2:1 N3:1 ntransf:1 threads:1 M:1e7 tol:1e-9 400.68 401.40 1.00x 0.99-1.01
fft:DUCC0 type:2 prec:d N1:1e4 N2:1 N3:1 ntransf:1 threads:1 M:1e7 tol:1e-9 150.81 149.55 1.01x 0.98-1.11
fft:DUCC0 type:3 prec:d N1:1e4 N2:1 N3:1 ntransf:1 threads:1 M:1e7 tol:1e-9 822.88 820.46 1.00x 1.00-1.01
fft:DUCC0 type:1 prec:f N1:320 N2:320 N3:1 ntransf:1 threads:1 M:1e7 tol:1e-4 564.26 561.63 1.00x 1.00-1.01
fft:DUCC0 type:2 prec:f N1:320 N2:320 N3:1 ntransf:1 threads:1 M:1e7 tol:1e-4 630.79 632.32 1.00x 0.97-1.05
fft:DUCC0 type:3 prec:f N1:320 N2:320 N3:1 ntransf:1 threads:1 M:1e7 tol:1e-4 781.54 777.20 1.01x 1.00-1.01
fft:DUCC0 type:1 prec:d N1:320 N2:320 N3:1 ntransf:1 threads:1 M:1e7 tol:1e-9 783.61 768.89 1.02x 1.01-1.02
fft:DUCC0 type:2 prec:d N1:320 N2:320 N3:1 ntransf:1 threads:1 M:1e7 tol:1e-9 844.90 853.95 0.99x 0.94-1.00
fft:DUCC0 type:3 prec:d N1:320 N2:320 N3:1 ntransf:1 threads:1 M:1e7 tol:1e-9 1230.18 1228.89 1.00x 1.00-1.01
fft:DUCC0 type:1 prec:f N1:320 N2:320 N3:1 ntransf:1 threads:0 M:3e5 tol:1e-4 39.49 39.40 1.00x 0.99-1.01
fft:DUCC0 type:2 prec:f N1:320 N2:320 N3:1 ntransf:1 threads:0 M:3e5 tol:1e-4 35.57 35.19 1.01x 0.97-1.08
fft:DUCC0 type:3 prec:f N1:320 N2:320 N3:1 ntransf:1 threads:0 M:3e5 tol:1e-4 112.60 108.84 1.03x 0.91-1.07
fft:DUCC0 type:1 prec:d N1:192 N2:192 N3:128 ntransf:1 threads:0 M:8e4 tol:1e-7 287.08 282.76 1.02x 0.70-1.30
fft:DUCC0 type:2 prec:d N1:192 N2:192 N3:128 ntransf:1 threads:0 M:8e4 tol:1e-7 191.75 191.41 1.00x 0.94-1.05
fft:DUCC0 type:3 prec:d N1:192 N2:192 N3:128 ntransf:1 threads:0 M:8e4 tol:1e-7 700.96 691.03 1.01x 0.86-1.16
microarchitecture and compiler

Microarchitecture: skylake_avx512

Compiler: c++ (GCC) 13.3.1 20240611 (Red Hat 13.3.1-2)

Flags: -march=native

perftest commands
taskset -c 1 master/build-DUCC0/perftest/perftest --arg --prec=f --N1=1e4 --N2=1 --N3=1 --ntransf=1 --threads=1 --M=1e7 --tol=2e-3 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=1
taskset -c 1 master/build-DUCC0/perftest/perftest --arg --prec=f --N1=1e4 --N2=1 --N3=1 --ntransf=1 --threads=1 --M=1e7 --tol=2e-3 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=2
taskset -c 1 master/build-DUCC0/perftest/perftest --arg --prec=f --N1=1e4 --N2=1 --N3=1 --ntransf=1 --threads=1 --M=1e7 --tol=2e-3 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=3
taskset -c 6 master/build-DUCC0/perftest/perftest --arg --prec=d --N1=1e4 --N2=1 --N3=1 --ntransf=1 --threads=1 --M=1e7 --tol=1e-9 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=1
taskset -c 6 master/build-DUCC0/perftest/perftest --arg --prec=d --N1=1e4 --N2=1 --N3=1 --ntransf=1 --threads=1 --M=1e7 --tol=1e-9 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=2
taskset -c 6 master/build-DUCC0/perftest/perftest --arg --prec=d --N1=1e4 --N2=1 --N3=1 --ntransf=1 --threads=1 --M=1e7 --tol=1e-9 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=3
taskset -c 3 master/build-DUCC0/perftest/perftest --arg --prec=f --N1=320 --N2=320 --N3=1 --ntransf=1 --threads=1 --M=1e7 --tol=1e-4 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=1
taskset -c 3 master/build-DUCC0/perftest/perftest --arg --prec=f --N1=320 --N2=320 --N3=1 --ntransf=1 --threads=1 --M=1e7 --tol=1e-4 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=2
taskset -c 3 master/build-DUCC0/perftest/perftest --arg --prec=f --N1=320 --N2=320 --N3=1 --ntransf=1 --threads=1 --M=1e7 --tol=1e-4 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=3
taskset -c 8 master/build-DUCC0/perftest/perftest --arg --prec=d --N1=320 --N2=320 --N3=1 --ntransf=1 --threads=1 --M=1e7 --tol=1e-9 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=1
taskset -c 8 master/build-DUCC0/perftest/perftest --arg --prec=d --N1=320 --N2=320 --N3=1 --ntransf=1 --threads=1 --M=1e7 --tol=1e-9 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=2
taskset -c 8 master/build-DUCC0/perftest/perftest --arg --prec=d --N1=320 --N2=320 --N3=1 --ntransf=1 --threads=1 --M=1e7 --tol=1e-9 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=3
master/build-DUCC0/perftest/perftest --prec=f --N1=320 --N2=320 --N3=1 --ntransf=1 --threads=0 --M=9600000 --tol=1e-4 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=1
master/build-DUCC0/perftest/perftest --prec=f --N1=320 --N2=320 --N3=1 --ntransf=1 --threads=0 --M=9600000 --tol=1e-4 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=2
master/build-DUCC0/perftest/perftest --prec=f --N1=320 --N2=320 --N3=1 --ntransf=1 --threads=0 --M=9600000 --tol=1e-4 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=3
master/build-DUCC0/perftest/perftest --prec=d --N1=192 --N2=192 --N3=128 --ntransf=1 --threads=0 --M=2560000 --tol=1e-7 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=1
master/build-DUCC0/perftest/perftest --prec=d --N1=192 --N2=192 --N3=128 --ntransf=1 --threads=0 --M=2560000 --tol=1e-7 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=2
master/build-DUCC0/perftest/perftest --prec=d --N1=192 --N2=192 --N3=128 --ntransf=1 --threads=0 --M=2560000 --tol=1e-7 --n_runs=5 --sort=2 --upsampfact=0 --debug=0 --type=3

GPU

Tesla V100-PCIE-16GB, 7.0, 16384 MiB, 580.159.03. Baseline master c3471b5.

cuperftest plot

cuFINUFFT perftest plot

how the benchmarks are measured

Ratio is master/PR-head time: >1 means the PR is faster. Time is makeplan plus setpts plus execute on both halves; the GPU host transfers stage the harness's own test data, so no library change moves them and they are left out. Each case runs 8 rounds with the two binaries interleaved and their order alternating; each arm is tabulated at its median round and the band spans the per-round ratios. A ratio is bold where the band excludes 1.00, which is where the run resolved a change; every other row resolved nothing. Every option a caller may leave alone is left alone (sorting, upsampling factor, kernel choice), so a change to one of finufft's heuristics shows up here as the change in time it causes. The thread count is the exception: a case is defined by the count it runs at.

per-case timings
case master (ms) PR head (ms) ratio band
type:1 prec:f N1:1e4 N2:1 N3:1 ntransf:1 M:1e7 tol:2e-3 9.99 9.99 1.00x 0.99-1.01
type:2 prec:f N1:1e4 N2:1 N3:1 ntransf:1 M:1e7 tol:2e-3 8.78 8.77 1.00x 0.99-1.01
type:3 prec:f N1:1e4 N2:1 N3:1 ntransf:1 M:1e7 tol:2e-3 13.84 13.86 1.00x 0.99-1.00
type:1 prec:d N1:1e4 N2:1 N3:1 ntransf:1 M:1e7 tol:1e-9 12.02 12.03 1.00x 0.98-1.01
type:2 prec:d N1:1e4 N2:1 N3:1 ntransf:1 M:1e7 tol:1e-9 9.78 9.80 1.00x 0.98-1.03
type:3 prec:d N1:1e4 N2:1 N3:1 ntransf:1 M:1e7 tol:1e-9 25.27 25.19 1.00x 1.00-1.01
type:1 prec:f N1:320 N2:320 N3:1 ntransf:1 M:1e7 tol:1e-4 24.14 24.16 1.00x 1.00-1.01
type:2 prec:f N1:320 N2:320 N3:1 ntransf:1 M:1e7 tol:1e-4 12.76 12.75 1.00x 1.00-1.01
type:3 prec:f N1:320 N2:320 N3:1 ntransf:1 M:1e7 tol:1e-4 54.21 54.17 1.00x 1.00-1.00
type:1 prec:d N1:320 N2:320 N3:1 ntransf:1 M:1e7 tol:1e-9 86.33 86.36 1.00x 1.00-1.00
type:2 prec:d N1:320 N2:320 N3:1 ntransf:1 M:1e7 tol:1e-9 14.61 14.60 1.00x 0.99-1.01
type:3 prec:d N1:320 N2:320 N3:1 ntransf:1 M:1e7 tol:1e-9 107.49 107.54 1.00x 1.00-1.00
type:1 prec:f N1:320 N2:320 N3:1 ntransf:1 M:3e5 tol:1e-4 91.41 91.43 1.00x 1.00-1.00
type:2 prec:f N1:320 N2:320 N3:1 ntransf:1 M:3e5 tol:1e-4 47.02 47.06 1.00x 1.00-1.00
type:3 prec:f N1:320 N2:320 N3:1 ntransf:1 M:3e5 tol:1e-4 205.13 205.18 1.00x 1.00-1.00
type:1 prec:d N1:192 N2:192 N3:128 ntransf:1 M:8e4 tol:1e-7 268.16 268.36 1.00x 1.00-1.00
type:2 prec:d N1:192 N2:192 N3:128 ntransf:1 M:8e4 tol:1e-7 67.80 67.74 1.00x 0.99-1.00
type:3 prec:d N1:192 N2:192 N3:128 ntransf:1 M:8e4 tol:1e-7 914.53 914.43 1.00x 1.00-1.00
device and toolkit

Device: Tesla V100-PCIE-16GB, 7.0, 16384 MiB, 580.159.03

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2025 NVIDIA Corporation
Built on Fri_Feb_21_20:23:50_PST_2025
Cuda compilation tools, release 12.8, V12.8.93
Build cuda_12.8.r12.8/compiler.35583870_0
cuperftest commands
master/build/perftest/cuda/cuperftest --prec=f --N1=1e4 --N2=1 --N3=1 --ntransf=1 --M=1e7 --tol=2e-3 --type=1 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=f --N1=1e4 --N2=1 --N3=1 --ntransf=1 --M=1e7 --tol=2e-3 --type=2 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=f --N1=1e4 --N2=1 --N3=1 --ntransf=1 --M=1e7 --tol=2e-3 --type=3 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=d --N1=1e4 --N2=1 --N3=1 --ntransf=1 --M=1e7 --tol=1e-9 --type=1 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=d --N1=1e4 --N2=1 --N3=1 --ntransf=1 --M=1e7 --tol=1e-9 --type=2 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=d --N1=1e4 --N2=1 --N3=1 --ntransf=1 --M=1e7 --tol=1e-9 --type=3 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=f --N1=320 --N2=320 --N3=1 --ntransf=1 --M=1e7 --tol=1e-4 --type=1 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=f --N1=320 --N2=320 --N3=1 --ntransf=1 --M=1e7 --tol=1e-4 --type=2 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=f --N1=320 --N2=320 --N3=1 --ntransf=1 --M=1e7 --tol=1e-4 --type=3 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=d --N1=320 --N2=320 --N3=1 --ntransf=1 --M=1e7 --tol=1e-9 --type=1 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=d --N1=320 --N2=320 --N3=1 --ntransf=1 --M=1e7 --tol=1e-9 --type=2 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=d --N1=320 --N2=320 --N3=1 --ntransf=1 --M=1e7 --tol=1e-9 --type=3 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=f --N1=320 --N2=320 --N3=1 --ntransf=1 --M=37200000 --tol=1e-4 --type=1 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=f --N1=320 --N2=320 --N3=1 --ntransf=1 --M=37200000 --tol=1e-4 --type=2 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=f --N1=320 --N2=320 --N3=1 --ntransf=1 --M=37200000 --tol=1e-4 --type=3 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=d --N1=192 --N2=192 --N3=128 --ntransf=1 --M=9920000 --tol=1e-7 --type=1 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=d --N1=192 --N2=192 --N3=128 --ntransf=1 --M=9920000 --tol=1e-7 --type=2 --n_runs=5 --sort=1 --debug=0
master/build/perftest/cuda/cuperftest --prec=d --N1=192 --N2=192 --N3=128 --ntransf=1 --M=9920000 --tol=1e-7 --type=3 --n_runs=5 --sort=1 --debug=0

@mreineck mreineck left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! Just a few minor comments...

finufft_setpts(plan, M, &x[0], &y[0], nullptr, 0, nullptr, nullptr, nullptr);
// step 3: do the adjoint of the planned transform. This maps
// c strength data, to F output, and is identical to the type 1 with isign=+1.
finufft_execute_adjoint(plan, &c[0], &F[0]);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, and then probably also NULL->nullptr.

Comment thread examples/cuda/example2d1many.cpp Outdated
nmodes[2] = 1;

ier = cufinufftf_makeplan(type, dim, nmodes, iflag, ntransf, tol, &dplan, NULL);
if (ier > 1) return ier;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and in analogous places: perhaps change to if (ier > 0), since the special "eps too small" warning case will go away soon (or already is fully gone)?

Bare abs() with <cmath> in scope is not guaranteed to resolve to the
floating-point overload; on some toolchains it picks the C int abs(),
silently truncating the argument. Switch the two FP call sites in the
CUDA spreader to std::abs to match the workaround suggested in flatironinstitute#740.
cufinufft_makeplan returned FINUFFT_WARN_EPS_TOO_SMALL (code 1) when tol was
clamped up to eps_mach. That code was the only positive non-error code the
library produced. Both clamp sites in setup_spreadinterp already warn on
stderr, so the return code carried nothing the caller cannot read there.

Drop the plan flag and return 0. The enum entry stays for ABI and is annotated
as retired. This discharges the two FIXMEs that asked for the legacy code-1
mapping in safe_call.h and the local alias in c_interface.cpp to go once the
GPU stopped returning the code.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
The checks used ier > 1 because code 1 was a warning the caller could tolerate.
That code is retired, so every code the library returns is an error. Compare
against 0 in tests, perftests and examples.

Assisted-by: Claude Opus 5 <noreply@anthropic.com>
@DiamonDinoia
DiamonDinoia merged commit 10f3753 into flatironinstitute:master Aug 20, 2026
43 checks passed
@DiamonDinoia
DiamonDinoia deleted the fix/740 branch August 20, 2026 16:05
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.

6 participants