ttnn-visualizer 0.26.0__py3-none-any.whl → 0.27.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 -5
- ttnn_visualizer/csv_queries.py +20 -4
- ttnn_visualizer/decorators.py +6 -6
- ttnn_visualizer/exceptions.py +7 -0
- ttnn_visualizer/models.py +11 -11
- ttnn_visualizer/queries.py +5 -5
- ttnn_visualizer/sessions.py +74 -36
- ttnn_visualizer/sockets.py +17 -17
- ttnn_visualizer/static/assets/{allPaths-egCeGMYd.js → allPaths-DfvpbqXZ.js} +1 -1
- ttnn_visualizer/static/assets/{allPathsLoader-ChZ_kotC.js → allPathsLoader-C1wkx2sM.js} +2 -2
- ttnn_visualizer/static/assets/{index-S-_ELv4m.css → index-BTfoVg9a.css} +2 -2
- ttnn_visualizer/static/assets/{index-rIoXC5rS.js → index-CeYOVqR1.js} +193 -193
- ttnn_visualizer/static/assets/{splitPathsBySizeLoader-BfocwQsJ.js → splitPathsBySizeLoader-C_Kuh9CJ.js} +1 -1
- ttnn_visualizer/static/index.html +2 -2
- ttnn_visualizer/views.py +34 -34
- {ttnn_visualizer-0.26.0.dist-info → ttnn_visualizer-0.27.0.dist-info}/METADATA +1 -1
- {ttnn_visualizer-0.26.0.dist-info → ttnn_visualizer-0.27.0.dist-info}/RECORD +22 -22
- {ttnn_visualizer-0.26.0.dist-info → ttnn_visualizer-0.27.0.dist-info}/LICENSE +0 -0
- {ttnn_visualizer-0.26.0.dist-info → ttnn_visualizer-0.27.0.dist-info}/LICENSE_understanding.txt +0 -0
- {ttnn_visualizer-0.26.0.dist-info → ttnn_visualizer-0.27.0.dist-info}/WHEEL +0 -0
- {ttnn_visualizer-0.26.0.dist-info → ttnn_visualizer-0.27.0.dist-info}/entry_points.txt +0 -0
- {ttnn_visualizer-0.26.0.dist-info → ttnn_visualizer-0.27.0.dist-info}/top_level.txt +0 -0
ttnn_visualizer/app.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# SPDX-FileCopyrightText: © 2024 Tenstorrent AI ULC
|
4
4
|
|
5
|
+
import argparse
|
5
6
|
import logging
|
6
7
|
import os
|
7
8
|
import subprocess
|
@@ -19,7 +20,8 @@ from flask_cors import CORS
|
|
19
20
|
from werkzeug.debug import DebuggedApplication
|
20
21
|
from werkzeug.middleware.proxy_fix import ProxyFix
|
21
22
|
|
22
|
-
from ttnn_visualizer.exceptions import DatabaseFileNotFoundException
|
23
|
+
from ttnn_visualizer.exceptions import DatabaseFileNotFoundException, InvalidProfilerPath, InvalidReportPath
|
24
|
+
from ttnn_visualizer.sessions import create_instance_from_local_paths
|
23
25
|
from ttnn_visualizer.settings import Config, DefaultConfig
|
24
26
|
|
25
27
|
logger = logging.getLogger(__name__)
|
@@ -135,9 +137,10 @@ def middleware(app: flask.Flask):
|
|
135
137
|
return None
|
136
138
|
|
137
139
|
|
138
|
-
def open_browser(host, port,
|
139
|
-
|
140
|
-
|
140
|
+
def open_browser(host, port, instance_id=None):
|
141
|
+
url = f"http://{host}:{port}"
|
142
|
+
if instance_id:
|
143
|
+
url = f"{url}?instanceId={instance_id}"
|
141
144
|
|
142
145
|
print(f"Launching browser with url: {url}")
|
143
146
|
try:
|
@@ -149,6 +152,13 @@ def open_browser(host, port, protocol="http"):
|
|
149
152
|
print(f"Could not open the default browser: {e}")
|
150
153
|
|
151
154
|
|
155
|
+
def parse_args():
|
156
|
+
parser = argparse.ArgumentParser(description="A tool for visualizing the Tenstorrent Neural Network model (TT-NN)")
|
157
|
+
parser.add_argument("--report-path", type=str, help="Specify a report path", default=None)
|
158
|
+
parser.add_argument("--profiler-path", help="Specify a profiler path", default=None)
|
159
|
+
return parser.parse_args()
|
160
|
+
|
161
|
+
|
152
162
|
def main():
|
153
163
|
|
154
164
|
run_command = sys.argv[0].split("/")
|
@@ -156,6 +166,23 @@ def main():
|
|
156
166
|
os.environ.setdefault("FLASK_ENV", "production")
|
157
167
|
|
158
168
|
config = cast(DefaultConfig, Config())
|
169
|
+
args = parse_args()
|
170
|
+
instance_id = None
|
171
|
+
|
172
|
+
if args.report_path or args.profiler_path:
|
173
|
+
app = create_app()
|
174
|
+
app.app_context().push()
|
175
|
+
try:
|
176
|
+
session = create_instance_from_local_paths(
|
177
|
+
report_path=args.report_path,
|
178
|
+
profiler_path=args.profiler_path,
|
179
|
+
)
|
180
|
+
except InvalidReportPath:
|
181
|
+
sys.exit("Invalid report path")
|
182
|
+
except InvalidProfilerPath:
|
183
|
+
sys.exit("Invalid profiler path")
|
184
|
+
|
185
|
+
instance_id = session.instance_id
|
159
186
|
|
160
187
|
# Check if DEBUG environment variable is set
|
161
188
|
debug_mode = os.environ.get("DEBUG", "false").lower() == "true"
|
@@ -182,7 +209,7 @@ def main():
|
|
182
209
|
flask_env = os.getenv("FLASK_ENV", "development")
|
183
210
|
port = config.PORT if flask_env == "production" else config.DEV_SERVER_PORT
|
184
211
|
host = config.HOST if flask_env == "production" else config.DEV_SERVER_HOST
|
185
|
-
threading.Timer(2, open_browser, [host, port]).start()
|
212
|
+
threading.Timer(2, open_browser, [host, port, instance_id]).start()
|
186
213
|
try:
|
187
214
|
subprocess.run(gunicorn_args)
|
188
215
|
except KeyboardInterrupt:
|
ttnn_visualizer/csv_queries.py
CHANGED
@@ -12,7 +12,7 @@ import pandas as pd
|
|
12
12
|
from tt_perf_report import perf_report
|
13
13
|
|
14
14
|
from ttnn_visualizer.exceptions import DataFormatError
|
15
|
-
from ttnn_visualizer.models import
|
15
|
+
from ttnn_visualizer.models import Instance
|
16
16
|
from ttnn_visualizer.ssh_client import get_client
|
17
17
|
|
18
18
|
|
@@ -278,7 +278,7 @@ class DeviceLogProfilerQueries:
|
|
278
278
|
"source file",
|
279
279
|
]
|
280
280
|
|
281
|
-
def __init__(self, session:
|
281
|
+
def __init__(self, session: Instance):
|
282
282
|
"""
|
283
283
|
Initialize the profiler with a session object.
|
284
284
|
The session determines whether to use a local or remote runner.
|
@@ -366,7 +366,7 @@ class DeviceLogProfilerQueries:
|
|
366
366
|
)
|
367
367
|
|
368
368
|
@staticmethod
|
369
|
-
def get_raw_csv(session:
|
369
|
+
def get_raw_csv(session: Instance):
|
370
370
|
from ttnn_visualizer.sftp_operations import read_remote_file
|
371
371
|
|
372
372
|
if (
|
@@ -455,7 +455,7 @@ class OpsPerformanceQueries:
|
|
455
455
|
"HWCommandQueue_write_buffer_TT_HOST_FUNC [ns]",
|
456
456
|
]
|
457
457
|
|
458
|
-
def __init__(self, session:
|
458
|
+
def __init__(self, session: Instance):
|
459
459
|
"""
|
460
460
|
Initialize the performance profiler with a session object.
|
461
461
|
"""
|
@@ -571,6 +571,10 @@ class OpsPerformanceReportQueries:
|
|
571
571
|
"raw_op_code"
|
572
572
|
]
|
573
573
|
|
574
|
+
PASSTHROUGH_COLUMNS = {
|
575
|
+
"pm_ideal_ns": "PM IDEAL [ns]",
|
576
|
+
}
|
577
|
+
|
574
578
|
DEFAULT_SIGNPOST = None
|
575
579
|
DEFAULT_IGNORE_SIGNPOSTS = None
|
576
580
|
DEFAULT_MIN_PERCENTAGE = 0.5
|
@@ -596,6 +600,12 @@ class OpsPerformanceReportQueries:
|
|
596
600
|
True,
|
597
601
|
)
|
598
602
|
|
603
|
+
ops_perf_results = []
|
604
|
+
ops_perf_results_reader = csv.DictReader(StringIO(raw_csv))
|
605
|
+
|
606
|
+
for row in ops_perf_results_reader:
|
607
|
+
ops_perf_results.append(row)
|
608
|
+
|
599
609
|
report = []
|
600
610
|
|
601
611
|
try:
|
@@ -610,6 +620,12 @@ class OpsPerformanceReportQueries:
|
|
610
620
|
processed_row["advice"] = processed_row["advice"].split(" • ")
|
611
621
|
else:
|
612
622
|
processed_row["advice"] = []
|
623
|
+
|
624
|
+
for key, value in cls.PASSTHROUGH_COLUMNS.items():
|
625
|
+
op_id = int(row[0])
|
626
|
+
idx = op_id - 2 # IDs in result column one correspond to row numbers in ops perf results csv
|
627
|
+
processed_row[key] = ops_perf_results[idx][value]
|
628
|
+
|
613
629
|
report.append(processed_row)
|
614
630
|
except csv.Error as e:
|
615
631
|
raise DataFormatError() from e
|
ttnn_visualizer/decorators.py
CHANGED
@@ -19,7 +19,7 @@ from ttnn_visualizer.exceptions import (
|
|
19
19
|
NoProjectsException,
|
20
20
|
RemoteSqliteException,
|
21
21
|
)
|
22
|
-
from ttnn_visualizer.sessions import
|
22
|
+
from ttnn_visualizer.sessions import get_or_create_instance
|
23
23
|
|
24
24
|
|
25
25
|
def with_session(func):
|
@@ -27,18 +27,18 @@ def with_session(func):
|
|
27
27
|
def wrapper(*args, **kwargs):
|
28
28
|
from flask import current_app
|
29
29
|
|
30
|
-
|
30
|
+
instance_id = request.args.get("instanceId")
|
31
31
|
|
32
|
-
if not
|
33
|
-
current_app.logger.error("No
|
32
|
+
if not instance_id:
|
33
|
+
current_app.logger.error("No instanceId present on request, returning 404")
|
34
34
|
abort(404)
|
35
35
|
|
36
|
-
session_query_data =
|
36
|
+
session_query_data = get_or_create_instance(instance_id=instance_id)
|
37
37
|
session = session_query_data.to_pydantic()
|
38
38
|
|
39
39
|
if not session.active_report:
|
40
40
|
current_app.logger.error(
|
41
|
-
f"No active report exists for
|
41
|
+
f"No active report exists for instanceId {instance_id}, returning 404"
|
42
42
|
)
|
43
43
|
# Raise 404 if report_path is missing or does not exist
|
44
44
|
abort(404)
|
ttnn_visualizer/exceptions.py
CHANGED
ttnn_visualizer/models.py
CHANGED
@@ -192,8 +192,8 @@ class RemoteReportFolder(SerializeableModel):
|
|
192
192
|
lastSynced: Optional[int] = None
|
193
193
|
|
194
194
|
|
195
|
-
class
|
196
|
-
|
195
|
+
class Instance(BaseModel):
|
196
|
+
instance_id: str
|
197
197
|
report_path: Optional[str] = None
|
198
198
|
profiler_path: Optional[str] = None
|
199
199
|
npe_path: Optional[str] = None
|
@@ -203,11 +203,11 @@ class TabSession(BaseModel):
|
|
203
203
|
remote_profile_folder: Optional[RemoteReportFolder] = None
|
204
204
|
|
205
205
|
|
206
|
-
class
|
207
|
-
__tablename__ = "
|
206
|
+
class InstanceTable(db.Model):
|
207
|
+
__tablename__ = "instances"
|
208
208
|
|
209
209
|
id = Column(Integer, primary_key=True)
|
210
|
-
|
210
|
+
instance_id = Column(String, unique=True, nullable=False)
|
211
211
|
report_path = Column(String)
|
212
212
|
profiler_path = Column(String, nullable=True)
|
213
213
|
npe_path = Column(String, nullable=True)
|
@@ -218,7 +218,7 @@ class TabSessionTable(db.Model):
|
|
218
218
|
|
219
219
|
def __init__(
|
220
220
|
self,
|
221
|
-
|
221
|
+
instance_id,
|
222
222
|
active_report,
|
223
223
|
remote_connection=None,
|
224
224
|
remote_folder=None,
|
@@ -227,7 +227,7 @@ class TabSessionTable(db.Model):
|
|
227
227
|
profiler_path=None,
|
228
228
|
npe_path=None,
|
229
229
|
):
|
230
|
-
self.
|
230
|
+
self.instance_id = instance_id
|
231
231
|
self.active_report = active_report
|
232
232
|
self.report_path = report_path
|
233
233
|
self.npe_path = npe_path
|
@@ -239,7 +239,7 @@ class TabSessionTable(db.Model):
|
|
239
239
|
def to_dict(self):
|
240
240
|
return {
|
241
241
|
"id": self.id,
|
242
|
-
"
|
242
|
+
"instance_id": self.instance_id,
|
243
243
|
"active_report": self.active_report,
|
244
244
|
"remote_connection": self.remote_connection,
|
245
245
|
"remote_folder": self.remote_folder,
|
@@ -249,9 +249,9 @@ class TabSessionTable(db.Model):
|
|
249
249
|
"npe_path": self.npe_path
|
250
250
|
}
|
251
251
|
|
252
|
-
def to_pydantic(self) ->
|
253
|
-
return
|
254
|
-
|
252
|
+
def to_pydantic(self) -> Instance:
|
253
|
+
return Instance(
|
254
|
+
instance_id=str(self.instance_id),
|
255
255
|
report_path=str(self.report_path) if self.report_path is not None else None,
|
256
256
|
profiler_path=(
|
257
257
|
str(self.profiler_path) if self.profiler_path is not None else None
|
ttnn_visualizer/queries.py
CHANGED
@@ -13,7 +13,7 @@ from ttnn_visualizer.models import (
|
|
13
13
|
DeviceOperation,
|
14
14
|
Buffer,
|
15
15
|
BufferPage,
|
16
|
-
|
16
|
+
Instance,
|
17
17
|
Tensor,
|
18
18
|
OperationArgument,
|
19
19
|
StackTrace,
|
@@ -31,7 +31,7 @@ import paramiko
|
|
31
31
|
|
32
32
|
|
33
33
|
class LocalQueryRunner:
|
34
|
-
def __init__(self, session: Optional[
|
34
|
+
def __init__(self, session: Optional[Instance] = None, connection=None):
|
35
35
|
|
36
36
|
if connection:
|
37
37
|
self.connection = connection
|
@@ -66,7 +66,7 @@ class LocalQueryRunner:
|
|
66
66
|
class RemoteQueryRunner:
|
67
67
|
column_delimiter = "|||"
|
68
68
|
|
69
|
-
def __init__(self, session:
|
69
|
+
def __init__(self, session: Instance):
|
70
70
|
self.session = session
|
71
71
|
self._validate_session()
|
72
72
|
self.ssh_client = self._get_ssh_client(self.session.remote_connection)
|
@@ -165,11 +165,11 @@ class RemoteQueryRunner:
|
|
165
165
|
|
166
166
|
class DatabaseQueries:
|
167
167
|
|
168
|
-
session: Optional[
|
168
|
+
session: Optional[Instance] = None
|
169
169
|
ssh_client = None
|
170
170
|
query_runner: LocalQueryRunner | RemoteQueryRunner
|
171
171
|
|
172
|
-
def __init__(self, session: Optional[
|
172
|
+
def __init__(self, session: Optional[Instance] = None, connection=None):
|
173
173
|
self.session = session
|
174
174
|
|
175
175
|
if connection:
|
ttnn_visualizer/sessions.py
CHANGED
@@ -2,13 +2,18 @@
|
|
2
2
|
#
|
3
3
|
# SPDX-FileCopyrightText: © 2024 Tenstorrent AI ULC
|
4
4
|
|
5
|
+
import json
|
6
|
+
import random
|
7
|
+
import string
|
5
8
|
from logging import getLogger
|
9
|
+
from pathlib import Path
|
6
10
|
|
7
11
|
from flask import request
|
8
12
|
|
13
|
+
from ttnn_visualizer.exceptions import InvalidReportPath, InvalidProfilerPath
|
9
14
|
from ttnn_visualizer.utils import get_report_path, get_profiler_path, get_npe_path
|
10
15
|
from ttnn_visualizer.models import (
|
11
|
-
|
16
|
+
InstanceTable,
|
12
17
|
)
|
13
18
|
from ttnn_visualizer.extensions import db
|
14
19
|
|
@@ -16,10 +21,9 @@ logger = getLogger(__name__)
|
|
16
21
|
|
17
22
|
from flask import jsonify, current_app
|
18
23
|
from sqlalchemy.exc import SQLAlchemyError
|
19
|
-
import json
|
20
24
|
|
21
25
|
|
22
|
-
def
|
26
|
+
def update_existing_instance(
|
23
27
|
session_data,
|
24
28
|
report_name,
|
25
29
|
profile_name,
|
@@ -66,12 +70,12 @@ def handle_sqlalchemy_error(error):
|
|
66
70
|
db.session.rollback()
|
67
71
|
|
68
72
|
|
69
|
-
def commit_and_log_session(session_data,
|
73
|
+
def commit_and_log_session(session_data, instance_id):
|
70
74
|
db.session.commit()
|
71
75
|
|
72
|
-
session_data =
|
76
|
+
session_data = InstanceTable.query.filter_by(instance_id=instance_id).first()
|
73
77
|
current_app.logger.info(
|
74
|
-
f"Session data for
|
78
|
+
f"Session data for instance {instance_id}: {json.dumps(session_data.to_dict(), indent=4)}"
|
75
79
|
)
|
76
80
|
|
77
81
|
|
@@ -99,8 +103,8 @@ def update_paths(
|
|
99
103
|
)
|
100
104
|
|
101
105
|
|
102
|
-
def
|
103
|
-
|
106
|
+
def create_new_instance(
|
107
|
+
instance_id,
|
104
108
|
report_name,
|
105
109
|
profile_name,
|
106
110
|
npe_name,
|
@@ -122,8 +126,8 @@ def create_new_tab_session(
|
|
122
126
|
remote_folder = None
|
123
127
|
remote_profile_folder = None
|
124
128
|
|
125
|
-
session_data =
|
126
|
-
|
129
|
+
session_data = InstanceTable(
|
130
|
+
instance_id=instance_id,
|
127
131
|
active_report=active_report,
|
128
132
|
report_path=get_report_path(
|
129
133
|
active_report,
|
@@ -142,8 +146,8 @@ def create_new_tab_session(
|
|
142
146
|
return session_data
|
143
147
|
|
144
148
|
|
145
|
-
def
|
146
|
-
|
149
|
+
def update_instance(
|
150
|
+
instance_id,
|
147
151
|
report_name=None,
|
148
152
|
profile_name=None,
|
149
153
|
npe_name=None,
|
@@ -153,10 +157,10 @@ def update_tab_session(
|
|
153
157
|
clear_remote=False,
|
154
158
|
):
|
155
159
|
try:
|
156
|
-
session_data =
|
160
|
+
session_data = get_or_create_instance(instance_id)
|
157
161
|
|
158
162
|
if session_data:
|
159
|
-
|
163
|
+
update_existing_instance(
|
160
164
|
session_data,
|
161
165
|
report_name,
|
162
166
|
profile_name,
|
@@ -167,8 +171,8 @@ def update_tab_session(
|
|
167
171
|
clear_remote,
|
168
172
|
)
|
169
173
|
else:
|
170
|
-
session_data =
|
171
|
-
|
174
|
+
session_data = create_new_instance(
|
175
|
+
instance_id,
|
172
176
|
report_name,
|
173
177
|
profile_name,
|
174
178
|
npe_name,
|
@@ -178,7 +182,7 @@ def update_tab_session(
|
|
178
182
|
clear_remote,
|
179
183
|
)
|
180
184
|
|
181
|
-
commit_and_log_session(session_data,
|
185
|
+
commit_and_log_session(session_data, instance_id)
|
182
186
|
return jsonify({"message": "Tab session updated successfully"}), 200
|
183
187
|
|
184
188
|
except SQLAlchemyError as e:
|
@@ -186,8 +190,8 @@ def update_tab_session(
|
|
186
190
|
return jsonify({"error": "Failed to update tab session"}), 500
|
187
191
|
|
188
192
|
|
189
|
-
def
|
190
|
-
|
193
|
+
def get_or_create_instance(
|
194
|
+
instance_id,
|
191
195
|
report_name=None,
|
192
196
|
profile_name=None,
|
193
197
|
npe_name=None,
|
@@ -196,16 +200,16 @@ def get_or_create_tab_session(
|
|
196
200
|
):
|
197
201
|
"""
|
198
202
|
Retrieve an existing tab session or create a new one if it doesn't exist.
|
199
|
-
Uses the
|
203
|
+
Uses the Instance model to manage session data and supports conditional updates.
|
200
204
|
"""
|
201
205
|
try:
|
202
206
|
# Query the database for the tab session
|
203
|
-
session_data =
|
207
|
+
session_data = InstanceTable.query.filter_by(instance_id=instance_id).first()
|
204
208
|
|
205
209
|
# If session doesn't exist, initialize it
|
206
210
|
if not session_data:
|
207
|
-
session_data =
|
208
|
-
|
211
|
+
session_data = InstanceTable(
|
212
|
+
instance_id=instance_id,
|
209
213
|
active_report={},
|
210
214
|
remote_connection=None,
|
211
215
|
remote_folder=None,
|
@@ -215,8 +219,8 @@ def get_or_create_tab_session(
|
|
215
219
|
|
216
220
|
# Update the session if any new data is provided
|
217
221
|
if report_name or profile_name or npe_name or remote_connection or remote_folder:
|
218
|
-
|
219
|
-
|
222
|
+
update_instance(
|
223
|
+
instance_id=instance_id,
|
220
224
|
report_name=report_name,
|
221
225
|
profile_name=profile_name,
|
222
226
|
npe_name=npe_name,
|
@@ -225,7 +229,7 @@ def get_or_create_tab_session(
|
|
225
229
|
)
|
226
230
|
|
227
231
|
# Query again to get the updated session data
|
228
|
-
session_data =
|
232
|
+
session_data = InstanceTable.query.filter_by(instance_id=instance_id).first()
|
229
233
|
|
230
234
|
return session_data
|
231
235
|
|
@@ -235,20 +239,20 @@ def get_or_create_tab_session(
|
|
235
239
|
return None
|
236
240
|
|
237
241
|
|
238
|
-
def
|
242
|
+
def get_instance():
|
239
243
|
"""
|
240
|
-
Middleware to retrieve or create a tab session based on the
|
244
|
+
Middleware to retrieve or create a tab session based on the instance_id.
|
241
245
|
"""
|
242
|
-
|
246
|
+
instance_id = request.args.get("instanceId", None)
|
243
247
|
|
244
|
-
current_app.logger.info(f"
|
245
|
-
if not
|
246
|
-
current_app.logger.error("
|
247
|
-
return jsonify({"error": "
|
248
|
+
current_app.logger.info(f"get_instance: Received instance_id: {instance_id}")
|
249
|
+
if not instance_id:
|
250
|
+
current_app.logger.error("get_instance: No instance_id found")
|
251
|
+
return jsonify({"error": "instanceId is required"}), 400
|
248
252
|
|
249
|
-
active_report =
|
253
|
+
active_report = get_or_create_instance(instance_id)
|
250
254
|
current_app.logger.info(
|
251
|
-
f"
|
255
|
+
f"get_instance: Session retrieved: {active_report.active_report}"
|
252
256
|
)
|
253
257
|
|
254
258
|
return jsonify({"active_report": active_report.active_report}), 200
|
@@ -258,5 +262,39 @@ def init_sessions(app):
|
|
258
262
|
"""
|
259
263
|
Initializes session middleware and hooks it into Flask.
|
260
264
|
"""
|
261
|
-
app.before_request(
|
265
|
+
app.before_request(get_instance)
|
262
266
|
app.logger.info("Sessions middleware initialized.")
|
267
|
+
|
268
|
+
|
269
|
+
def create_random_instance_id():
|
270
|
+
return ''.join(random.choices(string.ascii_lowercase + string.digits, k=10))
|
271
|
+
|
272
|
+
|
273
|
+
def create_instance_from_local_paths(report_path, profiler_path):
|
274
|
+
_report_path = Path(report_path)
|
275
|
+
_profiler_path = Path(profiler_path)
|
276
|
+
|
277
|
+
if not _report_path.exists():
|
278
|
+
raise InvalidReportPath()
|
279
|
+
|
280
|
+
if not _profiler_path.exists():
|
281
|
+
raise InvalidProfilerPath()
|
282
|
+
|
283
|
+
report_name = _report_path.parts[-2] if len(_report_path.parts) > 2 else ""
|
284
|
+
profile_name = _profiler_path.parts[-1] if len(_profiler_path.parts) > 2 else ""
|
285
|
+
session_data = InstanceTable(
|
286
|
+
instance_id=create_random_instance_id(),
|
287
|
+
active_report={
|
288
|
+
"report_name": report_name,
|
289
|
+
"profile_name": profile_name,
|
290
|
+
"npe_name": None,
|
291
|
+
},
|
292
|
+
report_path=report_path,
|
293
|
+
profiler_path=profiler_path,
|
294
|
+
remote_connection=None,
|
295
|
+
remote_folder=None,
|
296
|
+
remote_profile_folder=None,
|
297
|
+
)
|
298
|
+
db.session.add(session_data)
|
299
|
+
db.session.commit()
|
300
|
+
return session_data
|
ttnn_visualizer/sockets.py
CHANGED
@@ -51,7 +51,7 @@ debounce_delay = 0.5 # Delay in seconds (adjust as needed)
|
|
51
51
|
last_emit_time = 0
|
52
52
|
|
53
53
|
|
54
|
-
def emit_file_status(progress: FileProgress,
|
54
|
+
def emit_file_status(progress: FileProgress, instance_id=None):
|
55
55
|
"""Debounced emit for file status updates using a debounce timer."""
|
56
56
|
global debounce_timer, last_emit_time
|
57
57
|
|
@@ -59,10 +59,10 @@ def emit_file_status(progress: FileProgress, tab_id=None):
|
|
59
59
|
global last_emit_time
|
60
60
|
last_emit_time = time.time()
|
61
61
|
data = progress.to_dict()
|
62
|
-
data.update({"
|
62
|
+
data.update({"instance_id": instance_id})
|
63
63
|
try:
|
64
64
|
if socketio is not None and hasattr(socketio, "emit"):
|
65
|
-
socketio.emit(Messages.FILE_TRANSFER_PROGRESS, data, to=
|
65
|
+
socketio.emit(Messages.FILE_TRANSFER_PROGRESS, data, to=instance_id)
|
66
66
|
except NameError:
|
67
67
|
pass # Can silently pass since we know the NameError is from sockets being disabled
|
68
68
|
|
@@ -89,30 +89,30 @@ def register_handlers(socketio_instance):
|
|
89
89
|
|
90
90
|
sid = getattr(request, "sid", "")
|
91
91
|
|
92
|
-
|
93
|
-
print(f"Received
|
92
|
+
instance_id = request.args.get("instanceId")
|
93
|
+
print(f"Received instanceId: {instance_id}, socket ID: {sid}") # Log for debugging
|
94
94
|
|
95
|
-
if
|
96
|
-
join_room(
|
97
|
-
tab_clients[
|
98
|
-
print(f"Joined room: {
|
95
|
+
if instance_id:
|
96
|
+
join_room(instance_id) # Join the room identified by the instanceId
|
97
|
+
tab_clients[instance_id] = sid # Store the socket ID associated with this instanceId
|
98
|
+
print(f"Joined room: {instance_id}")
|
99
99
|
else:
|
100
|
-
print("No
|
100
|
+
print("No instanceId provided, disconnecting client.")
|
101
101
|
disconnect()
|
102
102
|
|
103
103
|
@socketio.on("disconnect")
|
104
104
|
def handle_disconnect():
|
105
105
|
from flask import request
|
106
106
|
|
107
|
-
|
108
|
-
# Find and remove the socket ID associated with this
|
107
|
+
instance_id = None
|
108
|
+
# Find and remove the socket ID associated with this instanceId
|
109
109
|
sid = getattr(request, "sid", "")
|
110
110
|
for key, value in tab_clients.items():
|
111
111
|
|
112
112
|
if value == sid:
|
113
|
-
|
113
|
+
instance_id = key
|
114
114
|
break
|
115
|
-
if
|
116
|
-
leave_room(
|
117
|
-
del tab_clients[
|
118
|
-
print(f"Client disconnected from
|
115
|
+
if instance_id:
|
116
|
+
leave_room(instance_id)
|
117
|
+
del tab_clients[instance_id]
|
118
|
+
print(f"Client disconnected from instanceId: {instance_id}, Socket ID: {sid}")
|
@@ -1 +1 @@
|
|
1
|
-
import{I as n}from"./index-BVMreIQm.js";import{I as e}from"./index-Do7YB6C4.js";import{p as r,I as s}from"./index-
|
1
|
+
import{I as n}from"./index-BVMreIQm.js";import{I as e}from"./index-Do7YB6C4.js";import{p as r,I as s}from"./index-CeYOVqR1.js";function I(o,t){var a=r(o);return t===s.STANDARD?n[a]:e[a]}function p(o){return r(o)}export{n as IconSvgPaths16,e as IconSvgPaths20,I as getIconPaths,p as iconNameToPathsRecordKey};
|
@@ -1,2 +1,2 @@
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/allPaths-
|
2
|
-
import{_ as o,a as n,b as i}from"./index-
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/allPaths-DfvpbqXZ.js","assets/index-BVMreIQm.js","assets/index-Do7YB6C4.js","assets/index-CeYOVqR1.js","assets/index-BTfoVg9a.css"])))=>i.map(i=>d[i]);
|
2
|
+
import{_ as o,a as n,b as i}from"./index-CeYOVqR1.js";var _=function(e,a){return o(void 0,void 0,void 0,function(){var t;return n(this,function(r){switch(r.label){case 0:return[4,i(()=>import("./allPaths-DfvpbqXZ.js"),__vite__mapDeps([0,1,2,3,4]))];case 1:return t=r.sent().getIconPaths,[2,t(e,a)]}})})};export{_ as allPathsLoader};
|