Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
176 commits
Select commit Hold shift + click to select a range
4da88b8
initial parallelization stuff
erhant Nov 5, 2025
de9fdb6
add type (smol commit)
erhant Nov 7, 2025
481c766
repl sketch
GandalfTea Oct 16, 2025
2e099c2
manage api server, discover and print nodes table
GandalfTea Oct 17, 2025
c7e5e7b
trace to file (+ trace frames)
GandalfTea Oct 19, 2025
e7bfee6
aggregate trace buffers back to api
GandalfTea Oct 20, 2025
01ff687
Receive correct data format, dump to temp log file without REPL regis…
GandalfTea Oct 20, 2025
5ae6ed2
register repl callback
GandalfTea Oct 20, 2025
b145c88
add llama3 model script
GandalfTea Oct 20, 2025
6e6cfd3
comment out unavailable models
GandalfTea Oct 20, 2025
e4312e2
embed correctly
GandalfTea Oct 20, 2025
e7a8ee8
don't filter weights based on is_api_layer
GandalfTea Oct 20, 2025
9103284
tracer config request, aggregate and separate api logger for less rep…
GandalfTea Oct 21, 2025
132f1cd
mlx bug in lm_head, transposes weights for no reason, manually comput…
GandalfTea Oct 21, 2025
6f9612b
wrap in trace frames
GandalfTea Oct 21, 2025
1b54b84
trace ingress worker
GandalfTea Oct 21, 2025
f96dd28
trace token request stall
GandalfTea Oct 21, 2025
a3125c3
stop printing state on empty prompt
GandalfTea Oct 21, 2025
80c23ef
trace startup
GandalfTea Oct 21, 2025
f706fde
trace prepare_activation
GandalfTea Oct 21, 2025
b664319
don't set _prefetch_pause
GandalfTea Oct 21, 2025
ba7e3aa
compute mean, p50, p99, etc. per trace symbol and print
GandalfTea Oct 21, 2025
fd13c72
append async symbols with 'wait'
GandalfTea Oct 22, 2025
1086f87
min bench wrapper
GandalfTea Oct 22, 2025
003b9f3
various
GandalfTea Oct 22, 2025
71835fb
fix indent and other rebase errors
GandalfTea Oct 22, 2025
c04c69b
add accidentally removed code
GandalfTea Oct 22, 2025
3a38948
fix indent for _send_activation last token
GandalfTea Oct 22, 2025
7e342ae
remove old startup file and add tracer endpoints in node.py:_setup_ro…
GandalfTea Oct 22, 2025
44d929d
runtime stats high-level frames
GandalfTea Oct 23, 2025
12bd227
runtime stats aggregator
GandalfTea Oct 23, 2025
69d3fe8
track per-nonce in-flight and in-wait times and append to ingress tra…
GandalfTea Oct 23, 2025
f4d957c
stop tracking bytes and target, change 'grpc' to 'network' for cleane…
GandalfTea Oct 23, 2025
2ec80fc
remove profiling logs
GandalfTea Oct 23, 2025
4b90381
aggregate per-nonce
GandalfTea Oct 23, 2025
7b3efd9
construct new request on embedding event
GandalfTea Oct 23, 2025
df9b2e6
handle frame with custom cost function
GandalfTea Oct 23, 2025
3d5b4f5
update canonical traces for stats, rename ingress to rx and egress to tx
GandalfTea Oct 23, 2025
38edeae
filter canonical frames
GandalfTea Oct 23, 2025
fdbf05b
move to on-request vars to avoid race conditions
GandalfTea Oct 24, 2025
8211356
auto topo and load model
GandalfTea Oct 24, 2025
7dafdb8
wrap in trace frames
GandalfTea Oct 24, 2025
0b3e80f
change file name
GandalfTea Oct 24, 2025
44efaee
various small stuff
GandalfTea Oct 24, 2025
57a2fdd
add tracer to api and send frames back to repl. emit special frames w…
GandalfTea Oct 24, 2025
933c3d8
track prompt tokens
GandalfTea Oct 24, 2025
739522b
move trace frame and add correct nonce and other metadata
GandalfTea Oct 24, 2025
abe0275
track nonce on all frames
GandalfTea Oct 24, 2025
7d75a4e
better track in-wait time and default to 0 for single shard
GandalfTea Oct 24, 2025
7f89800
started filtering counters and printing
GandalfTea Oct 24, 2025
74aacdf
basic counters working, ttft, tps, itl, token_count
GandalfTea Oct 25, 2025
d994619
track node_id for every frame
GandalfTea Oct 25, 2025
cbc9ab1
fix trace annotate
GandalfTea Oct 25, 2025
30bd452
aggreagate frame symbols into sub-groups for focusing and compute tot…
GandalfTea Oct 25, 2025
8471fb1
typo in activation timestamp
GandalfTea Oct 25, 2025
81bac7d
per-node info and restructured counting
GandalfTea Oct 25, 2025
70f37cd
reformat frames
GandalfTea Oct 26, 2025
ea079ca
better sorting
GandalfTea Oct 26, 2025
320dcfe
use epoch for t0
GandalfTea Oct 26, 2025
1d645c9
add stats nodes and fix node registration
GandalfTea Oct 26, 2025
2a11f02
always register t0
GandalfTea Oct 26, 2025
7a09d91
mark round
GandalfTea Oct 26, 2025
2c23660
don't track queue wait
GandalfTea Oct 27, 2025
cc94dc9
break down tx.enque into correct compute-network frames
GandalfTea Oct 27, 2025
d2a55c9
aggregate compound subsytem metrics correctly per node
GandalfTea Oct 27, 2025
f91293d
fix ms scaling
GandalfTea Oct 27, 2025
72b3b29
rename old grpc frames to network
GandalfTea Oct 27, 2025
465d398
correctly aggregate global memory use per node
GandalfTea Oct 27, 2025
eb80eab
request.round continue
GandalfTea Oct 27, 2025
c8f4ed6
update signature and unload
GandalfTea Oct 27, 2025
92e11e4
force quantization field in model config (mlx_lm doesn't have it)
GandalfTea Oct 27, 2025
6dc05bb
add ShardConfig to __init__
GandalfTea Oct 27, 2025
255ea0a
rm old bench framework
GandalfTea Oct 27, 2025
68fb939
remove old memory frame path
GandalfTea Oct 27, 2025
313312a
not-working chat interface
GandalfTea Oct 27, 2025
ac203d1
fix indent after rebase
GandalfTea Nov 3, 2025
b95c68f
cleanup weight_cache
GandalfTea Nov 3, 2025
464feee
Revert "cleanup weight_cache"
GandalfTea Nov 3, 2025
6d42b1c
remove double code in weight_cache from rebase
GandalfTea Nov 3, 2025
b406efa
comment message field for compatibility
GandalfTea Nov 3, 2025
9af0a49
fix indent and duplicates from rebase
GandalfTea Nov 3, 2025
95a42c7
small rebase fixes
GandalfTea Nov 3, 2025
3da09c9
change order of elements so callback_url is position 4 again
GandalfTea Nov 3, 2025
532f127
fix type issues, fix `is_head` setting
erhant Nov 10, 2025
062a91d
Merge pull request #38 from firstbatchxyz/erhant/parallel-profile-and…
andthattoo Nov 10, 2025
302f435
dnet-p2p commit update
andthattoo Nov 10, 2025
e3ef5de
Merge branch 'master' into refactor/shard-strategy-pattern
erhant Nov 10, 2025
fdbedc9
patchwork fix
andthattoo Nov 10, 2025
8417915
Merge pull request #40 from firstbatchxyz/refactor/shard-strategy-pat…
andthattoo Nov 10, 2025
7ad2468
repl sketch
GandalfTea Oct 16, 2025
70bb0c1
manage api server, discover and print nodes table
GandalfTea Oct 17, 2025
ba7d37e
trace to file (+ trace frames)
GandalfTea Oct 19, 2025
c2b5e6f
aggregate trace buffers back to api
GandalfTea Oct 20, 2025
81eeb44
Receive correct data format, dump to temp log file without REPL regis…
GandalfTea Oct 20, 2025
47e7860
register repl callback
GandalfTea Oct 20, 2025
b74bb27
add llama3 model script
GandalfTea Oct 20, 2025
e6242d8
comment out unavailable models
GandalfTea Oct 20, 2025
cbf479d
embed correctly
GandalfTea Oct 20, 2025
1043655
don't filter weights based on is_api_layer
GandalfTea Oct 20, 2025
670deed
tracer config request, aggregate and separate api logger for less rep…
GandalfTea Oct 21, 2025
5f604a6
mlx bug in lm_head, transposes weights for no reason, manually comput…
GandalfTea Oct 21, 2025
aa3c1cc
wrap in trace frames
GandalfTea Oct 21, 2025
cbd4995
trace ingress worker
GandalfTea Oct 21, 2025
2124522
trace token request stall
GandalfTea Oct 21, 2025
d6f63c8
stop printing state on empty prompt
GandalfTea Oct 21, 2025
079d6ce
trace startup
GandalfTea Oct 21, 2025
a2c9fc9
trace prepare_activation
GandalfTea Oct 21, 2025
001dac5
don't set _prefetch_pause
GandalfTea Oct 21, 2025
6c6c088
compute mean, p50, p99, etc. per trace symbol and print
GandalfTea Oct 21, 2025
a62fc38
append async symbols with 'wait'
GandalfTea Oct 22, 2025
60ada70
min bench wrapper
GandalfTea Oct 22, 2025
0b6e25f
various
GandalfTea Oct 22, 2025
aff5561
fix indent and other rebase errors
GandalfTea Oct 22, 2025
1a7ea70
add accidentally removed code
GandalfTea Oct 22, 2025
02747d4
fix indent for _send_activation last token
GandalfTea Oct 22, 2025
928cbf9
remove old startup file and add tracer endpoints in node.py:_setup_ro…
GandalfTea Oct 22, 2025
240300a
runtime stats high-level frames
GandalfTea Oct 23, 2025
ca8147f
runtime stats aggregator
GandalfTea Oct 23, 2025
4630c41
track per-nonce in-flight and in-wait times and append to ingress tra…
GandalfTea Oct 23, 2025
7bf6bbb
stop tracking bytes and target, change 'grpc' to 'network' for cleane…
GandalfTea Oct 23, 2025
242839f
remove profiling logs
GandalfTea Oct 23, 2025
2c2608b
aggregate per-nonce
GandalfTea Oct 23, 2025
adf3edf
construct new request on embedding event
GandalfTea Oct 23, 2025
c606249
handle frame with custom cost function
GandalfTea Oct 23, 2025
fe47f68
update canonical traces for stats, rename ingress to rx and egress to tx
GandalfTea Oct 23, 2025
4e7e12d
filter canonical frames
GandalfTea Oct 23, 2025
df240c5
move to on-request vars to avoid race conditions
GandalfTea Oct 24, 2025
df9705a
auto topo and load model
GandalfTea Oct 24, 2025
37a63b9
wrap in trace frames
GandalfTea Oct 24, 2025
e0a9fab
change file name
GandalfTea Oct 24, 2025
1e16b46
various small stuff
GandalfTea Oct 24, 2025
ffa89a2
add tracer to api and send frames back to repl. emit special frames w…
GandalfTea Oct 24, 2025
6fb7740
track prompt tokens
GandalfTea Oct 24, 2025
b458039
move trace frame and add correct nonce and other metadata
GandalfTea Oct 24, 2025
4600a5f
track nonce on all frames
GandalfTea Oct 24, 2025
d941191
better track in-wait time and default to 0 for single shard
GandalfTea Oct 24, 2025
3ac46e6
started filtering counters and printing
GandalfTea Oct 24, 2025
20af919
basic counters working, ttft, tps, itl, token_count
GandalfTea Oct 25, 2025
6674083
track node_id for every frame
GandalfTea Oct 25, 2025
c47a351
fix trace annotate
GandalfTea Oct 25, 2025
f505790
aggreagate frame symbols into sub-groups for focusing and compute tot…
GandalfTea Oct 25, 2025
f509b55
typo in activation timestamp
GandalfTea Oct 25, 2025
4727436
per-node info and restructured counting
GandalfTea Oct 25, 2025
f8495a0
reformat frames
GandalfTea Oct 26, 2025
ba43113
better sorting
GandalfTea Oct 26, 2025
9d6e4ff
use epoch for t0
GandalfTea Oct 26, 2025
a05eb75
add stats nodes and fix node registration
GandalfTea Oct 26, 2025
d8ce175
always register t0
GandalfTea Oct 26, 2025
2b44848
mark round
GandalfTea Oct 26, 2025
563160c
don't track queue wait
GandalfTea Oct 27, 2025
013ed18
break down tx.enque into correct compute-network frames
GandalfTea Oct 27, 2025
d7149c0
aggregate compound subsytem metrics correctly per node
GandalfTea Oct 27, 2025
a0780b1
fix ms scaling
GandalfTea Oct 27, 2025
547543d
rename old grpc frames to network
GandalfTea Oct 27, 2025
5924383
correctly aggregate global memory use per node
GandalfTea Oct 27, 2025
561accd
request.round continue
GandalfTea Oct 27, 2025
f13c0aa
update signature and unload
GandalfTea Oct 27, 2025
88ce17f
force quantization field in model config (mlx_lm doesn't have it)
GandalfTea Oct 27, 2025
994ccfa
add ShardConfig to __init__
GandalfTea Oct 27, 2025
9091031
rm old bench framework
GandalfTea Oct 27, 2025
1896d24
remove old memory frame path
GandalfTea Oct 27, 2025
20e39e1
not-working chat interface
GandalfTea Oct 27, 2025
ba93e0e
fix indent after rebase
GandalfTea Nov 3, 2025
af49e36
cleanup weight_cache
GandalfTea Nov 3, 2025
cc977c5
Revert "cleanup weight_cache"
GandalfTea Nov 3, 2025
0bc3253
remove double code in weight_cache from rebase
GandalfTea Nov 3, 2025
d186593
comment message field for compatibility
GandalfTea Nov 3, 2025
4ce0405
fix indent and duplicates from rebase
GandalfTea Nov 3, 2025
a176562
small rebase fixes
GandalfTea Nov 3, 2025
c6b1f58
change order of elements so callback_url is position 4 again
GandalfTea Nov 3, 2025
41b932c
fix missing if conditions in compute thread
GandalfTea Nov 10, 2025
de8e5ee
remove prepare topology response object
GandalfTea Nov 10, 2025
a768a7c
Merge branch 'oto/perf' of https://github.com/firstbatchxyz/dnet into…
GandalfTea Nov 10, 2025
c7a1356
refactor the model management system
GandalfTea Nov 11, 2025
6415a13
refactor help
GandalfTea Nov 11, 2025
bef2b12
basic chat interface
GandalfTea Nov 11, 2025
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
2 changes: 2 additions & 0 deletions src/dnet/perf/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

from .trace import TraceConfig, Tracer
319 changes: 319 additions & 0 deletions src/dnet/perf/trace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,319 @@

from __future__ import annotations

import os
import io
import sys
import time
import json
import pstats
import cProfile
import threading
import queue

from dataclasses import dataclass
from typing import Any, Dict, Optional, Tuple, List
from contextlib import contextmanager

import httpx

from dnet.utils.logger import logger

@dataclass
class TraceConfig:
file: str = "logs/dnet-trace.jsonl"
streaming: bool = True
include_prefixes: Tuple[str, ...] = ("src/dnet/",)
include_c_calls: bool = False
budget: int = 0 # 0 means unlimited
enabled: bool = True
node_id: Optional[str] = None
record_pid_tid: bool = True
aggregate: bool = False
aggregate_url: Optional[str] = None
agg_max_events: int = 300

class _NoopFrame:
def __enter__(self):
return self
def __exit__(self, *a):
return False
def event(self, *a, **k):
pass
def set(self, *a, **k):
pass

class _Frame:
__slots__ = ("t", "name", "attrs", "_t0")
def __init__(self, tracer: "Tracer", name: str, attrs: Optional[Dict[str, Any]]):
self.t = tracer
self.name = name
self.attrs = dict(attrs or {})
self._t0 = 0.0
def __enter__(self):
self._t0 = time.time_ns() # cross-node timekeeping
self.attrs.update({"t0": self._t0})
self.t._emit({"type": "B", "name": self.name, "args": dict(self.attrs)})
return self
def __exit__(self, ex_type, ex, tb):
dt_ms = (time.time_ns() - self._t0) * 1e-6
self.attrs.update({"ms": round(dt_ms, 3), "exc": bool(ex), "t0": time.time_ns()})
self.t._emit({"type": "E", "name": self.name, "args": self.attrs})
return False
def event(self, name: str, **attrs):
out = dict(attrs or {})
out.setdefault("t_rel_ms", (time.perf_counter() - self._t0) * 1000.0)
self.t._emit({"type": "I", "name": f"{self.name}.{name}", "args": out})
def set(self, key: str, val: Any):
self.attrs[key] = val

class Tracer:
def __init__(self, config: TraceConfig):
self.config = config
self._lock = threading.Lock()
self._fh: Optional[io.TextIOBase] = None
self._events: List[Dict[str, Any]] = []
self._req_id: str = None
self._active = False

self._agg_enabled: bool = False
self._agg_max_events: int = int(self.config.agg_max_events or 1000)
self._agg_q: queue.Queue[dict] = queue.Queue(maxsize=256)
self._agg_thread: Optional[threading.Thread] = None

if self.config.aggregate:
self.start_aggregator()

# Aggregator worker thread
def start_aggregator(self) -> None:
self._agg_enabled = True
self._agg_max_events = max(10, int(self.config.agg_max_events or 1000)) # 10 min, 1000 default
if not self._agg_thread or not self._agg_thread.is_alive():
self._agg_thread = threading.Thread(target=self._agg_exec, name="trace-agg", daemon=True)
self._agg_thread.start()

def stop_aggregator(self, *, flush: bool = True, timeout: float = 5.0) -> None:
self._agg_enabled = False
if flush and self._events:
try:
self._agg_q.put_nowait({
"req_id": (self._req_id or "run"),
"node_id": (self.config.node_id or "node"),
"events": list(self._events), })
except queue.Full:
logger.warning(f"Trace aggragator queue is full.")
self._events.clear()
if self._agg_thread and self._agg_thread.is_alive():
self._agg_thread.join(timeout)
self._agg_thread = None

def _agg_exec(self) -> None:
assert self.config.aggregate_url != ""
client = httpx.Client(timeout=5.0)
try:
logger.debug(f"Aggregation worker thread {self._agg_enabled}, {self._agg_q.empty()}")
while self._agg_enabled or not self._agg_q.empty():
try:
batch = self._agg_q.get(timeout=0.2)
except queue.Empty:
continue
logger.info(f"Sending trace buffer to API : {self.config.aggregate_url}")
try:
res = client.post(self.config.aggregate_url, json=batch)
if res.status_code != 200:
logger.error(f"Aggregator POST failed {res.status_code}: {res.text}")
except Exception as e:
logger.warning(f"Unable to POST trace aggregation data to {self.config.aggregate_url}: {e}")
finally:
self._agg_q.task_done()
finally:
try:
client.close()
except Exception:
logger.warining("Unable to close httpx client.")

def update_api_addr(self, addr):
self.config.aggregate_url = addr
logger.debug(f"Updated API Address: {self.config.aggregate_url}")

def start(self, *, reset: bool = True) -> None:
self._active = bool(self.config.enabled)
if not self._active:
logger.info("Initialized tracer.")
return
if self.config.file:
d = os.path.dirname(self.config.file) or "."
os.makedirs(d, exist_ok=True)
if reset and os.path.exists(self.config.file):
try:
os.remove(self.config.file)
except Exception:
logger.warning(f"Unable to remove existing trace file {self.config.file}")
if self.config.streaming:
with self._lock:
self._fh = open(self.config.file, "a", encoding="utf-8")
logger.info(f"Streaming trace to {self.config.file}.")
if self.config.aggregate and self.config.aggregate_url and self.config.node_id:
self.start_aggregator()

def stop(self, *, flush_events: bool = True) -> None:
if flush_events:
self.flush()
self._active = False
with self._lock:
if self._fh:
try:
self._fh.flush()
self._fh.close()
except Exception:
logger.warning(f"Unable to flush to file {self.config.file}")
self._fh = None

# Flush file to disk
def flush(self, *, clear: bool = False) -> None:
if not self._active: return
with self._lock:
if not self.config.streaming and self._events:
with open(self.config.file, "a", encoding="utf-8") as f:
for ev in self._events:
f.write(json.dumps(ev, ensure_ascii=False) + "\n")
if clear:
self._events.clear()

# Quick dump to memory
def snapshot(self, path: str) -> None:
with self._lock:
with open(path, "w", encoding="utf-8") as f:
for ev in self._events:
f.write(json.dumps(ev, ensure_ascii=False) + "\n")

# emit a new frame
def _emit(self, ev: Dict[str, Any]) -> None:
if not self._active: return
ev.setdefault("ts", time.perf_counter())
if self._req_id is not None:
ev.setdefault("req_id", self._req_id)
if self.config.record_pid_tid:
try:
ev.setdefault("pid", os.getpid())
ev.setdefault("tid", threading.get_ident())
except Exception:
logger.warning("Unable to get PID and TID for tracer frame.")

with self._lock:
if self.config.streaming and self._fh:
self._fh.write(json.dumps(ev, ensure_ascii=False) + "\n")
self._fh.flush()
else:
self._events.append(ev)

if self._agg_enabled:
if len(self._events) < self._agg_max_events: return
logger.debug(f"Queuing tracer frame batch of {len(self._events)}")
batch = { "run_id": (self._req_id or "NONE"),
"node_id": (self.config.node_id or "NODE"),
"events": list(self._events)}
try:
self._agg_q.put_nowait(batch)
except queue.Full:
logger.warning(f"Aggregator queue is full. Dropping {len(batch["events"])} frames.")
self._events.clear()

# Frames
def frame(self, scope: str, name: str, attrs: Optional[Dict[str, Any]] = None):
if not self._active:
return _NoopFrame()
return _Frame(self, f"{scope}.{name}", attrs)

# Same as normal frame but signals that this trace is a cannon event (required for runtime stats)
def canonical(self, scope: str, name: str, attrs: Optional[Dict[str, Any]] = None):
return self.frame(scope, name, attrs)

# Mark an event outside of a frame
def mark(self, name: str, attrs: Any = {}) -> None:
self._emit({"type": "I", "name": name, "args": attrs})

# Helpers
@contextmanager
def profile_block(self, outfile: Optional[str] = None, sort: str = "cumtime", limit: int = 40):
pr = cProfile.Profile()
pr.enable()
try:
yield pr
finally:
pr.disable()
s = io.StringIO()
pstats.Stats(pr, stream=s).strip_dirs().sort_stats(sort).print_stats(limit)
out = s.getvalue()
if outfile:
d = os.path.dirname(outfile) or "."
os.makedirs(d, exist_ok=True)
with open(outfile, "w", encoding="utf-8") as f:
f.write(out)
else:
self._emit({"type": "PROFILE", "name": "cprofile", "attrs": {"sort": sort, "limit": limit, "report": out}})

@contextmanager
def callgraph(
self,
include_prefixes: Optional[Tuple[str, ...]] = None,
budget_events: Optional[int] = None,
include_c_calls: Optional[bool] = None,
apply_to_new_threads: bool = False,
):
"""
Interpreter-level tracing (sys.setprofile) for all Python calls/returns
within the scope. Heavy overhead; best for deep debugging runs.
"""
prefixes = include_prefixes if include_prefixes is not None else self.config.include_prefixes
budget = (budget_events if budget_events is not None else self.config.budget) or 0
inc_c = include_c_calls if include_c_calls is not None else self.config.include_c_calls

emitted = 0
stack: list[Tuple[str, float]] = []

def prof(frame, event, arg):
nonlocal emitted
if budget and emitted >= budget:
return
if event in ("call", "return"):
code = frame.f_code
filename = code.co_filename or ""
if prefixes and not any(filename.startswith(p) for p in prefixes):
return
name = code.co_name
key = f"{filename}:{code.co_firstlineno}:{name}"
if event == "call":
stack.append((key, time.perf_counter()))
self._emit({"type": "B", "name": f"py.{name}", "attrs": {"file": filename, "line": code.co_firstlineno}})
emitted += 1
else:
if stack and stack[-1][0] == key:
_, t0 = stack.pop()
dt_ms = (time.perf_counter() - t0) * 1000.0
self._emit({"type": "E", "name": f"py.{name}", "attrs": {"ms": round(dt_ms, 3)}})
emitted += 1
elif inc_c and event in ("c_call", "c_return"):
func = getattr(arg, "__name__", None)
mod = getattr(arg, "__module__", None)
if not func:
return
if event == "c_call":
self._emit({"type": "B", "name": f"c.{mod}.{func}", "attrs": {}})
emitted += 1
else:
self._emit({"type": "E", "name": f"c.{mod}.{func}", "attrs": {}})
emitted += 1

prev = sys.getprofile()
sys.setprofile(prof)
prev_thread = None
if apply_to_new_threads:
prev_thread = threading.getprofile()
threading.setprofile(prof)
try:
yield
finally:
sys.setprofile(prev)
if apply_to_new_threads:
threading.setprofile(prev_thread)
1 change: 1 addition & 0 deletions src/dnet/perf/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .aggregators import TraceAggregator, StatsAggregator
Loading