Cada pedido carrega todo o lib/
A linha 46 do único ficheiro de entrada deste serviço:
foreach (glob(__DIR__ . '/lib/*.php') as $f) { require_once $f; }
São 65 ficheiros e 1,5 megabytes, carregados em cada pedido. Uma imagem de contador, uma página de estatísticas, um 404 — tudo igual. Ontem isso aconteceu 20.734 vezes.
O número que interessa é o pequeno
Carregar tudo do zero, com a cache de código desligada, leva cerca de 132 milissegundos. É o número que faria disto um escândalo, e não é o número que o servidor paga.
Com o código já compilado e em memória partilhada, resta listar a pasta e um stat() por ficheiro, porque a validação de datas está ligada: 0,33 milissegundos. Com o tráfego de ontem, isso dá menos de sete segundos de trabalho no dia inteiro.
Pelo meio há uma terceira medição, 18,2 milissegundos, com a cache de código a ler do disco em vez da memória. É um limite superior e não o valor verdadeiro — é o que acontece quando a cache existe mas é mais lenta do que a verdadeira. É relatada porque é o único valor a quente que se pode medir a partir da linha de comandos, e fingir o contrário seria o erro cómodo.
Portanto: isto quase não custa nada, e quase não custa nada inteiramente por causa de outra coisa. Desligue a cache de código e a mesma linha custa quatrocentas vezes mais. É uma dependência real, e é melhor saber que está lá do que descobri-la durante uma actualização.
O que há mesmo nos 1,5 megabytes
Quarenta e sete por cento — 715 kilobytes em 26 ficheiros — são famílias de modelos de contador. Desenhar uma imagem de contador precisa exactamente de uma. As outras 25 são carregadas, declaradas e nunca tocadas.
Depois: 189 kilobytes de dados de bandeiras, precisos na página dos países; 158 kilobytes de biblioteca de gráficos, precisa quando alguma coisa desenha um gráfico. Nenhum dos dois participa em servir uma imagem de contador, que é o pedido a que este serviço responde mais do que a qualquer outro.
O custo visível disso é memória e não tempo. O pico por pedido sobe uns quatro megabytes e, ao contrário do código compilado — que todos os processos partilham — essa parte paga-se por pedido, em paralelo, por cada trabalhador ao mesmo tempo.
Alguém já reparou
O glob é lib/*.php. Não desce, e mesmo por baixo estão duas pastas: lib/live/ com 229 kilobytes e lib/recht/ com 182 kilobytes. Quatrocentos kilobytes que estavam no caminho de carregamento e já não estão.
Foram movidos por serem grandes e raramente precisos: as secções de estatísticas e os textos legais. Estar uma pasta mais abaixo é o mecanismo inteiro. Não há configuração, não há carregador diferido, não há mapa de carregamento automático — um ficheiro está no glob ou não está.
Isso é uma correcção a sério e vale a pena dizê-lo, porque o passo seguinte óbvio seria um carregador automático, e um carregador automático aqui seria uma mudança grande para um problema que um mkdir já resolveu duas vezes.
Porque é que fica
Um único glob é a coisa mais simples que pode funcionar, e pela medição funciona: um terço de milissegundo, num Raspberry Pi, no caminho que tem de ser rápido. Substituí-lo por inclusões uma a uma significa que cada ficheiro novo precisa de uma linha algures, e a linha esquecida produz um erro fatal em produção em vez de um carregamento um pouco maior.
O que falta é escrever aquilo que o tornou suportável desde o início: quando um ficheiro em lib/ fica grande, muda-se para uma subpasta e é incluído onde serve. É a regra que aquelas duas pastas seguiam, e não estava escrita em lado nenhum até hoje.
A versão geral é mais aborrecida do que a medição. «Tudo carrega tudo» costuma ser a forma errada, e vale a pena saber se está a custar alguma coisa antes de reconstruir. Aqui custa 0,33 milissegundos e quatro megabytes, e os quatro megabytes são a parte a vigiar, porque crescem com a concorrência e os milissegundos não.