ttnn-visualizer 0.63.1__py3-none-any.whl → 0.65.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 +65 -2
- ttnn_visualizer/csv_queries.py +41 -12
- ttnn_visualizer/settings.py +12 -4
- ttnn_visualizer/static/assets/{allPaths-dy9nsQF7.js → allPaths-B6-2k5TG.js} +1 -1
- ttnn_visualizer/static/assets/allPathsLoader-Cylj0kPO.js +2 -0
- ttnn_visualizer/static/assets/{index-BzMUwfVf.css → index-C7m_PE7l.css} +1 -1
- ttnn_visualizer/static/assets/{index-B_nutJ_M.js → index-DMzz7de9.js} +238 -248
- ttnn_visualizer/static/assets/{splitPathsBySizeLoader-357aoIrt.js → splitPathsBySizeLoader-BVbD9Udb.js} +1 -1
- ttnn_visualizer/static/index.html +2 -2
- ttnn_visualizer/tests/test_utils.py +258 -2
- ttnn_visualizer/utils.py +63 -0
- ttnn_visualizer/views.py +58 -2
- {ttnn_visualizer-0.63.1.dist-info → ttnn_visualizer-0.65.0.dist-info}/METADATA +2 -2
- {ttnn_visualizer-0.63.1.dist-info → ttnn_visualizer-0.65.0.dist-info}/RECORD +19 -19
- {ttnn_visualizer-0.63.1.dist-info → ttnn_visualizer-0.65.0.dist-info}/licenses/LICENSE +0 -2
- ttnn_visualizer/static/assets/allPathsLoader-CQM4eIEo.js +0 -2
- {ttnn_visualizer-0.63.1.dist-info → ttnn_visualizer-0.65.0.dist-info}/WHEEL +0 -0
- {ttnn_visualizer-0.63.1.dist-info → ttnn_visualizer-0.65.0.dist-info}/entry_points.txt +0 -0
- {ttnn_visualizer-0.63.1.dist-info → ttnn_visualizer-0.65.0.dist-info}/licenses/LICENSE_understanding.txt +0 -0
- {ttnn_visualizer-0.63.1.dist-info → ttnn_visualizer-0.65.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-DMzz7de9.js";const n=async(o,_)=>{const i=r(o);let t;return _===s.STANDARD?t=await a(()=>import("./index-voJy5fZe.js").then(e=>e.I),[]):t=await a(()=>import("./index-BZITDwoa.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-DMzz7de9.js"></script>
|
|
38
|
+
<link rel="stylesheet" crossorigin href="/static/assets/index-C7m_PE7l.css">
|
|
39
39
|
</head>
|
|
40
40
|
<body>
|
|
41
41
|
|
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-FileCopyrightText: © 2025 Tenstorrent AI ULC
|
|
4
4
|
|
|
5
|
-
from unittest.mock import patch
|
|
5
|
+
from unittest.mock import mock_open, patch
|
|
6
6
|
|
|
7
|
-
from ttnn_visualizer.utils import
|
|
7
|
+
from ttnn_visualizer.utils import (
|
|
8
|
+
find_gunicorn_path,
|
|
9
|
+
get_app_data_directory,
|
|
10
|
+
is_running_in_container,
|
|
11
|
+
)
|
|
8
12
|
|
|
9
13
|
|
|
10
14
|
@patch("sys.argv", ["/home/user/.local/bin/ttnn-visualizer"])
|
|
@@ -104,3 +108,255 @@ def test_gunicorn_not_found(mock_which, mock_is_file, mock_exists, mock_access):
|
|
|
104
108
|
assert warning is not None
|
|
105
109
|
assert "ERROR" in warning
|
|
106
110
|
assert "not found" in warning
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# Tests for is_running_in_container()
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@patch("os.path.exists")
|
|
117
|
+
@patch("os.getenv")
|
|
118
|
+
def test_container_detection_via_dockerenv(mock_getenv, mock_exists):
|
|
119
|
+
"""Test container detection via /.dockerenv file."""
|
|
120
|
+
mock_exists.return_value = True
|
|
121
|
+
mock_getenv.return_value = None
|
|
122
|
+
|
|
123
|
+
result = is_running_in_container()
|
|
124
|
+
|
|
125
|
+
assert result is True
|
|
126
|
+
mock_exists.assert_called_once_with("/.dockerenv")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@patch("os.path.exists")
|
|
130
|
+
@patch(
|
|
131
|
+
"builtins.open",
|
|
132
|
+
new_callable=mock_open,
|
|
133
|
+
read_data="12:pids:/docker/abc123\n11:cpuset:/docker/abc123",
|
|
134
|
+
)
|
|
135
|
+
@patch("os.getenv")
|
|
136
|
+
def test_container_detection_via_cgroup_docker(mock_getenv, mock_file, mock_exists):
|
|
137
|
+
"""Test container detection via /proc/self/cgroup containing 'docker'."""
|
|
138
|
+
mock_exists.return_value = False # No /.dockerenv
|
|
139
|
+
mock_getenv.return_value = None
|
|
140
|
+
|
|
141
|
+
result = is_running_in_container()
|
|
142
|
+
|
|
143
|
+
assert result is True
|
|
144
|
+
mock_file.assert_called_once_with("/proc/self/cgroup", "r")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@patch("os.path.exists")
|
|
148
|
+
@patch(
|
|
149
|
+
"builtins.open",
|
|
150
|
+
new_callable=mock_open,
|
|
151
|
+
read_data="12:pids:/containerd/abc123\n11:cpuset:/containerd/abc123",
|
|
152
|
+
)
|
|
153
|
+
@patch("os.getenv")
|
|
154
|
+
def test_container_detection_via_cgroup_containerd(mock_getenv, mock_file, mock_exists):
|
|
155
|
+
"""Test container detection via /proc/self/cgroup containing 'containerd'."""
|
|
156
|
+
mock_exists.return_value = False
|
|
157
|
+
mock_getenv.return_value = None
|
|
158
|
+
|
|
159
|
+
result = is_running_in_container()
|
|
160
|
+
|
|
161
|
+
assert result is True
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@patch("os.path.exists")
|
|
165
|
+
@patch(
|
|
166
|
+
"builtins.open",
|
|
167
|
+
new_callable=mock_open,
|
|
168
|
+
read_data="12:pids:/lxc/container123\n11:cpuset:/lxc/container123",
|
|
169
|
+
)
|
|
170
|
+
@patch("os.getenv")
|
|
171
|
+
def test_container_detection_via_cgroup_lxc(mock_getenv, mock_file, mock_exists):
|
|
172
|
+
"""Test container detection via /proc/self/cgroup containing 'lxc'."""
|
|
173
|
+
mock_exists.return_value = False
|
|
174
|
+
mock_getenv.return_value = None
|
|
175
|
+
|
|
176
|
+
result = is_running_in_container()
|
|
177
|
+
|
|
178
|
+
assert result is True
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@patch("os.path.exists")
|
|
182
|
+
@patch(
|
|
183
|
+
"builtins.open",
|
|
184
|
+
new_callable=mock_open,
|
|
185
|
+
read_data="12:pids:/kubepods/besteffort/pod123\n11:cpuset:/kubepods/besteffort/pod123",
|
|
186
|
+
)
|
|
187
|
+
@patch("os.getenv")
|
|
188
|
+
def test_container_detection_via_cgroup_kubepods(mock_getenv, mock_file, mock_exists):
|
|
189
|
+
"""Test container detection via /proc/self/cgroup containing 'kubepods'."""
|
|
190
|
+
mock_exists.return_value = False
|
|
191
|
+
mock_getenv.return_value = None
|
|
192
|
+
|
|
193
|
+
result = is_running_in_container()
|
|
194
|
+
|
|
195
|
+
assert result is True
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@patch("os.path.exists")
|
|
199
|
+
@patch("builtins.open", side_effect=FileNotFoundError())
|
|
200
|
+
@patch("os.getenv")
|
|
201
|
+
def test_container_detection_cgroup_file_not_found(mock_getenv, mock_file, mock_exists):
|
|
202
|
+
"""Test container detection handles FileNotFoundError from /proc/self/cgroup."""
|
|
203
|
+
mock_exists.return_value = False
|
|
204
|
+
|
|
205
|
+
def getenv_side_effect(key):
|
|
206
|
+
return None
|
|
207
|
+
|
|
208
|
+
mock_getenv.side_effect = getenv_side_effect
|
|
209
|
+
|
|
210
|
+
result = is_running_in_container()
|
|
211
|
+
|
|
212
|
+
assert result is False
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@patch("os.path.exists")
|
|
216
|
+
@patch("builtins.open", side_effect=PermissionError())
|
|
217
|
+
@patch("os.getenv")
|
|
218
|
+
def test_container_detection_cgroup_permission_error(
|
|
219
|
+
mock_getenv, mock_file, mock_exists
|
|
220
|
+
):
|
|
221
|
+
"""Test container detection handles PermissionError from /proc/self/cgroup."""
|
|
222
|
+
mock_exists.return_value = False
|
|
223
|
+
|
|
224
|
+
def getenv_side_effect(key):
|
|
225
|
+
return None
|
|
226
|
+
|
|
227
|
+
mock_getenv.side_effect = getenv_side_effect
|
|
228
|
+
|
|
229
|
+
result = is_running_in_container()
|
|
230
|
+
|
|
231
|
+
assert result is False
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@patch("os.path.exists")
|
|
235
|
+
@patch(
|
|
236
|
+
"builtins.open",
|
|
237
|
+
new_callable=mock_open,
|
|
238
|
+
read_data="12:pids:/user.slice\n11:cpuset:/",
|
|
239
|
+
)
|
|
240
|
+
def test_container_detection_via_kubernetes_service_host(mock_file, mock_exists):
|
|
241
|
+
"""Test container detection via KUBERNETES_SERVICE_HOST environment variable."""
|
|
242
|
+
mock_exists.return_value = False
|
|
243
|
+
|
|
244
|
+
with patch.dict("os.environ", {"KUBERNETES_SERVICE_HOST": "10.0.0.1"}, clear=True):
|
|
245
|
+
result = is_running_in_container()
|
|
246
|
+
|
|
247
|
+
assert result is True
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@patch("os.path.exists")
|
|
251
|
+
@patch(
|
|
252
|
+
"builtins.open",
|
|
253
|
+
new_callable=mock_open,
|
|
254
|
+
read_data="12:pids:/user.slice\n11:cpuset:/",
|
|
255
|
+
)
|
|
256
|
+
def test_container_detection_via_kubernetes_port(mock_file, mock_exists):
|
|
257
|
+
"""Test container detection via KUBERNETES_PORT environment variable."""
|
|
258
|
+
mock_exists.return_value = False
|
|
259
|
+
|
|
260
|
+
with patch.dict(
|
|
261
|
+
"os.environ", {"KUBERNETES_PORT": "tcp://10.0.0.1:443"}, clear=True
|
|
262
|
+
):
|
|
263
|
+
result = is_running_in_container()
|
|
264
|
+
|
|
265
|
+
assert result is True
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
@patch("os.path.exists")
|
|
269
|
+
@patch(
|
|
270
|
+
"builtins.open",
|
|
271
|
+
new_callable=mock_open,
|
|
272
|
+
read_data="12:pids:/user.slice\n11:cpuset:/",
|
|
273
|
+
)
|
|
274
|
+
def test_container_detection_via_container_env(mock_file, mock_exists):
|
|
275
|
+
"""Test container detection via 'container' environment variable."""
|
|
276
|
+
mock_exists.return_value = False
|
|
277
|
+
|
|
278
|
+
with patch.dict("os.environ", {"container": "podman"}, clear=True):
|
|
279
|
+
result = is_running_in_container()
|
|
280
|
+
|
|
281
|
+
assert result is True
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
@patch("os.path.exists")
|
|
285
|
+
@patch(
|
|
286
|
+
"builtins.open",
|
|
287
|
+
new_callable=mock_open,
|
|
288
|
+
read_data="12:pids:/user.slice\n11:cpuset:/",
|
|
289
|
+
)
|
|
290
|
+
@patch("os.getenv")
|
|
291
|
+
def test_no_container_detection(mock_getenv, mock_file, mock_exists):
|
|
292
|
+
"""Test that no container is detected when all checks fail."""
|
|
293
|
+
mock_exists.return_value = False # No /.dockerenv
|
|
294
|
+
mock_getenv.return_value = None # No container env vars
|
|
295
|
+
|
|
296
|
+
result = is_running_in_container()
|
|
297
|
+
|
|
298
|
+
assert result is False
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
# Tests for get_app_data_directory()
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def test_get_app_data_directory_with_tt_metal_home():
|
|
305
|
+
"""Test that get_app_data_directory returns correct path when tt_metal_home is provided."""
|
|
306
|
+
tt_metal_home = "/path/to/tt-metal"
|
|
307
|
+
application_dir = "/default/app/dir"
|
|
308
|
+
|
|
309
|
+
result = get_app_data_directory(tt_metal_home, application_dir)
|
|
310
|
+
|
|
311
|
+
assert result == "/path/to/tt-metal/generated/ttnn-visualizer"
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def test_get_app_data_directory_with_none():
|
|
315
|
+
"""Test that get_app_data_directory returns application_dir when tt_metal_home is None."""
|
|
316
|
+
tt_metal_home = None
|
|
317
|
+
application_dir = "/default/app/dir"
|
|
318
|
+
|
|
319
|
+
result = get_app_data_directory(tt_metal_home, application_dir)
|
|
320
|
+
|
|
321
|
+
assert result == "/default/app/dir"
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def test_get_app_data_directory_with_empty_string():
|
|
325
|
+
"""Test that get_app_data_directory treats empty string as falsy and returns application_dir."""
|
|
326
|
+
tt_metal_home = ""
|
|
327
|
+
application_dir = "/default/app/dir"
|
|
328
|
+
|
|
329
|
+
result = get_app_data_directory(tt_metal_home, application_dir)
|
|
330
|
+
|
|
331
|
+
assert result == "/default/app/dir"
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def test_get_app_data_directory_with_special_characters():
|
|
335
|
+
"""Test that get_app_data_directory handles paths with special characters correctly."""
|
|
336
|
+
tt_metal_home = "/path/with spaces/and-dashes/tt-metal"
|
|
337
|
+
application_dir = "/default/app/dir"
|
|
338
|
+
|
|
339
|
+
result = get_app_data_directory(tt_metal_home, application_dir)
|
|
340
|
+
|
|
341
|
+
assert result == "/path/with spaces/and-dashes/tt-metal/generated/ttnn-visualizer"
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def test_get_app_data_directory_with_relative_path():
|
|
345
|
+
"""Test that get_app_data_directory handles relative paths correctly."""
|
|
346
|
+
tt_metal_home = "../relative/path/tt-metal"
|
|
347
|
+
application_dir = "/default/app/dir"
|
|
348
|
+
|
|
349
|
+
result = get_app_data_directory(tt_metal_home, application_dir)
|
|
350
|
+
|
|
351
|
+
assert result == "../relative/path/tt-metal/generated/ttnn-visualizer"
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def test_get_app_data_directory_with_trailing_slash():
|
|
355
|
+
"""Test that get_app_data_directory handles paths with trailing slashes correctly."""
|
|
356
|
+
tt_metal_home = "/path/to/tt-metal/"
|
|
357
|
+
application_dir = "/default/app/dir"
|
|
358
|
+
|
|
359
|
+
result = get_app_data_directory(tt_metal_home, application_dir)
|
|
360
|
+
|
|
361
|
+
# Path.join handles trailing slashes correctly
|
|
362
|
+
assert result == "/path/to/tt-metal/generated/ttnn-visualizer"
|
ttnn_visualizer/utils.py
CHANGED
|
@@ -21,6 +21,22 @@ logger = logging.getLogger(__name__)
|
|
|
21
21
|
LAST_SYNCED_FILE_NAME = ".last-synced"
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
def get_app_data_directory(tt_metal_home: Optional[str], application_dir: str) -> str:
|
|
25
|
+
"""
|
|
26
|
+
Calculate the APP_DATA_DIRECTORY based on TT_METAL_HOME or fallback to application_dir.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
tt_metal_home: Path to TT-Metal home directory, or None
|
|
30
|
+
application_dir: Fallback application directory path
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Path to the app data directory
|
|
34
|
+
"""
|
|
35
|
+
if tt_metal_home and tt_metal_home.strip():
|
|
36
|
+
return str(Path(tt_metal_home).expanduser() / "generated" / "ttnn-visualizer")
|
|
37
|
+
return application_dir
|
|
38
|
+
|
|
39
|
+
|
|
24
40
|
def find_gunicorn_path() -> tuple[str, Optional[str]]:
|
|
25
41
|
"""
|
|
26
42
|
Find the gunicorn executable, prioritizing the same bin directory as ttnn-visualizer.
|
|
@@ -222,6 +238,53 @@ def str_to_bool(string_value):
|
|
|
222
238
|
return string_value.lower() in ("yes", "true", "t", "1")
|
|
223
239
|
|
|
224
240
|
|
|
241
|
+
def is_running_in_container():
|
|
242
|
+
"""
|
|
243
|
+
Detect if running inside a container (Docker, Podman, Kubernetes, etc.).
|
|
244
|
+
|
|
245
|
+
Uses multiple detection methods for robustness:
|
|
246
|
+
1. /.dockerenv file (Docker-specific, fastest check)
|
|
247
|
+
2. /proc/self/cgroup contains container indicators
|
|
248
|
+
3. Container-specific environment variables
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
bool: True if running in a container, False otherwise
|
|
252
|
+
"""
|
|
253
|
+
# Method 1: Check for /.dockerenv (Docker-specific, most common)
|
|
254
|
+
if os.path.exists("/.dockerenv"):
|
|
255
|
+
logger.info("Container detected via /.dockerenv file")
|
|
256
|
+
return True
|
|
257
|
+
|
|
258
|
+
# Method 2: Check cgroup for container indicators
|
|
259
|
+
try:
|
|
260
|
+
with open("/proc/self/cgroup", "r") as f:
|
|
261
|
+
content = f.read()
|
|
262
|
+
# Check for various container runtimes
|
|
263
|
+
container_indicators = ["docker", "containerd", "lxc", "kubepods"]
|
|
264
|
+
if any(indicator in content for indicator in container_indicators):
|
|
265
|
+
logger.info(
|
|
266
|
+
f"Container detected via /proc/self/cgroup: {content[:100]}"
|
|
267
|
+
)
|
|
268
|
+
return True
|
|
269
|
+
except (FileNotFoundError, PermissionError):
|
|
270
|
+
# Not on Linux or no permission to read cgroup
|
|
271
|
+
pass
|
|
272
|
+
|
|
273
|
+
# Method 3: Check for container-specific environment variables
|
|
274
|
+
container_env_vars = [
|
|
275
|
+
"KUBERNETES_SERVICE_HOST", # Kubernetes
|
|
276
|
+
"KUBERNETES_PORT", # Kubernetes
|
|
277
|
+
"container", # systemd-nspawn and others
|
|
278
|
+
]
|
|
279
|
+
|
|
280
|
+
for env_var in container_env_vars:
|
|
281
|
+
if os.getenv(env_var):
|
|
282
|
+
logger.info(f"Container detected via environment variable: {env_var}")
|
|
283
|
+
return True
|
|
284
|
+
|
|
285
|
+
return False
|
|
286
|
+
|
|
287
|
+
|
|
225
288
|
@dataclasses.dataclass
|
|
226
289
|
class SerializeableDataclass:
|
|
227
290
|
def to_dict(self) -> dict:
|
ttnn_visualizer/views.py
CHANGED
|
@@ -727,8 +727,12 @@ def get_performance_results_report(instance: Instance):
|
|
|
727
727
|
)
|
|
728
728
|
|
|
729
729
|
name = request.args.get("name", None)
|
|
730
|
-
|
|
730
|
+
start_signpost = request.args.get("start_signpost", None)
|
|
731
|
+
end_signpost = request.args.get("end_signpost", None)
|
|
732
|
+
print_signposts = str_to_bool(request.args.get("print_signposts", "true"))
|
|
731
733
|
stack_by_in0 = str_to_bool(request.args.get("stack_by_in0", "true"))
|
|
734
|
+
hide_host_ops = str_to_bool(request.args.get("hide_host_ops", "true"))
|
|
735
|
+
merge_devices = str_to_bool(request.args.get("merge_devices", "true"))
|
|
732
736
|
|
|
733
737
|
if name and not current_app.config["SERVER_MODE"]:
|
|
734
738
|
performance_path = Path(instance.performance_path).parent / name
|
|
@@ -739,7 +743,11 @@ def get_performance_results_report(instance: Instance):
|
|
|
739
743
|
report = OpsPerformanceReportQueries.generate_report(
|
|
740
744
|
instance,
|
|
741
745
|
stack_by_in0=stack_by_in0,
|
|
742
|
-
|
|
746
|
+
start_signpost=start_signpost,
|
|
747
|
+
print_signposts=print_signposts,
|
|
748
|
+
end_signpost=end_signpost,
|
|
749
|
+
hide_host_ops=hide_host_ops,
|
|
750
|
+
merge_devices=merge_devices,
|
|
743
751
|
)
|
|
744
752
|
except DataFormatError:
|
|
745
753
|
return Response(status=HTTPStatus.UNPROCESSABLE_ENTITY)
|
|
@@ -747,6 +755,7 @@ def get_performance_results_report(instance: Instance):
|
|
|
747
755
|
return Response(orjson.dumps(report), mimetype="application/json")
|
|
748
756
|
|
|
749
757
|
|
|
758
|
+
# this is no longer used atm. keeping for now until confirmed "not needed"
|
|
750
759
|
@api.route("/performance/device-log/raw", methods=["GET"])
|
|
751
760
|
@with_instance
|
|
752
761
|
def get_performance_data_raw(instance: Instance):
|
|
@@ -769,6 +778,53 @@ def get_performance_data_raw(instance: Instance):
|
|
|
769
778
|
)
|
|
770
779
|
|
|
771
780
|
|
|
781
|
+
@api.route("/performance/device-log/meta", methods=["GET"])
|
|
782
|
+
@with_instance
|
|
783
|
+
def get_performance_device_meta(instance: Instance):
|
|
784
|
+
def get_first_line(file_path: Path) -> str:
|
|
785
|
+
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
|
|
786
|
+
return f.readline().strip()
|
|
787
|
+
|
|
788
|
+
def parse_arch_and_freq(line: str):
|
|
789
|
+
arch_match = re.search(r"ARCH:\s*([\w\d_]+)", line)
|
|
790
|
+
freq_match = re.search(r"CHIP_FREQ\[MHz\]:\s*(\d+)", line)
|
|
791
|
+
|
|
792
|
+
architecture = arch_match.group(1) if arch_match else None
|
|
793
|
+
frequency = int(freq_match.group(1)) if freq_match else None
|
|
794
|
+
|
|
795
|
+
return {
|
|
796
|
+
"architecture": architecture,
|
|
797
|
+
"frequency": frequency,
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
name = request.args.get("name", None)
|
|
801
|
+
|
|
802
|
+
if not instance.performance_path:
|
|
803
|
+
return Response(status=HTTPStatus.NOT_FOUND)
|
|
804
|
+
|
|
805
|
+
if name and not current_app.config["SERVER_MODE"]:
|
|
806
|
+
performance_path = Path(instance.performance_path).parent / name
|
|
807
|
+
instance.performance_path = str(performance_path)
|
|
808
|
+
logger.info(f"************ Performance path set to {instance.performance_path}")
|
|
809
|
+
|
|
810
|
+
file_path = Path(
|
|
811
|
+
instance.performance_path,
|
|
812
|
+
DeviceLogProfilerQueries.DEVICE_LOG_FILE,
|
|
813
|
+
)
|
|
814
|
+
|
|
815
|
+
if not file_path.exists():
|
|
816
|
+
return Response(status=HTTPStatus.NOT_FOUND)
|
|
817
|
+
|
|
818
|
+
try:
|
|
819
|
+
first_line = get_first_line(file_path)
|
|
820
|
+
meta = parse_arch_and_freq(first_line)
|
|
821
|
+
return jsonify(meta)
|
|
822
|
+
|
|
823
|
+
except Exception as e:
|
|
824
|
+
logger.exception("Failed to parse device meta")
|
|
825
|
+
return Response(str(e), status=HTTPStatus.INTERNAL_SERVER_ERROR)
|
|
826
|
+
|
|
827
|
+
|
|
772
828
|
@api.route("/performance/npe/manifest", methods=["GET"])
|
|
773
829
|
@with_instance
|
|
774
830
|
def get_npe_manifest(instance: Instance):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ttnn_visualizer
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.65.0
|
|
4
4
|
Summary: TT-NN Visualizer
|
|
5
5
|
Classifier: Programming Language :: Python :: 3
|
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -23,7 +23,7 @@ Requires-Dist: pydantic_core==2.27.1
|
|
|
23
23
|
Requires-Dist: pydantic==2.10.3
|
|
24
24
|
Requires-Dist: python-dotenv==1.0.1
|
|
25
25
|
Requires-Dist: PyYAML==6.0.2
|
|
26
|
-
Requires-Dist: tt-perf-report==1.1.
|
|
26
|
+
Requires-Dist: tt-perf-report==1.1.14
|
|
27
27
|
Requires-Dist: uvicorn==0.30.1
|
|
28
28
|
Requires-Dist: zstd==1.5.7.0
|
|
29
29
|
Provides-Extra: dev
|
|
@@ -1,6 +1,6 @@
|
|
|
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=M7kXzWjfMekaIfskFwa0YtKSFJIj5C7mqe1N-cda8TU,12565
|
|
3
|
+
ttnn_visualizer/csv_queries.py,sha256=9wlkYNnwA5eKgCp4hA5Q-RLT_ZYaBl2oZWAdIzXtSAc,20422
|
|
4
4
|
ttnn_visualizer/decorators.py,sha256=6xBg2J6kJrwc01fcHepLbFJoUhcEKBL410gfaR8YZuM,5383
|
|
5
5
|
ttnn_visualizer/enums.py,sha256=SEIqp1tlc_zw2vQ8nHH9YTaV0m3Cb8fjn_goqz5wurE,203
|
|
6
6
|
ttnn_visualizer/exceptions.py,sha256=KVZzb7YaWbq51DNMKPBcJHwG74RMYj_29WTSYOlXXeU,2096
|
|
@@ -11,21 +11,21 @@ ttnn_visualizer/models.py,sha256=udECbVuxseZ2n6wkLCJnBxMOYq10mbHkQXmhLIECaxk,837
|
|
|
11
11
|
ttnn_visualizer/pytest_plugin.py,sha256=bEG0cbqH0HUuZT5Ox9tFoexFNTyimBBPpI_jp75b54c,2629
|
|
12
12
|
ttnn_visualizer/queries.py,sha256=j9PYYwzJBKJF32Fa-hyV00cPApw1_Xr_y6MpqFGBI3k,9867
|
|
13
13
|
ttnn_visualizer/serializers.py,sha256=mKxcDu9g4gAxHB6wP_1l5VJvIBmnYDIJTikiaMYXupg,9374
|
|
14
|
-
ttnn_visualizer/settings.py,sha256=
|
|
14
|
+
ttnn_visualizer/settings.py,sha256=FvfSqzuXEOLDH3i_mXZODHjYQEJBE6V_mPQcqz6P6zA,5168
|
|
15
15
|
ttnn_visualizer/sftp_operations.py,sha256=9HwbPJPSO1UUQ98d5zeWAkEwR0zFPryUakcI68GqkVw,30181
|
|
16
16
|
ttnn_visualizer/sockets.py,sha256=_Hdne33r4FrB2tg58Vw87FWLbgQ_ikICVp4o1Mkv2mo,4789
|
|
17
17
|
ttnn_visualizer/ssh_client.py,sha256=x-BUUnsaKGReuOrSpHdcIaoH6RdGiQQYWx2_pOkGzJ0,13410
|
|
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=rYQuPXdIYj5O2_U9_rqoPkU7croyXcAomdr6sOYHmgA,18291
|
|
19
|
+
ttnn_visualizer/views.py,sha256=tq887jrIPREOnFftEVL789N-0C1o5HNnQ7KoQq2zhR0,50267
|
|
20
|
+
ttnn_visualizer/static/index.html,sha256=xtA8s6m9CNChhpiLtXwzK9fX7K3Hhb6bz6rAsZNyXRs,1135
|
|
21
|
+
ttnn_visualizer/static/assets/allPaths-B6-2k5TG.js,sha256=N0Xj4yyme5_7OXzSViiXW-6AszdqbwnAT0cPcn_0gB8,255
|
|
22
|
+
ttnn_visualizer/static/assets/allPathsLoader-Cylj0kPO.js,sha256=boLureHSp7YelQPB6kk3rtw8xWeYFVgdEtNGfK8U9mI,477
|
|
23
23
|
ttnn_visualizer/static/assets/index-BZITDwoa.js,sha256=ax1pY3gjtvqTUiQSBZ6ZN9M6P9VJ4-eXzZ-C9F46Ozg,303183
|
|
24
|
-
ttnn_visualizer/static/assets/index-
|
|
25
|
-
ttnn_visualizer/static/assets/index-
|
|
24
|
+
ttnn_visualizer/static/assets/index-C7m_PE7l.css,sha256=ZJCWCItLuUZxYxnj45YIq4b2X0xBSnCVaXY-BHVZeKo,630529
|
|
25
|
+
ttnn_visualizer/static/assets/index-DMzz7de9.js,sha256=xjTnTxf8zQgRq-mhdVIqMCC0a3CqYrzmx6xFVSDu_5Q,7899967
|
|
26
26
|
ttnn_visualizer/static/assets/index-voJy5fZe.js,sha256=4MEkPCpdjZkMgT0Kmxfdh5DCtJWMf-TAVQ3rc28BtEQ,293910
|
|
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-BVbD9Udb.js,sha256=9F4l3tvgOl20DJmhho4jcP5afUBXzDeUje-C69ecEJ0,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
|
|
@@ -34,11 +34,11 @@ ttnn_visualizer/static/sample-data/cluster-desc.yaml,sha256=LMxOmsRUXtVVU5ogzYkX
|
|
|
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
36
|
ttnn_visualizer/tests/test_serializers.py,sha256=xwWaiH-uQN-yiEkOScCsF-JEmQliQ62eKTURijdDPBo,18820
|
|
37
|
-
ttnn_visualizer/tests/test_utils.py,sha256=
|
|
38
|
-
ttnn_visualizer-0.
|
|
39
|
-
ttnn_visualizer-0.
|
|
40
|
-
ttnn_visualizer-0.
|
|
41
|
-
ttnn_visualizer-0.
|
|
42
|
-
ttnn_visualizer-0.
|
|
43
|
-
ttnn_visualizer-0.
|
|
44
|
-
ttnn_visualizer-0.
|
|
37
|
+
ttnn_visualizer/tests/test_utils.py,sha256=9vUuCNg1mwhtB5RZKdJf-vo0lt9M5niHwkSezFwmklk,11186
|
|
38
|
+
ttnn_visualizer-0.65.0.dist-info/licenses/LICENSE,sha256=73btFSS9sVfj4HGhNlBx6nYo4rkKnOlWOi8H1MpDoSE,20286
|
|
39
|
+
ttnn_visualizer-0.65.0.dist-info/licenses/LICENSE_understanding.txt,sha256=pymi-yb_RvYM9p2ZA4iSNsImcvhDBBxlGuJCY9dTq7M,233
|
|
40
|
+
ttnn_visualizer-0.65.0.dist-info/METADATA,sha256=NcKfAnEkkKKNRvuAW_GnI7Poh1G6qQOCF0sqptNqW7Y,8912
|
|
41
|
+
ttnn_visualizer-0.65.0.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
|
|
42
|
+
ttnn_visualizer-0.65.0.dist-info/entry_points.txt,sha256=QpuUpkmQ_mEHJTMqOBdU0MH2Z4WF_9iFsGACeyyAO1E,61
|
|
43
|
+
ttnn_visualizer-0.65.0.dist-info/top_level.txt,sha256=M1EGkvDOuIfbhDbcUdz2-TSdmCtDoQ2Uyag9k5JLDSY,16
|
|
44
|
+
ttnn_visualizer-0.65.0.dist-info/RECORD,,
|
|
@@ -91,7 +91,6 @@ The following separate and independent dependencies are utilized by this project
|
|
|
91
91
|
- @testing-library/dom - MIT - https://github.com/testing-library/dom-testing-library/blob/main/LICENSE
|
|
92
92
|
- @testing-library/jest-dom - MIT - https://github.com/testing-library/jest-dom/blob/main/LICENSE
|
|
93
93
|
- @testing-library/react - MIT - https://github.com/testing-library/react-testing-library/blob/main/LICENSE
|
|
94
|
-
- @types/papaparse - MIT - https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/LICENSE
|
|
95
94
|
- @types/react - MIT - https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/LICENSE
|
|
96
95
|
- @types/react-dom - MIT - https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/LICENSE
|
|
97
96
|
- @types/react-plotly.js - MIT - https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/LICENSE
|
|
@@ -130,7 +129,6 @@ The following separate and independent dependencies are utilized by this project
|
|
|
130
129
|
- mini-svg-data-uri - MIT - https://github.com/tigt/mini-svg-data-uri/blob/master/LICENSE
|
|
131
130
|
- normalize.css - MIT - https://github.com/necolas/normalize.css/blob/master/LICENSE.md
|
|
132
131
|
- only-allow - MIT - https://github.com/pnpm/only-allow/blob/master/LICENSE
|
|
133
|
-
- papaparse - MIT - https://github.com/mholt/PapaParse/blob/master/LICENSE
|
|
134
132
|
- plotly.js - MIT - https://github.com/plotly/plotly.js/blob/master/LICENSE
|
|
135
133
|
- prettier - MIT - https://github.com/prettier/eslint-config-prettier/blob/main/LICENSE
|
|
136
134
|
- react - MIT - https://github.com/facebook/react/blob/main/LICENSE
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/allPaths-dy9nsQF7.js","assets/index-voJy5fZe.js","assets/index-BZITDwoa.js","assets/index-B_nutJ_M.js","assets/index-BzMUwfVf.css"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{_ as e}from"./index-B_nutJ_M.js";const s=async(t,a)=>{const{getIconPaths:o}=await e(async()=>{const{getIconPaths:r}=await import("./allPaths-dy9nsQF7.js");return{getIconPaths:r}},__vite__mapDeps([0,1,2,3,4]));return o(t,a)};export{s as allPathsLoader};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|