Skip to content

Avoid modifying the input pixel array in place in wcs_pix2world#19859

Open
astrofrog wants to merge 3 commits into
astropy:mainfrom
astrofrog:fix-p2s-thread-safe-blocked
Open

Avoid modifying the input pixel array in place in wcs_pix2world#19859
astrofrog wants to merge 3 commits into
astropy:mainfrom
astrofrog:fix-p2s-thread-safe-blocked

Conversation

@astrofrog
Copy link
Copy Markdown
Member

@astrofrog astrofrog commented Jun 3, 2026

This is a fix for #16244 and an alternative to #16459

The basic idea here is that instead of modifying the input array in-place (which is very thread-unsafe), we iterate over the coordinates in blocks of 1024 elements. This size was chosen as it results in essentially no measurable overhead - it's an optimal value that is not too small yet fits in a typical L1 cache.

When origin=1, the block size is just the number of coordinates and there is no chunking necessary.

Fixes #16244

  • By checking this box, the PR author has requested that maintainers do NOT use the "Squash and Merge" button. Maintainers should respect this when possible; however, the final decision is at the discretion of the maintainer that merges the PR.

@astrofrog astrofrog requested a review from mcara as a code owner June 3, 2026 09:47
@astrofrog astrofrog added wcs Extra CI Run cron CI as part of PR multi-threading labels Jun 3, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 3, 2026

Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for rebase and squash.
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the bot.
  • Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) before merge.

@astrofrog astrofrog added the benchmark Run benchmarks for a PR label Jun 3, 2026
@astrofrog astrofrog added this to the v8.0.0 milestone Jun 3, 2026
@astrofrog astrofrog added the backport-v8.0.x on-merge: backport to v8.0.x label Jun 3, 2026
@astrofrog astrofrog requested a review from mhvk June 4, 2026 08:30
@astrofrog astrofrog removed the backport-v8.0.x on-merge: backport to v8.0.x label Jun 4, 2026
@astrofrog astrofrog modified the milestones: v8.0.0, v8.1.0 Jun 4, 2026
@astrofrog
Copy link
Copy Markdown
Member Author

I wonder if maybe it's best to not backport and to just say that we are going to focus on thread-safety issues for 8.1.0

Copy link
Copy Markdown
Contributor

@mhvk mhvk left a comment

Choose a reason for hiding this comment

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

This looks good! Two totally nitpicky comments, which can definitely be ignored.

npy_intp block = ncoord;
double* pixscratch = NULL;
if (delta != 0.0 && ncoord > 0) {
block = (ncoord < 1024) ? ncoord : 1024;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since you have access to numpy headers, you could use NPY_BUFSIZE here -- which ends up being the same (it is 8192 bytes).

double* pixscratch = NULL;
if (delta != 0.0 && ncoord > 0) {
block = (ncoord < 1024) ? ncoord : 1024;
pixscratch = (double*)malloc((size_t)block * nelem * sizeof(double));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is nelem typically 2? I'd tend to make the scratch size independent of its value.

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

Labels

benchmark Run benchmarks for a PR Extra CI Run cron CI as part of PR multi-threading wcs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WCS conversion functions modify input array in-place, making them thread-unsafe

2 participants