V2 : optimisation API (cache, index, vue materialisee)
- BDD (migrations 1.6.0 + 1.7.0, idempotentes) :
* 4 nouveaux index composites sur reactevents, triggerevents, sessions
* vue sessiondebriefs reecrite (sous-requetes correlees -> JOINs)
puis materialisee dans table session_debriefs_cache via procedure
stockee rebuild_debrief_cache, recalculee uniquement aux changements
* fix bug double JOIN participates : TargetRole = "IA" pour les hits
NPC/objets (au lieu d'un role aleatoire de participant)
- API PHP :
* connexion PDO en singleton + ATTR_PERSISTENT
* cache disque par session (cache/sess_<id>/) pour debrief, get, userhistory
avec invalidation ciblee sur events et lifecycle
* pagination opt-in (limit/offset) sur lists/sessions_for_user
* helpers ensure_/rebuild_/invalidate_session_debrief_cache_db
* debug/benchmark.php pour mesurer la latence des 6 endpoints cles
- Endpoints HTTP : signatures inchangees, compat Unreal preservee
- Gain mesure : -58% a -83% sur les 5 endpoints cles
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
106
ProserveAPI/htdocs/proserve/debug/benchmark.php
Normal file
106
ProserveAPI/htdocs/proserve/debug/benchmark.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
// Mesure de latence des endpoints lourds de l'API ProserveAPI.
|
||||
// A lancer AVANT et APRES chaque palier d'optimisation pour avoir des chiffres comparatifs.
|
||||
// Usage : POST sur ce fichier avec optionnellement userId et sessionId.
|
||||
// curl -X POST -d "userId=1&sessionId=42" http://localhost/proserve/debug/benchmark.php
|
||||
// ou ouvrir directement dans le navigateur (lance avec userId=-1 et sessionId=-1, certains endpoints retourneront vide mais la mesure du round-trip reste valide).
|
||||
|
||||
include_once '../config/init.php';
|
||||
|
||||
$userId = isset($_POST['userId']) ? intval($_POST['userId']) : (isset($_GET['userId']) ? intval($_GET['userId']) : -1);
|
||||
$sessionId = isset($_POST['sessionId']) ? intval($_POST['sessionId']) : (isset($_GET['sessionId']) ? intval($_GET['sessionId']) : -1);
|
||||
$iterations = isset($_POST['iterations']) ? max(1, intval($_POST['iterations'])) : (isset($_GET['iterations']) ? max(1, intval($_GET['iterations'])) : 5);
|
||||
|
||||
// si pas de sessionId fourni, prendre la plus recente pour avoir des donnees realistes
|
||||
if ($sessionId <= 0) {
|
||||
$stmt = $db->query("SELECT id FROM sessions ORDER BY id DESC LIMIT 1");
|
||||
$row = $stmt ? $stmt->fetch(PDO::FETCH_ASSOC) : null;
|
||||
if ($row) $sessionId = intval($row['id']);
|
||||
}
|
||||
if ($userId <= 0) {
|
||||
$stmt = $db->query("SELECT userId FROM participates WHERE sessionId=" . intval($sessionId) . " LIMIT 1");
|
||||
$row = $stmt ? $stmt->fetch(PDO::FETCH_ASSOC) : null;
|
||||
if ($row) $userId = intval($row['userId']);
|
||||
}
|
||||
|
||||
// resolution de l'URL de base (meme host et meme path)
|
||||
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
||||
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
|
||||
$base = $scheme . '://' . $host . rtrim(dirname(dirname($_SERVER['SCRIPT_NAME'])), '/\\');
|
||||
|
||||
$endpoints = [
|
||||
'session/debrief' => ['sessionId' => $sessionId, 'userId' => $userId],
|
||||
'session/get' => ['sessionId' => $sessionId],
|
||||
'stats/userhistory' => ['userId' => $userId, 'sessionId' => $sessionId, 'quickMode' => 'false'],
|
||||
'stats/get' => ['userId' => $userId, 'sessionId' => $sessionId],
|
||||
'lists/sessions_for_user' => ['userId' => $userId],
|
||||
'lists/users_in_session' => ['sessionId' => $sessionId],
|
||||
];
|
||||
|
||||
function call_endpoint($url, $params)
|
||||
{
|
||||
// ext-curl est dispo dans XAMPP par defaut et bcp plus rapide que
|
||||
// file_get_contents+stream_context_create sur Windows (qui ajoute ~10ms par appel).
|
||||
static $ch = null;
|
||||
if ($ch === null) {
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_TIMEOUT => 60,
|
||||
CURLOPT_FORBID_REUSE => false,
|
||||
CURLOPT_FRESH_CONNECT => false,
|
||||
]);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
|
||||
|
||||
$start = microtime(true);
|
||||
$resp = curl_exec($ch);
|
||||
$elapsed_ms = (microtime(true) - $start) * 1000;
|
||||
$err = curl_errno($ch);
|
||||
|
||||
return [
|
||||
'ms' => round($elapsed_ms, 2),
|
||||
'bytes' => $resp === false ? 0 : strlen($resp),
|
||||
'ok' => $err === 0 && $resp !== false,
|
||||
];
|
||||
}
|
||||
|
||||
function summarize($samples)
|
||||
{
|
||||
$times = array_column($samples, 'ms');
|
||||
sort($times);
|
||||
$n = count($times);
|
||||
return [
|
||||
'min' => $times[0],
|
||||
'max' => $times[$n - 1],
|
||||
'median' => $times[intval($n / 2)],
|
||||
'avg' => round(array_sum($times) / $n, 2),
|
||||
'bytes' => $samples[0]['bytes'],
|
||||
'ok' => count(array_filter(array_column($samples, 'ok'))) === $n,
|
||||
];
|
||||
}
|
||||
|
||||
$results = [
|
||||
'context' => [
|
||||
'userId' => $userId,
|
||||
'sessionId' => $sessionId,
|
||||
'iterations' => $iterations,
|
||||
'base_url' => $base,
|
||||
'timestamp' => date('c'),
|
||||
],
|
||||
'endpoints' => [],
|
||||
];
|
||||
|
||||
foreach ($endpoints as $path => $params) {
|
||||
$url = $base . '/' . $path . '.php';
|
||||
$samples = [];
|
||||
for ($i = 0; $i < $iterations; $i++) {
|
||||
$samples[] = call_endpoint($url, $params);
|
||||
}
|
||||
$results['endpoints'][$path] = summarize($samples);
|
||||
}
|
||||
|
||||
print_r(json_encode($results, JSON_PRETTY_PRINT));
|
||||
?>
|
||||
Reference in New Issue
Block a user