austin-python 2.1.0__py3-none-any.whl → 2.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
austin/events.py CHANGED
@@ -1,10 +1,9 @@
1
1
  import typing as t
2
- from collections import namedtuple
3
2
  from dataclasses import dataclass
4
3
 
5
4
 
6
- ThreadName = namedtuple("ThreadName", ["thread", "iid"])
7
5
  ProcessId = int
6
+ ThreadName = str
8
7
  InterpreterId = int
9
8
  MicroSeconds = int
10
9
  Bytes = int
@@ -1,6 +1,6 @@
1
- import typing as t
2
1
  from functools import singledispatchmethod
3
2
  from pathlib import Path
3
+ import typing as t
4
4
 
5
5
  from austin.events import AustinEvent
6
6
  from austin.events import AustinEventIterator
@@ -48,7 +48,7 @@ def parse_frame(frame: str) -> AustinFrame:
48
48
  filename, function, line = frame.rsplit(":", maxsplit=2)
49
49
  except ValueError:
50
50
  raise InvalidFrame(frame) from None
51
- return AustinFrame(filename=filename, function=function, line=int(line))
51
+ return AustinFrame(filename=filename, function=function, line=int(line or 0))
52
52
 
53
53
 
54
54
  def parse_collapsed_stack(sample: str) -> AustinSample:
austin/format/mojo.py CHANGED
@@ -277,7 +277,12 @@ def str_reader() -> t.Generator[t.Optional[str], bytes, str]:
277
277
  (b,) = yield bytes(buffer[:i]).decode(errors="replace")
278
278
  i = 0
279
279
  else:
280
- buffer[i] = b
280
+ try:
281
+ buffer[i] = b
282
+ except IndexError:
283
+ # Expand the buffer if needed
284
+ buffer += bytearray(i - len(buffer) + 1)
285
+ buffer[i] = b
281
286
  (b,) = yield None
282
287
  i += 1
283
288
 
@@ -353,6 +358,14 @@ class BaseMojoStreamReader(AustinEventIterator):
353
358
 
354
359
  return metadata
355
360
 
361
+ @property
362
+ def mode(self) -> t.Optional[str]:
363
+ return self.metadata.get("mode")
364
+
365
+ @property
366
+ def gc(self) -> t.Optional[str]:
367
+ return self.metadata.get("gc")
368
+
356
369
  def _finalize_sample(self) -> AustinSample:
357
370
  """Finalize the current sample."""
358
371
  assert self._running_sample is not None, self._running_sample
@@ -395,7 +408,13 @@ class BaseMojoStreamReader(AustinEventIterator):
395
408
  if self._running_sample is not None:
396
409
  self._finalize_sample()
397
410
 
398
- self._running_sample = _RunningSample(pid=pid, iid=iid, thread=thread)
411
+ self._running_sample = _RunningSample(
412
+ pid=pid,
413
+ iid=iid,
414
+ thread=thread,
415
+ idle=False if self.mode == "full" else None,
416
+ gc=False if self.gc is not None else None,
417
+ )
399
418
 
400
419
  return MojoStack(pid, iid if iid is not None else -1, thread)
401
420
 
@@ -22,6 +22,7 @@
22
22
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
23
23
 
24
24
  from argparse import ArgumentParser
25
+ from pathlib import Path
25
26
 
26
27
  from austin.events import AustinMetadata
27
28
  from austin.events import AustinSample
@@ -41,19 +42,21 @@ def main() -> None:
41
42
 
42
43
  arg_parser.add_argument(
43
44
  "input",
44
- type=str,
45
+ type=Path,
45
46
  help="The input file containing Austin samples.",
46
47
  )
47
48
  arg_parser.add_argument(
48
- "output", type=str, help="The name of the output pprof file."
49
+ "output",
50
+ type=Path,
51
+ help="The name of the output pprof file.",
49
52
  )
50
53
 
51
- arg_parser.add_argument("-V", "--version", action="version", version="0.2.0")
54
+ arg_parser.add_argument("-V", "--version", action="version", version="0.2.1")
52
55
 
53
56
  args = arg_parser.parse_args()
54
57
 
55
58
  try:
56
- with AustinFileReader(args.input) as fin:
59
+ with args.input.open() as austin, AustinFileReader(austin) as fin:
57
60
  pprof = None
58
61
  for e in fin:
59
62
  if isinstance(e, AustinMetadata) and e.name == "mode":
@@ -26,6 +26,7 @@ from dataclasses import asdict
26
26
  from dataclasses import dataclass
27
27
  from dataclasses import field
28
28
  from enum import Enum
29
+ from pathlib import Path
29
30
  from typing import Dict
30
31
  from typing import List
31
32
  from typing import Optional
@@ -33,13 +34,14 @@ from typing import TextIO
33
34
  from typing import Union
34
35
 
35
36
  from austin.events import AustinFrame
37
+ from austin.events import AustinMetadata
36
38
  from austin.events import AustinSample
37
39
  from austin.format import Mode
38
40
  from austin.format.collapsed_stack import AustinFileReader
39
41
  from austin.format.collapsed_stack import InvalidSample
40
42
 
41
43
 
42
- __version__ = "0.3.0"
44
+ __version__ = "0.3.1"
43
45
 
44
46
  SpeedscopeJson = Dict
45
47
  SpeedscopeWeight = int
@@ -208,11 +210,11 @@ def main() -> None:
208
210
 
209
211
  arg_parser.add_argument(
210
212
  "input",
211
- type=str,
213
+ type=Path,
212
214
  help="The input file containing Austin samples in normal format.",
213
215
  )
214
216
  arg_parser.add_argument(
215
- "output", type=str, help="The name of the output Speedscope JSON file."
217
+ "output", type=Path, help="The name of the output Speedscope JSON file."
216
218
  )
217
219
  arg_parser.add_argument(
218
220
  "--indent", type=int, help="Give a non-null value to prettify the JSON output."
@@ -223,24 +225,30 @@ def main() -> None:
223
225
  args = arg_parser.parse_args()
224
226
 
225
227
  try:
226
- with AustinFileReader(args.input) as fin:
227
- mode = fin.metadata["mode"]
228
- speedscope = Speedscope(os.path.basename(args.input), mode, args.indent)
228
+ with args.input.open() as austin, AustinFileReader(austin) as fin:
229
+ speedscope = None
229
230
  for event in fin:
230
- if not isinstance(event, AustinSample):
231
- continue
232
- try:
233
- speedscope.add_sample(event)
234
- except InvalidSample:
235
- continue
231
+ if isinstance(event, AustinMetadata):
232
+ if event.name == "mode":
233
+ speedscope = Speedscope(
234
+ os.path.basename(args.input), event.value, args.indent
235
+ )
236
+ elif isinstance(event, AustinSample):
237
+ if speedscope is not None:
238
+ speedscope.add_sample(event)
239
+ else:
240
+ raise ValueError("Invalid sample found in input file")
241
+
242
+ if speedscope is None:
243
+ raise RuntimeError("Invalid input file: no mode metadata found")
244
+
245
+ with args.output.open("w") as fout:
246
+ speedscope.dump(fout)
236
247
 
237
248
  except FileNotFoundError:
238
249
  print(f"No such input file: {args.input}")
239
250
  exit(1)
240
251
 
241
- with open(args.output, "w") as fout:
242
- speedscope.dump(fout)
243
-
244
252
 
245
253
  if __name__ == "__main__":
246
254
  main()
austin/stats.py CHANGED
@@ -21,6 +21,7 @@
21
21
  # You should have received a copy of the GNU General Public License
22
22
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
23
23
 
24
+ from collections import namedtuple
24
25
  from copy import deepcopy
25
26
  from dataclasses import dataclass
26
27
  from dataclasses import field
@@ -39,10 +40,12 @@ from austin.events import AustinMetadata
39
40
  from austin.events import AustinMetrics
40
41
  from austin.events import AustinSample
41
42
  from austin.events import ProcessId
42
- from austin.events import ThreadName
43
43
  from austin.format.collapsed_stack import AustinEventCollapsedStackFormatter
44
44
 
45
45
 
46
+ ThreadInfo = namedtuple("ThreadInfo", ["thread", "iid"])
47
+
48
+
46
49
  COLLAPSED_STACK_FORMATTER = AustinEventCollapsedStackFormatter()
47
50
 
48
51
 
@@ -136,12 +139,12 @@ class FrameStats(HierarchicalStats):
136
139
  class ThreadStats(HierarchicalStats):
137
140
  """Thread statistics."""
138
141
 
139
- label: ThreadName
142
+ label: ThreadInfo
140
143
  children: Dict[AustinFrame, FrameStats] = field(default_factory=dict) # type: ignore[assignment]
141
144
 
142
145
  def collapse(
143
146
  self, stats_type: AustinStatsType
144
- ) -> Generator[Tuple[ThreadName, List[AustinFrame], AustinMetrics], None, None]:
147
+ ) -> Generator[Tuple[ThreadInfo, List[AustinFrame], AustinMetrics], None, None]:
145
148
  """Collapse the hierarchical statistics."""
146
149
 
147
150
  if self.own:
@@ -166,7 +169,7 @@ class ProcessStats:
166
169
  """Process statistics."""
167
170
 
168
171
  pid: ProcessId
169
- threads: Dict[ThreadName, ThreadStats] = field(default_factory=dict)
172
+ threads: Dict[ThreadInfo, ThreadStats] = field(default_factory=dict)
170
173
 
171
174
  def collapse(
172
175
  self, stats_type: AustinStatsType
@@ -175,22 +178,22 @@ class ProcessStats:
175
178
  yield from (
176
179
  AustinSample(
177
180
  pid=self.pid,
178
- iid=thread_name.iid,
179
- thread=thread_name.thread,
181
+ iid=thread_info.iid,
182
+ thread=thread_info.thread,
180
183
  frames=tuple(frames),
181
184
  metrics=metric,
182
185
  )
183
186
  for thread in self.threads.values()
184
- for thread_name, frames, metric in thread.collapse(stats_type)
187
+ for thread_info, frames, metric in thread.collapse(stats_type)
185
188
  )
186
189
 
187
- def get_thread(self, thread_name: ThreadName) -> Optional[ThreadStats]:
190
+ def get_thread(self, thread_info: ThreadInfo) -> Optional[ThreadStats]:
188
191
  """Get thread statistics from this process by name.
189
192
 
190
193
  If the given thread name is not registered with this current process
191
194
  statistics, then ``None`` is returned.
192
195
  """
193
- return self.threads.get(thread_name)
196
+ return self.threads.get(thread_info)
194
197
 
195
198
 
196
199
  @dataclass
@@ -286,8 +289,8 @@ class AustinStats:
286
289
  return
287
290
 
288
291
  pid = sample.pid
289
- thread_name = ThreadName(sample.thread, sample.iid or 0)
290
- thread_stats = ThreadStats(thread_name, own=0, total=metric)
292
+ thread_info = ThreadInfo(sample.thread, sample.iid or 0)
293
+ thread_stats = ThreadStats(thread_info, own=0, total=metric)
291
294
 
292
295
  # Convert the list of frames into a nested FrameStats instance
293
296
  stats: HierarchicalStats = thread_stats
@@ -300,15 +303,15 @@ class AustinStats:
300
303
 
301
304
  with self._lock:
302
305
  if pid not in self.processes:
303
- self.processes[pid] = ProcessStats(pid, {thread_name: thread_stats})
306
+ self.processes[pid] = ProcessStats(pid, {thread_info: thread_stats})
304
307
  return
305
308
 
306
309
  process = self.processes[pid]
307
- if thread_name not in process.threads:
308
- process.threads[thread_name] = thread_stats
310
+ if thread_info not in process.threads:
311
+ process.threads[thread_info] = thread_stats
309
312
  return
310
313
 
311
- process.threads[thread_name] << thread_stats
314
+ process.threads[thread_info] << thread_stats
312
315
 
313
316
  def flatten(self) -> Generator[AustinSample, None, None]:
314
317
  for process in self.processes.values():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: austin-python
3
- Version: 2.1.0
3
+ Version: 2.1.2
4
4
  Summary: Python wrapper for Austin, the CPython frame stack sampler.
5
5
  Project-URL: homepage, https://github.com/P403n1x87/austin-python
6
6
  Project-URL: documentation, https://austin-python.readthedocs.io
@@ -4,26 +4,26 @@ austin/base.py,sha256=wAYVZQi3hcgJA9cVg3mfc3f3E0qwFXmeX7UX6qgn2Pk,7554
4
4
  austin/cli.py,sha256=--PKm2I4NBBSSSBV5l-YC0mcmLjrvb1FHzxgY4dkby4,7826
5
5
  austin/config.py,sha256=PEwdG2Cy8ay1SrFr2N6YfQSZwseYBA1BA5dMfocKR3A,2091
6
6
  austin/errors.py,sha256=lCDSTANW_95Az_eDXbn__JRBllB9yw7tGnFo1-tw09Q,1046
7
- austin/events.py,sha256=39BHP-pUHotZZxJ-MbECFu5_QOAnRJP-_hFEdYPYwKY,2235
7
+ austin/events.py,sha256=NppffZg_lbKIin2TyvIGgfJXnOmBKzB2e0nQV4_94JA,2160
8
8
  austin/simple.py,sha256=iTmJGAjSBeUv82SgdMTwdNlAQwuK33RyU8FkBCE8rRg,5579
9
- austin/stats.py,sha256=8cpuq3cyZUpGkm2VZS3j1Zpz-Yhr3i9Wg6bR-sGwWJM,10933
9
+ austin/stats.py,sha256=4kVeZ5NJsoSEnogqiDyjAbLeuf5DPiELHfCEbjFb0zk,10990
10
10
  austin/threads.py,sha256=AvcoOkr3FeFAGBcqgXukNIt9xOZUipv7pXMqPIL_Qts,3649
11
11
  austin/format/__init__.py,sha256=ZtBJCLpTiZaLFwCN1UbMXLQvYjOSpwmtyGwqgK8yruQ,405
12
- austin/format/collapsed_stack.py,sha256=D1JaB3vREouVW_CcO_yY3IuuIRP3lhi2WXHr2AXxYZM,7241
12
+ austin/format/collapsed_stack.py,sha256=VCkTJssgcF4IHGP6kzV5dT9AC9Qjbq8eGx9AVOp6cyU,7246
13
13
  austin/format/compress.py,sha256=YEceebWzVB7eSCntnJ89_rIcbzBskvZGy86D5QgZli0,3741
14
- austin/format/mojo.py,sha256=IlnFsH9gGofENWBMdbpAc0BrutNGvetk5JLLJeCHKuo,28294
15
- austin/format/speedscope.py,sha256=Ydfi02f90F9BZftA-tb5qSZO-zzbE-lKXPz3f6_YRUc,7981
14
+ austin/format/mojo.py,sha256=mEcKgaZkVkH4YGVLj4m31_MAPKfYK-BNI7oWyiPub0U,28824
15
+ austin/format/speedscope.py,sha256=RvlFugm0S3ATMf9lmzH8jrX4oBt8PJ0j9EsuXWayOQc,8381
16
16
  austin/format/pprof/__init__.py,sha256=DvY1CDnPqBc-GUv9fidtMplshIIXj_HWZ3SlWOJoLxc,6805
17
- austin/format/pprof/__main__.py,sha256=4O4gmVvw807A1Wmxajj7dGly0M9kd-NYhEq9m47Bjas,2583
17
+ austin/format/pprof/__main__.py,sha256=pzWoSmlFrjfmAAq5I4SIIDmxavdLStCnlw3NlBxgyDo,2652
18
18
  austin/format/pprof/profile.proto,sha256=fPfBgzXIEmFdrrwgTQWs-9GwKjt-TShRmJq-eaxDx88,8840
19
19
  austin/format/pprof/profile_pb2.py,sha256=i_uM8lDExR95yz7qnEVikhpkpNvetKaYzoiH7AbMAt8,28214
20
20
  austin/tools/diff.py,sha256=KnY9kD5mmSKALCNxnSe-dSObC4LgkoxLGnoTiklKa5M,4821
21
21
  austin/tools/mojodbg.py,sha256=BGdngj-r1c-GAQDrs_oJ_x4QZxuL4t_OQ194fvJJm7A,2817
22
22
  austin/tools/resolve.py,sha256=pEOBiP8FNkaJqDTj3fOK8dx5-EocroqZDXLL3CzCWLY,7677
23
- austin_python-2.1.0.dist-info/METADATA,sha256=UCOkS9lMa0CGoSYeSPTzzFmSz_0Ac3bSE2XklGEytgo,7535
24
- austin_python-2.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
25
- austin_python-2.1.0.dist-info/entry_points.txt,sha256=YatHOUQsHQ3WABcrNKPf4RWatQ0CzbR-1ClXjMjZys8,329
26
- austin_python-2.1.0.dist-info/licenses/AUTHORS,sha256=pARRmpJQYH8iWy_0SonXsxOiV02AFitowle4AtURxUI,45
27
- austin_python-2.1.0.dist-info/licenses/COPYING,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
28
- austin_python-2.1.0.dist-info/licenses/LICENSE.md,sha256=edVDhmEiPf2W5lWzqLkrj6EYLSrCeYg9MJy28YsiMFU,34937
29
- austin_python-2.1.0.dist-info/RECORD,,
23
+ austin_python-2.1.2.dist-info/METADATA,sha256=wdZJGpu-uI1aH1NwbKstmCYnYdsXzX2UZ-6c-gFzjTg,7535
24
+ austin_python-2.1.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
25
+ austin_python-2.1.2.dist-info/entry_points.txt,sha256=YatHOUQsHQ3WABcrNKPf4RWatQ0CzbR-1ClXjMjZys8,329
26
+ austin_python-2.1.2.dist-info/licenses/AUTHORS,sha256=pARRmpJQYH8iWy_0SonXsxOiV02AFitowle4AtURxUI,45
27
+ austin_python-2.1.2.dist-info/licenses/COPYING,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
28
+ austin_python-2.1.2.dist-info/licenses/LICENSE.md,sha256=edVDhmEiPf2W5lWzqLkrj6EYLSrCeYg9MJy28YsiMFU,34937
29
+ austin_python-2.1.2.dist-info/RECORD,,