|
| 1 | +"""A Streamlit visualization panel for the performance_checker.py example script.""" |
| 2 | + |
| 3 | +import statistics |
| 4 | +import time |
| 5 | +import timeit |
| 6 | +from functools import partial |
| 7 | +from typing import Any, Tuple |
| 8 | + |
| 9 | +import streamlit as st |
| 10 | +from streamlit_echarts import st_echarts |
| 11 | + |
| 12 | +import nipanel |
| 13 | + |
| 14 | + |
| 15 | +def profile_get_value( |
| 16 | + panel: "nipanel.StreamlitPanelValueAccessor", |
| 17 | + value_id: str, |
| 18 | + default_value: Any = None, |
| 19 | + num_runs: int = 5, |
| 20 | +) -> Tuple[Any, float]: |
| 21 | + """Measure the time it takes to get a value from the panel. |
| 22 | +
|
| 23 | + Args: |
| 24 | + panel: The panel accessor object |
| 25 | + value_id: The ID of the value to get |
| 26 | + default_value: Default value if the value is not found |
| 27 | + num_runs: Number of runs for timing |
| 28 | +
|
| 29 | + Returns: |
| 30 | + A tuple of (value, time_ms) where time_ms is the time in milliseconds |
| 31 | + """ |
| 32 | + value = panel.get_value(value_id, default_value) |
| 33 | + get_value_func = partial(panel.get_value, value_id, default_value) |
| 34 | + time_ms = timeit.timeit(get_value_func, number=num_runs) * 1000 / num_runs |
| 35 | + return value, time_ms |
| 36 | + |
| 37 | + |
| 38 | +st.set_page_config(page_title="Performance Checker Example", page_icon="📈", layout="wide") |
| 39 | +st.title("Performance Checker Example") |
| 40 | + |
| 41 | +if "refresh_history" not in st.session_state: |
| 42 | + st.session_state.refresh_history = [] # List of tuples (timestamp, refresh_time_ms) |
| 43 | + |
| 44 | +# Store current timestamp and calculate time since last refresh |
| 45 | +current_time = time.time() |
| 46 | +if "last_refresh_time" not in st.session_state: |
| 47 | + st.session_state.last_refresh_time = current_time |
| 48 | + time_since_last_refresh = 0.0 |
| 49 | +else: |
| 50 | + time_since_last_refresh = (current_time - st.session_state.last_refresh_time) * 1000 |
| 51 | + st.session_state.last_refresh_time = current_time |
| 52 | + |
| 53 | + # Store refresh times with timestamps, keeping only the last 1 second of data |
| 54 | + st.session_state.refresh_history.append((current_time, time_since_last_refresh)) |
| 55 | + |
| 56 | + # Remove entries older than 1 second |
| 57 | + cutoff_time = current_time - 1.0 # 1 second ago |
| 58 | + st.session_state.refresh_history = [ |
| 59 | + item for item in st.session_state.refresh_history if item[0] >= cutoff_time |
| 60 | + ] |
| 61 | + |
| 62 | +# Extract just the refresh times for calculations |
| 63 | +if st.session_state.refresh_history: |
| 64 | + refresh_history = [item[1] for item in st.session_state.refresh_history] |
| 65 | +else: |
| 66 | + refresh_history = [] |
| 67 | + |
| 68 | +min_refresh_time = min(refresh_history) if refresh_history else 0 |
| 69 | +max_refresh_time = max(refresh_history) if refresh_history else 0 |
| 70 | +avg_refresh_time = statistics.mean(refresh_history) if refresh_history else 0 |
| 71 | + |
| 72 | +panel = nipanel.get_panel_accessor() |
| 73 | + |
| 74 | +num_timing_runs = 5 |
| 75 | +time_points, time_points_ms = profile_get_value(panel, "time_points", [0.0], num_timing_runs) |
| 76 | +sine_values, sine_values_ms = profile_get_value(panel, "sine_values", [0.0], num_timing_runs) |
| 77 | +amplitude, amplitude_ms = profile_get_value(panel, "amplitude", 1.0, num_timing_runs) |
| 78 | +frequency, frequency_ms = profile_get_value(panel, "frequency", 1.0, num_timing_runs) |
| 79 | +unset_value, unset_value_ms = profile_get_value(panel, "unset_value", "default", num_timing_runs) |
| 80 | + |
| 81 | +data = [{"value": [x, y]} for x, y in zip(time_points, sine_values)] |
| 82 | + |
| 83 | +options = { |
| 84 | + "animation": False, # Disable animation for smoother updates |
| 85 | + "title": {"text": "Sine Wave"}, |
| 86 | + "tooltip": {"trigger": "axis"}, |
| 87 | + "xAxis": {"type": "value", "name": "Time (s)", "nameLocation": "middle", "nameGap": 30}, |
| 88 | + "yAxis": { |
| 89 | + "type": "value", |
| 90 | + "name": "Amplitude", |
| 91 | + "nameLocation": "middle", |
| 92 | + "nameGap": 30, |
| 93 | + }, |
| 94 | + "series": [ |
| 95 | + { |
| 96 | + "data": data, |
| 97 | + "type": "line", |
| 98 | + "showSymbol": True, |
| 99 | + "smooth": True, |
| 100 | + "lineStyle": {"width": 2, "color": "#1f77b4"}, |
| 101 | + "areaStyle": {"color": "#1f77b4", "opacity": 0.3}, |
| 102 | + "name": "Sine Wave", |
| 103 | + } |
| 104 | + ], |
| 105 | +} |
| 106 | + |
| 107 | +st_echarts(options=options, height="400px", key="graph") |
| 108 | + |
| 109 | +col1, col2, col3 = st.columns(3) |
| 110 | +with col1: |
| 111 | + st.metric("Amplitude", f"{amplitude:.2f}") |
| 112 | + st.metric("Frequency", f"{frequency:.2f} Hz") |
| 113 | +with col2: |
| 114 | + st.metric("Refresh Time", f"{time_since_last_refresh:.1f} ms") |
| 115 | + st.metric("Min Refresh Time", f"{min_refresh_time:.1f} ms") |
| 116 | + st.metric("Max Refresh Time", f"{max_refresh_time:.1f} ms") |
| 117 | + st.metric("Avg Refresh Time", f"{avg_refresh_time:.1f} ms") |
| 118 | + st.metric("FPS", f"{len(refresh_history)}") |
| 119 | + |
| 120 | +with col3: |
| 121 | + st.metric("get time_points", f"{time_points_ms:.1f} ms") |
| 122 | + st.metric("get sine_values", f"{sine_values_ms:.1f} ms") |
| 123 | + st.metric("get amplitude", f"{amplitude_ms:.1f} ms") |
| 124 | + st.metric("get frequency", f"{frequency_ms:.1f} ms") |
| 125 | + st.metric("get unset_value", f"{unset_value_ms:.1f} ms") |
0 commit comments