diff --git a/panels/TensorboardGroupViewer.py b/panels/TensorboardGroupViewer.py
index b452deb..f1a4747 100644
--- a/panels/TensorboardGroupViewer.py
+++ b/panels/TensorboardGroupViewer.py
@@ -19,6 +19,34 @@
import glob
import shutil
+# --- Per-instance port assignment (6000-6009) ---
+# All Streamlit panels share the same session_state, so this dict persists
+# across instances and can be reused by other panels that start servers.
+
+PORT_RANGE_START = 6000
+PORT_RANGE_END = 6010 # exclusive
+
+
+def get_instance_port(instance_id, registry_key="instance_port_map"):
+ """Return the port assigned to instance_id, assigning the next available
+ port if this instance hasn't been seen before. Raises RuntimeError when
+ the port range is exhausted."""
+ if registry_key not in st.session_state:
+ st.session_state[registry_key] = {}
+ registry = st.session_state[registry_key]
+ if instance_id not in registry:
+ next_port = PORT_RANGE_START + len(registry)
+ if next_port >= PORT_RANGE_END:
+ raise RuntimeError(
+ f"No available ports: all ports {PORT_RANGE_START}-{PORT_RANGE_END - 1} are in use."
+ )
+ registry[instance_id] = next_port
+ return registry[instance_id]
+
+
+instance_id = os.environ["COMET_PANEL_INSTANCE_ID"]
+port = get_instance_port(instance_id)
+
st.set_page_config(layout="wide")
from streamlit_js_eval import get_page_location
@@ -78,7 +106,7 @@
except:
pass
if not running:
- command = f"/home/stuser/.local/bin/tensorboard --logdir ./logs --port 6007".split()
+ command = f"/home/stuser/.local/bin/tensorboard --logdir ./logs --port {port}".split()
env = {} # {"PYTHONPATH": "/home/st_user/.local/lib/python3.9/site-packages"}
process = subprocess.Popen(command, preexec_fn=os.setsid, env=env)
needs_refresh = True
@@ -93,6 +121,6 @@
bar.empty()
path, _ = page_location["pathname"].split("/component")
- url = page_location["origin"] + path + f"/port/6007/server?x={random.random()}"
+ url = page_location["origin"] + path + f"/port/{port}/server?x={random.random()}"
st.markdown('⛶ Open in tab' % url, unsafe_allow_html=True)
components.iframe(src=url, height=700)
diff --git a/panels/TensorboardGroupViewer/TensorboardGroupViewer.py b/panels/TensorboardGroupViewer/TensorboardGroupViewer.py
index 65bfdd1..fd9f557 100644
--- a/panels/TensorboardGroupViewer/TensorboardGroupViewer.py
+++ b/panels/TensorboardGroupViewer/TensorboardGroupViewer.py
@@ -22,6 +22,34 @@
import socket
import signal
+# --- Per-instance port assignment (6000-6009) ---
+# All Streamlit panels share the same session_state, so this dict persists
+# across instances and can be reused by other panels that start servers.
+
+PORT_RANGE_START = 6000
+PORT_RANGE_END = 6010 # exclusive
+
+
+def get_instance_port(instance_id, registry_key="instance_port_map"):
+ """Return the port assigned to instance_id, assigning the next available
+ port if this instance hasn't been seen before. Raises RuntimeError when
+ the port range is exhausted."""
+ if registry_key not in st.session_state:
+ st.session_state[registry_key] = {}
+ registry = st.session_state[registry_key]
+ if instance_id not in registry:
+ next_port = PORT_RANGE_START + len(registry)
+ if next_port >= PORT_RANGE_END:
+ raise RuntimeError(
+ f"No available ports: all ports {PORT_RANGE_START}-{PORT_RANGE_END - 1} are in use."
+ )
+ registry[instance_id] = next_port
+ return registry[instance_id]
+
+
+instance_id = os.environ["COMET_PANEL_INSTANCE_ID"]
+port = get_instance_port(instance_id)
+
st.set_page_config(layout="wide")
from streamlit_js_eval import get_page_location
@@ -154,11 +182,11 @@ def wait_for_server(port=6007, max_wait=30):
print("Can't kill the server; continuing ...")
# Wait for server to stop before starting new one
- if not wait_for_server_stop(port=6007, max_wait=10):
+ if not wait_for_server_stop(port=port, max_wait=10):
st.warning("Previous Tensorboard server may still be running")
# Start new server
- command = f"/home/stuser/.local/bin/tensorboard --logdir ./logs --port 6007".split()
+ command = f"/home/stuser/.local/bin/tensorboard --logdir ./logs --port {port}".split()
env = (
{}
) # {"PYTHONPATH": "/home/st_user/.local/lib/python3.9/site-packages"}
@@ -166,12 +194,12 @@ def wait_for_server(port=6007, max_wait=30):
st.session_state["tensorboard_state"] = "group_viewer"
# Wait for server to be ready
- if wait_for_server(port=6007, max_wait=30):
+ if wait_for_server(port=port, max_wait=30):
path, _ = page_location["pathname"].split("/component")
url = (
page_location["origin"]
+ path
- + f"/port/6007/server?x={random.randint(1,1_000_000)}"
+ + f"/port/{port}/server?x={random.randint(1,1_000_000)}"
)
st.markdown(
'⛶ Open in tab'
@@ -189,7 +217,7 @@ def wait_for_server(port=6007, max_wait=30):
url = (
page_location["origin"]
+ path
- + f"/port/6007/server?x={random.randint(1,1_000_000)}"
+ + f"/port/{port}/server?x={random.randint(1,1_000_000)}"
)
st.markdown(
'⛶ Open in tab' % url,
diff --git a/panels/TensorboardProfileViewer.py b/panels/TensorboardProfileViewer.py
index 9a263e0..2d44107 100644
--- a/panels/TensorboardProfileViewer.py
+++ b/panels/TensorboardProfileViewer.py
@@ -17,7 +17,35 @@
import random
import signal
-st.set_page_config(layout="wide")
+# --- Per-instance port assignment (6000-6009) ---
+# All Streamlit panels share the same session_state, so this dict persists
+# across instances and can be reused by other panels that start servers.
+
+PORT_RANGE_START = 6000
+PORT_RANGE_END = 6010 # exclusive
+
+
+def get_instance_port(instance_id, registry_key="instance_port_map"):
+ """Return the port assigned to instance_id, assigning the next available
+ port if this instance hasn't been seen before. Raises RuntimeError when
+ the port range is exhausted."""
+ if registry_key not in st.session_state:
+ st.session_state[registry_key] = {}
+ registry = st.session_state[registry_key]
+ if instance_id not in registry:
+ next_port = PORT_RANGE_START + len(registry)
+ if next_port >= PORT_RANGE_END:
+ raise RuntimeError(
+ f"No available ports: all ports {PORT_RANGE_START}-{PORT_RANGE_END - 1} are in use."
+ )
+ registry[instance_id] = next_port
+ return registry[instance_id]
+
+
+instance_id = os.environ["COMET_PANEL_INSTANCE_ID"]
+port = get_instance_port(instance_id)
+
+st.set_page_config(layout="wide")
if "tensorboard_state" not in st.session_state:
st.session_state["tensorboard_state"] = None
@@ -31,6 +59,17 @@ class EmptyExperiment:
id = None
name = ""
+
+def select_experiment(experiment_list):
+ names = [exp.name for exp in experiment_list]
+ selected_idx = st.selectbox(
+ "Select Experiment with log:",
+ range(len(names)),
+ format_func=lambda i: names[i],
+ )
+ return experiment_list[selected_idx]
+
+
experiments_with_log = [EmptyExperiment()]
for experiment in experiments:
asset_list = experiment.get_asset_list("tensorflow-file")
@@ -41,13 +80,9 @@ class EmptyExperiment:
st.write("No experiments with log")
st.stop()
elif len(experiments_with_log) == 2:
- selected_experiment = experiments_with_log[1]
+ selected_experiment = experiments_with_log[1]
else:
- selected_experiment = st.selectbox(
- "Select Experiment with log:",
- experiments_with_log,
- format_func=lambda aexp: aexp.name
- )
+ selected_experiment = select_experiment(experiments_with_log)
if selected_experiment.id:
page_location = get_page_location()
@@ -62,7 +97,7 @@ class EmptyExperiment:
[""] + sorted(os.listdir("./%s/logs/" % selected_experiment.id))
)
if selected_log:
- command = f"/home/stuser/.local/bin/tensorboard --logdir ./{selected_experiment.id}/logs/{selected_log} --port 6007".split()
+ command = f"/home/stuser/.local/bin/tensorboard --logdir ./{selected_experiment.id}/logs/{selected_log} --port {port}".split()
env = {} # {"PYTHONPATH": "/.local/lib/python3.9/site-packages"}
if st.session_state["tensorboard_state"] != (selected_experiment.id, selected_log):
#print("Killing the hard way...")
@@ -86,6 +121,6 @@ class EmptyExperiment:
bar.empty()
path, _ = page_location["pathname"].split("/component")
- url = page_location["origin"] + path + f"/port/6007/server?x={random.randint(1,1_000_000)}#profile"
+ url = page_location["origin"] + path + f"/port/{port}/server?x={random.randint(1,1_000_000)}#profile"
st.markdown('⛶ Open in tab' % url, unsafe_allow_html=True)
components.iframe(src=url, height=700)
diff --git a/panels/TensorboardProfileViewer/TensorboardProfileViewer.py b/panels/TensorboardProfileViewer/TensorboardProfileViewer.py
index 086dfd5..0088ee5 100644
--- a/panels/TensorboardProfileViewer/TensorboardProfileViewer.py
+++ b/panels/TensorboardProfileViewer/TensorboardProfileViewer.py
@@ -2,9 +2,6 @@
# Log the tensorboard profile (and other data) with
# >>> experiment.log_tensorflow_folder("./logs")
-# NOTE: there is only one Tensorboard Server for your
-# Python Panels; logs are shared across them
-
from comet_ml import API
import streamlit as st
import streamlit.components.v1 as components
@@ -19,6 +16,34 @@
import requests
import socket
+# --- Per-instance port assignment (6000-6009) ---
+# All Streamlit panels share the same session_state, so this dict persists
+# across instances and can be reused by other panels that start servers.
+
+PORT_RANGE_START = 6000
+PORT_RANGE_END = 6010 # exclusive
+
+
+def get_instance_port(instance_id, registry_key="instance_port_map"):
+ """Return the port assigned to instance_id, assigning the next available
+ port if this instance hasn't been seen before. Raises RuntimeError when
+ the port range is exhausted."""
+ if registry_key not in st.session_state:
+ st.session_state[registry_key] = {}
+ registry = st.session_state[registry_key]
+ if instance_id not in registry:
+ next_port = PORT_RANGE_START + len(registry)
+ if next_port >= PORT_RANGE_END:
+ raise RuntimeError(
+ f"No available ports: all ports {PORT_RANGE_START}-{PORT_RANGE_END - 1} are in use."
+ )
+ registry[instance_id] = next_port
+ return registry[instance_id]
+
+
+instance_id = os.environ["COMET_PANEL_INSTANCE_ID"]
+port = get_instance_port(instance_id)
+
if "tensorboard_state" not in st.session_state:
st.session_state["tensorboard_state"] = None
@@ -35,6 +60,16 @@ class EmptyExperiment:
name = ""
+def select_experiment(experiment_list):
+ names = [exp.name for exp in experiment_list]
+ selected_idx = st.selectbox(
+ "Select Experiment with log:",
+ range(len(names)),
+ format_func=lambda i: names[i],
+ )
+ return experiment_list[selected_idx]
+
+
experiments_with_log = [EmptyExperiment()]
for experiment in experiments:
asset_list = experiment.get_asset_list("tensorflow-file")
@@ -47,14 +82,7 @@ class EmptyExperiment:
elif len(experiments_with_log) == 2:
selected_experiment = experiments_with_log[1]
else:
- names = [exp.name for exp in experiments_with_log]
- selected_experiment_name = st.selectbox(
- "Select Experiment with log:",
- names,
- )
- selected_experiment = [
- exp for exp in experiments_with_log if exp.name == selected_experiment_name
- ][0]
+ selected_experiment = select_experiment(experiments_with_log)
def wait_to_load(seconds):
@@ -152,11 +180,11 @@ def wait_for_server(port=6007, max_wait=30):
print("Can't kill the server; continuing ...")
# Wait for server to stop before starting new one
- if not wait_for_server_stop(port=6007, max_wait=10):
+ if not wait_for_server_stop(port=port, max_wait=10):
st.warning("Previous Tensorboard server may still be running")
# Start new server
- command = f"/home/stuser/.local/bin/tensorboard --logdir ./{selected_experiment.id}/logs/{selected_log} --port 6007".split()
+ command = f"/home/stuser/.local/bin/tensorboard --logdir ./{selected_experiment.id}/logs/{selected_log} --port {port}".split()
env = {} # {"PYTHONPATH": "/.local/lib/python3.9/site-packages"}
process = subprocess.Popen(command, preexec_fn=os.setsid, env=env)
st.session_state["tensorboard_state"] = (
@@ -165,12 +193,12 @@ def wait_for_server(port=6007, max_wait=30):
)
# Wait for server to be ready
- if wait_for_server(port=6007, max_wait=30):
+ if wait_for_server(port=port, max_wait=30):
path, _ = page_location["pathname"].split("/component")
url = (
page_location["origin"]
+ path
- + f"/port/6007/server?x={random.randint(1,1_000_000)}#profile"
+ + f"/port/{port}/server?x={random.randint(1,1_000_000)}#profile"
)
st.markdown(
'⛶ Open in tab'
@@ -188,7 +216,7 @@ def wait_for_server(port=6007, max_wait=30):
url = (
page_location["origin"]
+ path
- + f"/port/6007/server?x={random.randint(1,1_000_000)}#profile"
+ + f"/port/{port}/server?x={random.randint(1,1_000_000)}#profile"
)
st.markdown(
'⛶ Open in tab'
diff --git a/panels/TensorboardTorchProfilerViewer/TensorboardTorchProfilerViewer.py b/panels/TensorboardTorchProfilerViewer/TensorboardTorchProfilerViewer.py
index a8243c1..7fa4d8c 100644
--- a/panels/TensorboardTorchProfilerViewer/TensorboardTorchProfilerViewer.py
+++ b/panels/TensorboardTorchProfilerViewer/TensorboardTorchProfilerViewer.py
@@ -28,6 +28,34 @@
import requests
import socket
+# --- Per-instance port assignment (6000-6009) ---
+# All Streamlit panels share the same session_state, so this dict persists
+# across instances and can be reused by other panels that start servers.
+
+PORT_RANGE_START = 6000
+PORT_RANGE_END = 6010 # exclusive
+
+
+def get_instance_port(instance_id, registry_key="instance_port_map"):
+ """Return the port assigned to instance_id, assigning the next available
+ port if this instance hasn't been seen before. Raises RuntimeError when
+ the port range is exhausted."""
+ if registry_key not in st.session_state:
+ st.session_state[registry_key] = {}
+ registry = st.session_state[registry_key]
+ if instance_id not in registry:
+ next_port = PORT_RANGE_START + len(registry)
+ if next_port >= PORT_RANGE_END:
+ raise RuntimeError(
+ f"No available ports: all ports {PORT_RANGE_START}-{PORT_RANGE_END - 1} are in use."
+ )
+ registry[instance_id] = next_port
+ return registry[instance_id]
+
+
+instance_id = os.environ["COMET_PANEL_INSTANCE_ID"]
+port = get_instance_port(instance_id)
+
if "tensorboard_state" not in st.session_state:
st.session_state["tensorboard_state"] = None
@@ -44,6 +72,16 @@ class EmptyExperiment:
name = ""
+def select_experiment(experiment_list):
+ names = [exp.name for exp in experiment_list]
+ selected_idx = st.selectbox(
+ "Select Experiment with log:",
+ range(len(names)),
+ format_func=lambda i: names[i],
+ )
+ return experiment_list[selected_idx]
+
+
experiments_with_log = [EmptyExperiment()]
for experiment in experiments:
asset_list = experiment.get_asset_list("tensorflow-file")
@@ -56,14 +94,7 @@ class EmptyExperiment:
elif len(experiments_with_log) == 2:
selected_experiment = experiments_with_log[1]
else:
- names = [exp.name for exp in experiments_with_log]
- selected_experiment_name = st.selectbox(
- "Select Experiment with log:",
- names,
- )
- selected_experiment = [
- exp for exp in experiments_with_log if exp.name == selected_experiment_name
- ][0]
+ selected_experiment = select_experiment(experiments_with_log)
def wait_to_load(seconds):
@@ -162,11 +193,11 @@ def wait_for_server(port=6007, max_wait=30):
kill_status.warning("Can't kill the server; continuing ...")
kill_status.empty()
# Wait for server to stop before starting new one
- if not wait_for_server_stop(port=6007, max_wait=10):
+ if not wait_for_server_stop(port=port, max_wait=10):
st.warning("Previous Tensorboard server may still be running")
# Start new server
- command = f"/home/stuser/.local/bin/tensorboard --logdir ./{selected_experiment.id}/logs/{selected_log} --port 6007".split()
+ command = f"/home/stuser/.local/bin/tensorboard --logdir ./{selected_experiment.id}/logs/{selected_log} --port {port}".split()
env = {} # {"PYTHONPATH": "/.local/lib/python3.9/site-packages"}
process = subprocess.Popen(command, preexec_fn=os.setsid, env=env)
st.session_state["tensorboard_state"] = (
@@ -175,12 +206,12 @@ def wait_for_server(port=6007, max_wait=30):
)
# Wait for server to be ready
- if wait_for_server(port=6007, max_wait=30):
+ if wait_for_server(port=port, max_wait=30):
path, _ = page_location["pathname"].split("/component")
url = (
page_location["origin"]
+ path
- + f"/port/6007/server?x={random.randint(1,1_000_000)}#pytorch_profiler"
+ + f"/port/{port}/server?x={random.randint(1,1_000_000)}#pytorch_profiler"
)
st.markdown(
'⛶ Open in tab'
@@ -198,7 +229,7 @@ def wait_for_server(port=6007, max_wait=30):
url = (
page_location["origin"]
+ path
- + f"/port/6007/server?x={random.randint(1,1_000_000)}#pytorch_profiler"
+ + f"/port/{port}/server?x={random.randint(1,1_000_000)}#pytorch_profiler"
)
st.markdown(
'⛶ Open in tab'