Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 0 additions & 159 deletions src/server/core/profiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,162 +172,3 @@ def _save_csv_async():

# LANCIO THREAD: Scrittura CSV in background
threading.Thread(target=_save_csv_async, daemon=True).start()

####--------------- SINGLE THREAD ------------------------------------------#####
# import time
# import os
# import json
# import tracemalloc
# import numpy as np
# from datetime import datetime
# import cProfile
# import pstats
# import io
# import copy

# class AdvancedProfiler:
# def __init__(self, hw_tag="Device", log_dir="logs", enable_cprofile=False):
# self.hw_tag = hw_tag
# self.enable_cprofile = enable_cprofile

# # Gestione del percorso assoluto per i log
# if not os.path.isabs(log_dir):
# base_path = os.path.abspath(os.path.join(os.getcwd(), log_dir))
# else:
# base_path = log_dir
# self.log_dir = base_path

# self.phases = {}
# self.active_phases = {}

# # Inizializza cProfile solo se richiesto (debug mode)
# self.cprofiler = cProfile.Profile() if self.enable_cprofile else None

# if not os.path.exists(self.log_dir):
# os.makedirs(self.log_dir, exist_ok=True)

# # tracemalloc consuma molta CPU/RAM: lo attiviamo solo in debug
# if self.enable_cprofile:
# tracemalloc.start()

# # ---------------------------------------------------------
# # ANALISI MICRO (cProfile) - SALVATAGGIO SINCRONO (BLOCCANTE)
# # ---------------------------------------------------------
# def start_cprofile(self):
# if self.enable_cprofile and self.cprofiler:
# self.cprofiler.enable()

# def stop_cprofile(self, filename_prefix="deep_analysis"):
# if not self.enable_cprofile or not self.cprofiler:
# return

# self.cprofiler.disable()

# # Salviamo il profiler corrente
# old_profiler = self.cprofiler

# # Creiamo e attiviamo subito un nuovo profiler
# self.cprofiler = cProfile.Profile()
# self.cprofiler.enable()

# # CHIAMATA DIRETTA (SINCRONA): Il programma si ferma qui finché il file non è scritto
# print(f"💾 [Profiler] Salvataggio sincrono cProfile in corso...")
# self._save_cprofile_sync(old_profiler, filename_prefix)

# def _save_cprofile_sync(self, profiler_instance, filename_prefix):
# """Metodo bloccante per l'I/O di cProfile."""
# timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
# base_path = os.path.join(self.log_dir, f"{filename_prefix}_{self.hw_tag}_{timestamp}")

# # Salva il file .stats (binario)
# profiler_instance.dump_stats(f"{base_path}.stats")

# # Salva il file .txt (testuale)
# s = io.StringIO()
# ps = pstats.Stats(profiler_instance, stream=s).sort_stats('cumulative')
# ps.print_stats(30)
# with open(f"{base_path}.txt", "w") as f:
# f.write(s.getvalue())

# print(f"✅ [Profiler] Analisi salvata (operazione bloccante conclusa): {base_path}.stats")

# # ---------------------------------------------------------
# # ANALISI MACRO (Fasi logiche)
# # ---------------------------------------------------------
# def start_phase(self, phase_name, trace_id):
# start_wall = time.perf_counter()
# start_cpu = time.process_time()
# start_mem = tracemalloc.get_traced_memory()[1] if self.enable_cprofile else 0

# self.active_phases[f"{phase_name}_{trace_id}"] = {
# "start_wall": start_wall, "start_cpu": start_cpu, "start_mem": start_mem
# }

# def end_phase(self, phase_name, trace_id):
# key = f"{phase_name}_{trace_id}"
# if key not in self.active_phases: return

# end_wall = time.perf_counter()
# end_cpu = time.process_time()
# peak_mem = tracemalloc.get_traced_memory()[1] if self.enable_cprofile else 0

# data = self.active_phases.pop(key)

# if phase_name not in self.phases: self.phases[phase_name] = []
# self.phases[phase_name].append({
# "wall_ms": (end_wall - data["start_wall"]) * 1000,
# "cpu_ms": (end_cpu - data["start_cpu"]) * 1000,
# "mem_kb": (peak_mem - data["start_mem"]) / 1024
# })

# # ---------------------------------------------------------
# # ESPORTAZIONE DATI (JSON e CSV) - SALVATAGGIO SINCRONO
# # ---------------------------------------------------------
# def export_json(self, filename):
# if not self.phases: return

# # In modalità single-thread deepcopy è meno critico ma utile per consistenza
# phases_snapshot = copy.deepcopy(self.phases)

# # CHIAMATA DIRETTA (SINCRONA): Il programma attende la fine della scrittura JSON
# self._save_json_sync(filename, phases_snapshot)

# def _save_json_sync(self, filename, phases_data):
# stats = {"hardware": self.hw_tag, "phases": {}}
# for name, measurements in phases_data.items():
# if measurements:
# walls = [m["wall_ms"] for m in measurements]
# cpus = [m["cpu_ms"] for m in measurements]
# mems = [m["mem_kb"] for m in measurements]

# stats["phases"][name] = {
# "count": len(measurements),
# "wall_time_ms": {"mean": round(np.mean(walls), 2), "p95": round(np.percentile(walls, 95), 2)},
# "bottleneck_analysis": {
# "cpu_time_ms_mean": round(np.mean(cpus), 2),
# "io_wait_ms_mean": round(np.mean([max(0, m["wall_ms"] - m["cpu_ms"]) for m in measurements]), 2)
# },
# "memory_analysis": {"mem_used_kb_max": round(np.max(mems), 2)}
# }

# target_path = os.path.join(self.log_dir, filename)
# try:
# with open(target_path, 'w') as f:
# json.dump(stats, f, indent=4)
# except Exception as e:
# print(f"❌ [Profiler] Errore salvataggio JSON (sincrono): {e}")

# def export_csv_raw(self, filename):
# if not self.phases: return

# target_path = os.path.join(self.log_dir, filename)
# mode = 'a' if os.path.exists(target_path) else 'w'
# try:
# with open(target_path, mode) as f:
# if mode == 'w':
# f.write("phase_name,wall_ms,cpu_ms,mem_kb\n")
# for name, measurements in self.phases.items():
# for m in measurements:
# f.write(f"{name},{m['wall_ms']:.4f},{m['cpu_ms']:.4f},{m['mem_kb']:.2f}\n")
# except Exception as e:
# print(f"❌ [Profiler] Errore salvataggio CSV (sincrono): {e}")
14 changes: 14 additions & 0 deletions tests/unit/test_profiler_source.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import re
from pathlib import Path

PROFILER_SOURCE = (
Path(__file__).resolve().parents[2] / "src" / "server" / "core" / "profiler.py"
)


def test_profiler_has_no_leftover_commented_out_class():
source = PROFILER_SOURCE.read_text()
# The single-thread AdvancedProfiler variant was fully commented out and
# left in the file as dead code; it belongs in git history, not here.
assert len(re.findall(r"^class AdvancedProfiler", source, re.MULTILINE)) == 1
assert "# class AdvancedProfiler" not in source
Loading