Skip to content

Synchronize cypari2 stack and Python lifecycle #180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

ptrrsn
Copy link

@ptrrsn ptrrsn commented Jul 10, 2025

This PR attempts to fix #112.

As explained in #112, the main reason for the leak is that the cypari2 stack (not to be confused with PARI stack) holds ownership of the Gen objects. Therefore, the primary way for the Gen objects to be cleaned up is when the cypari2 stack reaches a certain threshold (half the maximum size) that triggers a cleanup.

For example, consider the following example from #112:

while True:
  M = pari.matrix(10, 10, range(100))

The behavior before this PR: on the second iteration, the old value of M is not deallocated because the cypari2 stack still holds a reference to it.

This PR solves this problem mainly by replacing cypari2 stack's reference to the Gens object to use weakref. In the above example, after this PR, on the second iteration, the old value of M will be deallocated because cypari2 only holds a weak reference to M, not a strong reference.

Therefore, the primary change introduced here is to replace Gen.next with a weak reference. To accommodate that, the following changes are made:

  1. Because there is no hidden ownership by cypari2 stack, Gen object deallocations now can happen more often and in any order. When the Gen object is in the middle of cypari2 stack, we need to move everything below it to the heap to avoid the stack being fragmented.
  2. Each object is now responsible only for its gunclone (hence, no gunclone_deep), even if it is a container type like matrix or vector. Therefore, an object in the PARI heap only needs a reference count of 1 and never needs to be 2, removing the complications of ref_target (which can increase ref count by 2). At the Python level, non-default entries are hold in Gen.itemcache of its container and will be deallocated when the itemcache is cleared. There is an exception for this and it is documented in the comment inside the move_gens_to_heap method.

The PR was tested with make check and memory leak checks similar to examples given in #112.

As a note, there is a tricky side effect of this PR explained in: #180 (comment)

@ptrrsn
Copy link
Author

ptrrsn commented Jul 10, 2025

cc @dimpase @tobiasdiez

@ptrrsn
Copy link
Author

ptrrsn commented Jul 10, 2025

TLDR, with this PR, the lifecycle of cypari2 objects behaves similarly to that of Python objects, while keeping the PARI stack and heap mechanics underneath up to a certain extent (please see the side effect above).

@dimpase
Copy link
Member

dimpase commented Jul 10, 2025

@tornaria @NathanDunfield @culler

Could you have a look please?

@soehms
Copy link
Member

soehms commented Jul 11, 2025

I'm not sure if this is related. But may I take the occasion to pull attention of Pari / Capari2 experts to sagemath/sage#40081.

In this PR I try to integrate Khoca as an optional package into Sage. Khoca is mainly written in C++ and uses native Pari (for Smith-form calculations). When I first tried to integrate it (in 2021) I got seg-faults from the Cypari2 interface (explicitely in _new_GEN_from_fmpz_mat_t_rotate90, see LLewark/khoca#3 (comment)). In this first step, Khoca was build from source in Sage.

In the meantime, I have made some improvements to the corresponding PyPI package. In particular, there are now binary wheels for Linux an MacOS. But even now sporadically a SystemError: calling remove_from_pari_stack() inside sig_on() is raised in one of the doctest (see LLewark/khoca#3 (comment) item 4).

I would apreciate if someone can take a look at it and help to bring this ahead. Thank you in advance!

@ptrrsn
Copy link
Author

ptrrsn commented Jul 11, 2025

@soehms Thank you for your comment. I am not an expert but I can try to debug the problem in your PR. I will drop comments in your PR later.

@ptrrsn
Copy link
Author

ptrrsn commented Jul 11, 2025

By the way, I made a mistake about the side effect in my original PR description (which I have edited). As an illustration, consider the following code:

while True:
  a = pari.matrix(...)
  b = pari.matrix(...)
  c = pari.matrix(...)
  d = pari.matrix(...)

Suppose that the values of a are a0, a1, ... where the i in ai indicate the iteration number and also similarly for b, c, and d.

Before this PR, it will create the following cypari2 stack:
a0 -> b0 -> c0 -> d0 -> a1 -> b1 -> ...
until it reaches the cleanup threshold.

Meanwhile, the value of the stack and heap at the end of the while loop at iterations:
0. Stack: a0 -> b0 -> c0 -> d0, heap: {}

  1. Stack: b1 -> c1 -> d1, heap: {a1}
  2. Stack: c2 -> d2, heap: {a2, b2}
  3. Stack: d3, heap: {a3, b3, c3}
  4. Stack: ``, heap: {a4, b4, c4, d4}
  5. Stack: a5 -> b5 -> c5 -> d5, heap: {}
  6. etc (repeating).

And if we have

while True:
  a = pari.matrix(...)

Then, a will be in stack ~50% of time and heap ~50% of time.

And in these variants of case, ~50% of the entire set of all values will live in the stack. I updated my original post to point to this comment for the side effect illustration.

@ptrrsn
Copy link
Author

ptrrsn commented Jul 11, 2025

The reason for such a complication is that in Python, the deallocation of a happens after the allocation of the new values of a when we have the statement:
a = ....
In PARI, it is not a problem because the language can detect such an assignment and clear the stack accordingly. So, the above side effect is the cost of synchronizing these two different languages with different object life cycles this way.

@ptrrsn
Copy link
Author

ptrrsn commented Jul 11, 2025

Perhaps as a middle ground, we can introduce a new method clear_stack() that will clear the stack so no variables will be pushed to heap, for advanced users who need more speed:

while True:
  pari.clear_stack()
  a = ...
  b = ...

Now, in the above example, all variables will live in stack.

And in this case, the current PR behavior is arguably better than before this PR because by default for most users, we have no memory leaks (oh, and this PR also fix the doctest memory leaks) and extra code is only needed for more advanced users who really need more performance.

@ptrrsn
Copy link
Author

ptrrsn commented Jul 11, 2025

Oh I accidentally deleted another mitigation of the side effect. We can also mitigated the side effects by lazily constructing the Gen object only when it is accessed. Consider the following code:

while True:
  a = pari.matrix(...)
  b = pari.matrix(...)
  a[5] = 2

We can make a change so that during pari.matrix(...) etc, the Gen object is not really constructed. Only the constructor parameters are saved. And then, when a was accessed, e.g., on a[5] = 2 then the Gen object is actually constructed on the PARI stack. And this way, we can mitigate the side effect and be more similar to PARI. But this will need complicated changes that should be done only if really needed.

@ptrrsn
Copy link
Author

ptrrsn commented Jul 11, 2025

Now I think about it again, implementing such lazy construction won't be too difficult. I will upload a separate PR for that once this one gets in good shape.

@ptrrsn
Copy link
Author

ptrrsn commented Jul 14, 2025

@dimpase replying to your email in sage-devel here as per your request, as it is about testing this PR and also @soehms PR:

I cloned sage to my local computer (WSL) and ran make. And then, I did
./sage -pip install ~/cypari2
with ~/cypari2 being my local clone of cypari2.

It seems that the sage -pip install command works as long as we don't change the structure of Gen (or maybe some other structures too). But with the Gen structure change introduced here, it gives the error:

<frozen importlib._bootstrap>:488: RuntimeWarning: cypari2.gen.Gen size changed, may indicate binary incompatibility. Expected 56 from C header, got 64 from PyObject

during import of cypari2 in sage.

@dimpase
Copy link
Member

dimpase commented Jul 14, 2025

It could be that you changed cypari2 API, and do Sage's use of cypari2 has to be adjusted?

Anyway, I would make sure sagelib is cleaned and uninstalled

make sagelib-clean sagelib-uninstall

and only then install newer cypari2 and rebuild sagelib with

make build

If you use the branch from Sage pr 39030 then it might be less onerous, so that uninstall/clean of sagelib is not needed, but I a not sure

@dimpase
Copy link
Member

dimpase commented Jul 14, 2025

It might be quicker for the purposes of testing to build a binary wheel of the modified cypari2, outside of Sagemath, and install this wheel. I'm lately using uv to create venvs and do this kind of stuff there.

@dimpase
Copy link
Member

dimpase commented Jul 14, 2025

anyway, you can also build a dist tarfile by doing something like make dist, and install this with
./sage --pip install <tarfile>. I tried this on macOS (my least fav. platform :-)).
I am getting a reproducible (on Intel macOS and on Intel Linux) segfault here:

sage: F = NumberField(x^3-2,'alpha') ## line 1790 ##
sage: F.__pari__()[0].nfdisc() ## line 1791 ##

**********************************************************************
----------------------------------------------------------------------
sage -t --warn-long 5.0 --random-seed=213905239097925453935457761809951287366 src/sage/libs/pari/tests.py  # Killed due to segmentation fault

The lines around this error don't produce a crash interactively, until I hit Ctrl-D to exit, and get

% ./sage
┌────────────────────────────────────────────────────────────────────┐
│ SageMath version 10.7.beta8, Release Date: 2025-07-06              │
│ Using Python 3.13.2. Type "help()" for help.                       │
└────────────────────────────────────────────────────────────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Warning: this is a prerelease version, and it may be unstable.     ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
sage: F = NumberField(x^3-2,'alpha')
sage: F.__pari__()[0].nfdisc()
-108
sage: G = NumberField(x^5-11,'beta')
sage: G.__pari__()[0].nfdisc()
45753125
sage:                                                                                                                                                                                    
------------------------------------------------------------------------
0   signals.cpython-313-darwin.so       0x0000000108e8a9b5 sigdie + 85
1   signals.cpython-313-darwin.so       0x0000000108e8a844 cysigs_signal_handler + 340
2   libsystem_platform.dylib            0x00007ff808d1b25d _sigtramp + 29
3   ???                                 0x0000000108d50ab0 0x0 + 4443146928
4   gen.cpython-313-darwin.so           0x000000010bd3df9d __pyx_tp_dealloc_7cypari2_3gen_Gen + 349
5   Python                              0x000000010940d78d dict_dealloc + 1853
6   Python                              0x000000010940dfb8 dict_dealloc + 3944
7   Python                              0x000000010947be44 subtype_clear + 116
8   Python                              0x00000001095df0fe gc_collect_main + 5182
9   Python                              0x0000000109625040 _Py_Finalize + 1024
10  Python                              0x00000001096616fe Py_RunMain + 798
11  Python                              0x0000000109663073 pymain_main + 483
12  Python                              0x000000010966317b Py_BytesMain + 43
13  dyld                                0x00007ff80893d530 start + 3056
------------------------------------------------------------------------
Unhandled SIGSEGV: A segmentation fault occurred.
This probably occurred because a *compiled* module has a bug
in it and is not properly wrapped with sig_on(), sig_off().
Python will now terminate.
------------------------------------------------------------------------
/Users/dima/software/sage/src/bin/sage-python: line 2: 43781 Segmentation fault: 11  sage -python "$@"

seems to indicate some "fun" memory issues.

@dimpase
Copy link
Member

dimpase commented Jul 14, 2025

cypari2-2.2.2.tar.gz
in case, this is the dist tarball I built and used to pip-install the package with the changes in this PR.
Please use it while I'll look into updating build instructions here

@dimpase
Copy link
Member

dimpase commented Jul 14, 2025

here is the same crash as above, but on Linux. Also, note the 1st line of output (about Gen size changed,)

$ ./sage
<frozen importlib._bootstrap>:488: RuntimeWarning: cypari2.gen.Gen size changed, may indicate binary incompatibility. Expected 56 from C header, got 64 from PyObject
┌────────────────────────────────────────────────────────────────────┐
│ SageMath version 10.7.beta8, Release Date: 2025-07-06              │
│ Using Python 3.13.3. Type "help()" for help.                       │
└────────────────────────────────────────────────────────────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Warning: this is a prerelease version, and it may be unstable.     ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
sage: F = NumberField(x^3-2,'alpha')
sage: F.__pari__()[0].nfdisc()
-108
sage: G = NumberField(x^5-11,'beta')
sage: G.__pari__()[0].nfdisc()
45753125
sage:                                                                                                                                                                                                                       
------------------------------------------------------------------------
/usr/lib/python3.13/site-packages/cysignals/signals.cpython-313-x86_64-linux-gnu.so(+0x790f) [0x7f69d4bff90f]
/usr/lib/python3.13/site-packages/cysignals/signals.cpython-313-x86_64-linux-gnu.so(+0x79dd) [0x7f69d4bff9dd]
/usr/lib/python3.13/site-packages/cysignals/signals.cpython-313-x86_64-linux-gnu.so(+0xa2d7) [0x7f69d4c022d7]
/usr/lib64/libc.so.6(+0x3d3b0) [0x7f69d564e3b0]
/usr/lib64/libpari-gmp-tls.so.9(gunclone+0x74) [0x7f69ce077af4]
/home/dima/software/sage-src/local/var/lib/sage/venv-python3.13/lib/python3.13/site-packages/cypari2/gen.cpython-313-x86_64-linux-gnu.so(+0x10997f) [0x7f69cd50997f]
/usr/lib64/libpython3.13.so.1.0(+0xe6420) [0x7f69d58e6420]
/usr/lib64/libpython3.13.so.1.0(+0xe60f1) [0x7f69d58e60f1]
/usr/lib64/libpython3.13.so.1.0(_PyObject_SetManagedDict+0x98) [0x7f69d58e8f78]
/usr/lib64/libpython3.13.so.1.0(PyObject_ClearManagedDict+0xf) [0x7f69d58eb2af]
/usr/lib64/libpython3.13.so.1.0(+0x113ec8) [0x7f69d5913ec8]
/usr/lib64/libpython3.13.so.1.0(+0x1dfd06) [0x7f69d59dfd06]
/usr/lib64/libpython3.13.so.1.0(PyGC_Collect+0x56) [0x7f69d59e06c6]
/usr/lib64/libpython3.13.so.1.0(+0x2a8aab) [0x7f69d5aa8aab]
/usr/lib64/libpython3.13.so.1.0(Py_RunMain+0x343) [0x7f69d5a3a4c3]
/usr/lib64/libpython3.13.so.1.0(Py_BytesMain+0x5a) [0x7f69d5a3b32a]
/usr/lib64/libc.so.6(+0x274ee) [0x7f69d56384ee]
/usr/lib64/libc.so.6(__libc_start_main+0x89) [0x7f69d56385a9]
python3(_start+0x25) [0x557a07ea1095]
------------------------------------------------------------------------
Attaching gdb to process id 32181.
Cannot find gdb installed
GDB is not installed.
Install gdb for enhanced tracebacks.
------------------------------------------------------------------------
Unhandled SIGSEGV: A segmentation fault occurred.
This probably occurred because a *compiled* module has a bug
in it and is not properly wrapped with sig_on(), sig_off().
Python will now terminate.
------------------------------------------------------------------------
/home/dima/software/sage-src/src/bin/sage-python: line 2: 32181 Segmentation fault      sage -python "$@"

On linux I see 2 more test failures:

sage -t --warn-long 5.0 --random-seed=283911431895368050787612828766461509246 src/sage/libs/pari/convert_sage_real_double.pyx
**********************************************************************
File "src/sage/libs/pari/convert_sage_real_double.pyx", line 9, in sage.libs.pari.convert_sage_real_double.new_gen_from_real_double_element
Failed example:
    from sage.libs.pari.convert_sage_real_double import new_gen_from_real_double_element
Expected nothing
Got:
    doctest:warning
      File "<doctest sage.libs.pari.convert_sage_real_double.new_gen_from_real_double_element[0]>", line 1, in <module>
        from sage.libs.pari.convert_sage_real_double import new_gen_from_real_double_element
      File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
      File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
      File "<frozen importlib._bootstrap_external>", line 1328, in exec_module
      File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
      File "/usr/lib/python3.13/warnings.py", line 110, in _showwarnmsg
        sw(msg.message, msg.category, msg.filename, msg.lineno,
    :
    RuntimeWarning: cypari2.gen.Gen size changed, may indicate binary incompatibility. Expected 56 from C header, got 64 from PyObject
**********************************************************************

and a very similar

<frozen importlib._bootstrap>:488: RuntimeWarning: cypari2.gen.Gen size changed, may indicate binary incompatibility. Expected 56 from C header, got 64 from PyObject
Running doctests with ID 2025-07-14-14-07-15-6fa90119.
Git branch: mesonready
Git ref: 10.7.beta8-59-g730429efc29-dirty
Running with SAGE_LOCAL='/home/dima/software/sage-src/local' and SAGE_VENV='/home/dima/software/sage-src/local/var/lib/sage/venv-python3.13'
Using --optional=gentoo,pip,sage,sage_spkg
Features to be detected: 4ti2,SAGE_SRC,benzene,bliss,buckygen,conway_polynomials,coxeter3,csdp,cvxopt,cvxopt,database_cremona_ellcurve,database_cremona_mini_ellcurve,database_cubic_hecke,database_ellcurves,database_graphs,database_jones_numfield,database_knotinfo,dot2tex,dvipng,ecm,flatter,fpylll,fricas,gap_package_atlasrep,gap_package_design,gap_package_grape,gap_package_guava,gap_package_hap,gap_package_polenta,gap_package_polycyclic,gap_package_qpa,gap_package_quagroup,gfan,giac,glucose,graphviz,imagemagick,info,ipython,jmol,jupymake,jupyter_sphinx,kenzo,kissat,latte_int,lrcalc_python,lrslib,mathics,matroid_database,mcqd,meataxe,meson_editable,mpmath,msolve,nauty,networkx,numpy,palp,pandoc,pdf2svg,pdftocairo,pexpect,phitigra,pillow,plantri,polytopes_db,polytopes_db_4d,pplpy,primecountpy,ptyprocess,pycosat,pycryptosat,pynormaliz,pyparsing,python_igraph,requests,rpy2,rubiks,sage.combinat,sage.geometry.polyhedron,sage.graphs,sage.groups,sage.libs.braiding,sage.libs.ecl,sage.libs.flint,sage.libs.gap,sage.libs.giac,sage.libs.homfly,sage.libs.linbox,sage.libs.m4ri,sage.libs.ntl,sage.libs.pari,sage.libs.singular,sage.misc.cython,sage.modular,sage.modules,sage.numerical.mip,sage.plot,sage.rings.complex_double,sage.rings.finite_rings,sage.rings.function_field,sage.rings.number_field,sage.rings.padics,sage.rings.polynomial.pbori,sage.rings.real_double,sage.rings.real_mpfr,sage.sat,sage.schemes,sage.symbolic,sage_numerical_backends_coin,sagemath_doc_html,scipy,singular,sirocco,sloane_database,sphinx,symengine_py,sympy,tdlib,threejs,topcom
Doctesting 1 file.
<frozen importlib._bootstrap>:488: RuntimeWarning: cypari2.gen.Gen size changed, may indicate binary incompatibility. Expected 56 from C header, got 64 from PyObject
sage -t --warn-long 5.0 --random-seed=283911431895368050787612828766461509246 src/sage/libs/pari/convert_sage.pyx
**********************************************************************
File "src/sage/libs/pari/convert_sage.pyx", line 344, in sage.libs.pari.convert_sage.set_integer_from_gen
Failed example:
    [Integer(pari(x)) for x in [1, 2^60, 2., GF(3)(1), GF(9,'a')(2)]]         # needs sage.rings.finite_rings
Expected:
    [1, 1152921504606846976, 2, 1, 2]
Got:
    doctest:warning
      File "<doctest sage.libs.pari.convert_sage.set_integer_from_gen[0]>", line 1, in <module>
        [Integer(pari(x)) for x in [Integer(1), Integer(2)**Integer(60), RealNumber('2.'), GF(Integer(3))(Integer(1)), GF(Integer(9),'a')(Integer(2))]]         # needs sage.rings.finite_rings
      File "/home/dima/software/sage-src/src/sage/rings/finite_rings/finite_field_constructor.py", line 639, in create_key_and_extra_args
        R = PolynomialRing(FiniteField(p), 'x')
      File "/home/dima/software/sage-src/src/sage/rings/polynomial/polynomial_ring_constructor.py", line 728, in PolynomialRing
        return _single_variate(base_ring, names, **kwds)
      File "/home/dima/software/sage-src/src/sage/rings/polynomial/polynomial_ring_constructor.py", line 828, in _single_variate
        R = constructor(base_ring, name, **kwds)
      File "/home/dima/software/sage-src/src/sage/rings/polynomial/polynomial_ring.py", line 3458, in __init__
        from .polynomial_zmod_flint import Polynomial_zmod_flint as element_class
      File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
      File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
      File "<frozen importlib._bootstrap_external>", line 1328, in exec_module
      File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
      File "/usr/lib/python3.13/warnings.py", line 110, in _showwarnmsg
        sw(msg.message, msg.category, msg.filename, msg.lineno,
    :
    RuntimeWarning: cypari2.gen.Gen size changed, may indicate binary incompatibility. Expected 56 from C header, got 64 from PyObject
    [1, 1152921504606846976, 2, 1, 2]
**********************************************************************
1 item had failures:
   1 of   3 in sage.libs.pari.convert_sage.set_integer_from_gen
    [100 tests, 1 failure, 0.18s wall]
----------------------------------------------------------------------
sage -t --warn-long 5.0 --random-seed=283911431895368050787612828766461509246 src/sage/libs/pari/convert_sage.pyx  # 1 doctest failed
----------------------------------------------------------------------
Total time for all tests: 0.7 seconds
    cpu time: 0.2 seconds
    cumulative wall time: 0.2 seconds
Features detected for doctesting: sage.modules,sage.rings.finite_rings,sage.rings.number_field,sage.rings.padics,sage.rings.real_mpfr,sage.symbolic

@dimpase
Copy link
Member

dimpase commented Jul 14, 2025

@tobiasdiez - with meson build, I keep getting

$ ./sage -t --warn-long 5.0 --random-seed=283911431895368050787612828766461509246 src/sage/libs/pari/convert_sage.pyx
<frozen importlib._bootstrap>:488: RuntimeWarning: cypari2.gen.Gen size changed, may indicate binary incompatibility. Expected 56 from C header, got 64 from PyObject

which is presumably something to do with numpy, but what? Is the state not cleaned by make sagelib-clean, and even after a numpy update, it still pops up?

$ ./sage --pip uninstall numpy
Found existing installation: numpy 2.3.1
Not uninstalling numpy at /usr/lib/python3.13/site-packages, outside environment /home/dima/software/sage-src/local/var/lib/sage/venv-python3.13
Can't uninstall 'numpy'. No files were found to uninstall.

@dimpase
Copy link
Member

dimpase commented Jul 15, 2025

I could narrow the warning to the following import

$ ./sage --python
Python 3.13.3 (main, May 28 2025, 09:14:23) [GCC 14.2.1 20241221] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sage.rings.padics.common_conversion
<frozen importlib._bootstrap>:488: RuntimeWarning: cypari2.gen.Gen size changed, may indicate binary incompatibility. Expected 56 from C header, got 64 from PyObject

so it's most probably nothing to do with numpy, but about the interaction between Sage and cypari2 in this module, sage.rings.padics.common_conversion

@ptrrsn
Copy link
Author

ptrrsn commented Jul 15, 2025

Thank you @dimpase! I will check the segmentation fault and the dist tarball that you created.

@dimpase
Copy link
Member

dimpase commented Jul 15, 2025

Thank you @dimpase! I will check the segmentation fault and the dist tarball that you created.

If you use the classical build of Sage, the fully correct way to update a Sage package (and that's what entails testing a cypari2 update with Sage - updating a Sage package) is as follows: put the dist tarball into Sage's upstream/ directory, bumping its name like cypari2-2.2.2.tar.gz -> cypari2-2.2.2p1.tar.gz, change the cypari Sage package version to 2.2.2p1, update the checksums (via ./sage --package fix-checksum cypari) to obtain

 diff --git a/build/pkgs/cypari/checksums.ini b/build/pkgs/cypari/checksums.ini
index 1bdcba515d5..bbbbf66db7f 100644
--- a/build/pkgs/cypari/checksums.ini
+++ b/build/pkgs/cypari/checksums.ini
@@ -1,4 +1,4 @@
 tarball=cypari2-VERSION.tar.gz
-sha1=5d91408a6e28e43d429667554d2696cfbd58c35b
-sha256=13a338735ea221c1068f8fc415561bf777d8c68725702bc749547264fd091720
+sha1=d0ca8921c6b61cc79061e7299d9ba89e60ee31f7
+sha256=295c931468158e40e954b2b4d097091dcf9e8ab2d738c6cb996fbecfd9a552b3
 upstream_url=https://files.pythonhosted.org/packages/source/c/cypari2/cypari2-VERSION.tar.gz
diff --git a/build/pkgs/cypari/package-version.txt b/build/pkgs/cypari/package-version.txt
index b1b25a5ffae..93338fcd951 100644
--- a/build/pkgs/cypari/package-version.txt
+++ b/build/pkgs/cypari/package-version.txt
@@ -1 +1 @@
-2.2.2
+2.2.2p1

then rebuild, i.e. run

make sagelib-clean sagelib-uninstall cypari-clean cypari-uninstall
make build

apparently, make sagelib-clean sagelib-uninstall is not needed in this case, as there is no API change, but still.

@ptrrsn
Copy link
Author

ptrrsn commented Jul 16, 2025

@dimpase thank you for the instruction!

Oh, and also thank you for the segmentation fault report. I was debugging it, and it seems there is some confusion in my code where a pari stack address was thought of as a pari heap address, and it was causing a segmentation fault because we cannot gunclone a stack address. I will fix it.

@ptrrsn ptrrsn marked this pull request as draft July 16, 2025 11:40
@dimpase
Copy link
Member

dimpase commented Jul 16, 2025

@ptrrsn - do you understand the reason for #180 (comment) ? This appears to be platform-specific (doesn't happen on macOS)

@ptrrsn
Copy link
Author

ptrrsn commented Jul 17, 2025

@dimpase Unfortunately, I don't know the reason yet, but I will try to debug it.

@ptrrsn
Copy link
Author

ptrrsn commented Jul 22, 2025

@dimpase As for #180 (comment), I unfortunately could not reproduce the error from the steps that you provided. I first checkout PR 39030, and then I did pip install etc following https://doc.sagemath.org/html/en/installation/meson.html. And then, I tried both workflows that you mentioned above:

  1. make sagelib-clean sagelib-uninstall -> ./sage -pip uninstall cypari2 -> ./sage -pip install ~/cypari2 -> make build
  2. and also after resetting the cypari2, I tried to directly ./sage -pip install my local cypari2.

In both workflows, I don't see the Gen size change error anymore.

But digging into this a bit (sorry for the unnecessary details if you are already aware of it), the number 56 for the old Gen are computed by Cython and baked into common_conversion.cpython-312-x86_64-linux-gnu.so. So it will be just about tracking this .so: as long as it gets recompiled after we change the cypari2 library, then we will not see the error anymore (it got updated in both workflows above).

Maybe I misunderstand your workflow, could you elaborate what steps did you use in #180 (comment) ?

@dimpase
Copy link
Member

dimpase commented Jul 22, 2025

@ptrrsn thanks for trying to reproduce this. It might be some kind of caching of object files which is too aggressive and leads to improper re-use. I'll try again, on a cleaner state.

@ptrrsn
Copy link
Author

ptrrsn commented Jul 22, 2025

@dimpase oh, I noticed that with PR 39030, a ./sage -pip install will trigger the compilations including the common_conversion.cpython-312-x86_64-linux-gnu.so the next time we run sage:

$ ./sage -pip install cypari2
Collecting cypari2
  Using cached cypari2-2.2.2-cp312-cp312-linux_x86_64.whl
Requirement already satisfied: cysignals>=1.11.3 in ./local/var/lib/sage/venv-python3.12.5/lib/python3.12/site-packages (from cypari2) (1.12.3)
Installing collected packages: cypari2
Successfully installed cypari2-2.2.2

and then we have

-rwxr-xr-x 1 risan risan 96304 Jul 22 10:19 ./build/sage-distro/src/sage/rings/padics/common_conversion.cpython-312-x86_64-linux-gnu.so

But after:

$ ./sage
┌────────────────────────────────────────────────────────────────────┐
│ SageMath version 10.7.beta8, Release Date: 2025-07-06              │
│ Using Python 3.12.5. Type "help()" for help.                       │
└────────────────────────────────────────────────────────────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Warning: this is a prerelease version, and it may be unstable.     ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
sage: exit()

we have the timestamp updated

-rwxr-xr-x 1 risan risan 96304 Jul 22 15:43 ./build/sage-distro/src/sage/rings/padics/common_conversion.cpython-312-x86_64-linux-gnu.so

Maybe just a data point, at least the recompilation is working for me during ./sage running phase.

@dimpase
Copy link
Member

dimpase commented Jul 22, 2025

@dimpase As for #180 (comment), I unfortunately could not reproduce the error from the steps that you provided. I first checkout PR 39030, and then I did pip install etc following https://doc.sagemath.org/html/en/installation/meson.html.

OK, apologies, that was indeed my local problem, with multiple copies of cypari2 lying around. After everything was cleaned up, no more weird warnings at startup. (well, the segfault I reported above didn't go away, but I understand it's not fixed here yet)

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.

Memory leak for vectors and matrices
3 participants