ttnn-visualizer 0.25.1__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/file_uploads.py +7 -0
- ttnn_visualizer/models.py +21 -12
- ttnn_visualizer/queries.py +5 -5
- ttnn_visualizer/sessions.py +95 -40
- ttnn_visualizer/settings.py +1 -1
- ttnn_visualizer/sockets.py +17 -17
- ttnn_visualizer/static/assets/{allPaths-BsZhgQ3T.js → allPaths-DfvpbqXZ.js} +1 -1
- ttnn_visualizer/static/assets/{allPathsLoader-DgFQ6cmn.js → allPathsLoader-C1wkx2sM.js} +2 -2
- ttnn_visualizer/static/assets/{index-C6f3UdbP.css → index-BTfoVg9a.css} +2 -2
- ttnn_visualizer/static/assets/{index-Fd4wdmZt.js → index-CeYOVqR1.js} +247 -247
- ttnn_visualizer/static/assets/{splitPathsBySizeLoader-BFDp4kIf.js → splitPathsBySizeLoader-C_Kuh9CJ.js} +1 -1
- ttnn_visualizer/static/index.html +3 -3
- ttnn_visualizer/utils.py +6 -0
- ttnn_visualizer/views.py +73 -32
- {ttnn_visualizer-0.25.1.dist-info → ttnn_visualizer-0.27.0.dist-info}/METADATA +6 -9
- {ttnn_visualizer-0.25.1.dist-info → ttnn_visualizer-0.27.0.dist-info}/RECORD +25 -25
- {ttnn_visualizer-0.25.1.dist-info → ttnn_visualizer-0.27.0.dist-info}/LICENSE +0 -0
- {ttnn_visualizer-0.25.1.dist-info → ttnn_visualizer-0.27.0.dist-info}/LICENSE_understanding.txt +0 -0
- {ttnn_visualizer-0.25.1.dist-info → ttnn_visualizer-0.27.0.dist-info}/WHEEL +0 -0
- {ttnn_visualizer-0.25.1.dist-info → ttnn_visualizer-0.27.0.dist-info}/entry_points.txt +0 -0
- {ttnn_visualizer-0.25.1.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/file_uploads.py
CHANGED
@@ -43,6 +43,13 @@ def extract_report_name(files):
|
|
43
43
|
unsplit_report_name = str(files[0].filename)
|
44
44
|
return unsplit_report_name.split("/")[0]
|
45
45
|
|
46
|
+
def extract_npe_name(files):
|
47
|
+
if not files:
|
48
|
+
return None
|
49
|
+
|
50
|
+
file_path = Path(files[0].filename)
|
51
|
+
return file_path.stem
|
52
|
+
|
46
53
|
|
47
54
|
def save_uploaded_files(
|
48
55
|
files,
|
ttnn_visualizer/models.py
CHANGED
@@ -182,6 +182,7 @@ class StatusMessage(SerializeableModel):
|
|
182
182
|
class ActiveReport(SerializeableModel):
|
183
183
|
report_name: Optional[str] = None
|
184
184
|
profile_name: Optional[str] = None
|
185
|
+
npe_name: Optional[str] = None
|
185
186
|
|
186
187
|
|
187
188
|
class RemoteReportFolder(SerializeableModel):
|
@@ -191,23 +192,25 @@ class RemoteReportFolder(SerializeableModel):
|
|
191
192
|
lastSynced: Optional[int] = None
|
192
193
|
|
193
194
|
|
194
|
-
class
|
195
|
-
|
195
|
+
class Instance(BaseModel):
|
196
|
+
instance_id: str
|
196
197
|
report_path: Optional[str] = None
|
197
198
|
profiler_path: Optional[str] = None
|
199
|
+
npe_path: Optional[str] = None
|
198
200
|
active_report: Optional[ActiveReport] = None
|
199
201
|
remote_connection: Optional[RemoteConnection] = None
|
200
202
|
remote_folder: Optional[RemoteReportFolder] = None
|
201
203
|
remote_profile_folder: Optional[RemoteReportFolder] = None
|
202
204
|
|
203
205
|
|
204
|
-
class
|
205
|
-
__tablename__ = "
|
206
|
+
class InstanceTable(db.Model):
|
207
|
+
__tablename__ = "instances"
|
206
208
|
|
207
209
|
id = Column(Integer, primary_key=True)
|
208
|
-
|
210
|
+
instance_id = Column(String, unique=True, nullable=False)
|
209
211
|
report_path = Column(String)
|
210
212
|
profiler_path = Column(String, nullable=True)
|
213
|
+
npe_path = Column(String, nullable=True)
|
211
214
|
active_report = db.Column(MutableDict.as_mutable(JSON), nullable=False, default={})
|
212
215
|
remote_connection = Column(JSON, nullable=True)
|
213
216
|
remote_folder = Column(JSON, nullable=True)
|
@@ -215,17 +218,19 @@ class TabSessionTable(db.Model):
|
|
215
218
|
|
216
219
|
def __init__(
|
217
220
|
self,
|
218
|
-
|
221
|
+
instance_id,
|
219
222
|
active_report,
|
220
223
|
remote_connection=None,
|
221
224
|
remote_folder=None,
|
225
|
+
remote_profile_folder=None,
|
222
226
|
report_path=None,
|
223
227
|
profiler_path=None,
|
224
|
-
|
228
|
+
npe_path=None,
|
225
229
|
):
|
226
|
-
self.
|
230
|
+
self.instance_id = instance_id
|
227
231
|
self.active_report = active_report
|
228
232
|
self.report_path = report_path
|
233
|
+
self.npe_path = npe_path
|
229
234
|
self.remote_connection = remote_connection
|
230
235
|
self.remote_folder = remote_folder
|
231
236
|
self.profiler_path = profiler_path
|
@@ -234,22 +239,26 @@ class TabSessionTable(db.Model):
|
|
234
239
|
def to_dict(self):
|
235
240
|
return {
|
236
241
|
"id": self.id,
|
237
|
-
"
|
242
|
+
"instance_id": self.instance_id,
|
238
243
|
"active_report": self.active_report,
|
239
244
|
"remote_connection": self.remote_connection,
|
240
245
|
"remote_folder": self.remote_folder,
|
241
246
|
"remote_profile_folder": self.remote_profile_folder,
|
242
247
|
"report_path": self.report_path,
|
243
248
|
"profiler_path": self.profiler_path,
|
249
|
+
"npe_path": self.npe_path
|
244
250
|
}
|
245
251
|
|
246
|
-
def to_pydantic(self) ->
|
247
|
-
return
|
248
|
-
|
252
|
+
def to_pydantic(self) -> Instance:
|
253
|
+
return Instance(
|
254
|
+
instance_id=str(self.instance_id),
|
249
255
|
report_path=str(self.report_path) if self.report_path is not None else None,
|
250
256
|
profiler_path=(
|
251
257
|
str(self.profiler_path) if self.profiler_path is not None else None
|
252
258
|
),
|
259
|
+
npe_path=(
|
260
|
+
str(self.npe_path) if self.npe_path is not None else None
|
261
|
+
),
|
253
262
|
active_report=(
|
254
263
|
(ActiveReport(**self.active_report) if self.active_report else None)
|
255
264
|
if isinstance(self.active_report, dict)
|
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
|
|
9
|
-
from ttnn_visualizer.
|
13
|
+
from ttnn_visualizer.exceptions import InvalidReportPath, InvalidProfilerPath
|
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,13 +21,13 @@ 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,
|
30
|
+
npe_name,
|
26
31
|
remote_connection,
|
27
32
|
remote_folder,
|
28
33
|
remote_profile_folder,
|
@@ -34,6 +39,8 @@ def update_existing_tab_session(
|
|
34
39
|
active_report["report_name"] = report_name
|
35
40
|
if profile_name:
|
36
41
|
active_report["profile_name"] = profile_name
|
42
|
+
if npe_name:
|
43
|
+
active_report["npe_name"] = npe_name
|
37
44
|
|
38
45
|
session_data.active_report = active_report
|
39
46
|
|
@@ -48,7 +55,7 @@ def update_existing_tab_session(
|
|
48
55
|
clear_remote_data(session_data)
|
49
56
|
|
50
57
|
update_paths(
|
51
|
-
session_data, active_report, remote_connection
|
58
|
+
session_data, active_report, remote_connection
|
52
59
|
)
|
53
60
|
|
54
61
|
|
@@ -63,17 +70,17 @@ def handle_sqlalchemy_error(error):
|
|
63
70
|
db.session.rollback()
|
64
71
|
|
65
72
|
|
66
|
-
def commit_and_log_session(session_data,
|
73
|
+
def commit_and_log_session(session_data, instance_id):
|
67
74
|
db.session.commit()
|
68
75
|
|
69
|
-
session_data =
|
76
|
+
session_data = InstanceTable.query.filter_by(instance_id=instance_id).first()
|
70
77
|
current_app.logger.info(
|
71
|
-
f"Session data for
|
78
|
+
f"Session data for instance {instance_id}: {json.dumps(session_data.to_dict(), indent=4)}"
|
72
79
|
)
|
73
80
|
|
74
81
|
|
75
82
|
def update_paths(
|
76
|
-
session_data, active_report, remote_connection
|
83
|
+
session_data, active_report, remote_connection
|
77
84
|
):
|
78
85
|
if active_report.get("profile_name"):
|
79
86
|
session_data.profiler_path = get_profiler_path(
|
@@ -89,11 +96,18 @@ def update_paths(
|
|
89
96
|
remote_connection=remote_connection,
|
90
97
|
)
|
91
98
|
|
99
|
+
if active_report.get("npe_name"):
|
100
|
+
session_data.npe_path = get_npe_path(
|
101
|
+
npe_name=active_report["npe_name"],
|
102
|
+
current_app=current_app
|
103
|
+
)
|
104
|
+
|
92
105
|
|
93
|
-
def
|
94
|
-
|
106
|
+
def create_new_instance(
|
107
|
+
instance_id,
|
95
108
|
report_name,
|
96
109
|
profile_name,
|
110
|
+
npe_name,
|
97
111
|
remote_connection,
|
98
112
|
remote_folder,
|
99
113
|
remote_profile_folder,
|
@@ -104,14 +118,16 @@ def create_new_tab_session(
|
|
104
118
|
active_report["report_name"] = report_name
|
105
119
|
if profile_name:
|
106
120
|
active_report["profile_name"] = profile_name
|
121
|
+
if npe_name:
|
122
|
+
active_report["npe_name"] = npe_name
|
107
123
|
|
108
124
|
if clear_remote:
|
109
125
|
remote_connection = None
|
110
126
|
remote_folder = None
|
111
127
|
remote_profile_folder = None
|
112
128
|
|
113
|
-
session_data =
|
114
|
-
|
129
|
+
session_data = InstanceTable(
|
130
|
+
instance_id=instance_id,
|
115
131
|
active_report=active_report,
|
116
132
|
report_path=get_report_path(
|
117
133
|
active_report,
|
@@ -130,40 +146,43 @@ def create_new_tab_session(
|
|
130
146
|
return session_data
|
131
147
|
|
132
148
|
|
133
|
-
def
|
134
|
-
|
149
|
+
def update_instance(
|
150
|
+
instance_id,
|
135
151
|
report_name=None,
|
136
152
|
profile_name=None,
|
153
|
+
npe_name=None,
|
137
154
|
remote_connection=None,
|
138
155
|
remote_folder=None,
|
139
156
|
remote_profile_folder=None,
|
140
157
|
clear_remote=False,
|
141
158
|
):
|
142
159
|
try:
|
143
|
-
session_data =
|
160
|
+
session_data = get_or_create_instance(instance_id)
|
144
161
|
|
145
162
|
if session_data:
|
146
|
-
|
163
|
+
update_existing_instance(
|
147
164
|
session_data,
|
148
165
|
report_name,
|
149
166
|
profile_name,
|
167
|
+
npe_name,
|
150
168
|
remote_connection,
|
151
169
|
remote_folder,
|
152
170
|
remote_profile_folder,
|
153
171
|
clear_remote,
|
154
172
|
)
|
155
173
|
else:
|
156
|
-
session_data =
|
157
|
-
|
174
|
+
session_data = create_new_instance(
|
175
|
+
instance_id,
|
158
176
|
report_name,
|
159
177
|
profile_name,
|
178
|
+
npe_name,
|
160
179
|
remote_connection,
|
161
180
|
remote_folder,
|
162
181
|
remote_profile_folder,
|
163
182
|
clear_remote,
|
164
183
|
)
|
165
184
|
|
166
|
-
commit_and_log_session(session_data,
|
185
|
+
commit_and_log_session(session_data, instance_id)
|
167
186
|
return jsonify({"message": "Tab session updated successfully"}), 200
|
168
187
|
|
169
188
|
except SQLAlchemyError as e:
|
@@ -171,25 +190,26 @@ def update_tab_session(
|
|
171
190
|
return jsonify({"error": "Failed to update tab session"}), 500
|
172
191
|
|
173
192
|
|
174
|
-
def
|
175
|
-
|
193
|
+
def get_or_create_instance(
|
194
|
+
instance_id,
|
176
195
|
report_name=None,
|
177
196
|
profile_name=None,
|
197
|
+
npe_name=None,
|
178
198
|
remote_connection=None,
|
179
199
|
remote_folder=None,
|
180
200
|
):
|
181
201
|
"""
|
182
202
|
Retrieve an existing tab session or create a new one if it doesn't exist.
|
183
|
-
Uses the
|
203
|
+
Uses the Instance model to manage session data and supports conditional updates.
|
184
204
|
"""
|
185
205
|
try:
|
186
206
|
# Query the database for the tab session
|
187
|
-
session_data =
|
207
|
+
session_data = InstanceTable.query.filter_by(instance_id=instance_id).first()
|
188
208
|
|
189
209
|
# If session doesn't exist, initialize it
|
190
210
|
if not session_data:
|
191
|
-
session_data =
|
192
|
-
|
211
|
+
session_data = InstanceTable(
|
212
|
+
instance_id=instance_id,
|
193
213
|
active_report={},
|
194
214
|
remote_connection=None,
|
195
215
|
remote_folder=None,
|
@@ -198,17 +218,18 @@ def get_or_create_tab_session(
|
|
198
218
|
db.session.commit()
|
199
219
|
|
200
220
|
# Update the session if any new data is provided
|
201
|
-
if report_name or profile_name or remote_connection or remote_folder:
|
202
|
-
|
203
|
-
|
221
|
+
if report_name or profile_name or npe_name or remote_connection or remote_folder:
|
222
|
+
update_instance(
|
223
|
+
instance_id=instance_id,
|
204
224
|
report_name=report_name,
|
205
225
|
profile_name=profile_name,
|
226
|
+
npe_name=npe_name,
|
206
227
|
remote_connection=remote_connection,
|
207
228
|
remote_folder=remote_folder,
|
208
229
|
)
|
209
230
|
|
210
231
|
# Query again to get the updated session data
|
211
|
-
session_data =
|
232
|
+
session_data = InstanceTable.query.filter_by(instance_id=instance_id).first()
|
212
233
|
|
213
234
|
return session_data
|
214
235
|
|
@@ -218,20 +239,20 @@ def get_or_create_tab_session(
|
|
218
239
|
return None
|
219
240
|
|
220
241
|
|
221
|
-
def
|
242
|
+
def get_instance():
|
222
243
|
"""
|
223
|
-
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.
|
224
245
|
"""
|
225
|
-
|
246
|
+
instance_id = request.args.get("instanceId", None)
|
226
247
|
|
227
|
-
current_app.logger.info(f"
|
228
|
-
if not
|
229
|
-
current_app.logger.error("
|
230
|
-
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
|
231
252
|
|
232
|
-
active_report =
|
253
|
+
active_report = get_or_create_instance(instance_id)
|
233
254
|
current_app.logger.info(
|
234
|
-
f"
|
255
|
+
f"get_instance: Session retrieved: {active_report.active_report}"
|
235
256
|
)
|
236
257
|
|
237
258
|
return jsonify({"active_report": active_report.active_report}), 200
|
@@ -241,5 +262,39 @@ def init_sessions(app):
|
|
241
262
|
"""
|
242
263
|
Initializes session middleware and hooks it into Flask.
|
243
264
|
"""
|
244
|
-
app.before_request(
|
265
|
+
app.before_request(get_instance)
|
245
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/settings.py
CHANGED
@@ -19,7 +19,7 @@ class DefaultConfig(object):
|
|
19
19
|
|
20
20
|
# Path Settings
|
21
21
|
REPORT_DATA_DIRECTORY = Path(__file__).parent.absolute().joinpath("data")
|
22
|
-
VERSION = "0.
|
22
|
+
VERSION = "0.26.0"
|
23
23
|
LOCAL_DATA_DIRECTORY = Path(REPORT_DATA_DIRECTORY).joinpath("local")
|
24
24
|
REMOTE_DATA_DIRECTORY = Path(REPORT_DATA_DIRECTORY).joinpath("remote")
|
25
25
|
APPLICATION_DIR = os.path.abspath(os.path.join(__file__, "..", os.pardir))
|