|
29 | 29 | document.getElementById("run-button-py").textContent = 'Run in PyScript';
|
30 | 30 | console.log('PyScript fully loaded');
|
31 | 31 | });
|
32 |
| - let pyTimerInterval = null; |
| 32 | + </script> |
| 33 | + <script> |
| 34 | + let pyTimer = null; |
33 | 35 | let pyStartTime = 0;
|
34 |
| - |
| 36 | + |
35 | 37 | function startPyTimer() {
|
36 | 38 | pyStartTime = performance.now();
|
37 | 39 | const timerElement = document.getElementById("py-timer-display");
|
38 |
| - |
39 |
| - clearInterval(pyTimerInterval); |
40 |
| - |
41 |
| - pyTimerInterval = setInterval(() => { |
42 |
| - const elapsed = (performance.now() - pyStartTime) / 1000; |
43 |
| - timerElement.textContent = `Timer: ${elapsed.toFixed(4)} s`; |
44 |
| - }, 100); |
| 40 | + |
| 41 | + // Usar requestAnimationFrame para máxima fluidez |
| 42 | + function updateTimer() { |
| 43 | + if (!pyTimer) return; |
| 44 | + |
| 45 | + const elapsedMs = performance.now() - pyStartTime; |
| 46 | + const elapsed = (elapsedMs / 1000).toFixed(3); // 3 decimales |
| 47 | + timerElement.textContent = `PyScript Timer: ${elapsed} s`; |
| 48 | + |
| 49 | + pyTimer = requestAnimationFrame(updateTimer); |
| 50 | + } |
| 51 | + |
| 52 | + cancelAnimationFrame(pyTimer); |
| 53 | + pyTimer = requestAnimationFrame(updateTimer); |
45 | 54 | }
|
46 |
| - |
| 55 | + |
47 | 56 | function stopPyTimer() {
|
48 |
| - clearInterval(pyTimerInterval); |
49 |
| - pyTimerInterval = null; |
| 57 | + cancelAnimationFrame(pyTimer); |
| 58 | + pyTimer = null; |
| 59 | + |
| 60 | + // Última actualización para precisión absoluta |
| 61 | + const elapsedMs = performance.now() - pyStartTime; |
| 62 | + const elapsed = (elapsedMs / 1000).toFixed(3); |
| 63 | + document.getElementById("py-timer-display").textContent = `PyScript Timer: ${elapsed} s`; |
50 | 64 | }
|
51 | 65 | </script>
|
52 | 66 | <script>
|
|
58 | 72 | document.getElementById("output").innerText += `PLT: ${loadTime.toFixed(2)} ms`;
|
59 | 73 | });
|
60 | 74 |
|
61 |
| - var startTimerWebAssembly; |
62 |
| - |
63 |
| - function runPyBenchmark() { |
64 |
| - startTimerWebAssembly = performance.now(); |
65 |
| - } |
66 |
| - |
67 | 75 | function clearCell(elementId) {
|
68 | 76 | const operations = ['output', 'exact'];
|
69 | 77 | operations.forEach(op => {
|
|
75 | 83 | }
|
76 | 84 | </script>
|
77 | 85 | <script>
|
| 86 | + let memoryMeasurements = {}; |
| 87 | + |
| 88 | + function measureMemory(phase) { |
| 89 | + if (performance.memory) { |
| 90 | + memoryMeasurements[phase] = { |
| 91 | + usedJSHeapSize: performance.memory.usedJSHeapSize, |
| 92 | + totalJSHeapSize: performance.memory.totalJSHeapSize, |
| 93 | + jsHeapSizeLimit: performance.memory.jsHeapSizeLimit, |
| 94 | + timestamp: performance.now() |
| 95 | + }; |
| 96 | + |
| 97 | + if (Object.keys(memoryMeasurements).length > 1) { |
| 98 | + const phases = Object.keys(memoryMeasurements); |
| 99 | + const prevPhase = phases[phases.length - 2]; |
| 100 | + const diff = memoryMeasurements[phase].usedJSHeapSize - |
| 101 | + memoryMeasurements[prevPhase].usedJSHeapSize; |
| 102 | + |
| 103 | + if (phase === 'final') { |
| 104 | + const outputDiv = document.getElementById("pyscript-output"); |
| 105 | + const memoryInMB = Math.round((diff / 1024) / 1024); |
| 106 | + outputDiv.innerHTML += `<div>Memory: ~${memoryInMB} MB</div>`; |
| 107 | + } |
| 108 | + } |
| 109 | + } else { |
| 110 | + console.warn("performance.memory API not available"); |
| 111 | + } |
| 112 | + } |
| 113 | + </script> |
| 114 | + |
| 115 | + <script> |
| 116 | + // Variables de medición interactividad |
| 117 | + let relayoutEvents = 0; |
| 118 | + let fpsMeasurements = []; |
| 119 | + let fpsInterval = null; |
| 120 | + |
| 121 | + function startFPSMeasurement(duration = 3000) { |
| 122 | + let start = performance.now(); |
| 123 | + let frames = 0; |
| 124 | + fpsMeasurements = []; |
| 125 | + |
| 126 | + function measure() { |
| 127 | + frames++; |
| 128 | + let now = performance.now(); |
| 129 | + fpsMeasurements.push(1000 / (now - start)); |
| 130 | + start = now; |
| 131 | + if (now - pyStartTime < duration) { |
| 132 | + requestAnimationFrame(measure); |
| 133 | + } else { |
| 134 | + const avgFPS = fpsMeasurements.reduce((a, b) => a + b, 0) / fpsMeasurements.length; |
| 135 | + console.log("Average FPS during interaction:", avgFPS.toFixed(2)); |
| 136 | + document.getElementById("pyscript-output").innerHTML += `<div>Average FPS: ${avgFPS.toFixed(2)}</div>`; |
| 137 | + } |
| 138 | + } |
| 139 | + requestAnimationFrame(measure); |
| 140 | + } |
| 141 | + |
| 142 | + function attachRelayoutListener(container) { |
| 143 | + container.on('plotly_relayout', function() { |
| 144 | + startFPSMeasurement(3000); |
| 145 | + relayoutEvents++; |
| 146 | + console.log("plotly_relayout event count:", relayoutEvents); |
| 147 | + }); |
| 148 | + } |
| 149 | + |
78 | 150 | function clearGraphContainer(id) {
|
79 | 151 | const container = document.getElementById(id);
|
| 152 | + // Limpieza más agresiva para Plotly |
| 153 | + if (container.data) Plotly.purge(container); |
80 | 154 | container.innerHTML = "";
|
81 | 155 | }
|
82 | 156 |
|
83 | 157 | function displayPlotPy(graph_json) {
|
84 | 158 | const container = document.getElementById("graph-container-py");
|
85 |
| - container.innerHTML = ""; |
| 159 | + |
| 160 | + // Limpiar completamente antes de renderizar |
| 161 | + clearGraphContainer("graph-container-py"); |
| 162 | + |
| 163 | + // Resetear mediciones |
| 164 | + fpsMeasurements = []; |
| 165 | + relayoutEvents = 0; |
| 166 | + |
86 | 167 | const parsed = JSON.parse(graph_json);
|
87 |
| - Plotly.newPlot(container, parsed.data, parsed.layout); |
| 168 | + Plotly.newPlot(container, parsed.data, parsed.layout).then(() => { |
| 169 | + attachRelayoutListener(container); |
| 170 | + }); |
88 | 171 | }
|
89 | 172 | </script>
|
90 | 173 | <body>
|
91 | 174 | <script type="py" src="python/main.py" config="json/pyscript-main.json"></script>
|
92 |
| - <h1>Graph Rendering Benchmark (Matplotlib/Canva)</h1> |
| 175 | + <h1>Generation of time series graphs (Plotly.py/Canva)</h1> |
93 | 176 |
|
94 | 177 | <h2 id="js-timer-display">JS Timer: 0.00 s</h2>
|
95 |
| - <h2 id="py-timer-display">Timer: 0.00 s</h2> |
| 178 | + <h2 id="py-timer-display">PyScriptTimer: 0.00 s</h2> |
96 | 179 |
|
97 | 180 | <label for="num-executions">Repeticiones:</label>
|
98 | 181 | <input type="number" id="num-executions-javascript" value="1" min="1">
|
99 | 182 | <button id="run-button-js" onclick="runJSBenchmark()">Run in JavaScript</button>
|
100 | 183 |
|
101 | 184 |
|
102 |
| - <label for="num-executions">Repeticiones:</label> |
103 |
| - <input type="number" id="num-executions-pyscript" value="1" min="1"> |
104 |
| - <button id="run-button-py" onclick="runPyBenchmark()" py-click="js_run_py_benchmark">Run in PyScript (Loading...)</button> |
| 185 | + <label for="num-series">N° Series:</label> |
| 186 | + <input type="number" id="num-series-py" value="5" min="1" max="100"> |
| 187 | + <label for="num-points">N° Puntos:</label> |
| 188 | + <input type="number" id="num-points-py" value="10000" min="1000" step="1000"> |
| 189 | + <button id="run-button-py" onclick="startPyTimer()" py-click="js_run_py_benchmark"> |
| 190 | + Run in PyScript (Loading...)</button> |
105 | 191 |
|
106 | 192 | <pre id="output"></pre>
|
107 | 193 | <div id="graph-containers" style="display: flex; flex-direction: row;">
|
|
0 commit comments