Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .flake8
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
[flake8]
select = ANN,B,B9,C,D,E,F,W,I
ignore = ANN101,ANN102,ANN401,B950,D100,D102,D103,D104,D107,E203,E501,I001,I005,W503,W606
ignore = ANN101,ANN102,ANN401,B905,B950,D100,D102,D103,D104,D107,E203,E501,I001,I005,W503,W606
exclude =
austin/format/pprof/profile_pb2.py
test/data/column.py
max-line-length = 88
docstring-convention = google
import-order-style = pep8
application-import-names = austin
per-file-ignores =
test/*:ANN,D
Expand Down
1 change: 0 additions & 1 deletion austin/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
from austin.events import AustinMetadata
from austin.events import AustinSample


SemVer = Tuple[int, int, int]


Expand Down
1 change: 0 additions & 1 deletion austin/events.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import typing as t
from dataclasses import dataclass


ProcessId = int
ThreadName = str
InterpreterId = int
Expand Down
9 changes: 4 additions & 5 deletions austin/format/collapsed_stack.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import typing as t
from functools import singledispatchmethod
from pathlib import Path
import typing as t

from austin.events import AustinEvent
from austin.events import AustinEventIterator
Expand All @@ -10,7 +10,6 @@
from austin.events import AustinSample
from austin.format.mojo import MojoStreamReader


__version__ = "0.1.0"


Expand Down Expand Up @@ -66,17 +65,17 @@ def parse_collapsed_stack(sample: str) -> AustinSample:
raise InvalidSample(sample)

if sample[0] != "P":
raise InvalidSample(f"No process ID in sample '{sample}'")
raise InvalidSample(f"No process ID in sample {sample!r}")

head, _, metrics = sample.rpartition(" ")
process, _, rest = head.partition(";")
try:
pid = int(process[1:])
except ValueError:
raise InvalidSample(f"Invalid process ID in sample '{sample}'") from None
raise InvalidSample(f"Invalid process ID in sample {sample!r}") from None

if rest[0] != "T":
raise InvalidSample(f"No thread ID in sample '{sample}'")
raise InvalidSample(f"No thread ID in sample {sample!r}")

thread, _, frames_data = rest.partition(";")
thread = thread[1:]
Expand Down
8 changes: 5 additions & 3 deletions austin/format/compress.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,11 @@ def compress(source: AustinFileReader, dest: TextIO, counts: bool = False) -> No
formatter.format(
AustinSample.from_key_and_metrics(
key,
AustinMetrics(memory=metrics)
if is_memory
else AustinMetrics(time=metrics),
(
AustinMetrics(memory=metrics)
if is_memory
else AustinMetrics(time=metrics)
),
)
)
+ "\n"
Expand Down
51 changes: 30 additions & 21 deletions austin/format/mojo.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class MojoEvent:
"""MOJO event."""

EVENT_ID: t.ClassVar = None
raw: t.ClassVar[bytes] = b""

def ref(self) -> int:
return getattr(self, fields(self)[0].name)
Expand All @@ -93,9 +94,7 @@ def to_bytes(self) -> bytes:
for f in fields(self):
value = getattr(self, f.name)
field_type = (
f.type.__args__[0]
if isinstance(f.type, t._UnionGenericAlias)
else f.type
t.get_args(f.type)[0] if t.get_origin(f.type) is t.Union else f.type
)
if field_type is str:
buffer += value.encode()
Expand Down Expand Up @@ -127,9 +126,11 @@ class MojoMetric(MojoEvent):
def to_bytes(self) -> bytes:
buffer = bytearray(
[
MojoEvents.METRIC_TIME
if self.metric_type is MojoMetricType.TIME
else MojoEvents.METRIC_MEMORY
(
MojoEvents.METRIC_TIME
if self.metric_type is MojoMetricType.TIME
else MojoEvents.METRIC_MEMORY
)
]
)
buffer += to_varint(self.value)
Expand Down Expand Up @@ -381,19 +382,21 @@ def _finalize_sample(self) -> AustinSample:
for metric_type, metric in self._running_sample.metrics.items()
}
),
frames=tuple(
AustinFrame(
filename=mf.filename.value,
function=mf.scope.value,
line=mf.line,
line_end=mf.line_end,
column=mf.column,
column_end=mf.column_end,
frames=(
tuple(
AustinFrame(
filename=mf.filename.value,
function=mf.scope.value,
line=mf.line,
line_end=mf.line_end,
column=mf.column,
column_end=mf.column_end,
)
for mf in self._running_sample.frames
)
for mf in self._running_sample.frames
)
if self._running_sample.frames
else None,
if self._running_sample.frames
else None
),
gc=self._running_sample.gc,
idle=self._running_sample.idle,
)
Expand Down Expand Up @@ -670,7 +673,9 @@ def __iter__(self) -> t.Iterator[AustinEvent]:
if self._running_sample is not None:
yield self._finalize_sample()

def hexdump(self, start: int, end: int, highlight: t.Set[int] = set()) -> None: # noqa: B006
def hexdump(
self, start: int, end: int, highlight: t.Set[int] = set() # noqa: B006
) -> None:
"""Print a hexdump of the MOJO file."""
self.mojo.seek(start)
data = self.mojo.read(end - start)
Expand Down Expand Up @@ -855,6 +860,8 @@ async def __aiter__(self) -> t.AsyncIterator[AustinEvent]:


class BaseMojoStreamWriter(abc.ABC):
"""Base class for MOJO stream writers."""

HEADER = b"MOJ\x03"

def __init__(self, mojo: t.Any) -> None:
Expand Down Expand Up @@ -904,11 +911,13 @@ def resolve_frame(self, frame: AustinFrame) -> MojoFrame:
return mojo_frame

@abc.abstractmethod
def write(self, event: AustinEvent) -> int: ...
def write(self, event: AustinEvent) -> int: ... # noqa: E704


class MojoStreamWriter(BaseMojoStreamWriter):
def __init__(self, mojo: io.BytesIO):
"""MOJO stream writer."""

def __init__(self, mojo: io.BytesIO) -> None:
super().__init__(mojo)

mojo.write(self.HEADER)
Expand Down
1 change: 0 additions & 1 deletion austin/format/pprof/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
from austin.format.pprof.profile_pb2 import Profile
from austin.format.pprof.profile_pb2 import Sample


PROCESS_ID_LABEL = "Process ID"
THREAD_ID_LABEL = "Thread ID"
INTERPRETER_ID_LABEL = "Interpreter ID"
Expand Down
2 changes: 0 additions & 2 deletions austin/format/speedscope.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@
from austin.events import AustinSample
from austin.format import Mode
from austin.format.collapsed_stack import AustinFileReader
from austin.format.collapsed_stack import InvalidSample


__version__ = "0.3.1"

Expand Down
18 changes: 10 additions & 8 deletions austin/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
from austin.events import ProcessId
from austin.format.collapsed_stack import AustinEventCollapsedStackFormatter


ThreadInfo = namedtuple("ThreadInfo", ["thread", "iid"])


Expand Down Expand Up @@ -123,9 +122,11 @@ def collapse(
if self.own:
yield (
[frame],
AustinMetrics(time=self.own)
if stats_type in {AustinStatsType.CPU, AustinStatsType.WALL}
else AustinMetrics(memory=self.own),
(
AustinMetrics(time=self.own)
if stats_type in {AustinStatsType.CPU, AustinStatsType.WALL}
else AustinMetrics(memory=self.own)
),
)

if self.children:
Expand All @@ -146,14 +147,15 @@ def collapse(
self, stats_type: AustinStatsType
) -> Generator[Tuple[ThreadInfo, List[AustinFrame], AustinMetrics], None, None]:
"""Collapse the hierarchical statistics."""

if self.own:
yield (
self.label,
[],
AustinMetrics(time=self.own)
if stats_type in {AustinStatsType.CPU, AustinStatsType.WALL}
else AustinMetrics(memory=self.own),
(
AustinMetrics(time=self.own)
if stats_type in {AustinStatsType.CPU, AustinStatsType.WALL}
else AustinMetrics(memory=self.own)
),
)

if self.children:
Expand Down
10 changes: 6 additions & 4 deletions austin/tools/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@
from typing import Tuple

from austin.events import AustinFrame
from austin.events import AustinMetrics
from austin.format.collapsed_stack import InvalidSample
from austin.format.collapsed_stack import parse_collapsed_stack
from austin.format.compress import compress


FoldedStack = List[AustinFrame]


Expand All @@ -41,7 +43,7 @@ def _similarities(
) -> List[Tuple[Tuple[int, int], float]]:
"""O(n * log(n)), n = len(x) * len(y)."""

def score(a: List[Frame], b: List[Frame]) -> float:
def score(a: List[AustinFrame], b: List[AustinFrame]) -> float:
"""Score two folded stacks."""
if not len(a) and not len(b):
return 1
Expand Down Expand Up @@ -90,12 +92,12 @@ def compressed(source: TextIO) -> str:
compress(source, _)
return _.getvalue()

def get_frames(text: str) -> List[Tuple[FoldedStack, Metric]]:
def get_frames(text: str) -> List[Tuple[FoldedStack, AustinMetrics]]:
"""Get the folded stacks and metrics from a string of samples."""
x = []
for _ in text.splitlines(keepends=False):
try:
sample = Sample.parse(_)
sample = parse_collapsed_stack(_)
x.append((sample.frames, sample.metrics))
except InvalidSample:
continue
Expand Down
1 change: 0 additions & 1 deletion austin/tools/mojodbg.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
from austin.format.mojo import MojoEvent
from austin.format.mojo import MojoStreamReader


__version__ = "0.1.0"


Expand Down
13 changes: 8 additions & 5 deletions austin/tools/resolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
from austin.format.mojo import MojoString
from austin.format.mojo import to_varint


__version__ = "0.2.0"


Expand Down Expand Up @@ -176,18 +175,22 @@ def resolve_mojo(input: str, output: str) -> None:
filename, scope, line = resolved
new_value = filename or scope

event.raw = event.raw.replace(
event.value.encode(), new_value.encode()
object.__setattr__(
event,
"raw",
event.raw.replace(event.value.encode(), new_value.encode()),
)

if filename is not None:
maps.lines[event.key] = to_varint(line)

elif isinstance(event, MojoFrame):
if event.filename.key in maps.lines:
event.raw = (
object.__setattr__(
event,
"raw",
event.raw[: -len(to_varint(event.line))]
+ maps.lines[event.filename.key]
+ maps.lines[event.filename.key],
)

fout.write(event.raw)
Expand Down
36 changes: 27 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,18 @@ tests = "pytest --cov=austin --cov-report=term-missing --cov-report=xml {args}"
python = ["3.10", "3.11", "3.12", "3.13", "3.14"]

[tool.hatch.envs.checks]
python = "3.10"
python = "3.13"
template = "checks"
dependencies = [
"mypy~=0.770",
"flake8~=5.0.4",
"flake8-annotations~=2.9.1",
"flake8-black",
"flake8-bugbear~=22.9.23",
"flake8-docstrings~=1.6.0",
"flake8-import-order~=0.18.1",
"flake8-isort~=5.0.0",
"black~=26.3",
"mypy~=0.990",
"flake8~=7.3",
"flake8-annotations~=3.2",
"flake8-black~=0.4",
"flake8-bugbear~=25.11",
"flake8-docstrings~=1.7",
"flake8-isort~=7.0",
"isort~=5.13",
]

[tool.hatch.envs.checks.scripts]
Expand Down Expand Up @@ -145,6 +146,23 @@ module = [
]
ignore_errors = true

[tool.black]
target-version = ["py310", "py311", "py312", "py313", "py314"]
extend-exclude = '''
(
/profile_pb2\.py
| /test/data/column\.py
)
'''

[tool.isort]
force_single_line = true
lines_after_imports = -1
skip = [
"austin/format/pprof/profile_pb2.py",
"test/data/column.py",
]

[build-system]
requires = ["hatchling", "hatch-vcs"]
build-backend = "hatchling.build"
Expand Down
1 change: 0 additions & 1 deletion test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import pytest


DATAPATH = pathlib.Path(__file__).parent / "data"


Expand Down
3 changes: 0 additions & 3 deletions test/format/test_mojo.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,10 @@
from austin.events import AustinSample
from austin.format.collapsed_stack import main
from austin.format.mojo import MojoFrame
from austin.format.mojo import MojoMetadata
from austin.format.mojo import MojoStreamReader
from austin.format.mojo import MojoStreamWriter
from austin.format.mojo import MojoString
from austin.format.mojo import to_varint
from austin.tools.mojodbg import mojodbg


HERE = Path(__file__).parent
DATA = HERE.parent / "data"
Expand Down
Loading
Loading