sys-bio / roadrunner

libRoadRunner: A high-performance SBML simulator
http://libroadrunner.org/
Other
36 stars 24 forks source link

Saving and loading state does not work across python interpreter sessions #1210

Closed matthiaskoenig closed 2 months ago

matthiaskoenig commented 3 months ago

Finally I could create an example for the issues with save state starting with libroadrunner > 2.3.1. Until version 2.3.1 it was possible to create a state file and load the state file in a later python interpreter run. In later versions this became very buggy (lots of segmentation faults) until impossible. I.e. creating a state file on disk and then using this state file in another python session does not work (most of the time).

Attached a minimal example:

This is a minimal example for the issue original described in #963. Two times running the script results in the python interpreter dying with segfaults. I think starting with >2.3.1 there was some state introduced which depends on the interpreter session (e.g. some variable memory layout).

Here the example model: omeprazole_body_flat.zip

import hashlib
from pathlib import Path
from typing import Optional

import roadrunner
print(f"roadrunner version: {roadrunner.__version__}")

def md5_for_path(path):
    """Calculate MD5 of file content."""

    # Open,close, read file and calculate MD5 on its contents
    with open(path, "rb") as f_check:
        # read contents of the file
        data = f_check.read()
        # pipe contents of the file through
        return hashlib.md5(data).hexdigest()

def get_state_path(sbml_path: Path) -> Optional[Path]:
    """Get path of the state file.

    The state file is a binary file which allows fast model loading.
    """
    md5 = md5_for_path(sbml_path)
    return Path(f"{sbml_path}_rr{roadrunner.__version__}_{md5}.state")

sbml_path = "omeprazole_body_flat.xml"
state_path = get_state_path(sbml_path)

# state saving and loading
r = roadrunner.RoadRunner()

if state_path.exists():
    r.loadState(str(state_path))
    print(f"Model loaded from state: '{state_path}'")
else:
    print(f"Load model from SBML: '{sbml_path}'")
    r = roadrunner.RoadRunner(str(sbml_path))
    # save state
    r.saveState(str(state_path))

print(f"Load from state: '{state_path}'")
r.loadState(str(state_path))
print(f"Model loaded from state: '{state_path}'")
matthiaskoenig commented 3 months ago

Here the output.

First run

roadrunner version: 2.6.0
Load model from SBML: 'omeprazole_body_flat.xml'
Load from state: 'omeprazole_body_flat.xml_rr2.6.0_f78e5cb032cd340849990dd3ed972ab8.state'
Model loaded from state: 'omeprazole_body_flat.xml_rr2.6.0_f78e5cb032cd340849990dd3ed972ab8.state'

Process finished with exit code 0

Second run

roadrunner version: 2.6.0
Model loaded from state: 'omeprazole_body_flat.xml_rr2.6.0_f78e5cb032cd340849990dd3ed972ab8.state'
Load from state: 'omeprazole_body_flat.xml_rr2.6.0_f78e5cb032cd340849990dd3ed972ab8.state'

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

As a side note: also pretty difficult to test because it requires two independent python interpreters in CI, one creating the state the other loading it.

hsauro commented 3 months ago

That's not good. I think Lucian is away at the moment but he'll be at Harmony, if you are there maybe it can be fixed then.

On Tue, Apr 2, 2024 at 1:18 PM Matthias König @.***> wrote:

Here the output.

First run

roadrunner version: 2.6.0 Load model from SBML: 'omeprazole_body_flat.xml' Load from state: 'omeprazole_body_flat.xml_rr2.6.0_f78e5cb032cd340849990dd3ed972ab8.state' Model loaded from state: 'omeprazole_body_flat.xml_rr2.6.0_f78e5cb032cd340849990dd3ed972ab8.state'

Process finished with exit code 0

Second run

roadrunner version: 2.6.0 Model loaded from state: 'omeprazole_body_flat.xml_rr2.6.0_f78e5cb032cd340849990dd3ed972ab8.state' Load from state: 'omeprazole_body_flat.xml_rr2.6.0_f78e5cb032cd340849990dd3ed972ab8.state'

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

As a side note: also pretty difficult to test because it requires two independent python interpreters in CI, one creating the state the other loading it.

— Reply to this email directly, view it on GitHub https://urldefense.com/v3/__https://github.com/sys-bio/roadrunner/issues/1210*issuecomment-2033019734__;Iw!!K-Hz7m0Vt54!m3Xx9JZqjU816cugyC2t8bR7gXAwejtIAEcQyZBCcXhMcknGIViDdRp7HCTy7dfo_Jkom7Z80kxYXADDdp6cFrsmG-PUdQ$, or unsubscribe https://urldefense.com/v3/__https://github.com/notifications/unsubscribe-auth/AAIBSDS72NHMWSOTN4PFRDTY3MG77AVCNFSM6AAAAABFUA5SMCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMZTGAYTSNZTGQ__;!!K-Hz7m0Vt54!m3Xx9JZqjU816cugyC2t8bR7gXAwejtIAEcQyZBCcXhMcknGIViDdRp7HCTy7dfo_Jkom7Z80kxYXADDdp6cFrt-rX6RYg$ . You are receiving this because you are subscribed to this thread.Message ID: @.***>

-- Herbert Sauro, Professor Director: NIH Center for model reproducibility University of Washington, Bioengineering 206-685-2119, www.sys-bio.org, http://reproduciblebiomodels.org/ Mobile: 206-880-8093 @.*** Books: http://books.analogmachine.org/

luciansmith commented 2 months ago

2.7.0 fixes this! Thanks for finding the example; it was critical in our discovering the bug.

matthiaskoenig commented 2 months ago

Works. Perfect. This helps a lot