Binary files /tmp/tmp7GIihR/7NMFOWzcT1/austin-1.0.0/art/austin_die_cut_sticker_twitter.png and /tmp/tmp7GIihR/p2qI6DrxTO/austin-1.0.1/art/austin_die_cut_sticker_twitter.png differ diff -Nru austin-1.0.0/art/austin_die_cut_sticker_twitter.svg austin-1.0.1/art/austin_die_cut_sticker_twitter.svg --- austin-1.0.0/art/austin_die_cut_sticker_twitter.svg 1970-01-01 00:00:00.000000000 +0000 +++ austin-1.0.1/art/austin_die_cut_sticker_twitter.svg 2020-05-21 18:13:56.000000000 +0000 @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + austin + + Binary files /tmp/tmp7GIihR/7NMFOWzcT1/austin-1.0.0/art/card.png and /tmp/tmp7GIihR/p2qI6DrxTO/austin-1.0.1/art/card.png differ diff -Nru austin-1.0.0/art/card.svg austin-1.0.1/art/card.svg --- austin-1.0.0/art/card.svg 1970-01-01 00:00:00.000000000 +0000 +++ austin-1.0.1/art/card.svg 2020-05-21 18:13:56.000000000 +0000 @@ -0,0 +1,7480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + austin + + + + + + + + + A Frame Stack Sampler for CPython + diff -Nru austin-1.0.0/ChangeLog austin-1.0.1/ChangeLog --- austin-1.0.0/ChangeLog 2019-10-16 18:23:41.000000000 +0000 +++ austin-1.0.1/ChangeLog 2020-05-21 18:13:56.000000000 +0000 @@ -1,3 +1,8 @@ +2020-05-16 v1.0.1 + + Bugfix: Fixed broken support for Python 3.8 on MacOS. + + 2019-07-28 v1.0.0 Austin can now profile multi-process Python application: @@ -25,7 +30,7 @@ - --full, -f: Generate samples with a full set of metrics, which include timing and - memory prifiling information. Note that the output from this mode needs + memory profiling information. Note that the output from this mode needs to be processed before it can be used with FlameGraph. - --output, -o: diff -Nru austin-1.0.0/choco/austin.nuspec austin-1.0.1/choco/austin.nuspec --- austin-1.0.0/choco/austin.nuspec 1970-01-01 00:00:00.000000000 +0000 +++ austin-1.0.1/choco/austin.nuspec 2020-05-23 00:02:01.000000000 +0000 @@ -0,0 +1,35 @@ + + + + + austin + %VERSION% + https://github.com/P403n1x87/austin/tree/release/choco/choco + Gabriele N. Tornetta + + Austin (Install) + Gabriele N. Tornetta + https://github.com/P403n1x87/austin + https://rawcdn.githack.com/P403n1x87/austin/8bea939fc7088a7ed1d2012d819890eecd8753c4/art/austin_logo.png + 2018 Gabriele N. Tornetta + https://github.com/P403n1x87/austin/raw/master/LICENSE.md + true + https://github.com/P403n1x87/austin + https://github.com/P403n1x87/austin/issues + python profiling + A Frame Stack Sampler for CPython + + Austin is a Python frame stack sampler for CPython written in pure C. It + samples the stack traces of a Python application so that they can be + visualised and analysed. As such, it serves the basis for building + powerful profilers for Python. + + + + + + diff -Nru austin-1.0.0/choco/tools/chocolateyinstall.ps1 austin-1.0.1/choco/tools/chocolateyinstall.ps1 --- austin-1.0.0/choco/tools/chocolateyinstall.ps1 1970-01-01 00:00:00.000000000 +0000 +++ austin-1.0.1/choco/tools/chocolateyinstall.ps1 2020-05-23 00:02:01.000000000 +0000 @@ -0,0 +1,21 @@ +$ErrorActionPreference = 'Stop'; +$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" + +$url64 = 'https://github.com/P403n1x87/austin/releases/download/v%VERSION%/austin-%VERSION%-win64.msi' + +$packageArgs = @{ + packageName = $env:ChocolateyPackageName + unzipLocation = $toolsDir + fileType = 'MSI' + url64bit = $url64 + + softwareName = 'austin*' + + checksum64 = '%WIN_MSI_HASH%' + checksumType64= 'sha256' + + silentArgs = "/qn /norestart /l*v `"$($env:TEMP)\$($packageName).$($env:chocolateyPackageVersion).MsiInstall.log`"" + validExitCodes= @(0, 3010, 1641) +} + +Install-ChocolateyPackage @packageArgs diff -Nru austin-1.0.0/configure.ac austin-1.0.1/configure.ac --- austin-1.0.0/configure.ac 2019-10-16 18:15:15.000000000 +0000 +++ austin-1.0.1/configure.ac 2020-05-21 18:13:56.000000000 +0000 @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) -AC_INIT([austin], [1.0.0], [https://github.com/p403n1x87/austin/issues]) +AC_INIT([austin], [1.0.1], [https://github.com/p403n1x87/austin/issues]) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE diff -Nru austin-1.0.0/debian/austin.1 austin-1.0.1/debian/austin.1 --- austin-1.0.0/debian/austin.1 2019-10-16 18:16:22.000000000 +0000 +++ austin-1.0.1/debian/austin.1 2020-06-05 16:24:00.000000000 +0000 @@ -1,7 +1,7 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6. -.TH AUSTIN "1" "October 2019" "austin 1.0.0" "User Commands" +.TH AUSTIN "1" "May 2020" "austin 1.0.1" "User Commands" .SH NAME -austin \- manual page for austin 1.0.0 +austin \- manual page for austin 1.0.1 .SH SYNOPSIS .B austin [\fI\,OPTION\/\fR...] \fI\,command \/\fR[\fI\,ARG\/\fR...] diff -Nru austin-1.0.0/debian/changelog austin-1.0.1/debian/changelog --- austin-1.0.0/debian/changelog 2019-10-20 16:10:00.000000000 +0000 +++ austin-1.0.1/debian/changelog 2020-06-05 16:24:00.000000000 +0000 @@ -1,3 +1,17 @@ +austin (1.0.1-2) unstable; urgency=medium + + Enhanced test sources. Closes: #962001. + + -- Gabriele N. Tornetta Fri, 05 Jun 2020 17:24:00 +0100 + + +austin (1.0.1-1) unstable; urgency=medium + + * Fixed support for Python 3.8 + + -- Gabriele N. Tornetta Sat, 16 May 2020 12:36:00 +0100 + + austin (1.0.0-1) unstable; urgency=medium * Added support for multi-process Python applications diff -Nru austin-1.0.0/debian/copyright austin-1.0.1/debian/copyright --- austin-1.0.0/debian/copyright 2019-04-07 21:18:47.000000000 +0000 +++ austin-1.0.1/debian/copyright 2020-05-21 18:13:56.000000000 +0000 @@ -4,7 +4,7 @@ Source: https://github.com/P403n1x87/austin Files: * -Copyright: 2018-2019 Gabriele N. Tornetta +Copyright: 2018-2020 Gabriele N. Tornetta License: GPL-3+ License: GPL-3+ diff -Nru austin-1.0.0/debian/patches/962001 austin-1.0.1/debian/patches/962001 --- austin-1.0.0/debian/patches/962001 1970-01-01 00:00:00.000000000 +0000 +++ austin-1.0.1/debian/patches/962001 2020-06-05 16:24:00.000000000 +0000 @@ -0,0 +1,1752 @@ +Description: Enhance test sources +--- austin-1.0.1.orig/.travis.yml ++++ austin-1.0.1/.travis.yml +@@ -30,7 +30,6 @@ jobs: + os: windows + + before_script: +- # Linux Dependencies + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; + then + sudo add-apt-repository ppa:deadsnakes/ppa -y; +@@ -50,12 +49,6 @@ before_script: + brew cask install anaconda || true; + fi + +- - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; +- then +- powershell Install-WindowsFeature Net-Framework-Core; +- cinst -y wixtoolset; +- fi +- + script: + - echo $TRAVIS_OS_NAME -- $TARGET + +@@ -64,12 +57,16 @@ script: + ./configure && + make && + sudo make check; ++ ++ test -f /tmp/austin_tests.log && cat /tmp/austin_tests.log; + fi + + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; + then + gcc -s -Wall -O3 -o src/austin src/*.c && + sudo bats test/macos/test.bats; ++ ++ test -f /tmp/austin_tests.log && cat /tmp/austin_tests.log; + fi + + - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; +@@ -78,6 +75,7 @@ script: + fi + + after_success: ++ ./src/austin -V; + ./src/austin --usage + + after_failure: +@@ -119,12 +117,6 @@ before_deploy: + export ZIP_CMD="7z a -tzip"; + export ZIP_SUFFIX="win-${TARGET%%-*}.zip"; + export AUSTIN_EXE=austin.exe; +- +- export WIN_MSI="austin-$VERSION-win64.msi"; +- +- sed -i "s/%VERSION%/$VERSION/g" wix/Austin.wxs; +- candle wix/Austin.wxs -out wix/Austin.wixobj; +- light -ext WixUIExtension wix/Austin.wixobj -out $WIN_MSI; + fi + + - export ARTEFACT="austin-${VERSION}-${ZIP_SUFFIX}" +@@ -140,30 +132,8 @@ before_deploy: + - git tag -a -f -m "Release $VERSION" $TRAVIS_TAG + + deploy: +- - provider: releases +- edge: true +- token: $GITHUB_TOKEN +- file: $ARTEFACT +- overwrite: true +- +- - provider: releases +- edge: true +- token: $GITHUB_TOKEN +- file: $WIN_MSI +- overwrite: true +- on: +- condition: "$TRAVIS_OS_NAME = windows" +- +-after_deploy: +- - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; +- then +- export WIN_MSI_HASH=$( sha256sum $WIN_MSI | head -c 64 ); +- +- cd choco; +- +- sed -i "s/%WIN_MSI_HASH%/$WIN_MSI_HASH/g" tools/chocolateyinstall.ps1; +- /bin/find . -type f -exec sed -i "s/%VERSION%/$VERSION/g" {} \; ; +- choco apikey --key $CHOCO_APIKEY --source https://push.chocolatey.org/; +- choco pack; +- choco push; +- fi ++ provider: releases ++ edge: true ++ token: $GITHUB_TOKEN ++ file: $ARTEFACT ++ overwrite: true +--- /dev/null ++++ austin-1.0.1/test/common.bash +@@ -0,0 +1,227 @@ ++# This file is part of "austin" which is released under GPL. ++# ++# See file LICENCE or go to http://www.gnu.org/licenses/ for full license ++# details. ++# ++# Austin is a Python frame stack sampler for CPython. ++# ++# Copyright (c) 2019 Gabriele N. Tornetta . ++# All rights reserved. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# ----------------------------------------------------------------------------- ++# -- Austin ++# ----------------------------------------------------------------------------- ++ ++AUSTIN=`test -f src/austin && echo "src/austin" || echo "austin"` ++ ++ ++# ----------------------------------------------------------------------------- ++# -- Python ++# ----------------------------------------------------------------------------- ++ ++function check_python { ++ version="${1}" ++ ++ if ! python$version -V; then skip "Python $version not found."; fi ++ ++ PYTHON="python$version" ++} ++ ++# ----------------------------------------------------------------------------- ++# -- Logging ++# ----------------------------------------------------------------------------- ++ ++function log { ++ echo "${1}" | tee -a "/tmp/austin_tests.log" ++} ++ ++# ----------------------------------------------------------------------------- ++ ++function step { ++ log " :: ${1}" ++} ++ ++ ++# ----------------------------------------------------------------------------- ++# -- Assertions ++# ----------------------------------------------------------------------------- ++ ++IGNORE=0 ++FAIL=0 ++REPEAT=0 ++ ++# ----------------------------------------------------------------------------- ++ ++function ignore { ++ IGNORE=1 ++} ++ ++# ----------------------------------------------------------------------------- ++ ++function check_ignored { ++ FAIL=1 ++ ++ if [ $IGNORE == 1 ] && [ $REPEAT == 0 ] ++ then ++ log " The test it marked as 'ignore'" ++ fi ++ log ++ log " Status: $status" ++ log ++ log " Collected Output" ++ log " ================" ++ log ++ for line in "${lines[@]}" ++ do ++ log " $line" ++ done ++ log ++ ++ if [ $IGNORE == 0 ] && [ $REPEAT == 0 ]; then false; fi ++} ++ ++# ----------------------------------------------------------------------------- ++ ++function assert { ++ local message="${1}" ++ local condition="${2}" ++ ++ if [ ! $condition ] ++ then ++ log " Assertion failed: \"${message}\"" ++ check_ignored ++ fi ++ ++ true ++} ++ ++# ----------------------------------------------------------------------------- ++ ++function assert_success { ++ : "${output?}" ++ : "${status?}" ++ ++ assert "Command was successful" "$status == 0" ++} ++ ++# ----------------------------------------------------------------------------- ++ ++function assert_output { ++ local pattern="${1}" ++ : "${output?}" ++ ++ if ! echo "$output" | grep -q "${pattern}" ++ then ++ log " Assertion failed: Output contains pattern '${pattern}'" ++ check_ignored ++ fi ++ ++ true ++} ++ ++# ----------------------------------------------------------------------------- ++ ++function assert_not_output { ++ local pattern="${1}" ++ : "${output?}" ++ ++ if echo "$output" | grep -q "${pattern}" ++ then ++ log " Assertion failed: Output does not contain pattern '${pattern}'" ++ check_ignored ++ fi ++ ++ true ++} ++ ++# ----------------------------------------------------------------------------- ++ ++function assert_file { ++ local file="$1" ++ local pattern="${2}" ++ ++ if ! cat "$file" | grep -q "${pattern}" ++ then ++ log " Assertion failed: File $file contains pattern '${pattern}'" ++ log ++ log "File content" ++ log "============" ++ log ++ log "$( head "$file" )" ++ log ". . ." ++ log "$( tail "$file" )" ++ log ++ check_ignored ++ fi ++ ++ true ++} ++ ++# ----------------------------------------------------------------------------- ++ ++function assert_not_file { ++ local file="$1" ++ local pattern="${2}" ++ ++ if ! test -f $file ++ then ++ log " Assertion failed: File $file does not exist" ++ check_ignored ++ fi ++ ++ if cat "$file" | grep -q "${pattern}" ++ then ++ log " Assertion failed: File $file does not contain pattern '${pattern}'" ++ log ++ log "File content" ++ log "============" ++ log ++ log "$( head "$file" )" ++ log ". . ." ++ log "$( tail "$file" )" ++ log ++ check_ignored ++ fi ++ ++ true ++} ++ ++# ----------------------------------------------------------------------------- ++ ++function repeat { ++ local times="${1}" ++ shift ++ ++ REPEAT=1 ++ ++ for ((i=1;i<=times;i++)) ++ do ++ log ">> Attempt $i of $times" ++ FAIL=0 ++ $@ ++ if [ $FAIL == 0 ]; then return; fi ++ done ++ ++ REPEAT=0 ++ ++ log "<< Test failed on $times attempt(s)." ++ ++ if [ $IGNORE == 1 ] ++ then ++ skip "Failed but marked as 'ignore'." ++ fi ++ ++ false ++} +--- austin-1.0.1.orig/test/macos/test.bats ++++ austin-1.0.1/test/macos/test.bats +@@ -1,9 +1,33 @@ ++# This file is part of "austin" which is released under GPL. ++# ++# See file LICENCE or go to http://www.gnu.org/licenses/ for full license ++# details. ++# ++# Austin is a Python frame stack sampler for CPython. ++# ++# Copyright (c) 2019 Gabriele N. Tornetta . ++# All rights reserved. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++load "../common" ++ ++ + test_case() { + run bats test/macos/test_$1.bats +- echo "$output" +- [ $status = 0 ] + } + ++ + @test "Test Austin: fork" { + test_case fork + } +@@ -17,9 +41,7 @@ test_case() { + } + + @test "Test Austin: valgrind" { +- skip "We skip valgrind on Mac OS for now" +- ++ ignore + if ! which valgrind; then skip "Valgrind not found"; fi +- + test_case valgrind + } +--- austin-1.0.1.orig/test/macos/test_attach.bats ++++ austin-1.0.1/test/macos/test_attach.bats +@@ -1,81 +1,69 @@ +-attach_austin() { +- python_bin=$1 +- ignore=$2 ++# This file is part of "austin" which is released under GPL. ++# ++# See file LICENCE or go to http://www.gnu.org/licenses/ for full license ++# details. ++# ++# Austin is a Python frame stack sampler for CPython. ++# ++# Copyright (c) 2019 Gabriele N. Tornetta . ++# All rights reserved. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . + +- if ! $python_bin -V; then skip "$python_bin not found."; fi +- +- for i in {1..3} +- do +- echo "> Run $i of 3" +- +- # ------------------------------------------------------------------------- ++load "../common" + +- echo " :: Time profiling" +- $python_bin test/sleepy.py & +- sleep 1 +- run sudo src/austin -i 10000 -t 10000 -p $! + +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi ++function attach_austin { ++ python_bin="${1}" + +- if ! echo "$output" | grep -q "; (test/sleepy.py);L[[:digit:]]* " +- then +- echo " Output: NOK" +- continue +- fi +- echo " Output: OK" ++ if ! $python_bin -V; then skip "$python_bin not found."; fi + +- # ------------------------------------------------------------------------- ++ log "Attach [Python $version]" + +- echo " :: Memory profiling" ++ # ------------------------------------------------------------------------- ++ step "Time profiling" ++ # ------------------------------------------------------------------------- + $python_bin test/sleepy.py & + sleep 1 +- run sudo src/austin -mi 100 -t 10000 -p $! ++ run sudo $AUSTIN -i 10000 -t 100 -p $! + +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi ++ assert_success ++ assert_output "; (test/sleepy.py);L[[:digit:]]* " + +- if echo "$output" | grep -q "Thread " +- then +- echo " Output: OK" +- return +- fi +- echo " Output: NOK" +- done +- +- if [ $ignore ] +- then +- echo "Test marked as 'Ignore' failed" +- fi +- echo +- echo "Collected Output" +- echo "================" +- echo +- echo "$output" +- echo +- +- false + } + + + # ----------------------------------------------------------------------------- +- +- +-# @test "Test Austin with the default Python 3" { +-# /usr/bin/python3 -m venv /tmp/py3 +-# source /tmp/py3/bin/activate +-# attach_austin "python3" +-# test -d /tmp/py3 && rm -rf /tmp/py3 +-# } ++# -- Test Cases ++# ----------------------------------------------------------------------------- + + @test "Test Austin with default Python 3 from Homebrew" { + attach_austin "/usr/local/bin/python3" + } + + @test "Test Austin with Python 3.8 from Homebrew (if available)" { +- attach_austin "/usr/local/opt/python@3.8/bin/python3" ignore ++ ignore ++ repeat 3 attach_austin "/usr/local/opt/python@3.8/bin/python3" + } + + @test "Test Austin with Python 3 from Anaconda (if available)" { +- attach_austin "/usr/local/anaconda3/bin/python" ignore ++ ignore ++ repeat 3 attach_austin "/usr/local/anaconda3/bin/python" + } ++ ++# @test "Test Austin with the default Python 3" { ++# /usr/bin/python3 -m venv /tmp/py3 ++# source /tmp/py3/bin/activate ++# attach_austin "python3" ++# test -d /tmp/py3 && rm -rf /tmp/py3 ++# } +--- austin-1.0.1.orig/test/macos/test_fork.bats ++++ austin-1.0.1/test/macos/test_fork.bats +@@ -1,98 +1,92 @@ +-#!/usr/bin/env bats ++# This file is part of "austin" which is released under GPL. ++# ++# See file LICENCE or go to http://www.gnu.org/licenses/ for full license ++# details. ++# ++# Austin is a Python frame stack sampler for CPython. ++# ++# Copyright (c) 2019 Gabriele N. Tornetta . ++# All rights reserved. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++load "../common" ++ ++ ++function invoke_austin { ++ python_bin="${1}" + +-invoke_austin() { +- python_bin=$1 +- ignore=$2 +- + if ! $python_bin -V; then skip "$python_bin not found."; fi + +- for i in {1..3} +- do +- echo "> Run $i of 3" +- +- # ------------------------------------------------------------------------- +- +- echo " :: Standard profiling" +- run sudo src/austin -i 1000 -t 10000 $python_bin test/target34.py +- +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi +- +- if ! echo "$output" | grep -q "keep_cpu_busy (test/target34.py);L" \ +- || echo "$output" | grep -q "Unwanted" +- then +- continue +- fi +- echo " Output: OK" +- +- # ------------------------------------------------------------------------- +- +- echo " :: Memory profiling" +- run sudo src/austin -i 1000 -t 10000 -m $python_bin test/target34.py +- +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi +- +- if ! echo "$output" | grep -q "keep_cpu_busy (test/target34.py);L" +- then +- continue +- fi +- echo " Output: OK" +- +- # ------------------------------------------------------------------------- +- +- echo " :: Output file" +- run sudo src/austin -i 10000 -t 10000 -o /tmp/austin_out.txt $python_bin test/target34.py +- +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi +- +- if ! echo "$output" | grep -q "Unwanted" \ +- || cat /tmp/austin_out.txt | grep -q "keep_cpu_busy (test/target34.py);L" +- then +- echo " Output: OK" +- return +- fi +- done +- +- if [ $ignore ] +- then +- skip "Test failed but marked as 'Ignore'" +- else +- echo +- echo "Collected Output" +- echo "================" +- echo +- echo "$output" +- echo +- false +- fi +-} ++ log "Fork [Python $version]" + ++ # ------------------------------------------------------------------------- ++ step "Standard profiling" ++ # ------------------------------------------------------------------------- ++ run sudo $AUSTIN -i 1000 -t 10000 $python_bin test/target34.py ++ ++ assert_success ++ assert_output "keep_cpu_busy (test/target34.py);L" ++ assert_not_output "Unwanted" ++ ++ # ------------------------------------------------------------------------- ++ step "Memory profiling" ++ # ------------------------------------------------------------------------- ++ run sudo $AUSTIN -i 1000 -t 10000 -m $python_bin test/target34.py ++ ++ assert_success ++ assert_output "keep_cpu_busy (test/target34.py);L" ++ ++ # ------------------------------------------------------------------------- ++ step "Output file" ++ # ------------------------------------------------------------------------- ++ run sudo $AUSTIN -i 10000 -t 10000 -o /tmp/austin_out.txt $python_bin test/target34.py ++ ++ assert_success ++ assert_output "Unwanted" ++ assert_not_output "keep_cpu_busy (test/target34.py);L" ++ assert_file "/tmp/austin_out.txt" "keep_cpu_busy (test/target34.py);L" + +-# ----------------------------------------------------------------------------- ++} + ++# ----------------------------------------------------------------------------- + + teardown() { + if [ -f /tmp/austin_out.txt ]; then rm /tmp/austin_out.txt; fi + } + + +-# @test "Test Austin with the default Python 3" { +-# /usr/bin/python3 -m venv --copies --without-pip /tmp/py3 +-# source /tmp/py3/bin/activate +-# invoke_austin "python3" +-# test -d /tmp/py3 && rm -rf /tmp/py3 +-# } ++# ----------------------------------------------------------------------------- ++# -- Test Cases ++# ----------------------------------------------------------------------------- + + @test "Test Austin with default Python 3 from Homebrew" { +- invoke_austin "/usr/local/bin/python3" ++ repeat 3 invoke_austin "/usr/local/bin/python3" + } + + @test "Test Austin with Python 3.8 from Homebrew (if available)" { +- invoke_austin "/usr/local/opt/python@3.8/bin/python3" ignore ++ ignore ++ repeat 3 invoke_austin "/usr/local/opt/python@3.8/bin/python3" + } + + @test "Test Austin with Python 3 from Anaconda (if available)" { +- invoke_austin "/usr/local/anaconda3/bin/python" ignore ++ ignore ++ repeat 3 invoke_austin "/usr/local/anaconda3/bin/python" + } ++ ++# @test "Test Austin with the default Python 3" { ++# /usr/bin/python3 -m venv --copies --without-pip /tmp/py3 ++# source /tmp/py3/bin/activate ++# invoke_austin "python3" ++# test -d /tmp/py3 && rm -rf /tmp/py3 ++# } +--- austin-1.0.1.orig/test/macos/test_fork_mp.bats ++++ austin-1.0.1/test/macos/test_fork_mp.bats +@@ -1,69 +1,72 @@ +-invoke_austin() { +- python_bin=$1 +- ignore=$2 ++# This file is part of "austin" which is released under GPL. ++# ++# See file LICENCE or go to http://www.gnu.org/licenses/ for full license ++# details. ++# ++# Austin is a Python frame stack sampler for CPython. ++# ++# Copyright (c) 2019 Gabriele N. Tornetta . ++# All rights reserved. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . + +- if ! $python_bin -V; then skip "$python_bin not found."; fi ++load "../common" ++ ++ ++function invoke_austin { ++ python_bin="${1}" + +- for i in {1..3} +- do +- echo "> Run $i of 3" ++ if ! $python_bin -V; then skip "$python_bin not found."; fi + +- # ------------------------------------------------------------------------- ++ log "Fork Multi-processing [Python $version]" + +- echo " :: Profiling of multi-process program" +- run sudo src/austin -i 100000 -C $python_bin test/target_mp.py ++ # ------------------------------------------------------------------------- ++ step "Profiling of multi-process program" ++ # ------------------------------------------------------------------------- ++ run sudo $AUSTIN -i 100000 -C $python_bin test/target_mp.py + +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi ++ assert_success + +- echo " - Check expected number of processes." + expected=3 +- n_procs=$( echo "$output" | sed -E 's/Process ([0-9]+);.+/\1/' | sort | uniq | wc -l ) +- echo " Expected at least $expected and got $n_procs" +- if [ $n_procs -lt $expected ]; then continue; fi +- +- echo " - Check output contains frames." +- if echo "$output" | grep -q "fact" +- then +- echo " Output: OK" +- return +- fi +- echo " Output: NOK" +- done +- +- if [ $ignore ] +- then +- echo "Test marked as 'Ignore' failed" +- fi +- echo +- echo "Collected Output" +- echo "================" +- echo +- echo "$output" +- echo +- +- false +-} ++ n_procs=$( echo "$output" | sed -E 's/P([0-9]+);.+/\1/' | sort | uniq | wc -l ) ++ assert "At least 3 parallel processes" "$n_procs >= $expected" + ++ assert_output "fact" + +-# ----------------------------------------------------------------------------- ++} + + +-# @test "Test Austin with the default Python 3" { +-# /usr/bin/python3 -m venv /tmp/py3 +-# source /tmp/py3/bin/activate +-# invoke_austin "python3" +-# test -d /tmp/py3 && rm -rf /tmp/py3 +-# } ++# ----------------------------------------------------------------------------- ++# -- Test Cases ++# ----------------------------------------------------------------------------- + + @test "Test Austin with default Python 3 from Homebrew" { +- invoke_austin "/usr/local/bin/python3" ++ repeat 3 invoke_austin "/usr/local/bin/python3" + } + + @test "Test Austin with Python 3.8 from Homebrew (if available)" { +- invoke_austin "/usr/local/opt/python@3.8/bin/python3" ignore ++ ignore ++ repeat 3 invoke_austin "/usr/local/opt/python@3.8/bin/python3" + } + + @test "Test Austin with Python 3 from Anaconda (if available)" { +- invoke_austin "/usr/local/anaconda3/bin/python" ignore +-} +\ No newline at end of file ++ ignore ++ repeat 3 invoke_austin "/usr/local/anaconda3/bin/python" ++} ++ ++# @test "Test Austin with the default Python 3" { ++# /usr/bin/python3 -m venv /tmp/py3 ++# source /tmp/py3/bin/activate ++# invoke_austin "python3" ++# test -d /tmp/py3 && rm -rf /tmp/py3 ++# } +--- austin-1.0.1.orig/test/macos/test_valgrind.bats ++++ austin-1.0.1/test/macos/test_valgrind.bats +@@ -1,66 +1,80 @@ +-invoke_austin() { +- python_bin=$1 +- ignore=$2 +- +- if ! $python_bin -V; then skip "$python not found."; fi +- +- for i in {1..3} +- do +- echo "> Run $i of 3" +- +- # ------------------------------------------------------------------------- +- +- echo " :: Valgrind test" +- run sudo valgrind \ ++# This file is part of "austin" which is released under GPL. ++# ++# See file LICENCE or go to http://www.gnu.org/licenses/ for full license ++# details. ++# ++# Austin is a Python frame stack sampler for CPython. ++# ++# Copyright (c) 2019 Gabriele N. Tornetta . ++# All rights reserved. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++load "../common" ++ ++ ++function invoke_austin { ++ python_bin="${1}" ++ ++ if ! $python_bin -V; then skip "$python_bin not found."; fi ++ ++ log "Valgrind [Python $version]" ++ ++ # ------------------------------------------------------------------------- ++ step "Valgrind test" ++ # ------------------------------------------------------------------------- ++ run valgrind \ + --error-exitcode=42 \ + --leak-check=full \ + --show-leak-kinds=all \ + --errors-for-leak-kinds=all \ + --track-fds=yes \ +- --track-origins=yes \ +- src/austin -i 100000 -t 10000 $python_bin test/target34.py +- echo " Exit code: $status" +- echo " Valgrind report: <" +- echo "$output" +- if [ $status = 0 ] ++ $AUSTIN -i 100000 -t 10000 -o /dev/null $PYTHON test/target34.py ++ ++ if [ ! $status == 0 ] + then +- return ++ log " Valgrind Report" ++ log " ===============" ++ for line in "${lines[@]}" ++ do ++ log " $line" ++ done ++ check_ignored + fi +- done +- +- if [ $ignore ] +- then +- echo "Test marked as 'Ignore' failed" +- fi +- echo +- echo "Collected Output" +- echo "================" +- echo +- echo "$output" +- echo +- +- false + } + + + # ----------------------------------------------------------------------------- +- +- +-# @test "Test Austin with the default Python 3" { +-# /usr/bin/python3 -m venv /tmp/py3 +-# source /tmp/py3/bin/activate +-# invoke_austin "python3" +-# test -d /tmp/py3 && rm -rf /tmp/py3 +-# } ++# -- Test Cases ++# ----------------------------------------------------------------------------- + + @test "Test Austin with default Python 3 from Homebrew" { +- invoke_austin "/usr/local/bin/python3" ++ repeat 3 invoke_austin "/usr/local/bin/python3" + } + + @test "Test Austin with Python 3.8 from Homebrew (if available)" { +- invoke_austin "/usr/local/opt/python@3.8/bin/python3" ignore ++ ignore ++ repeat 3 invoke_austin "/usr/local/opt/python@3.8/bin/python3" + } + + @test "Test Austin with Python 3 from Anaconda (if available)" { +- invoke_austin "/usr/local/anaconda3/bin/python" ignore ++ ignore ++ repeat 3 invoke_austin "/usr/local/anaconda3/bin/python" + } ++ ++# @test "Test Austin with the default Python 3" { ++# /usr/bin/python3 -m venv /tmp/py3 ++# source /tmp/py3/bin/activate ++# invoke_austin "python3" ++# test -d /tmp/py3 && rm -rf /tmp/py3 ++# } +--- austin-1.0.1.orig/test/sleepy.py ++++ austin-1.0.1/test/sleepy.py +@@ -3,7 +3,7 @@ + # See file LICENCE or go to http://www.gnu.org/licenses/ for full license + # details. + # +-# Sibilla is a Python ORM for the Oracle Database. ++# Austin is a Python frame stack sampler for CPython. + # + # Copyright (c) 2019 Gabriele N. Tornetta . + # All rights reserved. +@@ -25,11 +25,11 @@ import time + + def cpu_bound(): + a = [] +- for i in range(100000): ++ for i in range(1000000): + a.append(i) + + + if __name__ == "__main__": + for n in range(2): + cpu_bound() +- time.sleep(1) ++ time.sleep(.7) +--- austin-1.0.1.orig/test/target.py ++++ austin-1.0.1/test/target.py +@@ -5,7 +5,7 @@ + # See file LICENCE or go to http://www.gnu.org/licenses/ for full license + # details. + # +-# Sibilla is a Python ORM for the Oracle Database. ++# Austin is a Python frame stack sampler for CPython. + # + # Copyright (c) 2019 Gabriele N. Tornetta . + # All rights reserved. +--- austin-1.0.1.orig/test/target34.py ++++ austin-1.0.1/test/target34.py +@@ -5,7 +5,7 @@ + # See file LICENCE or go to http://www.gnu.org/licenses/ for full license + # details. + # +-# Sibilla is a Python ORM for the Oracle Database. ++# Austin is a Python frame stack sampler for CPython. + # + # Copyright (c) 2019 Gabriele N. Tornetta . + # All rights reserved. +@@ -29,7 +29,7 @@ def keep_cpu_busy(): + a = [] + for i in range(2000000): + a.append(i) +- if i % 100000 == 0: ++ if i % 1000000 == 0: + print("Unwanted output " + str(i)) + + +--- austin-1.0.1.orig/test/target_mp.py ++++ austin-1.0.1/test/target_mp.py +@@ -3,7 +3,7 @@ + # See file LICENCE or go to http://www.gnu.org/licenses/ for full license + # details. + # +-# Sibilla is a Python ORM for the Oracle Database. ++# Austin is a Python frame stack sampler for CPython. + # + # Copyright (c) 2019 Gabriele N. Tornetta . + # All rights reserved. +--- austin-1.0.1.orig/test/test.bats ++++ austin-1.0.1/test/test.bats +@@ -1,9 +1,30 @@ +-#!/usr/bin/env bats ++# This file is part of "austin" which is released under GPL. ++# ++# See file LICENCE or go to http://www.gnu.org/licenses/ for full license ++# details. ++# ++# Austin is a Python frame stack sampler for CPython. ++# ++# Copyright (c) 2019 Gabriele N. Tornetta . ++# All rights reserved. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++load "common" ++ + + test_case() { + run bats test/test_$1.bats +- echo "$output" +- [ $status = 0 ] + } + + @test "Test Austin: fork" { +@@ -22,5 +43,6 @@ test_case() { + } + + @test "Test Austin: valgrind" { ++ ignore + test_case valgrind + } +--- austin-1.0.1.orig/test/test_attach.bats ++++ austin-1.0.1/test/test_attach.bats +@@ -1,149 +1,94 @@ +-attach_austin_2_3() { +- if ! python$1 -V; then skip "Python $1 not found."; fi +- +- for i in {1..3} +- do +- echo "> Run $i of 3" +- +- # ------------------------------------------------------------------------- +- +- echo " :: Standard profiling" +- python$1 test/sleepy.py & +- sleep 1 +- run src/austin -i 100000 -t 10000 -p $! +- +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi +- +- if ! echo "$output" | grep -q ";? (test/sleepy.py);L[[:digit:]]* " +- then +- continue +- fi +- echo " Output: OK" +- +- # ------------------------------------------------------------------------- +- +- echo " :: Memory profiling" +- python$1 test/sleepy.py & +- sleep 1 +- run src/austin -mi 100 -t 10000 -p $! +- +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi +- +- if echo "$output" | grep -q "cpu_bound" +- then +- echo " Output: OK" +- return +- fi +- done +- +- if [ $2 ] +- then +- skip "Test failed but marked as 'Ignore'" +- else +- echo +- echo "Collected Output" +- echo "================" +- echo +- echo "$output" +- echo +- false +- fi +-} +- +-attach_austin() { +- if ! python$1 -V; then skip "Python $1 not found."; fi +- +- for i in {1..3} +- do +- echo "> Run $i of 3" +- +- # ------------------------------------------------------------------------- +- +- echo " :: Standard profiling" +- python$1 test/sleepy.py & +- sleep 1 +- run src/austin -i 10000 -t 10000 -p $! +- +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi +- +- if ! echo "$output" | grep -q "; (test/sleepy.py);L[[:digit:]]* " +- then +- continue +- fi +- echo " Output: OK" +- +- # ------------------------------------------------------------------------- +- +- python$1 test/sleepy.py & ++# This file is part of "austin" which is released under GPL. ++# ++# See file LICENCE or go to http://www.gnu.org/licenses/ for full license ++# details. ++# ++# Austin is a Python frame stack sampler for CPython. ++# ++# Copyright (c) 2019 Gabriele N. Tornetta . ++# All rights reserved. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++load "common" ++ ++ ++function attach_austin { ++ local version="${1}" ++ ++ check_python $version ++ ++ log "Attach [Python $version]" ++ ++ # ------------------------------------------------------------------------- ++ step "Standard profiling" ++ # ------------------------------------------------------------------------- ++ $PYTHON test/sleepy.py & + sleep 1 +- run src/austin -mi 100 -t 10000 -p $! ++ run $AUSTIN -i 100 -t 100 -p $! + +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi ++ assert_success ++ assert_output "(test/sleepy.py);L[[:digit:]]* " + +- if echo "$output" | grep -q "cpu_bound" +- then +- echo " Output: OK" +- return +- fi +- done +- +- if [ $2 ] +- then +- skip "Test failed but marked as 'Ignore'" +- else +- echo "$output" +- false +- fi + } + + + # ----------------------------------------------------------------------------- +- ++# -- Test Cases ++# ----------------------------------------------------------------------------- + + @test "Test Austin with Python 2.3" { +- attach_austin_2_3 "2.3" ignore ++ ignore ++ repeat 3 attach_austin "2.3" + } + + @test "Test Austin with Python 2.4" { +- attach_austin_2_3 "2.4" ignore ++ ignore ++ repeat 3 attach_austin "2.4" + } + + @test "Test Austin with Python 2.5" { +- attach_austin "2.5" ++ repeat 3 attach_austin "2.5" + } + + @test "Test Austin with Python 2.6" { +- attach_austin "2.6" ++ repeat 3 attach_austin "2.6" + } + + @test "Test Austin with Python 2.7" { +- attach_austin "2.7" ++ repeat 3 attach_austin "2.7" + } + + @test "Test Austin with Python 3.3" { +- attach_austin "3.3" ++ repeat 3 attach_austin "3.3" + } + + @test "Test Austin with Python 3.4" { +- attach_austin "3.4" ++ repeat 3 attach_austin "3.4" + } + + @test "Test Austin with Python 3.5" { +- attach_austin "3.5" ++ repeat 3 attach_austin "3.5" + } + + @test "Test Austin with Python 3.6" { +- attach_austin "3.6" ++ repeat 3 attach_austin "3.6" + } + + @test "Test Austin with Python 3.7" { +- attach_austin "3.7" ++ repeat 3 attach_austin "3.7" + } + + @test "Test Austin with Python 3.8" { +- attach_austin "3.8" ++ repeat 3 attach_austin "3.8" + } +--- austin-1.0.1.orig/test/test_fork.bats ++++ austin-1.0.1/test/test_fork.bats +@@ -1,120 +1,117 @@ +-#!/usr/bin/env bats ++# This file is part of "austin" which is released under GPL. ++# ++# See file LICENCE or go to http://www.gnu.org/licenses/ for full license ++# details. ++# ++# Austin is a Python frame stack sampler for CPython. ++# ++# Copyright (c) 2019 Gabriele N. Tornetta . ++# All rights reserved. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++load "common" ++ ++ ++function invoke_austin { ++ local version="${1}" ++ ++ check_python $version ++ ++ log "Fork [Python $version]" ++ ++ # ------------------------------------------------------------------------- ++ step "Standard profiling" ++ # ------------------------------------------------------------------------- ++ run $AUSTIN -i 1000 -t 10000 $PYTHON test/target34.py ++ ++ assert_success ++ assert_output "keep_cpu_busy (test/target34.py);L" ++ assert_not_output "Unwanted" ++ ++ # ------------------------------------------------------------------------- ++ step "Memory profiling" ++ # ------------------------------------------------------------------------- ++ run $AUSTIN -i 1000 -t 10000 -m $PYTHON test/target34.py ++ ++ assert_success ++ assert_output "keep_cpu_busy (test/target34.py);L" ++ ++ # ------------------------------------------------------------------------- ++ step "Output file" ++ # ------------------------------------------------------------------------- ++ run $AUSTIN -i 10000 -t 10000 -o /tmp/austin_out.txt $PYTHON test/target34.py ++ ++ assert_success ++ assert_output "Unwanted" ++ assert_not_output "keep_cpu_busy (test/target34.py);L" ++ assert_file "/tmp/austin_out.txt" "keep_cpu_busy (test/target34.py);L" + +-invoke_austin() { +- if ! python$1 -V; then skip "Python $1 not found."; fi +- +- for i in {1..3} +- do +- echo "> Run $i of 3" +- +- # ------------------------------------------------------------------------- +- +- echo " :: Standard profiling" +- run src/austin -i 1000 -t 10000 python$1 test/target34.py +- +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi +- +- if ! echo "$output" | grep -q "keep_cpu_busy (test/target34.py);L" \ +- || echo "$output" | grep -q "Unwanted" +- then +- continue +- fi +- echo " Output: OK" +- +- # ------------------------------------------------------------------------- +- +- echo " :: Memory profiling" +- run src/austin -i 1000 -t 10000 -m python$1 test/target34.py +- +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi +- +- if ! echo "$output" | grep -q "keep_cpu_busy (test/target34.py);L" +- then +- continue +- fi +- echo " Output: OK" +- +- # ------------------------------------------------------------------------- +- +- echo " :: Output file" +- run src/austin -i 10000 -t 10000 -o /tmp/austin_out.txt python$1 test/target34.py +- +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi +- +- if ! echo "$output" | grep -q "Unwanted" \ +- || cat /tmp/austin_out.txt | grep -q "keep_cpu_busy (test/target34.py);L" +- then +- echo " Output: OK" +- return +- fi +- done +- +- if [ $2 ] +- then +- skip "Test failed but marked as 'Ignore'" +- else +- echo +- echo "Collected Output" +- echo "================" +- echo +- echo "$output" +- echo +- false +- fi + } + +- + # ----------------------------------------------------------------------------- + +- +-teardown() { ++function teardown { + if [ -f /tmp/austin_out.txt ]; then rm /tmp/austin_out.txt; fi + } + + ++# ----------------------------------------------------------------------------- ++# -- Test Cases ++# ----------------------------------------------------------------------------- ++ + @test "Test Austin with Python 2.3" { +- invoke_austin "2.3" ignore ++ ignore ++ repeat 3 invoke_austin "2.3" + } + + @test "Test Austin with Python 2.4" { +- invoke_austin "2.4" ignore ++ ignore ++ repeat 3 invoke_austin "2.4" + } + + @test "Test Austin with Python 2.5" { +- invoke_austin "2.5" ++ repeat 3 invoke_austin "2.5" + } + + @test "Test Austin with Python 2.6" { +- invoke_austin "2.6" ++ repeat 3 invoke_austin "2.6" + } + + @test "Test Austin with Python 2.7" { +- invoke_austin "2.7" ++ repeat 3 invoke_austin "2.7" + } + + @test "Test Austin with Python 3.3" { +- invoke_austin "3.3" ++ repeat 3 invoke_austin "3.3" + } + + @test "Test Austin with Python 3.4" { +- invoke_austin "3.4" ++ repeat 3 invoke_austin "3.4" + } + + @test "Test Austin with Python 3.5" { +- invoke_austin "3.5" ++ repeat 3 invoke_austin "3.5" + } + + @test "Test Austin with Python 3.6" { +- invoke_austin "3.6" ++ repeat 3 invoke_austin "3.6" + } + + @test "Test Austin with Python 3.7" { +- invoke_austin "3.7" ++ repeat 3 invoke_austin "3.7" + } + + @test "Test Austin with Python 3.8" { +- invoke_austin "3.8" ++ repeat 3 invoke_austin "3.8" + } +--- austin-1.0.1.orig/test/test_fork_mp.bats ++++ austin-1.0.1/test/test_fork_mp.bats +@@ -1,95 +1,98 @@ +-#!/usr/bin/env bats ++# This file is part of "austin" which is released under GPL. ++# ++# See file LICENCE or go to http://www.gnu.org/licenses/ for full license ++# details. ++# ++# Austin is a Python frame stack sampler for CPython. ++# ++# Copyright (c) 2019 Gabriele N. Tornetta . ++# All rights reserved. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++load "common" ++ ++ ++function invoke_austin { ++ local version="${1}" ++ ++ check_python $version ++ ++ log "Fork Multi-processing [Python $version]" ++ ++ # ------------------------------------------------------------------------- ++ step "Profiling of multi-process program" ++ # ------------------------------------------------------------------------- ++ run $AUSTIN -i 10000 -C $PYTHON test/target_mp.py + +-invoke_austin() { +- if ! python$1 -V; then skip "Python $1 not found."; fi ++ assert_success + +- for i in {1..3} +- do +- echo "> Run $i of 3" +- +- # ------------------------------------------------------------------------- +- +- echo " :: Profiling of multi-process program" +- run src/austin -i 10000 -C python$1 test/target_mp.py ++ expected=3 ++ n_procs=$( echo "$output" | sed -r 's/P([0-9]+);.+/\1/' | sort | uniq | wc -l ) ++ assert "At least 3 parallel processes" "$n_procs >= $expected" + +- echo " Exit code: $status" +- if [ $status != 0 ]; then continue; fi ++ assert_output "do (test/target_mp.py);L[[:digit:]]*;fact (test/target_mp.py);L" + +- echo " - Check expected number of processes." +- expected=3 +- n_procs=$( echo "$output" | sed -r 's/Process ([0-9]+);.+/\1/' | sort | uniq | wc -l ) +- echo " Expected at least $expected and got $n_procs" +- if [ $n_procs < $expected ]; then continue; fi +- +- echo " - Check output contains frames." +- if echo "$output" | grep -q "do (test/target_mp.py);L[[:digit:]]*;fact (test/target_mp.py);L" +- then +- echo " Output: OK" +- return +- fi +- done +- +- if [ $2 ] +- then +- skip "Test failed but marked as 'Ignore'" +- else +- echo +- echo "Collected Output" +- echo "================" +- echo +- echo "$output" +- echo +- false +- fi + } + + + # ----------------------------------------------------------------------------- +- ++# -- Test Cases ++# ----------------------------------------------------------------------------- + + @test "Test Austin with Python 2.3" { + skip "Multiprocessing library introduced in Python 2.6" +- invoke_austin "2.3" ++ repeat 3 invoke_austin "2.3" + } + + @test "Test Austin with Python 2.4" { + skip "Multiprocessing library introduced in Python 2.6" +- invoke_austin "2.4" ++ repeat 3 invoke_austin "2.4" + } + + @test "Test Austin with Python 2.5" { + skip "Multiprocessing library introduced in Python 2.6" +- invoke_austin "2.5" ++ repeat 3 invoke_austin "2.5" + } + + @test "Test Austin with Python 2.6" { +- invoke_austin "2.6" ++ repeat 3 invoke_austin "2.6" + } + + @test "Test Austin with Python 2.7" { +- invoke_austin "2.7" ++ repeat 3 invoke_austin "2.7" + } + + @test "Test Austin with Python 3.3" { +- invoke_austin "3.3" ++ repeat 3 invoke_austin "3.3" + } + + @test "Test Austin with Python 3.4" { +- invoke_austin "3.4" ++ repeat 3 invoke_austin "3.4" + } + + @test "Test Austin with Python 3.5" { +- invoke_austin "3.5" ++ repeat 3 invoke_austin "3.5" + } + + @test "Test Austin with Python 3.6" { +- invoke_austin "3.6" ++ repeat 3 invoke_austin "3.6" + } + + @test "Test Austin with Python 3.7" { +- invoke_austin "3.7" ++ repeat 3 invoke_austin "3.7" + } + + @test "Test Austin with Python 3.8" { +- invoke_austin "3.8" ++ repeat 3 invoke_austin "3.8" + } +--- austin-1.0.1.orig/test/test_valgrind.bats ++++ austin-1.0.1/test/test_valgrind.bats +@@ -1,89 +1,105 @@ +-#!/usr/bin/env bats +- +-invoke_austin() { +- if ! python$1 -V; then skip "Python $1 not found."; fi +- +- for i in {1..3} +- do +- echo "> Run $i of 3" +- +- # ------------------------------------------------------------------------- +- +- echo " :: Valgrind test" ++# This file is part of "austin" which is released under GPL. ++# ++# See file LICENCE or go to http://www.gnu.org/licenses/ for full license ++# details. ++# ++# Austin is a Python frame stack sampler for CPython. ++# ++# Copyright (c) 2019 Gabriele N. Tornetta . ++# All rights reserved. ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++load "common" ++ ++ ++function invoke_austin { ++ local version="${1}" ++ ++ check_python $version ++ ++ log "Valgrind [Python $version]" ++ ++ # ------------------------------------------------------------------------- ++ step "Valgrind test" ++ # ------------------------------------------------------------------------- + run valgrind \ + --error-exitcode=42 \ + --leak-check=full \ + --show-leak-kinds=all \ + --errors-for-leak-kinds=all \ + --track-fds=yes \ +- src/austin -i 100000 -t 10000 python$1 test/target34.py +- echo " Exit code: $status" +- echo " Valgrind report: <" +- echo "$output" +- if [ $status = 0 ] ++ $AUSTIN -i 100000 -t 10000 -o /dev/null $PYTHON test/target34.py ++ ++ if [ ! $status == 0 ] + then +- return ++ log " Valgrind Report" ++ log " ===============" ++ for line in "${lines[@]}" ++ do ++ log " $line" ++ done ++ check_ignored + fi +- done +- +- if [ $2 ] +- then +- skip "Test failed but marked as 'Ignore'" +- else +- echo +- echo "Collected Output" +- echo "================" +- echo +- echo "$output" +- echo +- false +- fi + } + + + # ----------------------------------------------------------------------------- +- ++# -- Test Cases ++# ----------------------------------------------------------------------------- + + @test "Test Austin with Python 2.3" { +- invoke_austin "2.3" ignore ++ ignore ++ repeat 3 invoke_austin "2.3" + } + + @test "Test Austin with Python 2.4" { +- invoke_austin "2.4" ignore ++ ignore ++ repeat 3 invoke_austin "2.4" + } + + @test "Test Austin with Python 2.5" { +- invoke_austin "2.5" ++ repeat 3 invoke_austin "2.5" + } + + @test "Test Austin with Python 2.6" { +- invoke_austin "2.6" ++ repeat 3 invoke_austin "2.6" + } + + @test "Test Austin with Python 2.7" { +- invoke_austin "2.7" ++ repeat 3 invoke_austin "2.7" + } + + @test "Test Austin with Python 3.3" { +- invoke_austin "3.3" ++ repeat 3 invoke_austin "3.3" + } + + @test "Test Austin with Python 3.4" { +- invoke_austin "3.4" ++ repeat 3 invoke_austin "3.4" + } + + @test "Test Austin with Python 3.5" { +- invoke_austin "3.5" ++ repeat 3 invoke_austin "3.5" + } + + @test "Test Austin with Python 3.6" { +- invoke_austin "3.6" ++ repeat 3 invoke_austin "3.6" + } + + @test "Test Austin with Python 3.7" { +- invoke_austin "3.7" ++ repeat 3 invoke_austin "3.7" + } + + @test "Test Austin with Python 3.8" { +- invoke_austin "3.8" ++ repeat 3 invoke_austin "3.8" + } diff -Nru austin-1.0.0/debian/patches/series austin-1.0.1/debian/patches/series --- austin-1.0.0/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ austin-1.0.1/debian/patches/series 2020-06-05 16:24:00.000000000 +0000 @@ -0,0 +1 @@ +962001 diff -Nru austin-1.0.0/README austin-1.0.1/README --- austin-1.0.0/README 2019-10-20 16:08:24.000000000 +0000 +++ austin-1.0.1/README 2020-05-21 18:13:56.000000000 +0000 @@ -27,8 +27,8 @@ Debian package status - Version 1.0.0 + Version 1.0.1 LICENSE @@ -68,7 +68,7 @@

A frame stack sampler for CPython

-[![Build Status](https://travis-ci.org/P403n1x87/austin.svg?branch=master)](https://travis-ci.org/P403n1x87/austin) ![Version](https://img.shields.io/badge/version-1.0.0-blue.svg) [![License](https://img.shields.io/badge/license-GPLv3-ff69b4.svg)](https://github.com/P403n1x87/austin/blob/master/LICENSE.md) +[![Build Status](https://travis-ci.org/P403n1x87/austin.svg?branch=master)](https://travis-ci.org/P403n1x87/austin) ![Version](https://img.shields.io/badge/version-1.0.1-blue.svg) [![License](https://img.shields.io/badge/license-GPLv3-ff69b4.svg)](https://github.com/P403n1x87/austin/blob/master/LICENSE.md) --> @@ -323,6 +323,12 @@ | **arm** | ✓ | | | | **armv7** | ✓ | | | +Due to the **System Integrity Protection** introduced in **MacOS** with El +Capitan, Austin cannot profile Python processes that use an executable located +in the `/bin` folder, even with `sudo`. Hence, either run the interpreter from a +virtual environment or use a Python interpreter that is installed in, e.g., +`/Applications` or via `brew` with the default prefix (`/usr/local`). Even in +these cases, though, the use of `sudo` is required. > **NOTE** Austin *might* work with other versions of Python on all the > platforms and architectures above. So it is worth giving it a try even if diff -Nru austin-1.0.0/README.md austin-1.0.1/README.md --- austin-1.0.0/README.md 2019-10-20 16:08:24.000000000 +0000 +++ austin-1.0.1/README.md 2020-05-21 18:13:56.000000000 +0000 @@ -27,8 +27,8 @@ Debian package status
- Version 1.0.0 + Version 1.0.1 LICENSE @@ -68,7 +68,7 @@

A frame stack sampler for CPython

-[![Build Status](https://travis-ci.org/P403n1x87/austin.svg?branch=master)](https://travis-ci.org/P403n1x87/austin) ![Version](https://img.shields.io/badge/version-1.0.0-blue.svg) [![License](https://img.shields.io/badge/license-GPLv3-ff69b4.svg)](https://github.com/P403n1x87/austin/blob/master/LICENSE.md) +[![Build Status](https://travis-ci.org/P403n1x87/austin.svg?branch=master)](https://travis-ci.org/P403n1x87/austin) ![Version](https://img.shields.io/badge/version-1.0.1-blue.svg) [![License](https://img.shields.io/badge/license-GPLv3-ff69b4.svg)](https://github.com/P403n1x87/austin/blob/master/LICENSE.md) --> @@ -323,6 +323,12 @@ | **arm** | ✓ | | | | **armv7** | ✓ | | | +Due to the **System Integrity Protection** introduced in **MacOS** with El +Capitan, Austin cannot profile Python processes that use an executable located +in the `/bin` folder, even with `sudo`. Hence, either run the interpreter from a +virtual environment or use a Python interpreter that is installed in, e.g., +`/Applications` or via `brew` with the default prefix (`/usr/local`). Even in +these cases, though, the use of `sudo` is required. > **NOTE** Austin *might* work with other versions of Python on all the > platforms and architectures above. So it is worth giving it a try even if diff -Nru austin-1.0.0/snap/snapcraft.yaml austin-1.0.1/snap/snapcraft.yaml --- austin-1.0.0/snap/snapcraft.yaml 2019-10-19 14:31:05.000000000 +0000 +++ austin-1.0.1/snap/snapcraft.yaml 2020-05-21 18:13:56.000000000 +0000 @@ -1,5 +1,5 @@ name: austin -version: '1.0.0+git' +version: '1.0.1+git' summary: A Python frame stack sampler for CPython description: | Austin is a Python frame stack sampler for CPython written in pure C. It diff -Nru austin-1.0.0/src/austin.c austin-1.0.1/src/austin.c --- austin-1.0.0/src/austin.c 2019-10-19 10:37:23.000000000 +0000 +++ austin-1.0.1/src/austin.c 2020-02-21 19:27:02.000000000 +0000 @@ -112,7 +112,7 @@ // Since the parent process is not running we probably have waited long // enough so we can try to attach to child processes straight away. - pargs.timeout = 0; + pargs.timeout = 1; // Store the PID before it gets deleted by the update. pid_t ppid = py_proc->pid; diff -Nru austin-1.0.0/src/austin.h austin-1.0.1/src/austin.h --- austin-1.0.0/src/austin.h 2019-10-16 18:15:15.000000000 +0000 +++ austin-1.0.1/src/austin.h 2020-05-21 18:13:56.000000000 +0000 @@ -25,7 +25,7 @@ #define PROGRAM_NAME "austin" -#define VERSION "1.0.0" +#define VERSION "1.0.1" #endif diff -Nru austin-1.0.0/src/linux/py_proc.h austin-1.0.1/src/linux/py_proc.h --- austin-1.0.0/src/linux/py_proc.h 2019-10-19 10:37:23.000000000 +0000 +++ austin-1.0.1/src/linux/py_proc.h 2020-02-21 19:27:02.000000000 +0000 @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -57,6 +58,7 @@ struct _proc_extra_info { unsigned int page_size; char statm_file[24]; + pthread_t wait_thread_id; }; @@ -67,6 +69,14 @@ // ---------------------------------------------------------------------------- +static void * +wait_thread(void * py_proc) { + waitpid(((py_proc_t *) py_proc)->pid, 0, 0); + return NULL; +} + + +// ---------------------------------------------------------------------------- static Elf64_Addr _get_base_64(Elf64_Ehdr * ehdr, void * elf_map) { diff -Nru austin-1.0.0/src/logging.c austin-1.0.1/src/logging.c --- austin-1.0.0/src/logging.c 2018-10-27 18:10:56.000000000 +0000 +++ austin-1.0.1/src/logging.c 2020-05-21 18:13:56.000000000 +0000 @@ -43,7 +43,7 @@ #define LOG_INFO 6 /* informational */ #define LOG_DEBUG 7 /* debug-level messages */ -FILE * lf = NULL; +FILE * logfile = NULL; #endif #include "austin.h" @@ -56,12 +56,12 @@ vsyslog(prio, fmt, ap); #else - if (lf == NULL) { + if (logfile == NULL) { vfprintf(stderr, fmt, ap); fputc('\n', stderr); } else { - vfprintf(lf, fmt, ap); fputc('\n', lf); - fflush(lf); + vfprintf(logfile, fmt, ap); fputc('\n', logfile); + fflush(logfile); } #endif @@ -75,10 +75,10 @@ openlog ("austin", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); #else - if (lf == NULL) { + if (logfile == NULL) { char path[MAX_PATH]; ExpandEnvironmentStrings("%TEMP%\\austin.log", path, MAX_PATH); - lf = fopen(path, "a"); + logfile = fopen(path, "a"); } #endif } @@ -87,11 +87,13 @@ void log_f(const char * fmt, ...) { va_list args; - va_start(args, fmt); - _log_writer(LOG_CRIT, fmt, args); - vfprintf(stderr, fmt, args); fputc('\n', stderr); + va_start(args, fmt); + _log_writer(LOG_CRIT, fmt, args); + va_end(args); + va_start(args, fmt); + vfprintf(stderr, fmt, args); fputc('\n', stderr); va_end(args); } @@ -125,7 +127,20 @@ va_end(args); } -#if defined(DEBUG) || defined(TRACE) +void +log_m(const char * fmt, ...) { + va_list args; + + va_start(args, fmt); + _log_writer(LOG_INFO, fmt, args); + va_end(args); + + va_start(args, fmt); + vfprintf(stderr, fmt, args); fputc('\n', stderr); + va_end(args); +} + +#ifdef DEBUG void log_d(const char * fmt, ...) { va_list args; @@ -161,7 +176,7 @@ closelog(); #else - if (lf != NULL) - fclose(lf); + if (logfile != NULL) + fclose(logfile); #endif } diff -Nru austin-1.0.0/src/logging.h austin-1.0.1/src/logging.h --- austin-1.0.0/src/logging.h 2019-10-12 23:39:08.000000000 +0000 +++ austin-1.0.1/src/logging.h 2020-05-21 18:13:56.000000000 +0000 @@ -48,6 +48,9 @@ void log_i(const char *, ...); +void +log_m(const char *, ...); // metrics + #ifdef DEBUG void log_d(const char *, ...); diff -Nru austin-1.0.0/src/mac/py_proc.h austin-1.0.1/src/mac/py_proc.h --- austin-1.0.0/src/mac/py_proc.h 2019-10-12 23:39:08.000000000 +0000 +++ austin-1.0.1/src/mac/py_proc.h 2020-05-21 18:13:56.000000000 +0000 @@ -79,7 +79,10 @@ for (register int i = 0; cmd_cnt < 2 && i < ncmds; i++) { switch (cmd->cmd) { case LC_SEGMENT_64: - if (strcmp(cmd->segname, "__DATA") == 0) { + if (strcmp(cmd->segname, "__TEXT") == 0) { + img_base -= cmd->vmaddr; + } + else if (strcmp(cmd->segname, "__DATA") == 0) { int nsects = cmd->nsects; struct section_64 * sec = (struct section_64 *) ((void *) cmd + sizeof(struct segment_command_64)); self->map.bss.size = 0; @@ -87,6 +90,7 @@ if (strcmp(sec[j].sectname, "__bss") == 0) { self->map.bss.base += sec[j].addr; self->map.bss.size = sec[j].size; + log_d("BSS bounds [%p - %p]", self->map.bss.base, self->map.bss.base + self->map.bss.size); break; } } @@ -137,7 +141,10 @@ for (register int i = 0; cmd_cnt < 2 && i < ncmds; i++) { switch (cmd->cmd) { case LC_SEGMENT: - if (strcmp(cmd->segname, "__DATA") == 0) { + if (strcmp(cmd->segname, "__TEXT") == 0) { + img_base -= cmd->vmaddr; + } + else if (strcmp(cmd->segname, "__DATA") == 0) { int nsects = cmd->nsects; struct section * sec = (struct section *) ((void *) cmd + sizeof(struct segment_command)); self->map.bss.size = 0; @@ -145,6 +152,7 @@ if (strcmp(sec[j].sectname, "__bss") == 0) { self->map.bss.base += sec[j].addr; self->map.bss.size = sec[j].size; + log_d("BSS bounds [%p - %p]", self->map.bss.base, self->map.bss.base + self->map.bss.size); break; } } @@ -286,12 +294,18 @@ static int _py_proc__get_maps(py_proc_t * self) { mach_vm_address_t address = 0; - mach_vm_size_t size; + mach_vm_size_t size = 0; vm_region_basic_info_data_64_t region_info; mach_msg_type_number_t count = sizeof(vm_region_basic_info_data_64_t); mach_port_t object_name; - - usleep(10000); // NOTE: Mac OS X kernel bug + + char * path = (char *) calloc(MAXPATHLEN + 1, sizeof(char)); + if (path == NULL) + return 1; + + // NOTE: Mac OS X kernel bug. This also gives time to the VM maps to + // stabilise. + usleep(100000); self->extra->task_id = pid_to_task(self->pid); if (self->extra->task_id == 0) @@ -315,36 +329,55 @@ if ((void *) address + size > self->max_raddr) self->max_raddr = (void *) address + size; - char path[MAXPATHLEN]; int len = proc_regionfilename(self->pid, address, path, MAXPATHLEN); int path_len = strlen(path); if (size > 0 && len) { path[len] = 0; - if (self->bin_path == NULL && strstr(path, "python")) { + if (self->bin_path == NULL && strstr(path, "ython")) { if (strstr(path + path_len - 3, ".so") == NULL) { - // check that it is not a .so file + // not a .so file self->bin_path = strndup(path, path_len); + self->map.bss.base = (void *) address; // WARNING: Image base. Not yet the BSS base!! + if (_py_proc__analyze_macho(self, path, (void *) address, size)) { + // We haven't found the symbols in the binary so we look for a library. + self->map.bss.base = NULL; + } + goto next_map; } } - if (self->lib_path == NULL && strstr(path, "Python")) { + if (self->map.bss.base == NULL && self->lib_path == NULL && strstr(path, "ython") && size > (1 << 20)) { if (strstr(path + path_len - 3, ".so") == NULL) { self->lib_path = strndup(path, path_len); - self->map.bss.base = (void *) address; // WARNING: Partial result. Not yet the BSS base!! + self->map.bss.base = (void *) address; // WARNING: Image base. Not yet the BSS base!! if (_py_proc__analyze_macho(self, path, (void *) address, size)) - return 1; + goto error; + goto next_map; } } - } + // Make a best guess for the heap boundary. This would only work for + // 64-bit architectures. + if (address & 0x0000700000000000) { + if (self->map.heap.base == NULL) + self->map.heap.base = (void *) address; + self->map.heap.size += size; + } + } + next_map: address += size; } + log_d("HEAP bounds [%p - %p]", self->map.heap.base, self->map.heap.base + self->map.heap.size); + if (self->bin_path && self->lib_path && !strcmp(self->bin_path, self->lib_path)) self->bin_path = NULL; +error: + free(path); + return !self->sym_loaded; } diff -Nru austin-1.0.0/src/Makefile.am austin-1.0.1/src/Makefile.am --- austin-1.0.0/src/Makefile.am 2019-10-19 10:37:23.000000000 +0000 +++ austin-1.0.1/src/Makefile.am 2020-02-21 19:27:01.000000000 +0000 @@ -20,7 +20,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -AM_CFLAGS =-I$(top_srcdir)/src -Wall -O3 +AM_CFLAGS =-I$(top_srcdir)/src -Wall -O3 -pthread bin_PROGRAMS = austin austin_SOURCES = \ diff -Nru austin-1.0.0/src/mem.c austin-1.0.1/src/mem.c --- austin-1.0.0/src/mem.c 2018-10-27 18:10:56.000000000 +0000 +++ austin-1.0.1/src/mem.c 2020-05-21 18:13:56.000000000 +0000 @@ -32,6 +32,7 @@ #elif defined(PL_MACOS) #include #include + #include #endif @@ -60,14 +61,22 @@ #elif defined(PL_MACOS) /* MAC */ mach_port_t task; if (task_for_pid(mach_task_self(), pid, &task) != KERN_SUCCESS) { - log_d("Failed to obtain task from PID. Are you running austin with the right privileges?"); + log_d( + "Failed to obtain task from PID. Are you running austin with the right privileges?" + ); return -1; } mach_vm_size_t nread; - mach_vm_read_overwrite(task, (mach_vm_address_t) addr, len, (mach_vm_address_t) buf, &nread); + kern_return_t kr = mach_vm_read_overwrite( + task, (mach_vm_address_t) addr, len, (mach_vm_address_t) buf, &nread + ); + if (kr != KERN_SUCCESS) { + log_t("copy_memory: mach_vm_read_overwrite returned %d", kr); + return -1; + } - return nread == len ? nread : -1; + return nread; #endif } diff -Nru austin-1.0.0/src/py_proc.c austin-1.0.1/src/py_proc.c --- austin-1.0.0/src/py_proc.c 2019-10-19 10:37:23.000000000 +0000 +++ austin-1.0.1/src/py_proc.c 2020-05-21 18:13:56.000000000 +0000 @@ -226,13 +226,13 @@ if (py_proc__get_type(self, raddr, is)) return OUT_OF_BOUND; - log_t( - "PyInterpreterState loaded @ %p. Thread State head @ %p", - raddr, is.tstate_head - ); - - if (py_proc__get_type(self, is.tstate_head, tstate_head)) + if (py_proc__get_type(self, is.tstate_head, tstate_head)) { + log_t( + "Cannot copy PyThreadState head at %p from PyInterpreterState instance", + is.tstate_head + ); return 1; + } log_t("PyThreadState head loaded @ %p", is.tstate_head); @@ -244,6 +244,11 @@ raddr, raddr - self->map.heap.base ); + log_t( + "PyInterpreterState loaded @ %p. Thread State head @ %p", + raddr, is.tstate_head + ); + // As an extra sanity check, verify that the thread state is valid error = EOK; #if defined PL_WIN /* WIN */ @@ -328,6 +333,8 @@ if (py_proc__memcpy(self, self->map.bss.base, self->map.bss.size, self->bss)) return 1; + log_d("Scanning the BSS section for PyInterpreterState"); + void * upper_bound = self->bss + self->map.bss.size; #ifdef CHECK_HEAP // When the process uses the shared library we need to search in other maps @@ -372,13 +379,23 @@ if (self->py_runtime_raddr != NULL) { _PyRuntimeState py_runtime; - if (py_proc__get_type(self, self->py_runtime_raddr, py_runtime)) + if (py_proc__get_type(self, self->py_runtime_raddr, py_runtime)) { + log_d( + "Cannot copy _PyRuntimeState structure from remote address %p", + self->py_runtime_raddr + ); return 1; - interp_head_raddr = py_runtime.interpreters.head; + } + interp_head_raddr = V_FIELD(void *, py_runtime, py_runtime, o_interp_head); } else if (self->interp_head_raddr != NULL) { - if (py_proc__get_type(self, self->interp_head_raddr, interp_head_raddr)) + if (py_proc__get_type(self, self->interp_head_raddr, interp_head_raddr)) { + log_d( + "Cannot copy PyInterpreterState structure from remote address %p", + self->interp_head_raddr + ); return 1; + } } else return 1; @@ -399,6 +416,7 @@ // First try to de-reference interpreter head as the most reliable method if (_py_proc__deref_interp_head(self)) { + log_d("Cannot dereference PyInterpreterState head from symbols"); // If that fails try to get the current thread state (can be NULL during idle) tstate_current_raddr = py_proc__get_current_thread_state_raddr(self); if (tstate_current_raddr == NULL || tstate_current_raddr == (void *) -1) @@ -699,7 +717,8 @@ // not writing to stdout. if (pargs.output_file == NULL) { log_d("Redirecting child's STDOUT to " NULL_DEVICE); - freopen(NULL_DEVICE, "w", stdout); + if (freopen(NULL_DEVICE, "w", stdout) == NULL) + log_e("Unable to redirect child's STDOUT to " NULL_DEVICE); } execvp(exec, argv); @@ -707,9 +726,15 @@ log_e("Failed to fork process"); exit(127); } - #endif /* ANY */ + #if defined PL_LINUX + // On Linux we need to wait for the forked process or otherwise it will + // become a zombie and we cannot tell with kill if it has terminated. + pthread_create(&(self->extra->wait_thread_id), NULL, wait_thread, (void *) self); + log_d("Wait thread created with ID %x", self->extra->wait_thread_id); + #endif + log_d("New process created with PID %d", self->pid); return _py_proc__run(self); @@ -732,6 +757,12 @@ py_proc__wait(py_proc_t * self) { log_d("Waiting for process to terminate"); + #if defined PL_LINUX + if (self->extra->wait_thread_id) { + pthread_join(self->extra->wait_thread_id, NULL); + } + #endif + #ifdef PL_WIN /* WIN */ WaitForSingleObject(self->extra->h_proc, INFINITE); #else /* UNIX */ @@ -753,9 +784,9 @@ void * p_tstate_current; if (self->py_runtime_raddr != NULL) { - if (py_v->py_runtime.tstate_current_offset == 0 || py_proc__get_type( + if (self->tstate_current_offset == 0 || py_proc__get_type( self, - self->py_runtime_raddr + py_v->py_runtime.tstate_current_offset, + self->py_runtime_raddr + self->tstate_current_offset, p_tstate_current )) return (void *) -1; } @@ -785,7 +816,7 @@ if (py_proc__get_type(self, self->py_runtime_raddr, py_runtime)) return 1; - interp_head_raddr = py_runtime.interpreters.head; + interp_head_raddr = V_FIELD(void *, py_runtime, py_runtime, o_interp_head); // Search offset of current thread in _PyRuntimeState structure PyInterpreterState is; @@ -801,10 +832,10 @@ py_proc__get_type(self, raddr, current_thread_raddr); if (current_thread_raddr == thread_raddr) { if (++hit_count == 2) { - py_v->py_runtime.tstate_current_offset = (void *) raddr - self->py_runtime_raddr; + self->tstate_current_offset = (void *) raddr - self->py_runtime_raddr; log_d( "Offset of _PyRuntime.gilstate.tstate_current found at %x", - py_v->py_runtime.tstate_current_offset + self->tstate_current_offset ); return 0; } @@ -829,8 +860,7 @@ return pid_to_task(self->pid) != 0; #else /* LINUX */ - kill(self->pid, 0); - return errno == ESRCH ? 0 : 1; + return !(kill(self->pid, 0) == -1 && errno == ESRCH); #endif } diff -Nru austin-1.0.0/src/py_proc.h austin-1.0.1/src/py_proc.h --- austin-1.0.0/src/py_proc.h 2019-10-12 23:39:08.000000000 +0000 +++ austin-1.0.1/src/py_proc.h 2020-05-21 18:13:56.000000000 +0000 @@ -73,6 +73,9 @@ // Memory profiling support ssize_t last_resident_memory; + // Offset of the tstate_current field within the _PyRuntimeState structure + unsigned int tstate_current_offset; + // Platform-dependent fields proc_extra_info * extra; } py_proc_t; diff -Nru austin-1.0.0/src/py_proc_list.c austin-1.0.1/src/py_proc_list.c --- austin-1.0.0/src/py_proc_list.c 2019-10-19 10:37:23.000000000 +0000 +++ austin-1.0.1/src/py_proc_list.c 2020-02-21 19:27:02.000000000 +0000 @@ -223,10 +223,11 @@ if (stat_file == NULL) continue; - fscanf( + if (fscanf( stat_file, "%d %s %c %d", (int *) buffer, buffer, (char *) buffer, &(self->pid_table[pid]) - ); + ) != 4) + log_w("Failed to parse stat file for process %d", pid); if (pid > self->max_pid) self->max_pid = pid; @@ -283,6 +284,8 @@ item = item->next; } else { + py_proc__wait(item->py_proc); + py_proc_item_t * next = item->next; _py_proc_list__remove(self, item); item = next; @@ -299,10 +302,8 @@ py_proc_list__wait(py_proc_list_t * self) { log_d("Waiting for child processes to terminate"); - for (py_proc_item_t * item = self->first; item != NULL; item = item->next) { - if (py_proc__is_running(item->py_proc)) - py_proc__wait(item->py_proc); - } + for (py_proc_item_t * item = self->first; item != NULL; item = item->next) + py_proc__wait(item->py_proc); } /* py_proc_list__wait */ diff -Nru austin-1.0.0/src/python.h austin-1.0.1/src/python.h --- austin-1.0.0/src/python.h 2019-10-19 10:37:23.000000000 +0000 +++ austin-1.0.1/src/python.h 2020-05-21 18:13:56.000000000 +0000 @@ -125,10 +125,32 @@ PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) */ } PyCodeObject3_6; +typedef struct { + PyObject_HEAD + int co_argcount; /* #arguments, except *args */ + int co_posonlyargcount; /* #positional only arguments */ + int co_kwonlyargcount; /* #keyword only arguments */ + int co_nlocals; /* #local variables */ + int co_stacksize; /* #entries needed for evaluation stack */ + int co_flags; /* CO_..., see below */ + int co_firstlineno; /* first source line number */ + PyObject *co_code; /* instruction opcodes */ + PyObject *co_consts; /* list (constants used) */ + PyObject *co_names; /* list of strings (names used) */ + PyObject *co_varnames; /* tuple of strings (local variable names) */ + PyObject *co_freevars; /* tuple of strings (free variable names) */ + PyObject *co_cellvars; /* tuple of strings (cell variable names) */ + Py_ssize_t *co_cell2arg; /* Maps cell vars which are arguments. */ + PyObject *co_filename; /* unicode (where it was loaded from) */ + PyObject *co_name; /* unicode (name, for reference) */ + PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) */ +} PyCodeObject3_8; + typedef union { PyCodeObject2 v2; PyCodeObject3_3 v3_3; PyCodeObject3_6 v3_6; + PyCodeObject3_8 v3_8; } PyCodeObject; @@ -269,19 +291,41 @@ typedef void *PyThread_type_lock; -typedef struct pyruntimestate { +typedef struct pyruntimestate3_7 { int initialized; int core_initialized; PyThreadState *finalizing; - struct pyinterpreters { + struct pyinterpreters3_7 { PyThread_type_lock mutex; PyInterpreterState *head; PyInterpreterState *main; int64_t next_id; } interpreters; -} _PyRuntimeState; +} _PyRuntimeState3_7; + +// ---- internal/pycore_pystate.h --------------------------------------------- + +typedef struct pyruntimestate3_8 { + int preinitializing; + int preinitialized; + int core_initialized; + int initialized; + PyThreadState *finalizing; + + struct pyinterpreters3_8 { + PyThread_type_lock mutex; + PyInterpreterState *head; + PyInterpreterState *main; + int64_t next_id; + } interpreters; +} _PyRuntimeState3_8; + +typedef union { + _PyRuntimeState3_7 v3_7; + _PyRuntimeState3_8 v3_8; +} _PyRuntimeState; // ---- unicodeobject.h ------------------------------------------------------- diff -Nru austin-1.0.0/src/stats.c austin-1.0.1/src/stats.c --- austin-1.0.0/src/stats.c 2019-10-12 23:39:08.000000000 +0000 +++ austin-1.0.1/src/stats.c 2020-05-21 18:13:56.000000000 +0000 @@ -140,23 +140,23 @@ void stats_log_metrics(void) { if (!_sample_cnt) { - log_i("No samples collected."); + log_m("😣 No samples collected."); return; } - log_i("Sampling time statistics (min/avg/max) : %lu/%lu/%lu us", + log_m("🕑 Sampling time (min/avg/max) : %lu/%lu/%lu us", stats_get_min_sampling_time(), stats_get_avg_sampling_time(), stats_get_max_sampling_time() ); - log_i("Long-running sample rate: %d samples over sampling interval/%d (%.2f %%)", \ + log_m("🐢 Long sampling rate : %d/%d (%.2f %%) samples took longer than the sampling interval", \ _long_cnt, \ _sample_cnt, \ (float) _long_cnt / _sample_cnt * 100 \ ); - log_i("Error rate: %d invalid samples/%d (%.2f %%)", \ + log_m("💀 Error rate : %d/%d (%.2f %%) invalid samples", \ _error_cnt, \ _sample_cnt, \ (float) _error_cnt / _sample_cnt * 100 \ diff -Nru austin-1.0.0/src/version.c austin-1.0.1/src/version.c --- austin-1.0.0/src/version.c 2019-10-19 10:37:23.000000000 +0000 +++ austin-1.0.1/src/version.c 2020-05-21 18:13:56.000000000 +0000 @@ -29,7 +29,7 @@ #define UNSUPPORTED_VERSION log_w("Unsupported Python version detected. Austin might not work as expected.") -#define LATEST_VERSION &python_v3_7 +#define LATEST_VERSION (&python_v3_8) #define PY_CODE(s) { \ sizeof(s), \ @@ -73,8 +73,9 @@ n \ } -#define PY_RUNTIME(n) { \ - n \ +#define PY_RUNTIME(s) { \ + sizeof(s), \ + offsetof(s, interpreters.head), \ } // ---- Python 2 -------------------------------------------------------------- @@ -125,7 +126,18 @@ PY_THREAD (PyThreadState3_4), PY_UNICODE (3), PY_BYTES (3), - PY_RUNTIME (0) + PY_RUNTIME (_PyRuntimeState3_7) +}; + +// ---- Python 3.8 ------------------------------------------------------------ + +python_v python_v3_8 = { + PY_CODE (PyCodeObject3_8), + PY_FRAME (PyFrameObject3_7), + PY_THREAD (PyThreadState3_4), + PY_UNICODE (3), + PY_BYTES (3), + PY_RUNTIME (_PyRuntimeState3_8) }; @@ -179,6 +191,9 @@ // 3.7 case 7: py_v = &python_v3_7; break; + // 3.8 + case 8: py_v = &python_v3_8; break; + default: py_v = LATEST_VERSION; UNSUPPORTED_VERSION; } diff -Nru austin-1.0.0/src/version.h austin-1.0.1/src/version.h --- austin-1.0.0/src/version.h 2019-07-28 21:14:49.000000000 +0000 +++ austin-1.0.1/src/version.h 2020-05-21 18:13:56.000000000 +0000 @@ -37,6 +37,20 @@ #include "python.h" +/** + * Get the value of a field of a versioned structure. + * + * It works by retrieving the field offset from the offset table set at + * runtime, depending on the detected version of Python. + * + * @param ctype the C type of the field to retrieve, e.g. void *. + * @param py_obj the address of the beginning of the actual Python structure. + * @param py_type the Austin representation of the Python structure, e.g. py_thread. + * @param field the field of py_type to retrieve + * + * @return the value of of the field of py_obj at the offset specified + * by the field argument. + */ #define V_FIELD(ctype, py_obj, py_type, field) (*((ctype*) (((void *) &py_obj) + py_v->py_type.field))) @@ -82,9 +96,13 @@ int version; } py_bytes_v; + typedef struct { - unsigned int tstate_current_offset; -} py_runtime; + ssize_t size; + + offset_t o_interp_head; +} py_runtime_v; + typedef struct { py_code_v py_code; @@ -92,7 +110,7 @@ py_thread_v py_thread; py_unicode_v py_unicode; py_bytes_v py_bytes; - py_runtime py_runtime; + py_runtime_v py_runtime; } python_v; diff -Nru austin-1.0.0/test/macos/test_attach.bats austin-1.0.1/test/macos/test_attach.bats --- austin-1.0.0/test/macos/test_attach.bats 1970-01-01 00:00:00.000000000 +0000 +++ austin-1.0.1/test/macos/test_attach.bats 2020-05-21 18:13:56.000000000 +0000 @@ -0,0 +1,81 @@ +attach_austin() { + python_bin=$1 + ignore=$2 + + if ! $python_bin -V; then skip "$python_bin not found."; fi + + for i in {1..3} + do + echo "> Run $i of 3" + + # ------------------------------------------------------------------------- + + echo " :: Time profiling" + $python_bin test/sleepy.py & + sleep 1 + run sudo src/austin -i 10000 -t 10000 -p $! + + echo " Exit code: $status" + if [ $status != 0 ]; then continue; fi + + if ! echo "$output" | grep -q "; (test/sleepy.py);L[[:digit:]]* " + then + echo " Output: NOK" + continue + fi + echo " Output: OK" + + # ------------------------------------------------------------------------- + + echo " :: Memory profiling" + $python_bin test/sleepy.py & + sleep 1 + run sudo src/austin -mi 100 -t 10000 -p $! + + echo " Exit code: $status" + if [ $status != 0 ]; then continue; fi + + if echo "$output" | grep -q "Thread " + then + echo " Output: OK" + return + fi + echo " Output: NOK" + done + + if [ $ignore ] + then + echo "Test marked as 'Ignore' failed" + fi + echo + echo "Collected Output" + echo "================" + echo + echo "$output" + echo + + false +} + + +# ----------------------------------------------------------------------------- + + +# @test "Test Austin with the default Python 3" { +# /usr/bin/python3 -m venv /tmp/py3 +# source /tmp/py3/bin/activate +# attach_austin "python3" +# test -d /tmp/py3 && rm -rf /tmp/py3 +# } + +@test "Test Austin with default Python 3 from Homebrew" { + attach_austin "/usr/local/bin/python3" +} + +@test "Test Austin with Python 3.8 from Homebrew (if available)" { + attach_austin "/usr/local/opt/python@3.8/bin/python3" ignore +} + +@test "Test Austin with Python 3 from Anaconda (if available)" { + attach_austin "/usr/local/anaconda3/bin/python" ignore +} diff -Nru austin-1.0.0/test/macos/test.bats austin-1.0.1/test/macos/test.bats --- austin-1.0.0/test/macos/test.bats 1970-01-01 00:00:00.000000000 +0000 +++ austin-1.0.1/test/macos/test.bats 2020-05-21 18:13:56.000000000 +0000 @@ -0,0 +1,25 @@ +test_case() { + run bats test/macos/test_$1.bats + echo "$output" + [ $status = 0 ] +} + +@test "Test Austin: fork" { + test_case fork +} + +@test "Test Austin: fork multi-process" { + test_case fork_mp +} + +@test "Test Austin: attach" { + test_case attach +} + +@test "Test Austin: valgrind" { + skip "We skip valgrind on Mac OS for now" + + if ! which valgrind; then skip "Valgrind not found"; fi + + test_case valgrind +} diff -Nru austin-1.0.0/test/macos/test_fork.bats austin-1.0.1/test/macos/test_fork.bats --- austin-1.0.0/test/macos/test_fork.bats 1970-01-01 00:00:00.000000000 +0000 +++ austin-1.0.1/test/macos/test_fork.bats 2020-05-21 18:13:56.000000000 +0000 @@ -0,0 +1,98 @@ +#!/usr/bin/env bats + +invoke_austin() { + python_bin=$1 + ignore=$2 + + if ! $python_bin -V; then skip "$python_bin not found."; fi + + for i in {1..3} + do + echo "> Run $i of 3" + + # ------------------------------------------------------------------------- + + echo " :: Standard profiling" + run sudo src/austin -i 1000 -t 10000 $python_bin test/target34.py + + echo " Exit code: $status" + if [ $status != 0 ]; then continue; fi + + if ! echo "$output" | grep -q "keep_cpu_busy (test/target34.py);L" \ + || echo "$output" | grep -q "Unwanted" + then + continue + fi + echo " Output: OK" + + # ------------------------------------------------------------------------- + + echo " :: Memory profiling" + run sudo src/austin -i 1000 -t 10000 -m $python_bin test/target34.py + + echo " Exit code: $status" + if [ $status != 0 ]; then continue; fi + + if ! echo "$output" | grep -q "keep_cpu_busy (test/target34.py);L" + then + continue + fi + echo " Output: OK" + + # ------------------------------------------------------------------------- + + echo " :: Output file" + run sudo src/austin -i 10000 -t 10000 -o /tmp/austin_out.txt $python_bin test/target34.py + + echo " Exit code: $status" + if [ $status != 0 ]; then continue; fi + + if ! echo "$output" | grep -q "Unwanted" \ + || cat /tmp/austin_out.txt | grep -q "keep_cpu_busy (test/target34.py);L" + then + echo " Output: OK" + return + fi + done + + if [ $ignore ] + then + skip "Test failed but marked as 'Ignore'" + else + echo + echo "Collected Output" + echo "================" + echo + echo "$output" + echo + false + fi +} + + +# ----------------------------------------------------------------------------- + + +teardown() { + if [ -f /tmp/austin_out.txt ]; then rm /tmp/austin_out.txt; fi +} + + +# @test "Test Austin with the default Python 3" { +# /usr/bin/python3 -m venv --copies --without-pip /tmp/py3 +# source /tmp/py3/bin/activate +# invoke_austin "python3" +# test -d /tmp/py3 && rm -rf /tmp/py3 +# } + +@test "Test Austin with default Python 3 from Homebrew" { + invoke_austin "/usr/local/bin/python3" +} + +@test "Test Austin with Python 3.8 from Homebrew (if available)" { + invoke_austin "/usr/local/opt/python@3.8/bin/python3" ignore +} + +@test "Test Austin with Python 3 from Anaconda (if available)" { + invoke_austin "/usr/local/anaconda3/bin/python" ignore +} diff -Nru austin-1.0.0/test/macos/test_fork_mp.bats austin-1.0.1/test/macos/test_fork_mp.bats --- austin-1.0.0/test/macos/test_fork_mp.bats 1970-01-01 00:00:00.000000000 +0000 +++ austin-1.0.1/test/macos/test_fork_mp.bats 2020-05-21 18:13:56.000000000 +0000 @@ -0,0 +1,69 @@ +invoke_austin() { + python_bin=$1 + ignore=$2 + + if ! $python_bin -V; then skip "$python_bin not found."; fi + + for i in {1..3} + do + echo "> Run $i of 3" + + # ------------------------------------------------------------------------- + + echo " :: Profiling of multi-process program" + run sudo src/austin -i 100000 -C $python_bin test/target_mp.py + + echo " Exit code: $status" + if [ $status != 0 ]; then continue; fi + + echo " - Check expected number of processes." + expected=3 + n_procs=$( echo "$output" | sed -E 's/Process ([0-9]+);.+/\1/' | sort | uniq | wc -l ) + echo " Expected at least $expected and got $n_procs" + if [ $n_procs -lt $expected ]; then continue; fi + + echo " - Check output contains frames." + if echo "$output" | grep -q "fact" + then + echo " Output: OK" + return + fi + echo " Output: NOK" + done + + if [ $ignore ] + then + echo "Test marked as 'Ignore' failed" + fi + echo + echo "Collected Output" + echo "================" + echo + echo "$output" + echo + + false +} + + +# ----------------------------------------------------------------------------- + + +# @test "Test Austin with the default Python 3" { +# /usr/bin/python3 -m venv /tmp/py3 +# source /tmp/py3/bin/activate +# invoke_austin "python3" +# test -d /tmp/py3 && rm -rf /tmp/py3 +# } + +@test "Test Austin with default Python 3 from Homebrew" { + invoke_austin "/usr/local/bin/python3" +} + +@test "Test Austin with Python 3.8 from Homebrew (if available)" { + invoke_austin "/usr/local/opt/python@3.8/bin/python3" ignore +} + +@test "Test Austin with Python 3 from Anaconda (if available)" { + invoke_austin "/usr/local/anaconda3/bin/python" ignore +} \ No newline at end of file diff -Nru austin-1.0.0/test/macos/test_valgrind.bats austin-1.0.1/test/macos/test_valgrind.bats --- austin-1.0.0/test/macos/test_valgrind.bats 1970-01-01 00:00:00.000000000 +0000 +++ austin-1.0.1/test/macos/test_valgrind.bats 2020-05-21 18:13:56.000000000 +0000 @@ -0,0 +1,66 @@ +invoke_austin() { + python_bin=$1 + ignore=$2 + + if ! $python_bin -V; then skip "$python not found."; fi + + for i in {1..3} + do + echo "> Run $i of 3" + + # ------------------------------------------------------------------------- + + echo " :: Valgrind test" + run sudo valgrind \ + --error-exitcode=42 \ + --leak-check=full \ + --show-leak-kinds=all \ + --errors-for-leak-kinds=all \ + --track-fds=yes \ + --track-origins=yes \ + src/austin -i 100000 -t 10000 $python_bin test/target34.py + echo " Exit code: $status" + echo " Valgrind report: <" + echo "$output" + if [ $status = 0 ] + then + return + fi + done + + if [ $ignore ] + then + echo "Test marked as 'Ignore' failed" + fi + echo + echo "Collected Output" + echo "================" + echo + echo "$output" + echo + + false +} + + +# ----------------------------------------------------------------------------- + + +# @test "Test Austin with the default Python 3" { +# /usr/bin/python3 -m venv /tmp/py3 +# source /tmp/py3/bin/activate +# invoke_austin "python3" +# test -d /tmp/py3 && rm -rf /tmp/py3 +# } + +@test "Test Austin with default Python 3 from Homebrew" { + invoke_austin "/usr/local/bin/python3" +} + +@test "Test Austin with Python 3.8 from Homebrew (if available)" { + invoke_austin "/usr/local/opt/python@3.8/bin/python3" ignore +} + +@test "Test Austin with Python 3 from Anaconda (if available)" { + invoke_austin "/usr/local/anaconda3/bin/python" ignore +} diff -Nru austin-1.0.0/test/test_attach.bats austin-1.0.1/test/test_attach.bats --- austin-1.0.0/test/test_attach.bats 2019-10-19 10:37:23.000000000 +0000 +++ austin-1.0.1/test/test_attach.bats 2020-02-21 19:27:02.000000000 +0000 @@ -42,6 +42,12 @@ then skip "Test failed but marked as 'Ignore'" else + echo + echo "Collected Output" + echo "================" + echo + echo "$output" + echo false fi } @@ -137,3 +143,7 @@ @test "Test Austin with Python 3.7" { attach_austin "3.7" } + +@test "Test Austin with Python 3.8" { + attach_austin "3.8" +} diff -Nru austin-1.0.0/test/test_fork.bats austin-1.0.1/test/test_fork.bats --- austin-1.0.0/test/test_fork.bats 2019-10-19 10:37:23.000000000 +0000 +++ austin-1.0.1/test/test_fork.bats 2020-02-21 19:27:02.000000000 +0000 @@ -56,6 +56,12 @@ then skip "Test failed but marked as 'Ignore'" else + echo + echo "Collected Output" + echo "================" + echo + echo "$output" + echo false fi } @@ -109,6 +115,6 @@ invoke_austin "3.7" } -# @test "Test Austin with Python 3.8" { -# invoke_austin "3.8" -# } +@test "Test Austin with Python 3.8" { + invoke_austin "3.8" +} diff -Nru austin-1.0.0/test/test_fork_mp.bats austin-1.0.1/test/test_fork_mp.bats --- austin-1.0.0/test/test_fork_mp.bats 2019-10-19 10:37:23.000000000 +0000 +++ austin-1.0.1/test/test_fork_mp.bats 2020-05-21 18:13:56.000000000 +0000 @@ -18,9 +18,8 @@ echo " - Check expected number of processes." expected=3 n_procs=$( echo "$output" | sed -r 's/Process ([0-9]+);.+/\1/' | sort | uniq | wc -l ) - echo " Expected $expected and got $n_procs" - if [ $n_procs != $expected ] - then continue; fi + echo " Expected at least $expected and got $n_procs" + if [ $n_procs < $expected ]; then continue; fi echo " - Check output contains frames." if echo "$output" | grep -q "do (test/target_mp.py);L[[:digit:]]*;fact (test/target_mp.py);L" @@ -34,6 +33,12 @@ then skip "Test failed but marked as 'Ignore'" else + echo + echo "Collected Output" + echo "================" + echo + echo "$output" + echo false fi } @@ -85,6 +90,6 @@ invoke_austin "3.7" } -# @test "Test Austin with Python 3.8" { -# invoke_austin "3.8" -# } +@test "Test Austin with Python 3.8" { + invoke_austin "3.8" +} diff -Nru austin-1.0.0/test/test_valgrind.bats austin-1.0.1/test/test_valgrind.bats --- austin-1.0.0/test/test_valgrind.bats 2019-10-19 10:37:23.000000000 +0000 +++ austin-1.0.1/test/test_valgrind.bats 2020-02-21 19:27:02.000000000 +0000 @@ -30,6 +30,12 @@ then skip "Test failed but marked as 'Ignore'" else + echo + echo "Collected Output" + echo "================" + echo + echo "$output" + echo false fi } @@ -77,3 +83,7 @@ @test "Test Austin with Python 3.7" { invoke_austin "3.7" } + +@test "Test Austin with Python 3.8" { + invoke_austin "3.8" +} diff -Nru austin-1.0.0/.travis.yml austin-1.0.1/.travis.yml --- austin-1.0.0/.travis.yml 2019-10-19 10:37:23.000000000 +0000 +++ austin-1.0.1/.travis.yml 2020-05-23 00:02:01.000000000 +0000 @@ -6,12 +6,12 @@ git: depth: 1 -osx_image: xcode10 +osx_image: xcode11.4 -sudo: required +os: linux dist: bionic -matrix: +jobs: include: # Linux - env: TARGET=arm-unknown-linux-gnueabi @@ -31,38 +31,104 @@ before_script: # Linux Dependencies - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; - then - sudo add-apt-repository ppa:deadsnakes/ppa -y; - sudo add-apt-repository ppa:duggan/bats -y; - - sudo apt install bats valgrind python2.{3..7} python3.{3..7} -y; - fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then autoreconf --install; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; + then + sudo add-apt-repository ppa:deadsnakes/ppa -y; + sudo add-apt-repository ppa:duggan/bats -y; + + sudo apt install bats valgrind python2.{3..7} python3.{3..8} -y; + + autoreconf --install; + fi + + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; + then + brew install python || brew upgrade python; + brew install python@3.8 || true; + brew install bats-core; + brew install --HEAD valgrind || true; + brew cask install anaconda || true; + fi + + - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; + then + powershell Install-WindowsFeature Net-Framework-Core; + cinst -y wixtoolset; + fi script: - echo $TRAVIS_OS_NAME -- $TARGET - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./configure && make && sudo make check; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then gcc -s -Wall -O3 -o src/austin src/*.c; fi - - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then gcc -s -Wall -O3 -o src/austin src/*.c -lpsapi; fi + + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; + then + ./configure && + make && + sudo make check; + fi + + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; + then + gcc -s -Wall -O3 -o src/austin src/*.c && + sudo bats test/macos/test.bats; + fi + + - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; + then + gcc -s -Wall -O3 -o src/austin src/*.c -lpsapi; + fi after_success: ./src/austin --usage after_failure: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then cat /var/log/syslog.log | grep austin; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then cat test-suite.log; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; + then + test -f /var/log/syslog.log && cat /var/log/syslog.log | grep austin; + test -f test-suite.log && cat test-suite.log; + fi before_deploy: - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export VERSION=$(cat src/austin.h | sed -n -E "s/.*VERSION[ ]+\"(.+)\"/\1/p"); else export VERSION=$(cat src/austin.h | sed -r -n "s/.*VERSION[ ]+\"(.+)\"/\1/p"); fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; + then + SED_FLAGS="-n -E"; + else + SED_FLAGS="-r -n"; + fi; + export VERSION=$(cat src/austin.h | sed $SED_FLAGS "s/.*VERSION[ ]+\"(.+)\"/\1/p"); + - export TRAVIS_TAG=v$VERSION + - echo "==== Preparing to create GitHub Release for version $VERSION ====" - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export ZIP_CMD="tar -Jcf" && export ZIP_SUFFIX="linux-${TARGET%%-*}.tar.xz" && export AUSTIN_EXE=austin; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export ZIP_CMD="zip -r" && export ZIP_SUFFIX="mac-${TARGET%%-*}.zip" && export AUSTIN_EXE=austin; fi - - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then export ZIP_CMD="7z a -tzip" && export ZIP_SUFFIX="win-${TARGET%%-*}.zip" && export AUSTIN_EXE=austin.exe; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; + then + export ZIP_CMD="tar -Jcf"; + export ZIP_SUFFIX="linux-${TARGET%%-*}.tar.xz"; + export AUSTIN_EXE=austin; + fi + + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; + then + export ZIP_CMD="zip -r"; + export ZIP_SUFFIX="mac-${TARGET%%-*}.zip"; + export AUSTIN_EXE=austin; + fi + + - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; + then + export ZIP_CMD="7z a -tzip"; + export ZIP_SUFFIX="win-${TARGET%%-*}.zip"; + export AUSTIN_EXE=austin.exe; + + export WIN_MSI="austin-$VERSION-win64.msi"; + + sed -i "s/%VERSION%/$VERSION/g" wix/Austin.wxs; + candle wix/Austin.wxs -out wix/Austin.wixobj; + light -ext WixUIExtension wix/Austin.wixobj -out $WIN_MSI; + fi + - export ARTEFACT="austin-${VERSION}-${ZIP_SUFFIX}" + - echo " - Using command $ZIP_CMD to create artefact $ARTEFACT" - cd src @@ -74,8 +140,30 @@ - git tag -a -f -m "Release $VERSION" $TRAVIS_TAG deploy: - provider: releases - api_key: $GITHUB_TOKEN - file: $ARTEFACT - skip_cleanup: true - overwrite: true + - provider: releases + edge: true + token: $GITHUB_TOKEN + file: $ARTEFACT + overwrite: true + + - provider: releases + edge: true + token: $GITHUB_TOKEN + file: $WIN_MSI + overwrite: true + on: + condition: "$TRAVIS_OS_NAME = windows" + +after_deploy: + - if [[ "$TRAVIS_OS_NAME" == "windows" ]]; + then + export WIN_MSI_HASH=$( sha256sum $WIN_MSI | head -c 64 ); + + cd choco; + + sed -i "s/%WIN_MSI_HASH%/$WIN_MSI_HASH/g" tools/chocolateyinstall.ps1; + /bin/find . -type f -exec sed -i "s/%VERSION%/$VERSION/g" {} \; ; + choco apikey --key $CHOCO_APIKEY --source https://push.chocolatey.org/; + choco pack; + choco push; + fi diff -Nru austin-1.0.0/wix/Austin.wxs austin-1.0.1/wix/Austin.wxs --- austin-1.0.0/wix/Austin.wxs 1970-01-01 00:00:00.000000000 +0000 +++ austin-1.0.1/wix/Austin.wxs 2020-05-23 00:02:01.000000000 +0000 @@ -0,0 +1,83 @@ + + + + + + + + + + Msix64 + + + + + + + + + + + + + + + + + + + + 1 + 1 + + + + + + + +