Script de Debug para o Opcache

Script PHP para exibir um debug do Opcache.

Introdução

O Opcache é um recurso do PHP para cachear o byte-code do código interpretado de um script PHP. Para ajudar a debugar o uso do Opcache, o PHP oferece a função opcache_get_status. Neste artigo vou compartilhar um script para visualizar o debug do retorno dessa função de forma amigável.

<?php
$status = opcache_get_status(true);
$mb = 1024 * 1024;

switch ($_GET['action'] ?? null) {
    case 'invalidate_file':
        opcache_invalidate($_GET['file'], true);
        header(sprintf('Location: %s?%s', $_SERVER['PHP_SELF'], http_build_query(['sort' => $_GET['sort'] ?? 'full_path'])));
        exit(0);
        break;
    case 'reset_all':
        opcache_reset();
        header(sprintf('Location: %s?%s', $_SERVER['PHP_SELF'], http_build_query(['sort' => $_GET['sort'] ?? 'full_path'])));
        exit(0);
        break;
}

$sortOptions = [
    'full_path',
    'hits',
    'memory_consumption',
    'last_used_timestamp',
    'timestamp',
];

$sort = in_array($_GET['sort'] ?? null, $sortOptions) ? $_GET['sort'] : 'full_path';

usort($status['scripts'], fn($a, $b) => $a[$sort] <=> $b[$sort]);

?><!DOCTYPE html>
<head>
<title>Opcache Debug</title>
</head>
<body>

<div style="display: grid; grid-gap: 20px; grid-template-columns: auto auto; max-width: 1200px; margin: 10px auto;">

<div>
<table border>
<caption>php.ini</caption>
<tr><th>Config</th><th>Raw</th><th>Value</th></tr>
<?php foreach (opcache_get_configuration()['directives'] as $k => $v): ?>
    <?php
    printf(
        '<tr><th>%s</th><td>%s<td>%s</td></tr>',
        preg_replace('/^(opcache\.)/u', '<span style="color: #AAA;">\1</span>', $k),
        var_export(ini_get($k), true),
        var_export($v, true),
    );
    ?>
<?php endforeach ?>
</table>
</div>

<div>
<table border>
<caption>Debug</caption>
<tr><th colspan="2">Opcache</th></tr>
<?php
printf(
    '<tr><th>enabled</th><td>%s</td></tr><tr><th>full</th><td>%s</td></tr><tr><th>restart pending</th><td>%s</td></tr><tr><th>restart in progress</th><td>%s</td></tr>',
    var_export($status['opcache_enabled'], true),
    var_export($status['cache_full'], true),
    var_export($status['restart_pending'], true),
    var_export($status['restart_in_progress'], true),
);
?>
<tr><th colspan="2">Memory</th></tr>
<?php
printf(
    '<tr><td align="center" colspan="2"><progress value="%d" max="%d">%0.2f%%</progress> (%0.2f%%)</td></tr>',
    $status['memory_usage']['used_memory'],
    $status['memory_usage']['used_memory'] + $status['memory_usage']['free_memory'],
    $status['memory_usage']['used_memory'] * 100 / ($status['memory_usage']['used_memory'] + $status['memory_usage']['free_memory']),
    $status['memory_usage']['used_memory'] * 100 / ($status['memory_usage']['used_memory'] + $status['memory_usage']['free_memory']),
);
printf(
    '<tr><th>used</th><td>%0.2fMB</td></tr><tr><th>free</th><td>%0.2fMB</td></tr><tr><th>wasted</th><td>%0.2fMB (%0.2f%%)</td></tr>',
    $status['memory_usage']['used_memory'] / $mb,
    $status['memory_usage']['free_memory'] / $mb,
    $status['memory_usage']['wasted_memory'] / $mb,
    $status['memory_usage']['current_wasted_percentage'],
);
?>
<tr><th colspan="2">String</th></tr>
<?php
printf(
    '<tr><th>buffer</th><td>%0.2fMB</td></tr><tr><th>used</th><td>%0.2fMB</td></tr><tr><th>free</th><td>%0.2fMB</td></tr><tr><th>total</th><td>%d</td></tr>',
    $status['interned_strings_usage']['buffer_size'] / $mb,
    $status['interned_strings_usage']['used_memory'] / $mb,
    $status['interned_strings_usage']['free_memory'] / $mb,
    $status['interned_strings_usage']['number_of_strings'],
);
?>
<tr><th colspan="2">Stats</th></tr>
<?php
foreach ($status['opcache_statistics'] as $k => $v) {
    $fk = strtr($k, ['_' => ' ']);
    if (is_float($v)) {
        printf('<tr><th>%s</th><td>%0.2f</td></tr>', $fk, var_export($v, true));
    } elseif (preg_match('/_time$/', $k) && is_int($v)) {
        printf('<tr><th>%s</th><td>%s</td></tr>', $fk, date('c', $v));
    } elseif (is_int($v)) {
        printf('<tr><th>%s</th><td>%d</td></tr>', $fk, $v);
    } else {
        printf('<tr><th>%s</th><td>%s</td></tr>', $fk, var_export($v, true));
    }
}
?>
</table>
</div>

<div style="grid-column-start: 1; grid-column-end: 3;">
<table border style="width: 100%">
<caption>Scripts</caption>
<?php
printf(
    '<tr><th><a href="%s?%s">File</a></th><th><a href="%s?%s">hits</a></th><th><a href="%s?%s">mem. cons.</a></th><th><a href="%s?%s">last used</a></th><th><a href="%s?%s">created</a></th><th>options</th></tr>',
    $_SERVER['PHP_SELF'],
    http_build_query(['sort' => 'full_path']),
    $_SERVER['PHP_SELF'],
    http_build_query(['sort' => 'hits']),
    $_SERVER['PHP_SELF'],
    http_build_query(['sort' => 'memory_consumption']),
    $_SERVER['PHP_SELF'],
    http_build_query(['sort' => 'last_used_timestamp']),
    $_SERVER['PHP_SELF'],
    http_build_query(['sort' => 'timestamp']),
);
foreach ($status['scripts'] as $s) {
    printf(
        '<tr><td><small>%s</small></td><td>%d</td><td>%0.2fMB</td><td>%s</td><td>%s</td><td><a href="%s?%s">invalidate</a></td></tr>',
        $s['full_path'],
        $s['hits'],
        $s['memory_consumption'] / $mb,
        date('c', $s['last_used_timestamp']),
        $s['timestamp'] ? date('c', $s['timestamp']) : 'null',
        $_SERVER['PHP_SELF'],
        http_build_query(['action' => 'invalidate_file', 'file' => $s['full_path'], 'sort' => $sort]),
    );
}
?>
</table>
<?php
printf(
    '<p>Global options: <a href="%s?%s">reset all cache</a></p>',
    $_SERVER['PHP_SELF'],
    http_build_query(['action' => 'reset_all', 'sort' => $sort]),
);
?>
</div>

</div>
</body>
</html>

0 comentários