diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index ba03d71f16..d6f11e0ba2 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -48,7 +48,7 @@ jobs: python3.10-dbg - name: Install Python dependencies run: | - python3 -m pip install --upgrade pip cython pkgconfig + python3 -m pip install --upgrade pip scikit-build-core cython pkgconfig make test-install - name: Disable ptrace security restrictions run: | diff --git a/.gitignore b/.gitignore index 32fc3e5815..7dd5439202 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ CMakeFiles CMakeScripts Testing Makefile +!/Makefile cmake_install.cmake install_manifest.txt compile_commands.json diff --git a/CMakeLists.txt b/CMakeLists.txt index e0486eff45..1339740c50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.7) +cmake_minimum_required(VERSION 3.24...3.26) project(memray) set(CMAKE_CXX_STANDARD 17) @@ -21,21 +21,22 @@ if(NOT LZ4_FOUND) endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - pkg_check_modules(LIBUNWIND REQUIRED libunwind) + pkg_check_modules(UNWIND REQUIRED libunwind) + pkg_check_modules(DEBUGINFOD libdebuginfod) + if(NOT DEBUGINFOD_LIBRARIES) + set(DEBUGINFOD_LIBRARIES "debuginfod") + endif() endif() # Set compiler flags -set(COMPILER_FLAGS "-Wall") +add_compile_options(-Wall) if(NOT DEFINED ENV{NO_MEMRAY_FAST_TLS}) - add_definitions(-DUSE_MEMRAY_TLS_MODEL=1) + add_compile_definitions(-DUSE_MEMRAY_TLS_MODEL=1) endif() -if(DEFINED ENV{MEMRAY_MINIMIZE_INLINING}) - set(COMPILER_FLAGS ${COMPILER_FLAGS} -Og) -else() - set(COMPILER_FLAGS ${COMPILER_FLAGS} -flto) - set(LINKER_FLAGS ${LINKER_FLAGS} -flto) -endif() +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -flto") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og") if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(BINARY_FORMAT "elf") @@ -48,21 +49,23 @@ endif() # Set up libbacktrace set(LIBBACKTRACE_DIR ${CMAKE_SOURCE_DIR}/src/vendor/libbacktrace) set(LIBBACKTRACE_INSTALL_DIR ${LIBBACKTRACE_DIR}/install) -set(LIBBACKTRACE_INCLUDE_DIR ${LIBBACKTRACE_DIR}/install/include) -set(LIBBACKTRACE_LIB_DIR ${LIBBACKTRACE_DIR}/install/lib) +set(LIBBACKTRACE_INCLUDE_DIR ${LIBBACKTRACE_INSTALL_DIR}/include) +set(LIBBACKTRACE_LIB_DIR ${LIBBACKTRACE_INSTALL_DIR}/lib) # Add custom command to build libbacktrace add_custom_command( OUTPUT ${LIBBACKTRACE_LIB_DIR}/libbacktrace.a + OUTPUT ${LIBBACKTRACE_INCLUDE_DIR}/libbacktrace/backtrace.h + OUTPUT ${LIBBACKTRACE_INCLUDE_DIR}/libbacktrace/internal.h COMMAND mkdir -p ${LIBBACKTRACE_INSTALL_DIR} COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/libbacktrace_build COMMAND cd ${CMAKE_CURRENT_BINARY_DIR}/libbacktrace_build && - ${LIBBACKTRACE_DIR}/configure - --with-pic - --prefix=${LIBBACKTRACE_INSTALL_DIR} - --includedir=${LIBBACKTRACE_INSTALL_DIR}/include/libbacktrace - COMMAND cd ${CMAKE_CURRENT_BINARY_DIR}/libbacktrace_build && make -j - COMMAND cd ${CMAKE_CURRENT_BINARY_DIR}/libbacktrace_build && make install + ${LIBBACKTRACE_DIR}/configure + --with-pic + --prefix=${LIBBACKTRACE_INSTALL_DIR} + --includedir=${LIBBACKTRACE_INCLUDE_DIR}/libbacktrace + COMMAND make -C ${CMAKE_CURRENT_BINARY_DIR}/libbacktrace_build -j + COMMAND make -C ${CMAKE_CURRENT_BINARY_DIR}/libbacktrace_build install DEPENDS ${LIBBACKTRACE_DIR}/configure ) add_custom_target(libbacktrace DEPENDS ${LIBBACKTRACE_LIB_DIR}/libbacktrace.a) @@ -72,15 +75,22 @@ add_custom_target(libbacktrace DEPENDS ${LIBBACKTRACE_LIB_DIR}/libbacktrace.a) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_memray.cpp COMMAND Python::Interpreter -m cython - --cplus - -3 + --cplus + -3 + -X embedsignature=True + -X boundscheck=False + -X wraparound=False + -X cdivision=True + -X c_string_type=unicode + -X c_string_encoding=utf8 -I ${CMAKE_SOURCE_DIR}/src/memray/ - ${CMAKE_SOURCE_DIR}/src/memray/_memray.pyx + ${CMAKE_SOURCE_DIR}/src/memray/_memray.pyx -o ${CMAKE_CURRENT_BINARY_DIR}/_memray.cpp + --module-name memray._memray DEPENDS ${CMAKE_SOURCE_DIR}/src/memray/_memray.pyx VERBATIM ) -set(MEMRAY_SOURCES +python_add_library(_memray MODULE WITH_SOABI src/memray/_memray/compat.cpp src/memray/_memray/hooks.cpp src/memray/_memray/tracking_api.cpp @@ -95,17 +105,28 @@ set(MEMRAY_SOURCES src/memray/_memray/snapshot.cpp src/memray/_memray/socket_reader_thread.cpp src/memray/_memray/native_resolver.cpp + ${CMAKE_CURRENT_BINARY_DIR}/_memray.cpp ) -python_add_library(_memray MODULE WITH_SOABI ${MEMRAY_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/_memray.cpp) -target_include_directories(_memray PRIVATE + +target_include_directories(_memray PRIVATE ${CMAKE_SOURCE_DIR}/src/memray/_memray - ${LIBBACKTRACE_INCLUDE_DIR} + ${LIBBACKTRACE_INCLUDE_DIR} ${LZ4_INCLUDE_DIRS} + ${UNWIND_INCLUDE_DIRS} + ${DEBUGINFOD_INCLUDE_DIRS} ) -target_link_libraries(_memray PRIVATE ${LZ4_LIBRARIES} dl ${LIBUNWIND_LIBRARIES} ${LIBBACKTRACE_LIB_DIR}/libbacktrace.a) -target_link_options(_memray PRIVATE ${LZ4_LDFLAGS}) -target_compile_options(_memray PRIVATE ${COMPILER_FLAGS}) -target_link_options(_memray PRIVATE ${LINKER_FLAGS}) +target_link_libraries(_memray PRIVATE + ${LIBBACKTRACE_LIB_DIR}/libbacktrace.a + ${LZ4_LIBRARIES} + ${UNWIND_LIBRARIES} + ${DEBUGINFOD_LIBRARIES} + dl +) +set_target_properties(_memray PROPERTIES INSTALL_RPATH "${DEBUGINFOD_LIBRARY_DIRS}") + +set(CMAKE_BUILD_RPATH "${LZ4_LIBRARY_DIRS}:") +target_link_options(_memray PRIVATE ${LZ4_LDFLAGS} ${UNWIND_LDFLAGS} ${DEBUGINFOD_LDFLAGS}) +target_compile_options(_memray PRIVATE ${LZ4_CFLAGS} ${UNWIND_CFLAGS} ${DEBUGINFOD_CFLAGS}) add_dependencies(_memray libbacktrace) # _test_utils extension @@ -113,27 +134,34 @@ add_dependencies(_memray libbacktrace) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_memray_test_utils.cpp COMMAND Python::Interpreter -m cython - --cplus + --cplus -3 + -X embedsignature=True + -X boundscheck=False + -X wraparound=False + -X cdivision=True + -X c_string_type=unicode + -X c_string_encoding=utf8 -I ${CMAKE_SOURCE_DIR}/src/memray/ - ${CMAKE_SOURCE_DIR}/src/memray/_memray_test_utils.pyx + ${CMAKE_SOURCE_DIR}/src/memray/_memray_test_utils.pyx -o ${CMAKE_CURRENT_BINARY_DIR}/_memray_test_utils.cpp --module-name memray._test_utils DEPENDS ${CMAKE_SOURCE_DIR}/src/memray/_memray_test_utils.pyx VERBATIM ) -python_add_library(_test_utils MODULE WITH_SOABI ${CMAKE_CURRENT_BINARY_DIR}/_memray_test_utils.cpp) -target_include_directories(_test_utils PRIVATE +python_add_library(_test_utils MODULE WITH_SOABI + ${CMAKE_CURRENT_BINARY_DIR}/_memray_test_utils.cpp +) +target_include_directories(_test_utils PRIVATE ${CMAKE_SOURCE_DIR}/src/memray/_memray ) # _inject extension -set(INJECT_SOURCES +python_add_library(_inject MODULE WITH_SOABI USE_SABI 3.7 src/memray/_memray/inject.cpp ) -python_add_library(_inject MODULE WITH_SOABI USE_SABI 3.7 ${INJECT_SOURCES}) -target_include_directories(_inject PRIVATE +target_include_directories(_inject PRIVATE ${CMAKE_SOURCE_DIR}/src/memray ) target_compile_options(_test_utils PRIVATE ${COMPILER_FLAGS}) @@ -143,4 +171,4 @@ target_link_options(_inject PRIVATE ${LINKER_FLAGS}) # Install targets -install(TARGETS _memray _test_utils _inject LIBRARY DESTINATION memray) \ No newline at end of file +install(TARGETS _memray _test_utils _inject LIBRARY DESTINATION memray) diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 68f65802d0..0000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,41 +0,0 @@ -exclude .clang-format -exclude asv.conf.json -exclude CONTRIBUTING.md -exclude Dockerfile -exclude Jenkinsfile -exclude requirements-*.txt -exclude .medusarc -exclude valgrind.supp - -recursive-exclude src/vendor/libbacktrace/install * -recursive-exclude benchmarks * -recursive-exclude debian * -recursive-exclude docker * -recursive-exclude docs * -recursive-exclude src/memray *.cpp *.h -recursive-exclude src/memray *.md -recursive-exclude tests * -recursive-exclude news * -recursive-exclude vendor * - -include README.md -include Makefile -include pyproject.toml -include package.json -include package-lock.json -include .bumpversion.cfg -include .babelrc -include webpack.config.js -include NEWS.rst -include .flake8 -include src/memray/py.typed -include .pre-commit-config.yaml - -recursive-include src/vendor * -recursive-include src/memray *.py -recursive-include src/memray *.pyi -recursive-include src/memray *.html *.js *.css -recursive-include src/memray *.pyx *.pxd -recursive-include src/memray *.gdb *.lldb -recursive-include src/memray/_memray * -recursive-include tools *.sh diff --git a/Makefile b/Makefile index ed13906004..0877764e97 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,11 @@ build: build-js build-ext ## (default) Build package extensions and assets in-p .PHONY: build-ext build-ext: ## Build package extensions in-place - $(PYTHON) -m pip install --no-build-isolation --config-settings=editable.rebuild=true -Cbuild-dir=build -ve. + $(PYTHON) -m pip install -ve . \ + --no-build-isolation \ + --config-settings=editable.verbose=false \ + --config-settings=cmake.build-type=Debug \ + -Cbuild-dir=build $(reporters_path)/templates/assets/%.js: $(reporters_path)/assets/%.js $(NPM) install diff --git a/docs/examples/README.rst b/docs/examples/README.rst index d43e96ff2b..7be2aa1759 100644 --- a/docs/examples/README.rst +++ b/docs/examples/README.rst @@ -11,11 +11,11 @@ Make sure you install the required dependencies by running directory. The examples below use the project in the ``mandelbrot`` folder, but you can use the same instructions to launch the other examples as well. -To track memory allocations, invoke ``memray3.9 run``: +To track memory allocations, invoke ``memray run``: .. code:: shell - memray3.9 run mandelbrot/mandelbrot.py + memray run mandelbrot/mandelbrot.py Memray will print a message displaying the output file it creates. @@ -28,7 +28,7 @@ graph, use the following command: .. code:: shell - memray3.9 flamegraph mandelbrot/memray-mandelbrot.py.187967.bin + memray flamegraph mandelbrot/memray-mandelbrot.py.187967.bin The HTML file for the flame graph will be generated under ``mandelbrot/memray-flamegraph-mandelbrot.py.187967.html``. The flame graph diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 07e8f3e662..f54473b42e 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -26,19 +26,13 @@ You can invoke Memray the following way: python3.9 -m memray -Or alternatively through the version-qualified ``memrayX.Y`` script: - -.. code:: shell - - memray3.9 - -You can also invoke Memray without version-qualifying it: +Or alternatively through the ``memray`` script: .. code:: shell memray -The downside to the unqualified ``memray`` script is that it's not immediately +The downside to using the ``memray`` script is that it's not immediately clear what Python interpreter will be used to execute Memray. If you're using a virtual environment that's not a problem because you know exactly what interpreter is in use, but otherwise you need to be careful to ensure that ``memray`` is @@ -56,7 +50,7 @@ To run memray on the ``example.py`` script, use :doc:`the run subcommand `. .. code:: shell - memray3.9 run example.py + memray run example.py This will execute the script and track its memory allocations, displaying the name of the file where results are being recorded with a message like: @@ -72,7 +66,7 @@ the results file: .. code:: shell - memray3.9 flamegraph memray-example.py.4131.bin + memray flamegraph memray-example.py.4131.bin This will generate the ``memray-flamegraph-example.py.4131.html`` file in the current directory. See the :doc:`flamegraph` documentation which explains how to interpret flame graphs. diff --git a/docs/run.rst b/docs/run.rst index dee31e00ef..5e5354c94e 100644 --- a/docs/run.rst +++ b/docs/run.rst @@ -140,7 +140,7 @@ You can run a program in live mode using ``run --live``: .. code:: shell - memray3.9 run --live application.py + memray run --live application.py Immediately Memray will start your application in the background and will run a TUI in the foreground that you can use to analyze your application's memory usage. If you don't want to run your program in the background, you can instead @@ -148,7 +148,7 @@ use ``run --live-remote``: .. code:: shell - memray3.9 run --live-remote application.py + memray run --live-remote application.py In this mode, Memray will choose an unused port, bind to it, and display a message saying: @@ -160,7 +160,7 @@ It will wait for you to run: .. code:: shell - memray3.9 live + memray live in another terminal window to attach to it. Regardless of whether you choose to use one terminal or two, the resulting TUI is exactly the same. See :doc:`live` for details on how to interpret and control the TUI. diff --git a/pyproject.toml b/pyproject.toml index 6c5efc71e8..f8f7e909c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,21 +1,22 @@ [project] name = "memray" -version = "1.11.0" description = "A memory profiler for Python applications" readme = "README.md" requires-python = ">=3.7.0" license = { text = "Apache 2.0" } -authors = [{ name = "Pablo Galindo Salgado" }] +authors = [{ name = "Pablo Galindo Salgado" }, { name = "Matt Wozniski" }] classifiers = [ "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: POSIX :: Linux", "Operating System :: MacOS", + "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development :: Debuggers", ] @@ -25,6 +26,11 @@ dependencies = [ "rich >= 11.2.0", "textual >= 0.41.0", ] +dynamic = ["version"] + +[tool.scikit-build.metadata.version] +provider = "scikit_build_core.metadata.regex" +input = "src/memray/_version.py" [project.optional-dependencies] test = [ @@ -73,21 +79,37 @@ Homepage = "https://github.com/bloomberg/memray" [project.scripts] memray = "memray.__main__:main" -"memray3.7" = "memray.__main__:main" -"memray3.8" = "memray.__main__:main" -"memray3.9" = "memray.__main__:main" -"memray3.10" = "memray.__main__:main" -"memray3.11" = "memray.__main__:main" -"memray3.12" = "memray.__main__:main" [build-system] requires = ["scikit-build-core", "cython"] build-backend = "scikit_build_core.build" [tool.scikit-build] +minimum-version = "0.9" +cmake.verbose = true +cmake.version = ">=3.26.1" +cmake.build-type = "RelWithDebInfo" +logging.level = "INFO" +install.strip = false +sdist.exclude = [ + "/*/", + "!/src/", + ".*", + "/src/vendor/libbacktrace/install/**", + "/src/memray/*.cpp", + "/src/memray/*.h", + "/src/memray/**/*.md", + "/.clang-format", + "/asv.conf.json", + "/CONTRIBUTING.md", + "/Dockerfile", + "/Jenkinsfile", + "/requirements-*.txt", + "/.medusarc", + "/valgrind.supp", +] wheel.packages = ["src/memray"] - [tool.ruff] line-length = 95 select = ["C4", "E", "F", "I001", "PERF", "W"] @@ -140,6 +162,7 @@ build = ["cp38-*", "cp39-*", "cp310-*", "cp311-*"] skip = "*musllinux*{i686,aarch64}*" manylinux-x86_64-image = "manylinux2014" manylinux-i686-image = "manylinux2014" +musllinux-x86_64-image = "musllinux_1_1" [[tool.cibuildwheel.overrides]] select = "cp3{7,8,9,10}-*" @@ -148,8 +171,37 @@ manylinux-i686-image = "manylinux2010" [tool.cibuildwheel.linux] before-all = [ - "yum install -y libunwind-devel lz4-devel gdb", - "if ! yum install -y lldb; then echo lldb is not available; fi", + # Build the latest curl from source. + "yum install -y openssl-devel", + "cd /", + "CURL_VERS=8.7.1", + "curl -LO https://curl.se/download/curl-$CURL_VERS.tar.bz2", + "tar xf ./curl-$CURL_VERS.tar.bz2", + "cd curl-$CURL_VERS", + "./configure --with-openssl", + "make install", + + # Build the latest zstd from source + "yum install -y lz4-devel xz-devel", + "cd /", + "ZSTD_VERS=1.5.6", + "/usr/bin/curl -LO https://github.com/facebook/zstd/releases/download/v1.5.6/zstd-$ZSTD_VERS.tar.gz", + "tar xf ./zstd-$ZSTD_VERS.tar.gz", + "cd zstd-$ZSTD_VERS", + "V=1 LDLIBS=-lrt make install", + + # Build the latest elfutils from source. + "yum install -y lz4-devel", + "cd /", + "VERS=0.191", + "/usr/bin/curl https://sourceware.org/elfutils/ftp/$VERS/elfutils-$VERS.tar.bz2 > ./elfutils.tar.bz2", + "tar -xf elfutils.tar.bz2", + "cd elfutils-$VERS", + "CFLAGS='-Wno-error -g -O3' CXXFLAGS='-Wno-error -g -O3' LDFLAGS=-lrt ./configure --enable-libdebuginfod --disable-debuginfod --disable-nls --with-zstd", + "make install", + + # Install Memray's other build and test dependencies + "yum install -y libunwind-devel", ] [tool.cibuildwheel.macos] @@ -157,7 +209,8 @@ before-all = [ "git clone --depth 1 --branch v1.9.4 https://github.com/lz4/lz4 lz4", "cd lz4", "make", - "make install DESTDIR=/tmp/lz4_install", + "make install PREFIX=$LZ4_INSTALL_DIR", + "find $LZ4_INSTALL_DIR", ] before-test = [ "codesign --remove-signature /Library/Frameworks/Python.framework/Versions/*/bin/python3 || true", @@ -179,4 +232,39 @@ show_missing = true # Override the default linux before-all for musl linux [[tool.cibuildwheel.overrides]] select = "*-musllinux*" -before-all = ["apk add --update libunwind-dev lz4-dev gdb lldb"] +before-all = [ + # Remove gettext-dev, which conficts with the musl-libintl, which is a build + # dependency of elfutils. + "apk del gettext-dev glib-dev", + + # Build musl-fts from source. This is a build dependency of elfutils, but + # isn't in the Alpine repos of the musllinux_1_1 image. The build steps come + # from https://git.alpinelinux.org/aports/tree/main/musl-fts/APKBUILD + # Setting PATH before calling boostrap.sh fixes an automake failure. I think + # the failure may be caused by a different pkg-config in /usr/local/bin. + "cd /", + "apk add --update automake autoconf libtool", + "VERS=1.2.7", + "curl -L https://github.com/void-linux/musl-fts/archive/refs/tags/v$VERS.tar.gz > ./musl-fts.tar.gz", + "tar -xf musl-fts.tar.gz", + "cd musl-fts-$VERS", + "PATH=/usr/bin:/bin ./bootstrap.sh", + "CFLAGS=-fPIC ./configure", + "make install", + + # Build the latest elfutils from source. The build steps come from + # https://git.alpinelinux.org/aports/tree/main/elfutils, and the need to + # set the FNM_EXTMATCH macro to get the build to succeed is seen here: + # https://git.alpinelinux.org/aports/tree/main/elfutils/musl-macros.patch + "cd /", + "apk add --update argp-standalone bison bsd-compat-headers bzip2-dev curl-dev flex-dev libtool linux-headers musl-libintl musl-obstack-dev xz-dev zlib-dev zstd-dev", + "VERS=0.191", + "curl https://sourceware.org/elfutils/ftp/$VERS/elfutils-$VERS.tar.bz2 > ./elfutils.tar.bz2", + "tar -xf elfutils.tar.bz2", + "cd elfutils-$VERS", + "CFLAGS='-Wno-error -DFNM_EXTMATCH=0 -g -O3' CXXFLAGS='-Wno-error -g -O3' ./configure --enable-libdebuginfod --disable-debuginfod --disable-nls --with-zstd", + "make install", + + # Install Memray's other build and test dependencies + "apk add --update libunwind-dev lz4-dev" +] diff --git a/src/memray/_memray.pyx b/src/memray/_memray.pyx index 8d3ef971fa..417f6f2657 100644 --- a/src/memray/_memray.pyx +++ b/src/memray/_memray.pyx @@ -69,12 +69,12 @@ from libcpp.unordered_map cimport unordered_map from libcpp.utility cimport move from libcpp.vector cimport vector -from memray._destination import Destination -from memray._destination import FileDestination -from memray._destination import SocketDestination -from memray._metadata import Metadata -from memray._stats import Stats -from memray._thread_name_interceptor import ThreadNameInterceptor +from ._destination import Destination +from ._destination import FileDestination +from ._destination import SocketDestination +from ._metadata import Metadata +from ._stats import Stats +from ._thread_name_interceptor import ThreadNameInterceptor cdef extern from "pthread.h" nogil: diff --git a/src/memray/commands/attach.py b/src/memray/commands/attach.py index 6e239e4411..c89065a0ad 100644 --- a/src/memray/commands/attach.py +++ b/src/memray/commands/attach.py @@ -130,7 +130,7 @@ def deactivate_because_timer_elapsed(): def inject(debugger: str, pid: int, port: int, verbose: bool) -> str | None: """Executes a file in a running Python process.""" - injecter = pathlib.Path(memray.__file__).parent / "_inject.abi3.so" + injecter = pathlib.Path(memray._memray.__file__).parent / "_inject.abi3.so" assert injecter.exists() gdb_cmd = [ diff --git a/tests/integration/test_main.py b/tests/integration/test_main.py index 2df8e97a21..3a7753d1ac 100644 --- a/tests/integration/test_main.py +++ b/tests/integration/test_main.py @@ -1442,7 +1442,11 @@ def test_live_tracking(self, tmp_path, simple_test_file, free_port): assert client.returncode == 0 def test_live_tracking_waits_for_client(self, simple_test_file): - # GIVEN/WHEN + # GIVEN + env = os.environ.copy() + env["PYTHONUNBUFFERED"] = "1" + + # WHEN server = subprocess.Popen( [ sys.executable, @@ -1452,7 +1456,7 @@ def test_live_tracking_waits_for_client(self, simple_test_file): "--live-remote", str(simple_test_file), ], - env={"PYTHONUNBUFFERED": "1"}, + env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) @@ -1464,7 +1468,11 @@ def test_live_tracking_waits_for_client(self, simple_test_file): @pytest.mark.parametrize("port", [0, 2**16, 1000000]) def test_run_live_tracking_invalid_port(self, simple_test_file, port): - # GIVEN/WHEN + # GIVEN + env = os.environ.copy() + env["PYTHONUNBUFFERED"] = "1" + + # WHEN server = subprocess.Popen( [ sys.executable, @@ -1476,7 +1484,7 @@ def test_run_live_tracking_invalid_port(self, simple_test_file, port): str(port), str(simple_test_file), ], - env={"PYTHONUNBUFFERED": "1"}, + env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, @@ -1489,7 +1497,11 @@ def test_run_live_tracking_invalid_port(self, simple_test_file, port): @pytest.mark.parametrize("port", [0, 2**16, 1000000]) def test_live_tracking_invalid_port(self, port): - # GIVEN/WHEN + # GIVEN + env = os.environ.copy() + env["PYTHONUNBUFFERED"] = "1" + + # WHEN server = subprocess.Popen( [ sys.executable, @@ -1498,7 +1510,7 @@ def test_live_tracking_invalid_port(self, port): "live", str(port), ], - env={"PYTHONUNBUFFERED": "1"}, + env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, @@ -1511,6 +1523,9 @@ def test_live_tracking_invalid_port(self, port): def test_live_tracking_server_when_client_disconnects(self, free_port, tmp_path): # GIVEN + env = os.environ.copy() + env["PYTHONUNBUFFERED"] = "1" + test_file = tmp_path / "test.py" test_file.write_text("import time; time.sleep(3)") @@ -1525,7 +1540,7 @@ def test_live_tracking_server_when_client_disconnects(self, free_port, tmp_path) "--live-remote", str(test_file), ], - env={"PYTHONUNBUFFERED": "1"}, + env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, @@ -1566,6 +1581,9 @@ def test_live_tracking_server_when_client_disconnects(self, free_port, tmp_path) def test_live_tracking_server_exits_properly_on_sigint(self, simple_test_file): # GIVEN + env = os.environ.copy() + env["PYTHONUNBUFFERED"] = "1" + server = subprocess.Popen( [ sys.executable, @@ -1575,7 +1593,7 @@ def test_live_tracking_server_exits_properly_on_sigint(self, simple_test_file): "--live-remote", str(simple_test_file), ], - env={"PYTHONUNBUFFERED": "1"}, + env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, # Explicitly reset the signal handler for SIGINT to work around any signal diff --git a/tests/integration/test_tracking.py b/tests/integration/test_tracking.py index dbd0d5cfb6..a1b237c6c6 100644 --- a/tests/integration/test_tracking.py +++ b/tests/integration/test_tracking.py @@ -1,6 +1,7 @@ import collections import datetime import mmap +import os import signal import subprocess import sys @@ -1550,7 +1551,7 @@ def test_get_header(self, monkeypatch, tmpdir): metadata = reader.metadata # THEN - assert metadata.end_time > metadata.start_time + assert metadata.end_time >= metadata.start_time assert abs(metadata.start_time - start_time).seconds < 1 assert abs(metadata.end_time - end_time).seconds < 1 assert metadata.total_allocations == n_records @@ -1581,7 +1582,7 @@ def test_get_header_after_snapshot(self, monkeypatch, tmpdir): metadata = reader.metadata # THEN - assert metadata.end_time > metadata.start_time + assert metadata.end_time >= metadata.start_time assert abs(metadata.start_time - start_time).seconds < 1 assert abs(metadata.end_time - end_time).seconds < 1 assert metadata.total_allocations == peak.n_allocations @@ -1599,6 +1600,8 @@ def test_get_header_after_snapshot(self, monkeypatch, tmpdir): def test_header_allocator(self, allocator, allocator_name, tmpdir): # GIVEN output = Path(tmpdir) / "test.bin" + env = os.environ.copy() + env["PYTHONMALLOC"] = allocator # WHEN @@ -1617,7 +1620,7 @@ def test_header_allocator(self, allocator, allocator_name, tmpdir): subprocess.run( [sys.executable, "-c", subprocess_code], timeout=5, - env={"PYTHONMALLOC": allocator}, + env=env, ) reader = FileReader(output)