dv-flow-mgr 1.7.14886019138rc0__py3-none-any.whl → 1.8.14930698570rc0__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.
dv_flow/mgr/__init__.py CHANGED
@@ -31,7 +31,7 @@ from .task_node_ctor_wrapper import task
31
31
  from .task_runner import TaskSetRunner
32
32
  from .task_listener_log import TaskListenerLog
33
33
 
34
- VERSION="1.7.0"
35
- SUFFIX="14886019138rc0"
34
+ VERSION="1.8.0"
35
+ SUFFIX="14930698570rc0"
36
36
  __version__="%s%s" % (VERSION, SUFFIX)
37
37
 
@@ -28,6 +28,7 @@ from ..task_data import SeverityE
28
28
  from ..task_graph_builder import TaskGraphBuilder
29
29
  from ..task_runner import TaskSetRunner
30
30
  from ..task_listener_log import TaskListenerLog
31
+ from ..task_listener_trace import TaskListenerTrace
31
32
 
32
33
 
33
34
  class CmdRun(object):
@@ -98,7 +99,14 @@ class CmdRun(object):
98
99
  if args.j != -1:
99
100
  runner.nproc = int(args.j)
100
101
 
102
+ if not os.path.isdir(os.path.join(rundir, "log")):
103
+ os.makedirs(os.path.join(rundir, "log"))
104
+
105
+ fp = open(os.path.join(rundir, "log", "%s.trace.json" % pkg.name), "w")
106
+ trace = TaskListenerTrace(fp)
107
+
101
108
  runner.add_listener(listener.event)
109
+ runner.add_listener(trace.event)
102
110
 
103
111
  tasks = []
104
112
 
@@ -110,6 +118,9 @@ class CmdRun(object):
110
118
 
111
119
  asyncio.run(runner.run(tasks))
112
120
 
121
+ trace.close()
122
+ fp.close()
123
+
113
124
  return runner.status
114
125
 
115
126
 
@@ -0,0 +1,171 @@
1
+ import dataclasses as dc
2
+ import json
3
+ import time
4
+ from typing import Dict, List, TextIO
5
+ from .task_node import TaskNode
6
+
7
+ @dc.dataclass
8
+ class TaskListenerTrace(object):
9
+ """Task listener that generates Google Trace Event Format output."""
10
+
11
+ fp: TextIO # File to write trace events to
12
+ _free_tids: List = dc.field(default_factory=list) # Pool of available thread IDs
13
+ _task_tid_map: Dict = dc.field(default_factory=dict) # Map of tasks to their assigned thread IDs
14
+ _next_tid: int = dc.field(default=1) # Next thread ID to assign if pool is empty
15
+ _next_flow_id: int = dc.field(default=1) # Counter for unique flow IDs
16
+ _events: List = dc.field(default_factory=list) # Store events in memory
17
+
18
+ def __post_init__(self):
19
+ # Add metadata event
20
+ self._events.append({
21
+ "name": "metadata",
22
+ "ph": "M",
23
+ "pid": 1,
24
+ "tid": 0,
25
+ "args": {
26
+ "name": "Task Execution",
27
+ "timeUnit": "us"
28
+ }
29
+ })
30
+
31
+ def close(self):
32
+ """Write the complete trace file and close it."""
33
+ trace = {
34
+ "traceEvents": self._events,
35
+ "displayTimeUnit": "ms" # Show times in milliseconds in the viewer
36
+ }
37
+ json.dump(trace, self.fp, indent=2)
38
+ self.fp.flush()
39
+
40
+ def _get_tid(self, task: TaskNode) -> int:
41
+ """Get a thread ID for a task, either from the pool or creating a new one."""
42
+ if task in self._task_tid_map:
43
+ return self._task_tid_map[task]
44
+
45
+ if len(self._free_tids) > 0:
46
+ tid = self._free_tids.pop()
47
+ else:
48
+ tid = self._next_tid
49
+ self._next_tid += 1
50
+
51
+ self._task_tid_map[task] = tid
52
+ return tid
53
+
54
+ def _release_tid(self, task: TaskNode):
55
+ """Return a task's thread ID to the pool."""
56
+ if task in self._task_tid_map:
57
+ tid = self._task_tid_map[task]
58
+ del self._task_tid_map[task]
59
+ self._free_tids.append(tid)
60
+
61
+ def _get_task_data(self, task: TaskNode) -> dict:
62
+ """Extract serializable task data"""
63
+ data = {}
64
+
65
+ # Add any parameters
66
+ if hasattr(task, 'params') and task.params:
67
+ # If params is a dataclass or has __dict__, get its fields
68
+ if hasattr(task.params, '__dict__'):
69
+ data['params'] = task.params.__dict__
70
+ elif isinstance(task.params, dict):
71
+ data['params'] = task.params
72
+
73
+ # Add inputs if present
74
+ if hasattr(task, 'needs') and task.needs:
75
+ inputs = []
76
+ for need, _ in task.needs:
77
+ if hasattr(need, 'output') and need.output:
78
+ inputs.append({
79
+ 'task': need.name,
80
+ 'data': need.output.__dict__ if hasattr(need.output, '__dict__') else need.output
81
+ })
82
+ if inputs:
83
+ data['inputs'] = inputs
84
+
85
+ return data
86
+
87
+ def event(self, task: TaskNode, reason: str):
88
+ """Record a task execution event.
89
+
90
+ Args:
91
+ task: The task that generated the event
92
+ reason: Either 'enter' or 'leave' marking start/end of task execution
93
+ """
94
+ # Get/create thread ID for this task
95
+ tid = self._get_tid(task)
96
+
97
+ # Map the event type
98
+ ph = 'B' if reason == 'enter' else 'E'
99
+
100
+ # Get current timestamp in microseconds
101
+ ts = int(time.time() * 1_000_000) if reason == "enter" else int(task.end.timestamp() * 1_000_000)
102
+
103
+ # Create the duration event with initial args
104
+ args = {}
105
+
106
+ # Add task data
107
+ if reason == "enter":
108
+ # Add input data on task start
109
+ input_data = self._get_task_data(task)
110
+ if input_data:
111
+ args = input_data
112
+
113
+ elif reason == 'leave':
114
+ if task.result:
115
+ # Add status and change info
116
+ args["status"] = task.result.status
117
+ args["changed"] = task.result.changed
118
+
119
+ # Add output data if present
120
+ if hasattr(task.result, 'output') and task.result.output:
121
+ args["output"] = [
122
+ out.__dict__ if hasattr(out, '__dict__') else out
123
+ for out in task.result.output
124
+ ]
125
+
126
+ self._release_tid(task)
127
+
128
+ # Create the event with collected args
129
+ event = {
130
+ "name": task.name,
131
+ "cat": "task",
132
+ "ph": ph,
133
+ "pid": 1,
134
+ "tid": tid,
135
+ "ts": ts,
136
+ "args": args
137
+ }
138
+
139
+ # Store the duration event
140
+ self._events.append(event)
141
+
142
+ # Add flow event for dependencies
143
+ if reason == "enter":
144
+ # When task starts, add flow event from each dependency
145
+ for need, _ in task.needs:
146
+ # Create flow start from completed task to this one
147
+ flow = {
148
+ "name": f"{need.name} -> {task.name}",
149
+ "cat": "flow",
150
+ "ph": "s", # Flow start
151
+ "pid": 1,
152
+ "tid": self._task_tid_map.get(need, 0),
153
+ "ts": int(need.end.timestamp() * 1_000_000) if need.end else ts,
154
+ "id": self._next_flow_id,
155
+ "bp": "e"
156
+ }
157
+ self._events.append(flow)
158
+
159
+ # Create flow finish at the start of this task
160
+ flow_end = {
161
+ "name": f"{need.name} -> {task.name}",
162
+ "cat": "flow",
163
+ "ph": "f", # Flow finish
164
+ "pid": 1,
165
+ "tid": tid,
166
+ "ts": ts,
167
+ "id": self._next_flow_id,
168
+ "bp": "e"
169
+ }
170
+ self._events.append(flow_end)
171
+ self._next_flow_id += 1
dv_flow/mgr/task_node.py CHANGED
@@ -24,6 +24,7 @@ import json
24
24
  import os
25
25
  import sys
26
26
  import dataclasses as dc
27
+ import datetime
27
28
  import pydantic.dataclasses as pdc
28
29
  import logging
29
30
  import toposort
@@ -55,8 +56,8 @@ class TaskNode(object):
55
56
  rundir : List[str] = dc.field(default=None)
56
57
  output : TaskDataOutput = dc.field(default=None)
57
58
  result : TaskDataResult = dc.field(default=None)
58
- start : float = dc.field(default=None)
59
- end : float = dc.field(default=None)
59
+ start : datetime.datetime = dc.field(default=None)
60
+ end : datetime.datetime = dc.field(default=None)
60
61
  save_exec_data : bool = dc.field(default=True)
61
62
  iff : bool = dc.field(default=True)
62
63
  parent : 'TaskNode' = dc.field(default=None)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dv-flow-mgr
3
- Version: 1.7.14886019138rc0
3
+ Version: 1.8.14930698570rc0
4
4
  Summary: DV Flow Manager is a build system for silicon design
5
5
  Author-email: Matthew Ballance <matt.ballance@gmail.com>
6
6
  License: Apache License
@@ -1,4 +1,4 @@
1
- dv_flow/mgr/__init__.py,sha256=IGdCSIE1H9oiKxdBHCoep36ZQbA0PNZeiF-QVlXh3gQ,1315
1
+ dv_flow/mgr/__init__.py,sha256=SuHUNRUr03Dy5bvMChNK6x76Zw1l66AEIps_uNN-cOQ,1315
2
2
  dv_flow/mgr/__main__.py,sha256=BogNdBkXhgg05E8_IumNkVoag6WwvfbpiI8346oOtPo,3844
3
3
  dv_flow/mgr/cond_def.py,sha256=2ZkzPusqVkN1fFMTvkDl9O_OJLPdD_cK3xzX9J75RMw,343
4
4
  dv_flow/mgr/config.py,sha256=b2MVlVVNB0psk8x4bQRAYshkpNJrtyMtV1Ymhmx9AfM,137
@@ -37,7 +37,8 @@ dv_flow/mgr/task_def.py,sha256=8NPwtTROfWDkMqcO9mKXV4dw0sC4mCMmnsNuv8uTdTY,5094
37
37
  dv_flow/mgr/task_graph_builder.py,sha256=q7BS7OLYkS6uZwQLvo6P_CtJkhIvPal_tXLZHgUuLpU,28172
38
38
  dv_flow/mgr/task_graph_dot_writer.py,sha256=qK4Imy9o2_F1aKoU1tJ-qoBHslq2BhSMbdjAUPfpN7I,6009
39
39
  dv_flow/mgr/task_listener_log.py,sha256=Ai-6X5BOoGsaNTgnlXEW0-czrjJm7__ShNK501CUmko,4337
40
- dv_flow/mgr/task_node.py,sha256=3L1qqwisV_qRdbUdRG25uzcsO57T2Z7fbvXYF87Ta1U,5191
40
+ dv_flow/mgr/task_listener_trace.py,sha256=6MvVmy4Rc30qTYpA4yaF760Qlszk34FQOCtRD9slkNE,6064
41
+ dv_flow/mgr/task_node.py,sha256=OC3rkeRSFv9wmgkMZ_7eJu7nuXGJcwW_b6FGQM-w7AU,5231
41
42
  dv_flow/mgr/task_node_compound.py,sha256=0biBPT_2SpCPJL7DFaFY27_K7kNxJ1taIut3Fv12HXk,3347
42
43
  dv_flow/mgr/task_node_ctor.py,sha256=YsoVMX5WbpbzcHvEK7ps_ZRV-J7MZ3F8NNozQw7vbog,4418
43
44
  dv_flow/mgr/task_node_ctor_compound.py,sha256=290JdcTnL3b3Gv7s_wRLjdM02ezKhc9QnxZE0mv72i8,4379
@@ -56,7 +57,7 @@ dv_flow/mgr/type.py,sha256=hoJTatlPC0yOazKSWduK-5CfY38RPkc6qXFzOCcVSdM,723
56
57
  dv_flow/mgr/type_def.py,sha256=4sge3PibO1jDnS0cXdX0PiurcKbDA3kT6rb4DGIKwEM,1176
57
58
  dv_flow/mgr/yaml_srcinfo_loader.py,sha256=29BNRiB8Hj1FepkrLtdjHSv5U_85Q432gBeeK80nKEA,1606
58
59
  dv_flow/mgr/cmds/cmd_graph.py,sha256=yg5KbNrGvm3dySiI0Qei_pMWZkOE9GtEyaQ4IdNVmoE,2852
59
- dv_flow/mgr/cmds/cmd_run.py,sha256=J53JJnUPn9yLDFHFv_DJdnZR2qMvbhsGWY8APHoVtWE,3707
60
+ dv_flow/mgr/cmds/cmd_run.py,sha256=SsCZXwutJW1XT5iXtJqvdeg6p6HEa86V5hELNKuaWgA,4082
60
61
  dv_flow/mgr/cmds/cmd_show.py,sha256=JOIFaVXt8YCf9bKXfq6qzV5wQdxdLHqE-yCj0ecGREs,3755
61
62
  dv_flow/mgr/share/flow.json,sha256=lNmZex9NXkYbyb2aZseQfUOkV9CMyfH0iLODEI7EPBw,5096
62
63
  dv_flow/mgr/std/create_file.py,sha256=SEpKTQdiY32002C7b4kYfAiK9v_xajixOJU5WftW75I,2957
@@ -73,9 +74,9 @@ dv_flow/mgr/util/util.py,sha256=BO7iqP_c9ttmXkojq7nKDN-g8wl1_Pco9k-KnrXxjwE,1889
73
74
  dv_flow/mgr/util/cmds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
75
  dv_flow/mgr/util/cmds/cmd_schema.py,sha256=IJzZdxCSEgIQ79LpYiM7UqJ9RJ-7yraqmBN2XVgAgXA,1752
75
76
  dv_flow/mgr/util/cmds/cmd_workspace.py,sha256=egmaIXpe5L-TePwmcfisfrG6tdiTUWSjqa9Za5WChVs,890
76
- dv_flow_mgr-1.7.14886019138rc0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
77
- dv_flow_mgr-1.7.14886019138rc0.dist-info/METADATA,sha256=BdTQJ9Wt87mId9RnZiwCzqIYuHtedmHd8zGNmMykNDc,13335
78
- dv_flow_mgr-1.7.14886019138rc0.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
79
- dv_flow_mgr-1.7.14886019138rc0.dist-info/entry_points.txt,sha256=1roy8wAFM48LabOvr6jiOw0MUs-qE8X3Vf8YykPazxk,50
80
- dv_flow_mgr-1.7.14886019138rc0.dist-info/top_level.txt,sha256=amfVTkggzYPtWwLqNmRukfz1Buu0pGS2SrYBBLhXm04,8
81
- dv_flow_mgr-1.7.14886019138rc0.dist-info/RECORD,,
77
+ dv_flow_mgr-1.8.14930698570rc0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
78
+ dv_flow_mgr-1.8.14930698570rc0.dist-info/METADATA,sha256=vPln7CEjSer8daHBSV2zvvNRpQi2dYtKvYLIJ3R1yog,13335
79
+ dv_flow_mgr-1.8.14930698570rc0.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
80
+ dv_flow_mgr-1.8.14930698570rc0.dist-info/entry_points.txt,sha256=1roy8wAFM48LabOvr6jiOw0MUs-qE8X3Vf8YykPazxk,50
81
+ dv_flow_mgr-1.8.14930698570rc0.dist-info/top_level.txt,sha256=amfVTkggzYPtWwLqNmRukfz1Buu0pGS2SrYBBLhXm04,8
82
+ dv_flow_mgr-1.8.14930698570rc0.dist-info/RECORD,,