ttnn-visualizer 0.46.0__py3-none-any.whl → 0.48.0__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.
- ttnn_visualizer/app.py +36 -1
- ttnn_visualizer/csv_queries.py +2 -1
- ttnn_visualizer/file_uploads.py +1 -1
- ttnn_visualizer/models.py +1 -0
- ttnn_visualizer/queries.py +1 -1
- ttnn_visualizer/settings.py +1 -0
- ttnn_visualizer/sockets.py +31 -0
- ttnn_visualizer/static/assets/{allPaths-esBqnTg5.js → allPaths-DyhSRH--.js} +1 -1
- ttnn_visualizer/static/assets/allPathsLoader-DXd_rN1a.js +2 -0
- ttnn_visualizer/static/assets/{index-BuHal8Ii.css → index-CZ0Uonoz.css} +2 -2
- ttnn_visualizer/static/assets/{index-BANm1CMY.js → index-T8PVeTUn.js} +227 -227
- ttnn_visualizer/static/assets/{splitPathsBySizeLoader-DYuDhweD.js → splitPathsBySizeLoader-Gsi3qlIM.js} +1 -1
- ttnn_visualizer/static/index.html +2 -2
- ttnn_visualizer/tests/test_serializers.py +6 -0
- ttnn_visualizer/utils.py +190 -28
- ttnn_visualizer/views.py +90 -31
- {ttnn_visualizer-0.46.0.dist-info → ttnn_visualizer-0.48.0.dist-info}/METADATA +2 -1
- {ttnn_visualizer-0.46.0.dist-info → ttnn_visualizer-0.48.0.dist-info}/RECORD +23 -23
- {ttnn_visualizer-0.46.0.dist-info → ttnn_visualizer-0.48.0.dist-info}/licenses/LICENSE +95 -50
- ttnn_visualizer/static/assets/allPathsLoader-KPOKJ-lr.js +0 -2
- {ttnn_visualizer-0.46.0.dist-info → ttnn_visualizer-0.48.0.dist-info}/WHEEL +0 -0
- {ttnn_visualizer-0.46.0.dist-info → ttnn_visualizer-0.48.0.dist-info}/entry_points.txt +0 -0
- {ttnn_visualizer-0.46.0.dist-info → ttnn_visualizer-0.48.0.dist-info}/licenses/LICENSE_understanding.txt +0 -0
- {ttnn_visualizer-0.46.0.dist-info → ttnn_visualizer-0.48.0.dist-info}/top_level.txt +0 -0
@@ -1 +1 @@
|
|
1
|
-
import{p as r,I as s,_ as a}from"./index-
|
1
|
+
import{p as r,I as s,_ as a}from"./index-T8PVeTUn.js";const n=async(o,_)=>{const i=r(o);let t;return _===s.STANDARD?t=await a(()=>import("./index-03c8d4Gh.js").then(e=>e.I),[]):t=await a(()=>import("./index-PKNBViIU.js").then(e=>e.I),[]),t[i]};export{n as splitPathsBySizeLoader};
|
@@ -34,8 +34,8 @@
|
|
34
34
|
/* SERVER_CONFIG */
|
35
35
|
</script>
|
36
36
|
|
37
|
-
<script type="module" crossorigin src="/static/assets/index-
|
38
|
-
<link rel="stylesheet" crossorigin href="/static/assets/index-
|
37
|
+
<script type="module" crossorigin src="/static/assets/index-T8PVeTUn.js"></script>
|
38
|
+
<link rel="stylesheet" crossorigin href="/static/assets/index-CZ0Uonoz.css">
|
39
39
|
</head>
|
40
40
|
<body>
|
41
41
|
|
@@ -161,12 +161,14 @@ class TestSerializers(unittest.TestCase):
|
|
161
161
|
"device_id": 1,
|
162
162
|
"address": 1000,
|
163
163
|
"buffer_type": 0,
|
164
|
+
"buffer_layout": None,
|
164
165
|
"size": 256,
|
165
166
|
},
|
166
167
|
{
|
167
168
|
"device_id": 2,
|
168
169
|
"address": 2000,
|
169
170
|
"buffer_type": 1,
|
171
|
+
"buffer_layout": None,
|
170
172
|
"size": 512,
|
171
173
|
},
|
172
174
|
],
|
@@ -179,6 +181,7 @@ class TestSerializers(unittest.TestCase):
|
|
179
181
|
"device_id": 3,
|
180
182
|
"address": 3000,
|
181
183
|
"buffer_type": 1,
|
184
|
+
"buffer_layout": None,
|
182
185
|
"size": 1024,
|
183
186
|
},
|
184
187
|
],
|
@@ -260,12 +263,14 @@ class TestSerializers(unittest.TestCase):
|
|
260
263
|
"device_id": 1,
|
261
264
|
"address": 1000,
|
262
265
|
"buffer_type": 0,
|
266
|
+
"buffer_layout": None,
|
263
267
|
"size": 256,
|
264
268
|
},
|
265
269
|
{
|
266
270
|
"device_id": 2,
|
267
271
|
"address": 2000,
|
268
272
|
"buffer_type": 1,
|
273
|
+
"buffer_layout": None,
|
269
274
|
"size": 512,
|
270
275
|
},
|
271
276
|
],
|
@@ -389,6 +394,7 @@ class TestSerializers(unittest.TestCase):
|
|
389
394
|
"buffers": [
|
390
395
|
{
|
391
396
|
"address": 1000,
|
397
|
+
"buffer_layout": None,
|
392
398
|
"buffer_type": 0,
|
393
399
|
"device_id": 1,
|
394
400
|
"max_size_per_bank": 256,
|
ttnn_visualizer/utils.py
CHANGED
@@ -18,6 +18,127 @@ logger = logging.getLogger(__name__)
|
|
18
18
|
LAST_SYNCED_FILE_NAME = ".last-synced"
|
19
19
|
|
20
20
|
|
21
|
+
class PathResolver:
|
22
|
+
"""Centralized path resolution for both TT-Metal and upload/sync modes."""
|
23
|
+
|
24
|
+
def __init__(self, current_app):
|
25
|
+
self.current_app = current_app
|
26
|
+
self.tt_metal_home = current_app.config.get("TT_METAL_HOME")
|
27
|
+
self.is_direct_report_mode = bool(self.tt_metal_home)
|
28
|
+
|
29
|
+
def get_base_report_path(self, report_type: str, remote_connection=None):
|
30
|
+
"""
|
31
|
+
Get the base path for a report type (profiler/performance).
|
32
|
+
|
33
|
+
Args:
|
34
|
+
report_type: Either 'profiler' or 'performance'
|
35
|
+
remote_connection: Optional remote connection for upload/sync mode
|
36
|
+
|
37
|
+
Returns:
|
38
|
+
Path object to the base directory for this report type
|
39
|
+
"""
|
40
|
+
if self.is_direct_report_mode:
|
41
|
+
tt_metal_base = Path(self.tt_metal_home) / "generated"
|
42
|
+
if report_type == "profiler":
|
43
|
+
return tt_metal_base / "ttnn" / "reports"
|
44
|
+
elif report_type == "performance":
|
45
|
+
return tt_metal_base / "profiler" / "reports"
|
46
|
+
else:
|
47
|
+
raise ValueError(f"Unknown report type: {report_type}")
|
48
|
+
else:
|
49
|
+
# Upload/sync mode - use existing logic
|
50
|
+
local_dir = Path(self.current_app.config["LOCAL_DATA_DIRECTORY"])
|
51
|
+
remote_dir = Path(self.current_app.config["REMOTE_DATA_DIRECTORY"])
|
52
|
+
|
53
|
+
if remote_connection:
|
54
|
+
base_dir = remote_dir / remote_connection.host
|
55
|
+
else:
|
56
|
+
base_dir = local_dir
|
57
|
+
|
58
|
+
if report_type == "profiler":
|
59
|
+
return base_dir / self.current_app.config["PROFILER_DIRECTORY_NAME"]
|
60
|
+
elif report_type == "performance":
|
61
|
+
return base_dir / self.current_app.config["PERFORMANCE_DIRECTORY_NAME"]
|
62
|
+
else:
|
63
|
+
raise ValueError(f"Unknown report type: {report_type}")
|
64
|
+
|
65
|
+
def get_profiler_path(self, profiler_name: str, remote_connection=None):
|
66
|
+
"""Get the full path to a profiler report's db.sqlite file."""
|
67
|
+
if not profiler_name:
|
68
|
+
return ""
|
69
|
+
|
70
|
+
base_path = self.get_base_report_path("profiler", remote_connection)
|
71
|
+
|
72
|
+
if self.is_direct_report_mode and not base_path.exists():
|
73
|
+
logger.warning(f"TT-Metal profiler reports not found: {base_path}")
|
74
|
+
return ""
|
75
|
+
|
76
|
+
profiler_path = base_path / profiler_name
|
77
|
+
target_path = profiler_path / self.current_app.config["SQLITE_DB_PATH"]
|
78
|
+
|
79
|
+
return str(target_path)
|
80
|
+
|
81
|
+
def get_performance_path(self, performance_name: str, remote_connection=None):
|
82
|
+
"""Get the full path to a performance report directory."""
|
83
|
+
base_path = self.get_base_report_path("performance", remote_connection)
|
84
|
+
|
85
|
+
if self.is_direct_report_mode and not base_path.exists():
|
86
|
+
logger.warning(f"TT-Metal performance reports not found: {base_path}")
|
87
|
+
return ""
|
88
|
+
|
89
|
+
performance_path = base_path / performance_name
|
90
|
+
return str(performance_path)
|
91
|
+
|
92
|
+
def get_mode_info(self):
|
93
|
+
"""Get information about the current mode for debugging/display."""
|
94
|
+
if self.is_direct_report_mode:
|
95
|
+
return {
|
96
|
+
"mode": "tt_metal",
|
97
|
+
"tt_metal_home": self.tt_metal_home,
|
98
|
+
"profiler_base": str(
|
99
|
+
Path(self.tt_metal_home) / "generated" / "ttnn" / "reports"
|
100
|
+
),
|
101
|
+
"performance_base": str(
|
102
|
+
Path(self.tt_metal_home) / "generated" / "profiler" / "reports"
|
103
|
+
),
|
104
|
+
}
|
105
|
+
else:
|
106
|
+
return {
|
107
|
+
"mode": "upload_sync",
|
108
|
+
"local_dir": str(self.current_app.config["LOCAL_DATA_DIRECTORY"]),
|
109
|
+
"remote_dir": str(self.current_app.config["REMOTE_DATA_DIRECTORY"]),
|
110
|
+
}
|
111
|
+
|
112
|
+
def validate_tt_metal_setup(self):
|
113
|
+
"""Validate that TT-Metal directories exist and are accessible."""
|
114
|
+
if not self.is_direct_report_mode:
|
115
|
+
return True, "Not in TT-Metal mode"
|
116
|
+
|
117
|
+
tt_metal_base = Path(self.tt_metal_home)
|
118
|
+
if not tt_metal_base.exists():
|
119
|
+
return False, f"TT_METAL_HOME directory does not exist: {tt_metal_base}"
|
120
|
+
|
121
|
+
generated_dir = tt_metal_base / "generated"
|
122
|
+
if not generated_dir.exists():
|
123
|
+
return False, f"TT-Metal generated directory not found: {generated_dir}"
|
124
|
+
|
125
|
+
profiler_base = self.get_base_report_path("profiler")
|
126
|
+
performance_base = self.get_base_report_path("performance")
|
127
|
+
|
128
|
+
messages = []
|
129
|
+
if not profiler_base.exists():
|
130
|
+
messages.append(f"Profiler reports directory not found: {profiler_base}")
|
131
|
+
if not performance_base.exists():
|
132
|
+
messages.append(
|
133
|
+
f"Performance reports directory not found: {performance_base}"
|
134
|
+
)
|
135
|
+
|
136
|
+
if messages:
|
137
|
+
return False, "; ".join(messages)
|
138
|
+
|
139
|
+
return True, "TT-Metal setup is valid"
|
140
|
+
|
141
|
+
|
21
142
|
def str_to_bool(string_value):
|
22
143
|
return string_value.lower() in ("yes", "true", "t", "1")
|
23
144
|
|
@@ -52,20 +173,10 @@ def get_performance_path(performance_name, current_app, remote_connection=None):
|
|
52
173
|
:param current_app: Flask current application object.
|
53
174
|
:param remote_connection: Remote connection model instance
|
54
175
|
|
55
|
-
:return:
|
176
|
+
:return: Performance path as a string.
|
56
177
|
"""
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
if remote_connection:
|
61
|
-
base_dir = Path(remote_dir).joinpath(remote_connection.host)
|
62
|
-
else:
|
63
|
-
base_dir = local_dir
|
64
|
-
|
65
|
-
profiler_dir = base_dir / current_app.config["PERFORMANCE_DIRECTORY_NAME"]
|
66
|
-
performance_path = profiler_dir / performance_name
|
67
|
-
|
68
|
-
return str(performance_path)
|
178
|
+
resolver = PathResolver(current_app)
|
179
|
+
return resolver.get_performance_path(performance_name, remote_connection)
|
69
180
|
|
70
181
|
|
71
182
|
def get_profiler_path(profiler_name, current_app, remote_connection=None):
|
@@ -77,24 +188,75 @@ def get_profiler_path(profiler_name, current_app, remote_connection=None):
|
|
77
188
|
|
78
189
|
:return: profiler_path as a string
|
79
190
|
"""
|
80
|
-
|
81
|
-
|
82
|
-
remote_dir = current_app.config["REMOTE_DATA_DIRECTORY"]
|
191
|
+
resolver = PathResolver(current_app)
|
192
|
+
return resolver.get_profiler_path(profiler_name, remote_connection)
|
83
193
|
|
84
|
-
if profiler_name:
|
85
|
-
if remote_connection:
|
86
|
-
base_dir = Path(remote_dir).joinpath(remote_connection.host)
|
87
|
-
else:
|
88
|
-
base_dir = local_dir
|
89
194
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
target_path = profiler_path / database_file_name
|
195
|
+
def create_path_resolver(current_app):
|
196
|
+
"""Create a PathResolver instance for the current app."""
|
197
|
+
return PathResolver(current_app)
|
94
198
|
|
95
|
-
|
96
|
-
|
97
|
-
|
199
|
+
|
200
|
+
def get_available_reports(current_app):
|
201
|
+
"""
|
202
|
+
Get available reports in the current mode.
|
203
|
+
|
204
|
+
Returns a dict with 'profiler' and 'performance' keys containing lists of available reports.
|
205
|
+
This is a convenience function for views that need to discover available reports.
|
206
|
+
"""
|
207
|
+
resolver = PathResolver(current_app)
|
208
|
+
|
209
|
+
reports = {"profiler": [], "performance": []}
|
210
|
+
|
211
|
+
# Get profiler reports
|
212
|
+
try:
|
213
|
+
profiler_base = resolver.get_base_report_path("profiler")
|
214
|
+
if profiler_base.exists():
|
215
|
+
for report_dir in profiler_base.iterdir():
|
216
|
+
if report_dir.is_dir():
|
217
|
+
db_file = report_dir / current_app.config["SQLITE_DB_PATH"]
|
218
|
+
if db_file.exists():
|
219
|
+
reports["profiler"].append(
|
220
|
+
{
|
221
|
+
"name": report_dir.name,
|
222
|
+
"path": str(report_dir),
|
223
|
+
"modified": report_dir.stat().st_mtime,
|
224
|
+
}
|
225
|
+
)
|
226
|
+
except Exception as e:
|
227
|
+
logger.warning(f"Error reading profiler reports: {e}")
|
228
|
+
|
229
|
+
# Get performance reports
|
230
|
+
try:
|
231
|
+
performance_base = resolver.get_base_report_path("performance")
|
232
|
+
if performance_base.exists():
|
233
|
+
for report_dir in performance_base.iterdir():
|
234
|
+
if report_dir.is_dir():
|
235
|
+
# Check for typical performance files
|
236
|
+
has_perf_files = any(
|
237
|
+
(report_dir / filename).exists()
|
238
|
+
for filename in [
|
239
|
+
"profile_log_device.csv",
|
240
|
+
"tracy_profile_log_host.tracy",
|
241
|
+
]
|
242
|
+
) or any(report_dir.glob("ops_perf_results*.csv"))
|
243
|
+
|
244
|
+
if has_perf_files:
|
245
|
+
reports["performance"].append(
|
246
|
+
{
|
247
|
+
"name": report_dir.name,
|
248
|
+
"path": str(report_dir),
|
249
|
+
"modified": report_dir.stat().st_mtime,
|
250
|
+
}
|
251
|
+
)
|
252
|
+
except Exception as e:
|
253
|
+
logger.warning(f"Error reading performance reports: {e}")
|
254
|
+
|
255
|
+
# Sort by modification time (newest first)
|
256
|
+
reports["profiler"].sort(key=lambda x: x["modified"], reverse=True)
|
257
|
+
reports["performance"].sort(key=lambda x: x["modified"], reverse=True)
|
258
|
+
|
259
|
+
return reports
|
98
260
|
|
99
261
|
|
100
262
|
def get_npe_path(npe_name, current_app):
|
ttnn_visualizer/views.py
CHANGED
@@ -12,6 +12,7 @@ from http import HTTPStatus
|
|
12
12
|
from pathlib import Path
|
13
13
|
from typing import List
|
14
14
|
|
15
|
+
import orjson
|
15
16
|
import yaml
|
16
17
|
import zstd
|
17
18
|
from flask import Blueprint, Response, current_app, jsonify, request, session
|
@@ -68,6 +69,7 @@ from ttnn_visualizer.sftp_operations import (
|
|
68
69
|
)
|
69
70
|
from ttnn_visualizer.ssh_client import SSHClient
|
70
71
|
from ttnn_visualizer.utils import (
|
72
|
+
create_path_resolver,
|
71
73
|
get_cluster_descriptor_path,
|
72
74
|
read_last_synced_file,
|
73
75
|
timer,
|
@@ -368,20 +370,18 @@ def get_operation_buffers(operation_id, instance: Instance):
|
|
368
370
|
@api.route("/profiler", methods=["GET"])
|
369
371
|
@with_instance
|
370
372
|
def get_profiler_data_list(instance: Instance):
|
371
|
-
#
|
372
|
-
|
373
|
-
# config_key = "REMOTE_DATA_DIRECTORY" if is_remote else "LOCAL_DATA_DIRECTORY"
|
374
|
-
config_key = "LOCAL_DATA_DIRECTORY"
|
375
|
-
data_directory = Path(current_app.config[config_key])
|
373
|
+
# Use PathResolver to get the base path for profiler reports
|
374
|
+
resolver = create_path_resolver(current_app)
|
376
375
|
|
377
|
-
#
|
378
|
-
|
379
|
-
# path = data_directory / connection.host / current_app.config["PROFILER_DIRECTORY_NAME"]
|
380
|
-
# else:
|
381
|
-
path = data_directory / current_app.config["PROFILER_DIRECTORY_NAME"]
|
376
|
+
# Note: "profiler" in app terminology maps to tt-metal's ttnn/reports
|
377
|
+
path = resolver.get_base_report_path("profiler", instance.remote_connection)
|
382
378
|
|
383
379
|
if not path.exists():
|
384
|
-
|
380
|
+
if resolver.is_direct_report_mode:
|
381
|
+
logger.warning(f"TT-Metal profiler reports not found: {path}")
|
382
|
+
return jsonify([])
|
383
|
+
else:
|
384
|
+
path.mkdir(parents=True, exist_ok=True)
|
385
385
|
|
386
386
|
valid_dirs = []
|
387
387
|
|
@@ -437,7 +437,6 @@ def get_profiler_data_list(instance: Instance):
|
|
437
437
|
continue
|
438
438
|
if not any(file.name == "config.json" for file in files):
|
439
439
|
continue
|
440
|
-
|
441
440
|
valid_dirs.append({"path": dir_path.name, "reportName": report_name})
|
442
441
|
|
443
442
|
return jsonify(valid_dirs)
|
@@ -491,13 +490,20 @@ def delete_profiler_report(profiler_name, instance: Instance):
|
|
491
490
|
@api.route("/performance", methods=["GET"])
|
492
491
|
@with_instance
|
493
492
|
def get_performance_data_list(instance: Instance):
|
493
|
+
# Use PathResolver to get the base path for performance reports
|
494
|
+
resolver = create_path_resolver(current_app)
|
495
|
+
|
496
|
+
# Note: "performance" in app terminology maps to tt-metal's profiler/reports
|
497
|
+
path = resolver.get_base_report_path("performance", instance.remote_connection)
|
498
|
+
|
494
499
|
is_remote = True if instance.remote_connection else False
|
495
|
-
config_key = "REMOTE_DATA_DIRECTORY" if is_remote else "LOCAL_DATA_DIRECTORY"
|
496
|
-
data_directory = Path(current_app.config[config_key])
|
497
|
-
path = data_directory / current_app.config["PERFORMANCE_DIRECTORY_NAME"]
|
498
500
|
|
499
|
-
if not
|
500
|
-
|
501
|
+
if not path.exists():
|
502
|
+
if resolver.is_direct_report_mode:
|
503
|
+
logger.warning(f"TT-Metal performance reports not found: {path}")
|
504
|
+
return jsonify([])
|
505
|
+
elif not is_remote:
|
506
|
+
path.mkdir(parents=True, exist_ok=True)
|
501
507
|
|
502
508
|
if current_app.config["SERVER_MODE"]:
|
503
509
|
session_instances = session.get("instances", [])
|
@@ -521,15 +527,7 @@ def get_performance_data_list(instance: Instance):
|
|
521
527
|
set(db_directory_names + session_directory_names + demo_directory_names)
|
522
528
|
)
|
523
529
|
else:
|
524
|
-
|
525
|
-
connection = RemoteConnection.model_validate(
|
526
|
-
instance.remote_connection, strict=False
|
527
|
-
)
|
528
|
-
path = (
|
529
|
-
data_directory
|
530
|
-
/ connection.host
|
531
|
-
/ current_app.config["PERFORMANCE_DIRECTORY_NAME"]
|
532
|
-
)
|
530
|
+
# PathResolver already handles remote vs local logic
|
533
531
|
directory_names = (
|
534
532
|
[directory.name for directory in path.iterdir() if directory.is_dir()]
|
535
533
|
if path.exists()
|
@@ -868,12 +866,10 @@ def create_npe_files():
|
|
868
866
|
data_directory = current_app.config["LOCAL_DATA_DIRECTORY"]
|
869
867
|
|
870
868
|
for file in files:
|
871
|
-
if not file.filename.endswith(".json") and not file.filename.endswith(
|
872
|
-
".npeviz.zst"
|
873
|
-
):
|
869
|
+
if not file.filename.endswith(".json") and not file.filename.endswith(".zst"):
|
874
870
|
return StatusMessage(
|
875
871
|
status=ConnectionTestStates.FAILED,
|
876
|
-
message="NPE requires a valid .json or .
|
872
|
+
message="NPE requires a valid .json or .zst file",
|
877
873
|
).model_dump()
|
878
874
|
|
879
875
|
npe_name = extract_npe_name(files)
|
@@ -1275,4 +1271,67 @@ def get_npe_data(instance: Instance):
|
|
1275
1271
|
with open(uncompressed_path, "r") as file:
|
1276
1272
|
npe_data = json.load(file)
|
1277
1273
|
|
1278
|
-
|
1274
|
+
# Use orjson for much faster JSON serialization of large files
|
1275
|
+
return Response(orjson.dumps(npe_data), mimetype="application/json")
|
1276
|
+
|
1277
|
+
|
1278
|
+
@api.route("/notify", methods=["POST"])
|
1279
|
+
def notify_report_update():
|
1280
|
+
"""
|
1281
|
+
Endpoint to receive notifications about report updates and broadcast them via websockets.
|
1282
|
+
"""
|
1283
|
+
from ttnn_visualizer.sockets import (
|
1284
|
+
ExitStatus,
|
1285
|
+
ReportGenerated,
|
1286
|
+
emit_report_generated,
|
1287
|
+
)
|
1288
|
+
|
1289
|
+
try:
|
1290
|
+
data = request.get_json()
|
1291
|
+
if not data:
|
1292
|
+
return jsonify({"error": "No JSON data provided"}), 400
|
1293
|
+
|
1294
|
+
report_name = data.get("report_name")
|
1295
|
+
exit_status_str = data.get("exit_status")
|
1296
|
+
|
1297
|
+
if not report_name:
|
1298
|
+
return jsonify({"error": "report_name is required"}), 400
|
1299
|
+
|
1300
|
+
# Validate status
|
1301
|
+
try:
|
1302
|
+
exit_status = (
|
1303
|
+
ExitStatus(exit_status_str.upper()) if exit_status_str else None
|
1304
|
+
)
|
1305
|
+
except ValueError:
|
1306
|
+
return (
|
1307
|
+
jsonify({"error": "Invalid exit_status."}),
|
1308
|
+
400,
|
1309
|
+
)
|
1310
|
+
|
1311
|
+
# Create and emit the report update
|
1312
|
+
report_generated = ReportGenerated(
|
1313
|
+
report_name=report_name,
|
1314
|
+
exit_status=exit_status,
|
1315
|
+
profiler_path=data.get("profiler_path"),
|
1316
|
+
performance_path=data.get("performance_path"),
|
1317
|
+
)
|
1318
|
+
emit_report_generated(report_generated)
|
1319
|
+
|
1320
|
+
logger.info(f"Report generated notification processed: {report_name}")
|
1321
|
+
|
1322
|
+
return (
|
1323
|
+
jsonify(
|
1324
|
+
{
|
1325
|
+
"report_name": report_name,
|
1326
|
+
"profiler_path": report_generated.profiler_path,
|
1327
|
+
"performance_path": report_generated.performance_path,
|
1328
|
+
"exit_status": exit_status.value if exit_status else None,
|
1329
|
+
"timestamp": report_generated.timestamp,
|
1330
|
+
}
|
1331
|
+
),
|
1332
|
+
200,
|
1333
|
+
)
|
1334
|
+
|
1335
|
+
except Exception as e:
|
1336
|
+
logger.error(f"Error processing report update notification: {str(e)}")
|
1337
|
+
return jsonify({"error": "Internal server error"}), 500
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ttnn_visualizer
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.48.0
|
4
4
|
Summary: TT-NN Visualizer
|
5
5
|
Classifier: Programming Language :: Python :: 3
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
@@ -17,6 +17,7 @@ Requires-Dist: Flask-Static-Digest==0.4.1
|
|
17
17
|
Requires-Dist: Flask==3.1.1
|
18
18
|
Requires-Dist: gevent==24.10.2
|
19
19
|
Requires-Dist: gunicorn~=23.0.0
|
20
|
+
Requires-Dist: orjson>=3.9.0
|
20
21
|
Requires-Dist: pandas==2.2.3
|
21
22
|
Requires-Dist: pydantic_core==2.27.1
|
22
23
|
Requires-Dist: pydantic==2.10.3
|
@@ -1,31 +1,31 @@
|
|
1
1
|
ttnn_visualizer/__init__.py,sha256=FCQeTWnXsf-Wx-fay53-lQsm0y5-GcPMUmzhE5upDx0,93
|
2
|
-
ttnn_visualizer/app.py,sha256=
|
3
|
-
ttnn_visualizer/csv_queries.py,sha256=
|
2
|
+
ttnn_visualizer/app.py,sha256=5LEFKR-jn5HGqzYU1OWE4LCHzS4OAzwLKge5jSRDsBc,8663
|
3
|
+
ttnn_visualizer/csv_queries.py,sha256=pQV3WJ0jSMo84L7kOdAbGO5lGfOtcq-oAlHzu09ND2Q,15089
|
4
4
|
ttnn_visualizer/decorators.py,sha256=8k73rTiGPSpPP5CHxzLxTQPxoQTAlhMQNcEbplQL3Ek,5805
|
5
5
|
ttnn_visualizer/enums.py,sha256=SEIqp1tlc_zw2vQ8nHH9YTaV0m3Cb8fjn_goqz5wurE,203
|
6
6
|
ttnn_visualizer/exceptions.py,sha256=XwTIykJpdvZV8nqrd9JZdHIYL0EBFBhTbE9H09VZluA,2273
|
7
7
|
ttnn_visualizer/extensions.py,sha256=6OIRJ8-_ccfjOaXSruRXiS29jEbxp4Pyk-0JlD8IHBQ,379
|
8
|
-
ttnn_visualizer/file_uploads.py,sha256=
|
8
|
+
ttnn_visualizer/file_uploads.py,sha256=HFcC6TBt5I0oBkiKgM2Qw1W7hpixE8TOTACS5N-rmGE,5013
|
9
9
|
ttnn_visualizer/instances.py,sha256=XctQgQXdlwtuXWFXFletRoX1m1lGUZdiW3TwIIjY0uw,11564
|
10
|
-
ttnn_visualizer/models.py,sha256=
|
11
|
-
ttnn_visualizer/queries.py,sha256=
|
10
|
+
ttnn_visualizer/models.py,sha256=QCL64uynSS3WbUI05UoHIgex6eWgMGqf0-YTm1XwCwI,7854
|
11
|
+
ttnn_visualizer/queries.py,sha256=0s2zGA7CH1fbV6BWB-MhdHfWW7GhkDti4gVJyDmeCE8,9607
|
12
12
|
ttnn_visualizer/remote_sqlite_setup.py,sha256=VdJk5LfkaJo1XPC-yxy909I0AOgJF1GUjryj0Oe0O14,3498
|
13
13
|
ttnn_visualizer/serializers.py,sha256=LmjHIrFg8BLx1JKVFh9Nd_TcA7nyy1MwY2BOGnX1MKw,8029
|
14
|
-
ttnn_visualizer/settings.py,sha256=
|
14
|
+
ttnn_visualizer/settings.py,sha256=W0PCeBCGXONNfFHqI7ATCVGhKv0a02-BhwBwrB3Clag,4660
|
15
15
|
ttnn_visualizer/sftp_operations.py,sha256=9HwbPJPSO1UUQ98d5zeWAkEwR0zFPryUakcI68GqkVw,30181
|
16
|
-
ttnn_visualizer/sockets.py,sha256=
|
16
|
+
ttnn_visualizer/sockets.py,sha256=_Hdne33r4FrB2tg58Vw87FWLbgQ_ikICVp4o1Mkv2mo,4789
|
17
17
|
ttnn_visualizer/ssh_client.py,sha256=-GS2_1tdlUqVoLfRS02i3_o1fQaM39UQN-jtAnPBmzQ,13511
|
18
|
-
ttnn_visualizer/utils.py,sha256=
|
19
|
-
ttnn_visualizer/views.py,sha256=
|
20
|
-
ttnn_visualizer/static/index.html,sha256=
|
21
|
-
ttnn_visualizer/static/assets/allPaths-
|
22
|
-
ttnn_visualizer/static/assets/allPathsLoader-
|
18
|
+
ttnn_visualizer/utils.py,sha256=_W990vRnup9zlWJ-g_Bggyo-wDjCYF49p0nPxWNgxrE,12934
|
19
|
+
ttnn_visualizer/views.py,sha256=E5UFdbR8_lqHRPJmGrjq3S_F0Wu1WCsydWNihSUj9Fk,45133
|
20
|
+
ttnn_visualizer/static/index.html,sha256=PtUUC8PiSjaLZOgM7sFiII-ykqwrL1rX95MzjzYcXmc,1135
|
21
|
+
ttnn_visualizer/static/assets/allPaths-DyhSRH--.js,sha256=EUUj2FYiXwESHvwikbQ1n87byC2le5LLW8Q0LY3VyfM,255
|
22
|
+
ttnn_visualizer/static/assets/allPathsLoader-DXd_rN1a.js,sha256=eMyPpUy4eYuBbW1TRf5zx1fkA0ihMVzP_joOkP9GMow,477
|
23
23
|
ttnn_visualizer/static/assets/index-03c8d4Gh.js,sha256=k0jIi5q-lzXcPCqAD7K091vBMOkJHmx_fYcYKh-fOnM,285602
|
24
|
-
ttnn_visualizer/static/assets/index-
|
25
|
-
ttnn_visualizer/static/assets/index-BuHal8Ii.css,sha256=YCXZxX68jwt682YZ5gMTPzmXN9r2NjHfItOsrCQqRXk,622571
|
24
|
+
ttnn_visualizer/static/assets/index-CZ0Uonoz.css,sha256=Xl6ASk5fzFtSKl55fxH-0Qw_RjPZC1aNvIqZmrzSdck,622981
|
26
25
|
ttnn_visualizer/static/assets/index-PKNBViIU.js,sha256=dUuCyAPr_QvvTY0Xula4q4rgOm1J7xgdbppL67off4k,294225
|
26
|
+
ttnn_visualizer/static/assets/index-T8PVeTUn.js,sha256=1hk1rZB2-tBCp5WIQB_UZQDnbayuBQp2IX4s62i3-hY,7883860
|
27
27
|
ttnn_visualizer/static/assets/site-BTBrvHC5.webmanifest,sha256=Uy_XmnGuYFVf-OZuma2NvgEPdrCrevb3HZvaxSIHoA0,456
|
28
|
-
ttnn_visualizer/static/assets/splitPathsBySizeLoader-
|
28
|
+
ttnn_visualizer/static/assets/splitPathsBySizeLoader-Gsi3qlIM.js,sha256=ssz5DwLHNfrtvO7Bji0ya9GLCkwQU9bYScLIErs2j5o,281
|
29
29
|
ttnn_visualizer/static/favicon/android-chrome-192x192.png,sha256=BZWA09Zxaa3fXbaeS6nhWo2e-DUSjm9ElzNQ_xTB5XU,6220
|
30
30
|
ttnn_visualizer/static/favicon/android-chrome-512x512.png,sha256=HBiJSZyguB3o8fMJuqIGcpeBy_9JOdImme3wD02UYCw,62626
|
31
31
|
ttnn_visualizer/static/favicon/favicon-32x32.png,sha256=Zw201qUsczQv1UvoQvJf5smQ2ss10xaTeWxmQNYCGtY,480
|
@@ -33,11 +33,11 @@ ttnn_visualizer/static/favicon/favicon.svg,sha256=wDPY3VrekJ_DE1TnJ2vUy602K3S4Xe
|
|
33
33
|
ttnn_visualizer/static/sample-data/cluster-desc.yaml,sha256=LMxOmsRUXtVVU5ogzYkXUozB3dg2IzqIRJQpV_O5qMU,29618
|
34
34
|
ttnn_visualizer/tests/__init__.py,sha256=FCQeTWnXsf-Wx-fay53-lQsm0y5-GcPMUmzhE5upDx0,93
|
35
35
|
ttnn_visualizer/tests/test_queries.py,sha256=HqaDXwudZpXiigJdHkdJP8oiUc-PtHASbpLnQQpbD7A,13792
|
36
|
-
ttnn_visualizer/tests/test_serializers.py,sha256=
|
37
|
-
ttnn_visualizer-0.
|
38
|
-
ttnn_visualizer-0.
|
39
|
-
ttnn_visualizer-0.
|
40
|
-
ttnn_visualizer-0.
|
41
|
-
ttnn_visualizer-0.
|
42
|
-
ttnn_visualizer-0.
|
43
|
-
ttnn_visualizer-0.
|
36
|
+
ttnn_visualizer/tests/test_serializers.py,sha256=IJekAZRBpyOr_Ffp0dqSrnhFOU_ZZ8pHma_JO0j23TQ,18762
|
37
|
+
ttnn_visualizer-0.48.0.dist-info/licenses/LICENSE,sha256=NQB3xoEB14Z4uKwzMDm2AZSYIcx4hZ5ZNgJNcIChWCo,19504
|
38
|
+
ttnn_visualizer-0.48.0.dist-info/licenses/LICENSE_understanding.txt,sha256=pymi-yb_RvYM9p2ZA4iSNsImcvhDBBxlGuJCY9dTq7M,233
|
39
|
+
ttnn_visualizer-0.48.0.dist-info/METADATA,sha256=k9gZwu0y6_VmfFxAUwmKwlSYYOkmv9Si--B3AVoMQoE,7780
|
40
|
+
ttnn_visualizer-0.48.0.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
|
41
|
+
ttnn_visualizer-0.48.0.dist-info/entry_points.txt,sha256=QpuUpkmQ_mEHJTMqOBdU0MH2Z4WF_9iFsGACeyyAO1E,61
|
42
|
+
ttnn_visualizer-0.48.0.dist-info/top_level.txt,sha256=M1EGkvDOuIfbhDbcUdz2-TSdmCtDoQ2Uyag9k5JLDSY,16
|
43
|
+
ttnn_visualizer-0.48.0.dist-info/RECORD,,
|