pydftracer 2.0.4.post13.dev0__tar.gz → 2.0.5.post1.dev0__tar.gz

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.
Files changed (54) hide show
  1. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/PKG-INFO +1 -1
  2. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/api/core.rst +15 -0
  3. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/_version.py +3 -3
  4. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/common.py +205 -3
  5. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/pydftracer.egg-info/PKG-INFO +1 -1
  6. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/pydftracer.egg-info/scm_file_list.json +1 -0
  7. pydftracer-2.0.5.post1.dev0/python/pydftracer.egg-info/scm_version.json +8 -0
  8. pydftracer-2.0.4.post13.dev0/python/pydftracer.egg-info/scm_version.json +0 -8
  9. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/.readthedocs.yml +0 -0
  10. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/LICENSE +0 -0
  11. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/MANIFEST.in +0 -0
  12. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/NOTICE +0 -0
  13. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/README.md +0 -0
  14. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/Makefile +0 -0
  15. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/README.md +0 -0
  16. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/make.bat +0 -0
  17. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/requirements.txt +0 -0
  18. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/ai_ml_guide.rst +0 -0
  19. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/api/ai.rst +0 -0
  20. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/api/dynamo.rst +0 -0
  21. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/api/env.rst +0 -0
  22. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/api/index.rst +0 -0
  23. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/conf.py +0 -0
  24. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/developers.rst +0 -0
  25. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/dynamo_guide.rst +0 -0
  26. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/examples.rst +0 -0
  27. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/index.rst +0 -0
  28. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/installation.rst +0 -0
  29. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/pytorch.rst +0 -0
  30. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/quickstart.rst +0 -0
  31. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/docs/source/type_safety.rst +0 -0
  32. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/pyproject.toml +0 -0
  33. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/__init__.py +0 -0
  34. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/ai.py +0 -0
  35. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/ai_common.py +0 -0
  36. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/ai_init.py +0 -0
  37. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/dbg/__init__.py +0 -0
  38. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/dbg/ai.py +0 -0
  39. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/dbg/logger.py +0 -0
  40. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/dbg/torch/__init__.py +0 -0
  41. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/dbg/torch/profiler.py +0 -0
  42. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/dynamo.py +0 -0
  43. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/env.py +0 -0
  44. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/logger.py +0 -0
  45. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/py.typed +0 -0
  46. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/torch/__init__.py +0 -0
  47. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/torch/common.py +0 -0
  48. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/dftracer/python/torch/profiler.py +0 -0
  49. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/pydftracer.egg-info/SOURCES.txt +0 -0
  50. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/pydftracer.egg-info/dependency_links.txt +0 -0
  51. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/pydftracer.egg-info/requires.txt +0 -0
  52. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/python/pydftracer.egg-info/top_level.txt +0 -0
  53. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/setup.cfg +0 -0
  54. {pydftracer-2.0.4.post13.dev0 → pydftracer-2.0.5.post1.dev0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydftracer
3
- Version: 2.0.4.post13.dev0
3
+ Version: 2.0.5.post1.dev0
4
4
  Summary: Python libs for DFTracer
5
5
  Author-email: "Hariharan Devarajan (Hari)" <hariharandev1@llnl.gov>, Ray Andrew Sinurat <raydreww@gmail.com>
6
6
  Maintainer-email: "Hariharan Devarajan (Hari)" <hariharandev1@llnl.gov>, Ray Andrew Sinurat <raydreww@gmail.com>
@@ -38,6 +38,21 @@ Tag Types
38
38
  :undoc-members:
39
39
  :show-inheritance:
40
40
 
41
+ Entity Types
42
+ ~~~~~~~~~~~~
43
+
44
+ .. autoclass:: dftracer.python.EntityStore
45
+ :members:
46
+ :undoc-members:
47
+
48
+ .. autoclass:: dftracer.python.EntityRole
49
+ :members:
50
+ :undoc-members:
51
+
52
+ .. autoclass:: dftracer.python.EntityRelation
53
+ :members:
54
+ :undoc-members:
55
+
41
56
  Profiler Protocol
42
57
  ~~~~~~~~~~~~~~~~~
43
58
 
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.0.4.post13.dev0'
22
- __version_tuple__ = version_tuple = (2, 0, 4, 'post13', 'dev0')
21
+ __version__ = version = '2.0.5.post1.dev0'
22
+ __version_tuple__ = version_tuple = (2, 0, 5, 'post1', 'dev0')
23
23
 
24
- __commit_id__ = commit_id = 'g311e91297'
24
+ __commit_id__ = commit_id = 'g676e7a176'
@@ -4,7 +4,7 @@ import os
4
4
  import signal
5
5
  import sys
6
6
  from collections.abc import Iterable, Sequence
7
- from enum import Enum
7
+ from enum import Enum, IntEnum
8
8
  from functools import wraps
9
9
  from pathlib import Path
10
10
  from typing import (
@@ -33,6 +33,50 @@ T = TypeVar("T") # For generic iterator types
33
33
  TagValueTuple = Tuple[int, Union[int, float, str]]
34
34
 
35
35
 
36
+ class EntityStore(IntEnum):
37
+ """Where an entity instance lives (mirrors core/common/entity.h)."""
38
+
39
+ MEMORY = 0
40
+ GPU_MEMORY = 1
41
+ LOCAL_DISK = 2
42
+ PARALLEL_FS = 3
43
+ BURST_BUFFER = 4
44
+ OBJECT_STORE = 5
45
+ DATABASE = 6
46
+ NETWORK = 7
47
+ OTHER = 8
48
+
49
+
50
+ class EntityRole(IntEnum):
51
+ """Role of an entity type in the workflow."""
52
+
53
+ UNKNOWN = 0
54
+ INPUT = 1
55
+ OUTPUT = 2
56
+ INTERMEDIATE = 3
57
+ PARAMETER = 4
58
+ REFERENCE = 5
59
+
60
+
61
+ class EntityRelation(IntEnum):
62
+ """Event->entity relations (< 16) and entity->entity relations (>= 16)."""
63
+
64
+ USED = 0
65
+ GENERATED = 1
66
+ INVALIDATED = 2
67
+ UPDATED = 3
68
+ DERIVED_FROM = 16
69
+ REVISION_OF = 17
70
+ CONTAINS = 18
71
+ PART_OF = 19
72
+ SPECIALIZATION_OF = 20
73
+ ALTERNATE_OF = 21
74
+ DEPENDS_ON = 22
75
+
76
+
77
+ EntityID = int # 64-bit id; 0 means "no entity" (tracing off)
78
+
79
+
36
80
  class ProfilerProtocol(Protocol):
37
81
  """Protocol defining the interface for profiler implementations."""
38
82
 
@@ -70,14 +114,30 @@ class ProfilerProtocol(Protocol):
70
114
  int_args: Optional[Dict[str, TagValueTuple]] = None,
71
115
  string_args: Optional[Dict[str, TagValueTuple]] = None,
72
116
  float_args: Optional[Dict[str, TagValueTuple]] = None,
117
+ relations: Optional[Dict[Any, List[int]]] = None,
73
118
  ) -> None:
74
- """Log a profiling event."""
119
+ """Log a profiling event. ``relations`` maps an EntityRelation to
120
+ entity ids from declare_entity."""
75
121
  ... # pragma: no cover
76
122
 
77
123
  def log_metadata_event(self, key: str, value: str) -> None:
78
124
  """Log a metadata event."""
79
125
  ... # pragma: no cover
80
126
 
127
+ def declare_entity(self, type: str, key: str, store: Any, uri: str) -> EntityID:
128
+ """Declare an entity (type, key) once per process; return its id."""
129
+ ... # pragma: no cover
130
+
131
+ def declare_entity_type(self, type: str, role: Any, description: str) -> None:
132
+ """Describe an entity type (role, description) once per process."""
133
+ ... # pragma: no cover
134
+
135
+ def relate_entities(
136
+ self, relation: Any, subject: EntityID, object: EntityID
137
+ ) -> None:
138
+ """Relate two entities (entity->entity relation)."""
139
+ ... # pragma: no cover
140
+
81
141
  def set_app_metadata_int(self, key: str, value: int) -> None:
82
142
  """Set process-global app metadata (int), folded into the trace's
83
143
  end event at finalize."""
@@ -131,12 +191,24 @@ class NoOpProfiler:
131
191
  int_args: Optional[Dict[str, TagValueTuple]] = None,
132
192
  string_args: Optional[Dict[str, TagValueTuple]] = None,
133
193
  float_args: Optional[Dict[str, TagValueTuple]] = None,
194
+ relations: Optional[Dict[Any, List[int]]] = None,
134
195
  ) -> None:
135
196
  pass
136
197
 
137
198
  def log_metadata_event(self, key: str, value: str) -> None:
138
199
  pass
139
200
 
201
+ def declare_entity(self, type: str, key: str, store: Any, uri: str) -> EntityID:
202
+ return 0
203
+
204
+ def declare_entity_type(self, type: str, role: Any, description: str) -> None:
205
+ pass
206
+
207
+ def relate_entities(
208
+ self, relation: Any, subject: EntityID, object: EntityID
209
+ ) -> None:
210
+ pass
211
+
140
212
  def set_app_metadata_int(self, key: str, value: int) -> None:
141
213
  pass
142
214
 
@@ -355,12 +427,24 @@ class dftracer:
355
427
  int_args: Optional[Dict[str, TagValueTuple]] = None,
356
428
  float_args: Optional[Dict[str, TagValueTuple]] = None,
357
429
  string_args: Optional[Dict[str, TagValueTuple]] = None,
430
+ relations: Optional[Dict[EntityRelation, List[int]]] = None,
358
431
  ) -> None:
359
432
  if DFTRACER_ENABLE and self.logger:
360
433
  if self.dbg_logging:
361
434
  self.dbg_logging.debug(
362
- f"logger.log_event {name} {cat} {start_time} {duration} int={int_args} str={string_args} float={float_args}"
435
+ f"logger.log_event {name} {cat} {start_time} {duration} int={int_args} str={string_args} float={float_args} rel={relations}"
363
436
  )
437
+ kwargs: Dict[str, Any] = {}
438
+ if relations:
439
+ # Older native modules have no relations kwarg; pass it only
440
+ # when there is something to relate. Keys are converted to the
441
+ # native EntityRelation enum.
442
+ native = self._native_enum("EntityRelation")
443
+ kwargs["relations"] = {
444
+ (native(int(k)) if native else int(k)): v
445
+ for k, v in relations.items()
446
+ if v
447
+ }
364
448
  self.logger.log_event(
365
449
  name=name,
366
450
  cat=cat,
@@ -369,6 +453,7 @@ class dftracer:
369
453
  int_args=int_args or {},
370
454
  float_args=float_args or {},
371
455
  string_args=string_args or {},
456
+ **kwargs,
372
457
  )
373
458
 
374
459
  def log_metadata_event(self, key: str, value: str) -> None:
@@ -377,6 +462,75 @@ class dftracer:
377
462
  self.dbg_logging.debug(f"logger.log_metadata_event {key} {value}")
378
463
  self.logger.log_metadata_event(key=key, value=value)
379
464
 
465
+ # ---- entities and relations -------------------------------------------
466
+ # An entity is a typed instance (type, key) -> 64-bit EntityID computed by
467
+ # the native core (FNV-1a), identical in every language and process and
468
+ # recorded once per process. Events relate to entities by id with an
469
+ # EntityRelation (see dft_fn.uses / generates / relate); entities relate
470
+ # to each other with relate_entities. Strings are truncated and sanitized
471
+ # by the core (type 32, uri 256, description 256 characters).
472
+
473
+ def _native_enum(self, name: str) -> Any:
474
+ return getattr(self.logger, name, None) if self.logger else None
475
+
476
+ def _has(self, fn: str) -> bool:
477
+ return self._native(fn) is not None
478
+
479
+ def _native(self, fn: str) -> Optional[ProfilerProtocol]:
480
+ """The native module, if tracing is on and it carries `fn` -- older
481
+ wheels predate the entity API."""
482
+ logger = self.logger
483
+ if DFTRACER_ENABLE and logger is not None and hasattr(logger, fn):
484
+ return logger
485
+ return None
486
+
487
+ def declare_entity(
488
+ self,
489
+ type: str,
490
+ key: Any,
491
+ store: EntityStore = EntityStore.MEMORY,
492
+ uri: str = "",
493
+ ) -> EntityID:
494
+ """Declare (type, key) once per process; return its EntityID (0 when
495
+ tracing is off or the native module predates the entity API)."""
496
+ logger = self._native("declare_entity")
497
+ if logger is None:
498
+ return 0
499
+ native = self._native_enum("EntityStore")
500
+ return int(
501
+ logger.declare_entity(
502
+ type, str(key), native(int(store)) if native else int(store), uri or ""
503
+ )
504
+ )
505
+
506
+ def declare_entity_type(
507
+ self,
508
+ type: str,
509
+ role: EntityRole = EntityRole.UNKNOWN,
510
+ description: str = "",
511
+ ) -> None:
512
+ """Describe an entity type once per process: role and description."""
513
+ logger = self._native("declare_entity_type")
514
+ if logger is not None:
515
+ native = self._native_enum("EntityRole")
516
+ logger.declare_entity_type(
517
+ type, native(int(role)) if native else int(role), description or ""
518
+ )
519
+
520
+ def relate_entities(
521
+ self, relation: EntityRelation, subject: EntityID, object: EntityID
522
+ ) -> None:
523
+ """Relate two entities with an entity->entity relation (>= 16), e.g.
524
+ EntityRelation.CONTAINS or DERIVED_FROM."""
525
+ if int(relation) < 16 or not subject or not object:
526
+ return
527
+ logger = self._native("relate_entities")
528
+ if logger is not None:
529
+ native = self._native_enum("EntityRelation")
530
+ logger.relate_entities(
531
+ native(int(relation)) if native else int(relation), subject, object
532
+ )
533
+
380
534
  def set_app_metadata_int(self, key: str, value: int) -> None:
381
535
  if DFTRACER_ENABLE and self.logger:
382
536
  if self.dbg_logging:
@@ -430,6 +584,7 @@ class dft_fn:
430
584
  self._arguments_int: Dict[str, TagValueTuple] = {}
431
585
  self._arguments_float: Dict[str, TagValueTuple] = {}
432
586
  self._arguments_string: Dict[str, TagValueTuple] = {}
587
+ self._relations: Dict[EntityRelation, List[int]] = {}
433
588
  self._t1: int = 0
434
589
  self._t2: int = 0
435
590
  self._flush: bool = False
@@ -513,6 +668,48 @@ class dft_fn:
513
668
  ).value()
514
669
  return self
515
670
 
671
+ # ---- relations to entities (see dftracer.declare_entity) --------------
672
+ def relate(self, relation: EntityRelation, entity: EntityID) -> "dft_fn":
673
+ """Relate this event to an entity id with an event relation (< 16)."""
674
+ if DFTRACER_ENABLE and self._enable and entity and int(relation) < 16:
675
+ self._relations.setdefault(EntityRelation(int(relation)), []).append(entity)
676
+ return self
677
+
678
+ def relate_entity(
679
+ self,
680
+ relation: EntityRelation,
681
+ type: str,
682
+ key: Any,
683
+ store: EntityStore = EntityStore.MEMORY,
684
+ uri: str = "",
685
+ ) -> EntityID:
686
+ """Declare (type, key) and relate it in one step; return its id."""
687
+ if not (DFTRACER_ENABLE and self._enable):
688
+ return 0
689
+ eid = dftracer.get_instance().declare_entity(type, key, store, uri)
690
+ self.relate(relation, eid)
691
+ return eid
692
+
693
+ def uses(
694
+ self,
695
+ type: str,
696
+ key: Any,
697
+ store: EntityStore = EntityStore.MEMORY,
698
+ uri: str = "",
699
+ ) -> EntityID:
700
+ """Provenance cause: this event consumed entity (type, key)."""
701
+ return self.relate_entity(EntityRelation.USED, type, key, store, uri)
702
+
703
+ def generates(
704
+ self,
705
+ type: str,
706
+ key: Any,
707
+ store: EntityStore = EntityStore.MEMORY,
708
+ uri: str = "",
709
+ ) -> EntityID:
710
+ """Provenance effect: this event produced entity (type, key)."""
711
+ return self.relate_entity(EntityRelation.GENERATED, type, key, store, uri)
712
+
516
713
  def flush(self) -> "dft_fn":
517
714
  if DFTRACER_ENABLE and self._enable:
518
715
  self._t2 = dftracer.get_instance().get_time()
@@ -524,6 +721,7 @@ class dft_fn:
524
721
  int_args=self._arguments_int,
525
722
  float_args=self._arguments_float,
526
723
  string_args=self._arguments_string,
724
+ relations=self._relations,
527
725
  )
528
726
  dftracer.get_instance().exit_event()
529
727
  self._flush = True
@@ -535,6 +733,10 @@ class dft_fn:
535
733
  dftracer.get_instance().enter_event()
536
734
  self._t2 = self._t1
537
735
  self._flush = False
736
+ # Relations describe the event just finished, so a new event starts
737
+ # without them; otherwise a reused dft_fn reports the same entities
738
+ # again on every later event.
739
+ self._relations = {}
538
740
  return self
539
741
 
540
742
  @overload
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydftracer
3
- Version: 2.0.4.post13.dev0
3
+ Version: 2.0.5.post1.dev0
4
4
  Summary: Python libs for DFTracer
5
5
  Author-email: "Hariharan Devarajan (Hari)" <hariharandev1@llnl.gov>, Ray Andrew Sinurat <raydreww@gmail.com>
6
6
  Maintainer-email: "Hariharan Devarajan (Hari)" <hariharandev1@llnl.gov>, Ray Andrew Sinurat <raydreww@gmail.com>
@@ -55,6 +55,7 @@
55
55
  "tests/test_coverage_improvements.py",
56
56
  "tests/test_dftracer.py",
57
57
  "tests/test_dynamo.py",
58
+ "tests/test_entities.py",
58
59
  "tests/test_general.py",
59
60
  "tests/test_parallel_workers.py",
60
61
  "tests/test_pytorch_profiler.py",
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "2.0.5",
3
+ "distance": 1,
4
+ "node": "g676e7a176e5ecd4005db1ebc0b2a003658a8a8ff",
5
+ "dirty": false,
6
+ "branch": "develop",
7
+ "node_date": "2026-10-02"
8
+ }
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "2.0.4",
3
- "distance": 13,
4
- "node": "g311e91297136e3f0e66bfdec189b87ef3bce4ea3",
5
- "dirty": false,
6
- "branch": "develop",
7
- "node_date": "2026-09-30"
8
- }