ttnn-visualizer 0.69.0__py3-none-any.whl → 0.71.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 +32 -1
- ttnn_visualizer/csv_queries.py +64 -36
- ttnn_visualizer/models.py +0 -1
- ttnn_visualizer/queries.py +25 -2
- ttnn_visualizer/settings.py +9 -7
- ttnn_visualizer/sftp_operations.py +2 -4
- ttnn_visualizer/static/assets/allPaths-D6qA1aj4.js +1 -0
- ttnn_visualizer/static/assets/allPathsLoader-t8G4bNwo.js +2 -0
- ttnn_visualizer/static/assets/{index-C28SjqxA.js → index-8RVye9cY.js} +335 -364
- ttnn_visualizer/static/assets/index-BVzPYDVR.css +1 -0
- ttnn_visualizer/static/assets/index-BmDjQHI0.js +1 -0
- ttnn_visualizer/static/assets/index-CzNKtOwn.js +1 -0
- ttnn_visualizer/static/assets/splitPathsBySizeLoader--w3Ey8_r.js +1 -0
- ttnn_visualizer/static/index.html +2 -2
- ttnn_visualizer/tests/test_queries.py +1 -2
- ttnn_visualizer/tests/test_serializers.py +4 -12
- ttnn_visualizer/tests/test_utils.py +98 -6
- ttnn_visualizer/utils.py +259 -9
- ttnn_visualizer/views.py +20 -22
- {ttnn_visualizer-0.69.0.dist-info → ttnn_visualizer-0.71.0.dist-info}/METADATA +2 -2
- ttnn_visualizer-0.71.0.dist-info/RECORD +44 -0
- {ttnn_visualizer-0.69.0.dist-info → ttnn_visualizer-0.71.0.dist-info}/licenses/LICENSE +2 -0
- ttnn_visualizer/static/assets/allPaths-Clj2DdFL.js +0 -1
- ttnn_visualizer/static/assets/allPathsLoader-DisDEJDi.js +0 -2
- ttnn_visualizer/static/assets/index-BZITDwoa.js +0 -1
- ttnn_visualizer/static/assets/index-D_AHNWw3.css +0 -1
- ttnn_visualizer/static/assets/index-voJy5fZe.js +0 -1
- ttnn_visualizer/static/assets/splitPathsBySizeLoader-D98y4BkT.js +0 -1
- ttnn_visualizer-0.69.0.dist-info/RECORD +0 -44
- {ttnn_visualizer-0.69.0.dist-info → ttnn_visualizer-0.71.0.dist-info}/WHEEL +0 -0
- {ttnn_visualizer-0.69.0.dist-info → ttnn_visualizer-0.71.0.dist-info}/entry_points.txt +0 -0
- {ttnn_visualizer-0.69.0.dist-info → ttnn_visualizer-0.71.0.dist-info}/licenses/LICENSE_understanding.txt +0 -0
- {ttnn_visualizer-0.69.0.dist-info → ttnn_visualizer-0.71.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{p as r,I as s,_ as a}from"./index-8RVye9cY.js";const n=async(o,_)=>{const i=r(o);let t;return _===s.STANDARD?t=await a(()=>import("./index-BmDjQHI0.js").then(e=>e.I),[]):t=await a(()=>import("./index-CzNKtOwn.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-8RVye9cY.js"></script>
|
|
38
|
+
<link rel="stylesheet" crossorigin href="/static/assets/index-BVzPYDVR.css">
|
|
39
39
|
</head>
|
|
40
40
|
<body>
|
|
41
41
|
|
|
@@ -119,7 +119,6 @@ class TestDatabaseQueries(unittest.TestCase):
|
|
|
119
119
|
address_at_first_l1_cb_buffer int,
|
|
120
120
|
num_banks_per_storage_core int,
|
|
121
121
|
num_compute_cores int,
|
|
122
|
-
num_storage_cores int,
|
|
123
122
|
total_l1_memory int,
|
|
124
123
|
total_l1_for_tensors int,
|
|
125
124
|
total_l1_for_interleaved_buffers int,
|
|
@@ -336,7 +335,7 @@ class TestDatabaseQueries(unittest.TestCase):
|
|
|
336
335
|
|
|
337
336
|
def test_query_devices(self):
|
|
338
337
|
self.connection.execute(
|
|
339
|
-
"INSERT INTO devices VALUES (1, 4, 4, 2, 2, 1024, 4, 256, 0, 0, 1, 2,
|
|
338
|
+
"INSERT INTO devices VALUES (1, 4, 4, 2, 2, 1024, 4, 256, 0, 0, 1, 2, 4096, 2048, 2048, 2048, 256)"
|
|
340
339
|
)
|
|
341
340
|
results = list(self.db_queries.query_devices(filters={"device_id": 1}))
|
|
342
341
|
self.assertEqual(len(results), 1)
|
|
@@ -65,9 +65,7 @@ class TestSerializers(unittest.TestCase):
|
|
|
65
65
|
[25],
|
|
66
66
|
),
|
|
67
67
|
]
|
|
68
|
-
devices = [
|
|
69
|
-
Device(1, 4, 4, 2, 2, 256, 4, 64, 0, 0, 1, 2, 512, 256, 128, 64, 1, 512)
|
|
70
|
-
]
|
|
68
|
+
devices = [Device(1, 4, 4, 2, 2, 256, 4, 64, 0, 0, 1, 2, 256, 128, 64, 1, 512)]
|
|
71
69
|
producers_consumers = [ProducersConsumers(1, [2], [3])]
|
|
72
70
|
device_operations = [DeviceOperation(1, '[{"counter": 1, "op_id": 1}]')]
|
|
73
71
|
|
|
@@ -195,10 +193,8 @@ class TestSerializers(unittest.TestCase):
|
|
|
195
193
|
|
|
196
194
|
def test_serialize_devices(self):
|
|
197
195
|
devices = [
|
|
198
|
-
Device(1, 4, 4, 2, 2, 256, 4, 64, 0, 0, 1, 2,
|
|
199
|
-
Device(
|
|
200
|
-
2, 8, 8, 4, 4, 512, 8, 128, 1, 1, 2, 4, 1024, 512, 256, 128, 2, 1024
|
|
201
|
-
),
|
|
196
|
+
Device(1, 4, 4, 2, 2, 256, 4, 64, 0, 0, 1, 2, 256, 128, 64, 1, 512),
|
|
197
|
+
Device(2, 8, 8, 4, 4, 512, 8, 128, 1, 1, 2, 4, 512, 256, 128, 2, 1024),
|
|
202
198
|
]
|
|
203
199
|
|
|
204
200
|
result = serialize_devices(devices)
|
|
@@ -213,7 +209,6 @@ class TestSerializers(unittest.TestCase):
|
|
|
213
209
|
"l1_num_banks": 4,
|
|
214
210
|
"num_banks_per_storage_core": 1,
|
|
215
211
|
"num_compute_cores": 2,
|
|
216
|
-
"num_storage_cores": 512,
|
|
217
212
|
"num_x_compute_cores": 2,
|
|
218
213
|
"num_x_cores": 4,
|
|
219
214
|
"num_y_compute_cores": 2,
|
|
@@ -233,7 +228,6 @@ class TestSerializers(unittest.TestCase):
|
|
|
233
228
|
"l1_num_banks": 8,
|
|
234
229
|
"num_banks_per_storage_core": 2,
|
|
235
230
|
"num_compute_cores": 4,
|
|
236
|
-
"num_storage_cores": 1024,
|
|
237
231
|
"num_x_compute_cores": 4,
|
|
238
232
|
"num_x_cores": 8,
|
|
239
233
|
"num_y_compute_cores": 4,
|
|
@@ -373,9 +367,7 @@ class TestSerializers(unittest.TestCase):
|
|
|
373
367
|
[200, 300],
|
|
374
368
|
)
|
|
375
369
|
]
|
|
376
|
-
devices = [
|
|
377
|
-
Device(1, 4, 4, 2, 2, 256, 4, 64, 0, 0, 1, 2, 512, 256, 128, 64, 1, 512)
|
|
378
|
-
]
|
|
370
|
+
devices = [Device(1, 4, 4, 2, 2, 256, 4, 64, 0, 0, 1, 2, 256, 128, 64, 1, 512)]
|
|
379
371
|
producers_consumers = [ProducersConsumers(1, [2], [3])]
|
|
380
372
|
device_operations = [DeviceOperation(1, '[{"counter": 1, "op_id": 1}]')]
|
|
381
373
|
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-FileCopyrightText: © 2025 Tenstorrent AI ULC
|
|
4
4
|
|
|
5
|
+
from pathlib import Path
|
|
5
6
|
from unittest.mock import mock_open, patch
|
|
6
7
|
|
|
7
8
|
from ttnn_visualizer.utils import (
|
|
8
9
|
find_gunicorn_path,
|
|
9
10
|
get_app_data_directory,
|
|
11
|
+
get_report_data_directory,
|
|
10
12
|
is_running_in_container,
|
|
11
13
|
)
|
|
12
14
|
|
|
@@ -311,24 +313,34 @@ def test_get_app_data_directory_with_tt_metal_home():
|
|
|
311
313
|
assert result == "/path/to/tt-metal/generated/ttnn-visualizer"
|
|
312
314
|
|
|
313
315
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
+
@patch("os.getenv")
|
|
317
|
+
@patch("ttnn_visualizer.utils.is_running_in_container", return_value=False)
|
|
318
|
+
@patch("pathlib.Path.home", return_value=Path("/home/testuser"))
|
|
319
|
+
def test_get_app_data_directory_with_none(mock_home, mock_container, mock_getenv):
|
|
320
|
+
"""Test that get_app_data_directory returns ~/.ttnn-visualizer/app when tt_metal_home is None."""
|
|
321
|
+
mock_getenv.return_value = None # No APP_DATA_DIRECTORY env var
|
|
316
322
|
tt_metal_home = None
|
|
317
323
|
application_dir = "/default/app/dir"
|
|
318
324
|
|
|
319
325
|
result = get_app_data_directory(tt_metal_home, application_dir)
|
|
320
326
|
|
|
321
|
-
assert result == "/
|
|
327
|
+
assert result == "/home/testuser/.ttnn-visualizer/app"
|
|
322
328
|
|
|
323
329
|
|
|
324
|
-
|
|
325
|
-
|
|
330
|
+
@patch("os.getenv")
|
|
331
|
+
@patch("ttnn_visualizer.utils.is_running_in_container", return_value=False)
|
|
332
|
+
@patch("pathlib.Path.home", return_value=Path("/home/testuser"))
|
|
333
|
+
def test_get_app_data_directory_with_empty_string(
|
|
334
|
+
mock_home, mock_container, mock_getenv
|
|
335
|
+
):
|
|
336
|
+
"""Test that get_app_data_directory returns ~/.ttnn-visualizer/app when tt_metal_home is empty."""
|
|
337
|
+
mock_getenv.return_value = None # No APP_DATA_DIRECTORY env var
|
|
326
338
|
tt_metal_home = ""
|
|
327
339
|
application_dir = "/default/app/dir"
|
|
328
340
|
|
|
329
341
|
result = get_app_data_directory(tt_metal_home, application_dir)
|
|
330
342
|
|
|
331
|
-
assert result == "/
|
|
343
|
+
assert result == "/home/testuser/.ttnn-visualizer/app"
|
|
332
344
|
|
|
333
345
|
|
|
334
346
|
def test_get_app_data_directory_with_special_characters():
|
|
@@ -360,3 +372,83 @@ def test_get_app_data_directory_with_trailing_slash():
|
|
|
360
372
|
|
|
361
373
|
# Path.join handles trailing slashes correctly
|
|
362
374
|
assert result == "/path/to/tt-metal/generated/ttnn-visualizer"
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
@patch("os.getenv")
|
|
378
|
+
@patch("ttnn_visualizer.utils.is_running_in_container", return_value=False)
|
|
379
|
+
@patch("pathlib.Path.home", return_value=Path("/home/testuser"))
|
|
380
|
+
def test_get_app_data_directory_with_env_var(mock_home, mock_container, mock_getenv):
|
|
381
|
+
"""Test that get_app_data_directory respects APP_DATA_DIRECTORY environment variable."""
|
|
382
|
+
mock_getenv.side_effect = lambda key, default=None: (
|
|
383
|
+
"/custom/app/data" if key == "APP_DATA_DIRECTORY" else None
|
|
384
|
+
)
|
|
385
|
+
tt_metal_home = None
|
|
386
|
+
application_dir = "/default/app/dir"
|
|
387
|
+
|
|
388
|
+
result = get_app_data_directory(tt_metal_home, application_dir)
|
|
389
|
+
|
|
390
|
+
assert result == "/custom/app/data"
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
@patch("os.getenv")
|
|
394
|
+
@patch("ttnn_visualizer.utils.is_running_in_container", return_value=True)
|
|
395
|
+
@patch("os.geteuid", return_value=0)
|
|
396
|
+
def test_get_app_data_directory_in_container_as_root(
|
|
397
|
+
mock_geteuid, mock_container, mock_getenv
|
|
398
|
+
):
|
|
399
|
+
"""Test that get_app_data_directory returns /var/lib/ttnn-visualizer/app when running as root in container."""
|
|
400
|
+
mock_getenv.return_value = None # No APP_DATA_DIRECTORY env var
|
|
401
|
+
tt_metal_home = None
|
|
402
|
+
application_dir = "/default/app/dir"
|
|
403
|
+
|
|
404
|
+
result = get_app_data_directory(tt_metal_home, application_dir)
|
|
405
|
+
|
|
406
|
+
assert result == "/var/lib/ttnn-visualizer/app"
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
@patch("os.getenv")
|
|
410
|
+
@patch("ttnn_visualizer.utils.is_running_in_container", return_value=True)
|
|
411
|
+
@patch("os.geteuid", return_value=1000)
|
|
412
|
+
@patch("pathlib.Path.home", return_value=Path("/home/testuser"))
|
|
413
|
+
def test_get_app_data_directory_in_container_as_non_root(
|
|
414
|
+
mock_home, mock_geteuid, mock_container, mock_getenv
|
|
415
|
+
):
|
|
416
|
+
"""Test that get_app_data_directory returns ~/.ttnn-visualizer/app when running as non-root in container."""
|
|
417
|
+
mock_getenv.return_value = None # No APP_DATA_DIRECTORY env var
|
|
418
|
+
tt_metal_home = None
|
|
419
|
+
application_dir = "/default/app/dir"
|
|
420
|
+
|
|
421
|
+
result = get_app_data_directory(tt_metal_home, application_dir)
|
|
422
|
+
|
|
423
|
+
assert result == "/home/testuser/.ttnn-visualizer/app"
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
# Tests for get_report_data_directory()
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
@patch("os.getenv")
|
|
430
|
+
@patch("ttnn_visualizer.utils.is_running_in_container", return_value=False)
|
|
431
|
+
@patch("pathlib.Path.home", return_value=Path("/home/testuser"))
|
|
432
|
+
def test_get_report_data_directory_default(mock_home, mock_container, mock_getenv):
|
|
433
|
+
"""Test that get_report_data_directory returns ~/.ttnn-visualizer/reports by default."""
|
|
434
|
+
mock_getenv.return_value = None # No REPORT_DATA_DIRECTORY env var
|
|
435
|
+
tt_metal_home = None
|
|
436
|
+
application_dir = "/default/app/dir"
|
|
437
|
+
|
|
438
|
+
result = get_report_data_directory(tt_metal_home, application_dir)
|
|
439
|
+
|
|
440
|
+
assert result == "/home/testuser/.ttnn-visualizer/reports"
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
@patch("os.getenv")
|
|
444
|
+
def test_get_report_data_directory_with_env_var(mock_getenv):
|
|
445
|
+
"""Test that get_report_data_directory respects REPORT_DATA_DIRECTORY environment variable."""
|
|
446
|
+
mock_getenv.side_effect = lambda key, default=None: (
|
|
447
|
+
"/custom/reports" if key == "REPORT_DATA_DIRECTORY" else None
|
|
448
|
+
)
|
|
449
|
+
tt_metal_home = None
|
|
450
|
+
application_dir = "/default/app/dir"
|
|
451
|
+
|
|
452
|
+
result = get_report_data_directory(tt_metal_home, application_dir)
|
|
453
|
+
|
|
454
|
+
assert result == "/custom/reports"
|
ttnn_visualizer/utils.py
CHANGED
|
@@ -9,6 +9,7 @@ import logging
|
|
|
9
9
|
import os
|
|
10
10
|
import re
|
|
11
11
|
import shutil
|
|
12
|
+
import sqlite3
|
|
12
13
|
import sys
|
|
13
14
|
import time
|
|
14
15
|
from functools import wraps
|
|
@@ -23,18 +24,271 @@ LAST_SYNCED_FILE_NAME = ".last-synced"
|
|
|
23
24
|
|
|
24
25
|
def get_app_data_directory(tt_metal_home: Optional[str], application_dir: str) -> str:
|
|
25
26
|
"""
|
|
26
|
-
Calculate the APP_DATA_DIRECTORY
|
|
27
|
+
Calculate the APP_DATA_DIRECTORY with sensible defaults.
|
|
28
|
+
|
|
29
|
+
Priority:
|
|
30
|
+
1. TT_METAL_HOME (if set) -> {tt_metal_home}/generated/ttnn-visualizer
|
|
31
|
+
2. Environment variable APP_DATA_DIRECTORY (if set)
|
|
32
|
+
3. Container detection -> /var/lib/ttnn-visualizer/app (root) or ~/.ttnn-visualizer/app (non-root)
|
|
33
|
+
4. Regular user -> ~/.ttnn-visualizer/app
|
|
27
34
|
|
|
28
35
|
Args:
|
|
29
36
|
tt_metal_home: Path to TT-Metal home directory, or None
|
|
30
|
-
application_dir: Fallback application directory path
|
|
37
|
+
application_dir: Fallback application directory path (legacy, used for migration detection)
|
|
31
38
|
|
|
32
39
|
Returns:
|
|
33
40
|
Path to the app data directory
|
|
34
41
|
"""
|
|
42
|
+
# Priority 1: TT_METAL_HOME mode
|
|
35
43
|
if tt_metal_home and tt_metal_home.strip():
|
|
36
44
|
return str(Path(tt_metal_home).expanduser() / "generated" / "ttnn-visualizer")
|
|
37
|
-
|
|
45
|
+
|
|
46
|
+
# Priority 2: Explicit environment variable
|
|
47
|
+
if env_dir := os.getenv("APP_DATA_DIRECTORY"):
|
|
48
|
+
return env_dir
|
|
49
|
+
|
|
50
|
+
# Priority 3: Container detection
|
|
51
|
+
if is_running_in_container():
|
|
52
|
+
# If running as root in container, use /var/lib
|
|
53
|
+
try:
|
|
54
|
+
if os.geteuid() == 0:
|
|
55
|
+
return "/var/lib/ttnn-visualizer/app"
|
|
56
|
+
except AttributeError:
|
|
57
|
+
# Windows doesn't have geteuid(), assume non-root
|
|
58
|
+
pass
|
|
59
|
+
# Otherwise use home directory (even in container)
|
|
60
|
+
return str(Path.home() / ".ttnn-visualizer" / "app")
|
|
61
|
+
|
|
62
|
+
# Priority 4: Default for regular users
|
|
63
|
+
return str(Path.home() / ".ttnn-visualizer" / "app")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def get_report_data_directory(
|
|
67
|
+
tt_metal_home: Optional[str], application_dir: str
|
|
68
|
+
) -> str:
|
|
69
|
+
"""
|
|
70
|
+
Calculate the REPORT_DATA_DIRECTORY with sensible defaults.
|
|
71
|
+
|
|
72
|
+
Uses the same base directory as app data, but points to reports subdirectory.
|
|
73
|
+
Structure: {base}/reports (where base is ~/.ttnn-visualizer or /var/lib/ttnn-visualizer)
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
tt_metal_home: Path to TT-Metal home directory, or None
|
|
77
|
+
application_dir: Fallback application directory path (legacy, used for migration detection)
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Path to the report data directory
|
|
81
|
+
"""
|
|
82
|
+
# Priority 1: Explicit environment variable
|
|
83
|
+
if env_dir := os.getenv("REPORT_DATA_DIRECTORY"):
|
|
84
|
+
return env_dir
|
|
85
|
+
|
|
86
|
+
# Priority 2: Use same base as app data, but in reports subdirectory
|
|
87
|
+
app_data_dir = get_app_data_directory(tt_metal_home, application_dir)
|
|
88
|
+
base_dir = Path(app_data_dir).parent
|
|
89
|
+
return str(base_dir / "reports")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def migrate_old_data_directory(
|
|
93
|
+
old_app_data_dir: str,
|
|
94
|
+
old_report_data_dir: str,
|
|
95
|
+
new_app_data_dir: str,
|
|
96
|
+
new_report_data_dir: str,
|
|
97
|
+
db_version: str,
|
|
98
|
+
) -> bool:
|
|
99
|
+
"""
|
|
100
|
+
Migrate data from old site-packages directory to new user directory.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
old_app_data_dir: Old app data directory (typically in site-packages)
|
|
104
|
+
old_report_data_dir: Old report data directory (typically in site-packages)
|
|
105
|
+
new_app_data_dir: New app data directory (typically ~/.ttnn-visualizer/app)
|
|
106
|
+
new_report_data_dir: New report data directory (typically ~/.ttnn-visualizer/reports)
|
|
107
|
+
db_version: Database version string (e.g., "0.29.0") to construct database filename
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
True if migration was performed, False otherwise
|
|
111
|
+
"""
|
|
112
|
+
old_app_path = Path(old_app_data_dir)
|
|
113
|
+
old_report_path = Path(old_report_data_dir)
|
|
114
|
+
new_app_path = Path(new_app_data_dir)
|
|
115
|
+
new_report_path = Path(new_report_data_dir)
|
|
116
|
+
|
|
117
|
+
# Construct the database filename
|
|
118
|
+
db_filename = f"ttnn_{db_version}.db"
|
|
119
|
+
old_db_path = old_app_path / db_filename
|
|
120
|
+
|
|
121
|
+
# Check if old directories exist and have data
|
|
122
|
+
old_app_has_data = old_db_path.exists()
|
|
123
|
+
old_report_has_data = old_report_path.exists() and any(old_report_path.iterdir())
|
|
124
|
+
|
|
125
|
+
if not old_app_has_data and not old_report_has_data:
|
|
126
|
+
return False
|
|
127
|
+
|
|
128
|
+
# Check if new directories already have data (don't overwrite)
|
|
129
|
+
new_db_path = new_app_path / db_filename
|
|
130
|
+
new_app_has_data = new_db_path.exists()
|
|
131
|
+
new_report_has_data = new_report_path.exists() and any(new_report_path.iterdir())
|
|
132
|
+
|
|
133
|
+
if new_app_has_data or new_report_has_data:
|
|
134
|
+
logger.info(
|
|
135
|
+
f"New data directories already exist with data, skipping migration. "
|
|
136
|
+
f"App: {new_app_path}, Reports: {new_report_path}"
|
|
137
|
+
)
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
# Check if old directory is actually in site-packages (to avoid migrating from custom locations)
|
|
141
|
+
old_app_str = str(old_app_path)
|
|
142
|
+
if "site-packages" not in old_app_str and "dist-packages" not in old_app_str:
|
|
143
|
+
logger.info(
|
|
144
|
+
f"Old app data directory is not in site-packages, skipping migration: {old_app_path}"
|
|
145
|
+
)
|
|
146
|
+
return False
|
|
147
|
+
|
|
148
|
+
print("\n" + "=" * 70)
|
|
149
|
+
print("📦 DATA DIRECTORY MIGRATION")
|
|
150
|
+
print("=" * 70)
|
|
151
|
+
print(f"Detected old data in site-packages directory.")
|
|
152
|
+
print(f" Old app data: {old_app_path}")
|
|
153
|
+
print(f" Old reports: {old_report_path}")
|
|
154
|
+
print(f"\nNew location:")
|
|
155
|
+
print(f" New app data: {new_app_path}")
|
|
156
|
+
print(f" New reports: {new_report_path}")
|
|
157
|
+
print("\nWould you like to migrate the data? (y/n): ", end="", flush=True)
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
response = input().strip().lower()
|
|
161
|
+
if response not in ("y", "yes"):
|
|
162
|
+
print("Migration cancelled by user.")
|
|
163
|
+
return False
|
|
164
|
+
except (EOFError, KeyboardInterrupt):
|
|
165
|
+
print("\nMigration cancelled.")
|
|
166
|
+
return False
|
|
167
|
+
|
|
168
|
+
# Create new directories
|
|
169
|
+
new_app_path.mkdir(parents=True, exist_ok=True)
|
|
170
|
+
new_report_path.mkdir(parents=True, exist_ok=True)
|
|
171
|
+
|
|
172
|
+
migrated = False
|
|
173
|
+
|
|
174
|
+
# Migrate app data (only the specific database file)
|
|
175
|
+
if old_app_has_data:
|
|
176
|
+
print(f"\nMigrating database file from {old_app_path} to {new_app_path}...")
|
|
177
|
+
try:
|
|
178
|
+
# Move the database file
|
|
179
|
+
shutil.move(str(old_db_path), str(new_db_path))
|
|
180
|
+
print(f" ✓ Moved {db_filename}")
|
|
181
|
+
migrated = True
|
|
182
|
+
except Exception as e:
|
|
183
|
+
logger.error(f"Error migrating database file: {e}")
|
|
184
|
+
print(f" ❌ Error: {e}")
|
|
185
|
+
|
|
186
|
+
# Migrate report data (all files and directories)
|
|
187
|
+
if old_report_has_data:
|
|
188
|
+
print(f"\nMigrating reports from {old_report_path} to {new_report_path}...")
|
|
189
|
+
try:
|
|
190
|
+
for item in old_report_path.iterdir():
|
|
191
|
+
dest = new_report_path / item.name
|
|
192
|
+
if item.is_file():
|
|
193
|
+
shutil.move(str(item), str(dest))
|
|
194
|
+
print(f" ✓ Moved {item.name}")
|
|
195
|
+
elif item.is_dir():
|
|
196
|
+
shutil.move(str(item), str(dest))
|
|
197
|
+
print(f" ✓ Moved directory {item.name}")
|
|
198
|
+
migrated = True
|
|
199
|
+
except Exception as e:
|
|
200
|
+
logger.error(f"Error migrating report data: {e}")
|
|
201
|
+
print(f" ❌ Error: {e}")
|
|
202
|
+
|
|
203
|
+
# Update paths in the database after migration
|
|
204
|
+
# Note: We use the old_report_path for matching even though files are moved,
|
|
205
|
+
# because the database still contains the old paths that need to be updated
|
|
206
|
+
if migrated and old_app_has_data:
|
|
207
|
+
print(f"\nUpdating paths in database...")
|
|
208
|
+
try:
|
|
209
|
+
_update_database_paths(new_db_path, old_report_path, new_report_path)
|
|
210
|
+
print(f" ✓ Updated paths in database")
|
|
211
|
+
except Exception as e:
|
|
212
|
+
logger.error(f"Error updating database paths: {e}")
|
|
213
|
+
print(f" ⚠️ Warning: Could not update paths in database: {e}")
|
|
214
|
+
print(f" You may need to manually update paths in the instances table.")
|
|
215
|
+
|
|
216
|
+
if migrated:
|
|
217
|
+
print("\n✅ Migration completed successfully!")
|
|
218
|
+
print(f" Data has been moved from: {old_app_path}")
|
|
219
|
+
else:
|
|
220
|
+
print("\n⚠️ No data was migrated.")
|
|
221
|
+
|
|
222
|
+
print("=" * 70 + "\n")
|
|
223
|
+
|
|
224
|
+
return migrated
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _update_database_paths(
|
|
228
|
+
db_path: Path, old_report_data_dir: Path, new_report_data_dir: Path
|
|
229
|
+
) -> None:
|
|
230
|
+
"""
|
|
231
|
+
Update absolute paths in the instances table after migration.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
db_path: Path to the SQLite database file
|
|
235
|
+
old_report_data_dir: Old report data directory path
|
|
236
|
+
new_report_data_dir: New report data directory path
|
|
237
|
+
"""
|
|
238
|
+
# Normalize paths to handle symlinks and ensure consistent format
|
|
239
|
+
old_report_data_dir = old_report_data_dir.resolve()
|
|
240
|
+
new_report_data_dir = new_report_data_dir.resolve()
|
|
241
|
+
old_report_str = str(old_report_data_dir)
|
|
242
|
+
new_report_str = str(new_report_data_dir)
|
|
243
|
+
|
|
244
|
+
try:
|
|
245
|
+
conn = sqlite3.connect(str(db_path))
|
|
246
|
+
cursor = conn.cursor()
|
|
247
|
+
|
|
248
|
+
# Update profiler_path
|
|
249
|
+
cursor.execute(
|
|
250
|
+
"""
|
|
251
|
+
UPDATE instances
|
|
252
|
+
SET profiler_path = REPLACE(profiler_path, ?, ?)
|
|
253
|
+
WHERE profiler_path LIKE ? || '%'
|
|
254
|
+
""",
|
|
255
|
+
(old_report_str, new_report_str, old_report_str),
|
|
256
|
+
)
|
|
257
|
+
profiler_updated = cursor.rowcount
|
|
258
|
+
|
|
259
|
+
# Update performance_path
|
|
260
|
+
cursor.execute(
|
|
261
|
+
"""
|
|
262
|
+
UPDATE instances
|
|
263
|
+
SET performance_path = REPLACE(performance_path, ?, ?)
|
|
264
|
+
WHERE performance_path LIKE ? || '%'
|
|
265
|
+
""",
|
|
266
|
+
(old_report_str, new_report_str, old_report_str),
|
|
267
|
+
)
|
|
268
|
+
performance_updated = cursor.rowcount
|
|
269
|
+
|
|
270
|
+
# Update npe_path
|
|
271
|
+
cursor.execute(
|
|
272
|
+
"""
|
|
273
|
+
UPDATE instances
|
|
274
|
+
SET npe_path = REPLACE(npe_path, ?, ?)
|
|
275
|
+
WHERE npe_path LIKE ? || '%'
|
|
276
|
+
""",
|
|
277
|
+
(old_report_str, new_report_str, old_report_str),
|
|
278
|
+
)
|
|
279
|
+
npe_updated = cursor.rowcount
|
|
280
|
+
|
|
281
|
+
conn.commit()
|
|
282
|
+
conn.close()
|
|
283
|
+
|
|
284
|
+
if profiler_updated > 0 or performance_updated > 0 or npe_updated > 0:
|
|
285
|
+
logger.info(
|
|
286
|
+
f"Updated database paths: {profiler_updated} profiler_path, "
|
|
287
|
+
f"{performance_updated} performance_path, {npe_updated} npe_path"
|
|
288
|
+
)
|
|
289
|
+
except sqlite3.Error as e:
|
|
290
|
+
logger.error(f"SQLite error updating paths: {e}")
|
|
291
|
+
raise
|
|
38
292
|
|
|
39
293
|
|
|
40
294
|
def find_gunicorn_path() -> tuple[str, Optional[str]]:
|
|
@@ -428,13 +682,9 @@ def get_mesh_descriptor_paths(instance):
|
|
|
428
682
|
return []
|
|
429
683
|
|
|
430
684
|
parent = Path(instance.profiler_path).parent
|
|
431
|
-
|
|
685
|
+
glob_pattern = "physical_chip_mesh_coordinate_mapping_[0-9]_of_[0-9].yaml"
|
|
432
686
|
|
|
433
|
-
return sorted(
|
|
434
|
-
str(path)
|
|
435
|
-
for path in parent.iterdir()
|
|
436
|
-
if path.is_file() and pattern.fullmatch(path.name)
|
|
437
|
-
)
|
|
687
|
+
return sorted(str(path) for path in parent.glob(glob_pattern) if path.is_file())
|
|
438
688
|
|
|
439
689
|
|
|
440
690
|
def read_last_synced_file(directory: str) -> Optional[int]:
|
ttnn_visualizer/views.py
CHANGED
|
@@ -732,9 +732,10 @@ def get_performance_results_report(instance: Instance):
|
|
|
732
732
|
start_signpost = request.args.get("start_signpost", None)
|
|
733
733
|
end_signpost = request.args.get("end_signpost", None)
|
|
734
734
|
print_signposts = str_to_bool(request.args.get("print_signposts", "true"))
|
|
735
|
-
stack_by_in0 = str_to_bool(request.args.get("stack_by_in0", "true"))
|
|
736
735
|
hide_host_ops = str_to_bool(request.args.get("hide_host_ops", "true"))
|
|
737
736
|
merge_devices = str_to_bool(request.args.get("merge_devices", "true"))
|
|
737
|
+
tracing_mode = str_to_bool(request.args.get("tracing_mode", "false"))
|
|
738
|
+
group_by = request.args.get("group_by", None)
|
|
738
739
|
|
|
739
740
|
if name and not current_app.config["SERVER_MODE"]:
|
|
740
741
|
performance_path = Path(instance.performance_path).parent / name
|
|
@@ -744,12 +745,13 @@ def get_performance_results_report(instance: Instance):
|
|
|
744
745
|
try:
|
|
745
746
|
report = OpsPerformanceReportQueries.generate_report(
|
|
746
747
|
instance,
|
|
747
|
-
stack_by_in0=stack_by_in0,
|
|
748
748
|
start_signpost=start_signpost,
|
|
749
749
|
print_signposts=print_signposts,
|
|
750
750
|
end_signpost=end_signpost,
|
|
751
751
|
hide_host_ops=hide_host_ops,
|
|
752
752
|
merge_devices=merge_devices,
|
|
753
|
+
tracing_mode=tracing_mode,
|
|
754
|
+
group_by=group_by,
|
|
753
755
|
)
|
|
754
756
|
except DataFormatError:
|
|
755
757
|
return Response(status=HTTPStatus.UNPROCESSABLE_ENTITY)
|
|
@@ -1164,29 +1166,25 @@ def get_cluster_descriptor(instance: Instance):
|
|
|
1164
1166
|
@api.route("/mesh-descriptor", methods=["GET"])
|
|
1165
1167
|
@with_instance
|
|
1166
1168
|
def get_mesh_descriptor(instance: Instance):
|
|
1167
|
-
|
|
1169
|
+
paths = get_mesh_descriptor_paths(instance)
|
|
1170
|
+
|
|
1171
|
+
if not paths:
|
|
1168
1172
|
return (
|
|
1169
|
-
jsonify(
|
|
1170
|
-
|
|
1173
|
+
jsonify(
|
|
1174
|
+
{"error": "physical_chip_mesh_coordinate_mapping_1_of_1.yaml not found"}
|
|
1175
|
+
),
|
|
1176
|
+
HTTPStatus.NOT_FOUND,
|
|
1171
1177
|
)
|
|
1172
|
-
else:
|
|
1173
|
-
paths = get_mesh_descriptor_paths(instance)
|
|
1174
|
-
if not paths:
|
|
1175
|
-
return jsonify({"error": "mesh.yaml not found"}), 404
|
|
1176
1178
|
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
return jsonify(
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
except yaml.YAMLError as e:
|
|
1187
|
-
return jsonify({"error": f"Failed to parse YAML: {str(e)}"}), 400
|
|
1188
|
-
|
|
1189
|
-
return jsonify({"error": "Mesh descriptor not found"}), 404
|
|
1179
|
+
try:
|
|
1180
|
+
with open(paths[0]) as mesh_descriptor_path:
|
|
1181
|
+
yaml_data = yaml.safe_load(mesh_descriptor_path)
|
|
1182
|
+
return jsonify(yaml_data) # yaml_data is not compatible with orjson
|
|
1183
|
+
except yaml.YAMLError as e:
|
|
1184
|
+
return (
|
|
1185
|
+
jsonify({"error": f"Failed to parse YAML: {str(e)}"}),
|
|
1186
|
+
HTTPStatus.BAD_REQUEST,
|
|
1187
|
+
)
|
|
1190
1188
|
|
|
1191
1189
|
|
|
1192
1190
|
@api.route("/remote/test", methods=["POST"])
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ttnn_visualizer
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.71.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.2.1
|
|
27
27
|
Requires-Dist: uvicorn==0.30.1
|
|
28
28
|
Requires-Dist: zstd==1.5.7.0
|
|
29
29
|
Provides-Extra: dev
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
ttnn_visualizer/__init__.py,sha256=FCQeTWnXsf-Wx-fay53-lQsm0y5-GcPMUmzhE5upDx0,93
|
|
2
|
+
ttnn_visualizer/app.py,sha256=fiOg_aUMLPGZu_FjUemgpwJYzz6uE50lEvOcy8cuBp4,14631
|
|
3
|
+
ttnn_visualizer/csv_queries.py,sha256=Q3lLhcZ8FWelTEPHg7j9qaakeeFqltHLGEW8nOVwDpw,21897
|
|
4
|
+
ttnn_visualizer/decorators.py,sha256=YY_5zQdD9VOuBC5iP1Z9CEMjYz3ofD1Lc3ZrBvzQx8U,5779
|
|
5
|
+
ttnn_visualizer/enums.py,sha256=SEIqp1tlc_zw2vQ8nHH9YTaV0m3Cb8fjn_goqz5wurE,203
|
|
6
|
+
ttnn_visualizer/exceptions.py,sha256=KVZzb7YaWbq51DNMKPBcJHwG74RMYj_29WTSYOlXXeU,2096
|
|
7
|
+
ttnn_visualizer/extensions.py,sha256=6OIRJ8-_ccfjOaXSruRXiS29jEbxp4Pyk-0JlD8IHBQ,379
|
|
8
|
+
ttnn_visualizer/file_uploads.py,sha256=HFcC6TBt5I0oBkiKgM2Qw1W7hpixE8TOTACS5N-rmGE,5013
|
|
9
|
+
ttnn_visualizer/instances.py,sha256=yoWGV0I3xNm8nFZrQHJMq7k6C_moFiic9ZgMkgfxsHU,13406
|
|
10
|
+
ttnn_visualizer/models.py,sha256=6z0WwKWwaOhYMgHEIM5NHxiybDoipL3vJD1uRgZPuSI,8620
|
|
11
|
+
ttnn_visualizer/pytest_plugin.py,sha256=bEG0cbqH0HUuZT5Ox9tFoexFNTyimBBPpI_jp75b54c,2629
|
|
12
|
+
ttnn_visualizer/queries.py,sha256=gfI8Jzlp7VHCh8VDSqgYqbhlf9eaj2QvwkXovNCjqXg,13620
|
|
13
|
+
ttnn_visualizer/serializers.py,sha256=mKxcDu9g4gAxHB6wP_1l5VJvIBmnYDIJTikiaMYXupg,9374
|
|
14
|
+
ttnn_visualizer/settings.py,sha256=4R9LVsxs9XRtJx6f7oW84jPeq4ffuDZkN2QEVE8Ie8Q,5216
|
|
15
|
+
ttnn_visualizer/sftp_operations.py,sha256=l5MEorNJ93e9X_Nf7fgLb3cSftuErE3PKzAki2T5Hpc,31585
|
|
16
|
+
ttnn_visualizer/sockets.py,sha256=_Hdne33r4FrB2tg58Vw87FWLbgQ_ikICVp4o1Mkv2mo,4789
|
|
17
|
+
ttnn_visualizer/ssh_client.py,sha256=x-BUUnsaKGReuOrSpHdcIaoH6RdGiQQYWx2_pOkGzJ0,13410
|
|
18
|
+
ttnn_visualizer/utils.py,sha256=CzFX4AuVmHaAxq6ZklUk3PMWPliNb4-seAtRuXiDthg,27995
|
|
19
|
+
ttnn_visualizer/views.py,sha256=oD31TaN-g5Fb7G7oDFyRtuJYBUON_HGjGxI-EnQtF4Q,52477
|
|
20
|
+
ttnn_visualizer/static/index.html,sha256=QxpENVT5XwOnFv_Jh-AgcO3rBZRrI4rwG7zz3u738FM,1135
|
|
21
|
+
ttnn_visualizer/static/assets/allPaths-D6qA1aj4.js,sha256=BnjOCm8ifqgwLBAmRP5cO-lpMnZfAySNyoZoooU7vIA,255
|
|
22
|
+
ttnn_visualizer/static/assets/allPathsLoader-t8G4bNwo.js,sha256=j-q8s8ju02Aqy_3WaBo3fNtPHRw6tadfqH4aAdP-U7k,477
|
|
23
|
+
ttnn_visualizer/static/assets/index-8RVye9cY.js,sha256=-u_M4wiPslSSnTuq2OMyf2X_czVdzr1wUnTScyE6P_E,7982508
|
|
24
|
+
ttnn_visualizer/static/assets/index-BVzPYDVR.css,sha256=_fSlNYmeC54u6mXYoyiQDIXeRD9ajwaKIWE2M7e1uJk,618970
|
|
25
|
+
ttnn_visualizer/static/assets/index-BmDjQHI0.js,sha256=Np8PB0IkYR44ybu3HDpLI7b6XWw2sZQL-MIbQxV7CcA,294299
|
|
26
|
+
ttnn_visualizer/static/assets/index-CzNKtOwn.js,sha256=i4B-DZkbAK68FWdRZAGppuLcytv1ETOLu6m6s_0a7r4,303575
|
|
27
|
+
ttnn_visualizer/static/assets/site-BTBrvHC5.webmanifest,sha256=Uy_XmnGuYFVf-OZuma2NvgEPdrCrevb3HZvaxSIHoA0,456
|
|
28
|
+
ttnn_visualizer/static/assets/splitPathsBySizeLoader--w3Ey8_r.js,sha256=KAjd3n5fEUXoGPOA7V5JrfsPWnatp8tyl6xZ9LgqpBk,281
|
|
29
|
+
ttnn_visualizer/static/favicon/android-chrome-192x192.png,sha256=BZWA09Zxaa3fXbaeS6nhWo2e-DUSjm9ElzNQ_xTB5XU,6220
|
|
30
|
+
ttnn_visualizer/static/favicon/android-chrome-512x512.png,sha256=HBiJSZyguB3o8fMJuqIGcpeBy_9JOdImme3wD02UYCw,62626
|
|
31
|
+
ttnn_visualizer/static/favicon/favicon-32x32.png,sha256=Zw201qUsczQv1UvoQvJf5smQ2ss10xaTeWxmQNYCGtY,480
|
|
32
|
+
ttnn_visualizer/static/favicon/favicon.svg,sha256=wDPY3VrekJ_DE1TnJ2vUy602K3S4Xe9TgrdZ7jXK9c8,633
|
|
33
|
+
ttnn_visualizer/static/sample-data/cluster-desc.yaml,sha256=LMxOmsRUXtVVU5ogzYkXUozB3dg2IzqIRJQpV_O5qMU,29618
|
|
34
|
+
ttnn_visualizer/tests/__init__.py,sha256=FCQeTWnXsf-Wx-fay53-lQsm0y5-GcPMUmzhE5upDx0,93
|
|
35
|
+
ttnn_visualizer/tests/test_queries.py,sha256=3je_FKRgZLdoDTfIe6kENLFXWUeeYVgY3ZDVnvWgCJo,13754
|
|
36
|
+
ttnn_visualizer/tests/test_serializers.py,sha256=KLzkqQhDlqPTaJ5MUy-r7Nb2WT2hp5aTm_ceA0tlxIo,18911
|
|
37
|
+
ttnn_visualizer/tests/test_utils.py,sha256=bI2oMdir9BIy1RsIXTn80VTOrnleL5exOMjpDfhp6JY,14938
|
|
38
|
+
ttnn_visualizer-0.71.0.dist-info/licenses/LICENSE,sha256=DsbsWC-ymVM85l4HKV_ruheRbr37-FJ8KGxL0_cZdb0,20463
|
|
39
|
+
ttnn_visualizer-0.71.0.dist-info/licenses/LICENSE_understanding.txt,sha256=pymi-yb_RvYM9p2ZA4iSNsImcvhDBBxlGuJCY9dTq7M,233
|
|
40
|
+
ttnn_visualizer-0.71.0.dist-info/METADATA,sha256=iScWAvGleF5cr1BuoDS-sWLI-GoQK2joTw-dVJ8QE8A,8911
|
|
41
|
+
ttnn_visualizer-0.71.0.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
|
|
42
|
+
ttnn_visualizer-0.71.0.dist-info/entry_points.txt,sha256=QpuUpkmQ_mEHJTMqOBdU0MH2Z4WF_9iFsGACeyyAO1E,61
|
|
43
|
+
ttnn_visualizer-0.71.0.dist-info/top_level.txt,sha256=M1EGkvDOuIfbhDbcUdz2-TSdmCtDoQ2Uyag9k5JLDSY,16
|
|
44
|
+
ttnn_visualizer-0.71.0.dist-info/RECORD,,
|
|
@@ -87,6 +87,8 @@ The following separate and independent dependencies are utilized by this project
|
|
|
87
87
|
- @eslint/eslintrc - MIT - https://github.com/eslint/eslintrc/blob/main/LICENSE
|
|
88
88
|
- @eslint/js - MIT - https://github.com/eslint/eslint/blob/main/LICENSE
|
|
89
89
|
- @eslint/rewrite - Apache-2.0 - https://github.com/eslint/rewrite/blob/main/LICENSE
|
|
90
|
+
- @tanstack/react-query - MIT - https://github.com/TanStack/query/blob/main/LICENSE
|
|
91
|
+
- @tanstack/react-query-devtools - MIT - https://github.com/TanStack/query/blob/main/LICENSE
|
|
90
92
|
- @tanstack/react-virtual - MIT - https://github.com/TanStack/virtual/blob/main/LICENSE
|
|
91
93
|
- @testing-library/dom - MIT - https://github.com/testing-library/dom-testing-library/blob/main/LICENSE
|
|
92
94
|
- @testing-library/jest-dom - MIT - https://github.com/testing-library/jest-dom/blob/main/LICENSE
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as s}from"./index-voJy5fZe.js";import{I as r}from"./index-BZITDwoa.js";import{p as n,I as c}from"./index-C28SjqxA.js";function p(t,a){const o=n(t);return a===c.STANDARD?s[o]:r[o]}export{s as IconSvgPaths16,r as IconSvgPaths20,p as getIconPaths};
|