Visão geral
Atualmente, encontramos no mercado servidores, PCs desktops, notebooks, tablets, smartphones e outros computadores do gênero, com unidades de processamento que varia de 2 a até 64 núcleos! Inclusive, associamos também o conceito de que quanto mais núcleos, mais poderosa será a unidade em questão, já que ela poderá realizar bem mais cálculos, se comparada com as demais unidades baseadas na mesma arquitetura (com menos núcleos). Sem contar ainda, aqueles que possuem a tecnologia HT habilitada…
No entanto, não foi sempre assim. Desde o surgimento do processador x86 (1978) até o aparecimento das primeiras unidades dual-core (2005), as CPUs mono-nucleares eram a regra (e não a exceção). E mesmo assim, elas continuaram sobrevivendo por um bom tempo no mercado, já que as unidades multi-nucleares foram inicialmente designadas para o mercado high-end e posteriormente, foram tomando conta dos demais mercado, conforme elas foram se tornando acessíveis e ofereciam uma relação de custo vs benefício melhor.
Eis, a proposta do artigo deste mês: entender como surgiram as CPUs multi-nucleares e como evoluíram ao longo dos anos, bem como o impacto causado aos sistemas operacionais.
Um pouco de história…
Em 2005, quando as técnicas de produção (litografia) dos processadores x86 começavam a chegar na barreira dos 0.065 nanômetros, os fabricantes viram a oportunidade de acrescentarem mais transistores em suas CPUs, para aumentar o seu desempenho e dar continuidade ao processo de evolução das suas linhas de produtos. Mas na prática, não foi exatamente isto o que aconteceu: além da velocidade de clock ter estacionado na casa dos 3 GHz (qualquer ganho incremental na velocidade resultava em um aumento exponencial do consumo de energia), as complexidades técnicas eram tantas, que faria mais sentido aproveitar a possibilidade de incluir duas CPUs “modestas” ao invés de apenas uma “grande”!
Nasceu então o Pentium D, a primeira CPU dual-core desenvolvida para o mercado comercial. Contando basicamente com 2 CPUs Pentium 4 baseadas no projeto Presscott e integradas em um único envelope, ele trazia a promessa de duplicar a capacidade de processamento dos PCs desktops da época. Mas infelizmente, o ganho em termos de desempenho não dobrou, como se acreditava. O aumento oferecido pelas CPUs dual-core, se comparado com as CPUs single-core com as mesmas características, era na ordem de 20 a 50%, sem contar ainda a péssima relação custo vs benefício, já que estes produtos se situavam no topo da tabela de preços.
A “culpa” não estava apenas no novo processador, embora ele tenha a sua pequena parcela. Os softwares da época – tanto o sistema operacional, quanto os drivers, as bibliotecas, as APIs e outros tantos aplicativos – não faziam o uso eficiente da capacidade de processamento paralelo que lhes eram oferecidos. À partir de então, se iniciou uma verdadeira evolução tecnológica para promover as melhores condições possíveis, com o objetivo de maximizar a capacidade de processamento das CPUs multi-cores.
A evolução das CPUs dual-core
Apesar de ter inovado neste aspecto, as CPUs Pentium D eram basicamente duas unidades single-core “coladas com super-bonde”! elas não só eram apenas composto por 2 CPUs distintas (separadas em 2 pastilhas), como também eram interligadas através do lento, sobrecarregado e obsoleto FSB (Front Side Bus). Para que uma CPU dual-core oferecer a máxima performance, também é necessário dispor de canais de comunicação entre elas, que permitam um tráfego de dados mais veloz entre elas, além de otimizações na arquitetura que possibilitem compartilhar de forma eficiente, os recursos computacionais do sistema (memórias cache e RAM).
Dentre primeiras evoluções neste sentido, está o desenvolvimento de melhorias tecnológicas, para a concepção dos novos processadores multi-nucleares. Por exemplo, embora a AMD também tenha utilizado as suas já conhecidas CPUs single-core para formar novas CPUs dual-core, o Athlon64 X2 diferenciou-se da Intel por optar em integrá-las em uma mesma pastilha de silício, além de interligá-las através do barramento HT (HyperTransport). Para variar, as unidades da AMD já possuíam o controlador de memória embutido na CPU, ao passo que as unidades da Intel o controlador se situava no chipset ponte-norte, o que degradava ainda mais o desempenho de suas CPUs dual-core. Por fim, as arquiteturas as quais eram baseadas os antigos Pentium 4 (e posteriormente, o D) eram extremamente ineficientes em vista do longo pipeline (até 31 estágios).
Por isso, a AMD estava a um passo à frente da Intel, oferecendo uma solução bem mais elegante, com melhores otimizações e dotada de melhor performance! Obviamente, o Pentium D era apenas um solução provisória para a Intel, que por sua vez iria lançar uma nova arquitetura moderna e escalável: surgiu então o CoreDuo, sendo logo seguido pelos Core2Duo. Este último, foi um processador concebido originalmente para ser bi-nuclear (mas agora, com CPUs dual-core “nativas” ao invés de CPUs single-core “coladas”). No entanto, o FSB ainda foi mantido (afetando especialmente para as unidades Core2Quad, compostas por duas pastilhas dual-core interligadas pelo FSB). Apesar desta também não ser uma solução lá muito elegante, o Core2Duo mostrou-se até eficiente, graças aos avanços proporcionados pela arquitetura Core (e o controlador de memória integrado), que por sua vez era baseada no bom e velho Pentium 3/M, que por sua vez eram muito mais eficientes que o Pentium 4.
À partir daí, os processadores multi-nucleares começavam a se popularizarem. Enquanto que a linha Athlon64 X2 era oferecida a preços bastantes acessíveis, a Intel aproveitou a oportunidade para lançar diferentes linhas de produtos: os primeiros Pentium da série “E” (dotados de núcleos Core) possuíam quantidades de memória cache reduzida, ao mesmo tempo que operavam em frequências mais baixas e eram as CPUs dual-cores mais baratas (estabelecendo o fim da era das CPUs mono-nucleares). Enquanto isso, os Core2Duo da série “E” ocupavam a linha intermediária, oferecendo mais memória cache. Por fim, a linha avançada eram ocupadas pelos Core2Extreme e Core2Quad, os quais ofereciam de 2 a 4 núcleos, muita memória cache e altas frequências. No geral, a Intel possuía CPUs com arquiteturas mais poderosas, ao passo que a AMD era dotada de CPUs com design multi-nuclear mais eficiente, o que acabou equilibrando a disputa até certo ponto.
A chegada das CPUs quad-core
Três anos depois, a Intel inaugura a sua nova linha de processadores Core, baseadas no projeto Nehalem, que por sua vez viria dar a vida para as CPUs comerciais Core i3, Core i5 e Core i7. Esta última, se destaca por ser a primeira CPU quad-core “nativa” disponível no mercado e oferecia uma série de melhorias e otimizações, se comparada ao antigo Core2Quad. Destaque para o Intel QuickPath, uma interconexão de alta velocidade ponto-a-ponto e designada para substituir o famigerado FSB, além de outras pequenas melhorias. Quanto a memória RAM, o Core i7 também foi agraciado com 3 canais de acesso, possibilitando utilizar até 6 módulos de memória e aumentar o fluxo de dados, para servir as 4 CPUs integradas em seu die. Mas infelizmente, as novas gerações Intel Core retornaram com o suporte a apenas 2 canais de memória, compensando-os com o aumento da quantidade de memória cache.
Obviamente, a AMD não ficou a trás e também ofereceu na mesma época, as suas soluções de processadores dual, tri e quad-core Phenom, baseadas na nova arquitetura Barcelona. Tal como os novos Core i7 Nehalem, o Phenom X4 utilizava um novo soquete AM2+, que por sua vez oferecia compatibilidade ao barramento HyperTransport 3.0, entregando até 4 GT/s em transferência de dados. No entanto, tais melhorias e otimizações não foram suficientes para fazer frente aos produtos da Intel, que além de oferecer uma arquitetura de processadores bem mais poderosa, já contava com as otimizações de hardware necessárias para obter maior desempenho e eficiência em sistemas multi-nucleares. Desde então, a Intel liderou com folga por alguns bons anos o mercado de CPUs, sendo ameaçada apenas após o surgimento da linha de processadores AMD Ryzen.
O design híbrido big.LITTLE
Enquanto que a Intel e a AMD duelavam em vários segmentos do mercado de processadores x86, a ARM Holdings já estava consolidada no mercado de dispositivos móveis, graças a sua eficiente arquitetura ARM Cortex. Apesar de equipar dispositivos que exigem um baixo consumo de energia, a linha Cortex tinha como premissa oferecer uma boa performance para estes dispositivos, equilibrando os pilares PPA (Power, Performance and Area). Por isto, não demorou muito para a empresa britânica projetar designs de SoCs, dotados de CPUs dual e quad-core. Surgiram então (2009), as primeiras CPUs ARM Cortex-A9, baseadas no suporte a aplicações de 32 bits e dotadas de unidades dual e quad-core! Tempos depois, surgiram outras unidades como os Cortex A12 e A15, além das variantes de baixo consumo como os Cortex A5 e A7.
No entanto, foi a partir das unidades Cortex das séries A5x e A7x (com suporte a aplicações de 64 bits), que a AMD inovou ao trazer o suporte a um design inédito chamado big.LITTLE, o qual basicamente consiste na combinação de núcleos de alta performance com núcleos de baixo consumo em um único SoC! Esta solução surgiu em vista da necessidade dos dispositivos móveis alternarem com frequência, entre a execução de aplicações pesadas (full) e o retorno a estados de baixo consumo (idle), pois nestes cenários, tanto as CPUs de alta performance quanto as de baixo consumo deixam a desejar. Por isso, a adoção de ambas as CPUs vieram para contornar este problema, bastando apenas o sistema operacional realizar a gestão dos recursos, alocando os processos de acordo com a CPU ideal para a tarefa em questão.
O impacto dos sistemas operacionais
Com o avento as unidades multi-nucleares, uma série de mudanças começaram a aparecer neste novo cenário. Neles, os sistemas operacionais foram os principais elementos que sentiram o impacto das destas mudanças. O Windows XP, apesar de ser um sistema operacional leve, funcional e muito popular, não havia sido projetado originalmente para tirar proveito das CPUs multi-nucleares, embora a edição Professional tenha o suporte a sistemas com duas CPUs físicas (dual-sockets). Sobro para os sucessores do Windows XP, a tarefa de mostrar boa performance e desempenho em sistemas dotados de CPUs multi-nucleares, além de oferecer também suporte para as extensões de 64 bits!
Os sistemas operacionais modernos possuem um componente chamado agendador de tarefas (schedule). Este por sua vez, é o responsável por gerenciar as instâncias de processo que estão ativas, concorrendo entre si para fazer o uso dos recursos do sistema. Cabe ao agendador de tarefas designar uma fila e definir as prioridades de cada processo, de forma que apenas um por vez receba a atenção das CPUs e tenha as suas instruções executadas por ela. Até então, como as CPUs antigas eram dotadas de um único núcleo, podemos até dizer que as tarefas designadas para o agendador de tarefas eram relativamente “tranquilas”, embora ainda tenha que lidar com as complexidades inerentes do hardware e as suas interrupções.
Antes mesmo da chegada das CPUs dual-core, a Intel já havia disponibilizado uma tecnologia chamada Hyper Threading (ou simplesmente HT), a qual duplicava alguns circuitos dos processadores, para criar uma “ilusão” de que o sistema é equipado com uma unidade dual-core. Na prática, ele apenas terá a competência e processar duas threads de um processo ao mesmo tempo, apesar de ainda ser limitado a processar uma única tarefa por vez. No entanto, esta capacidade deverá ser suportada tanto pelo software (o que nem sempre acontece para aplicações mais antigas), quanto pelo agendador de tarefas, que por sua vez pode definir quais threads poderão ser executadas naquele instante.
A partir das CPUs multi-nucleares, o agendador de tarefas passou a receber uma atenção especial por parte dos desenvolvedores. Além de ter que realizar o gerenciamento de processos entre núcleos diferentes e balancear a carga entre eles, este componente também passou a ter que lidar com as diferenças em relação ao design dos processadores de diferentes fabricantes. Por exemplo, a Intel utilizavam um barramento lento para a interconexão entre as CPUs, além de dispor de memória cache L2 dedicada para cada CPU e o controlador de memória separado (no chipset), o que tornava mais complexa a gestão dos processos pelo agendador de tarefas. A escalabilidade e o multiprocessamento eram bastante afetados, impossibilitando o sistema de oferecer a melhor performance possível, mesmo com a disponibilidade de duas CPUs.
Estes problemas começaram a aparecer já a partir do Windows Vista (2006), apesar dele incorporar alguns avanços no que concerne a operar sob hardwares dotados de CPUs multi-nucleares. Se por um lado o sistema passou a funcionar melhor que o antigo Windows XP (escalando processos de forma mais eficiente), por outro ele teve muitas dificuldades em utilizar com mais eficiência, o processamento extra oferecido pela disponibilidade de mais de um núcleo. Por isso, os ganhos de performance geralmente era limitados a 20~50%, se comparado com os sistemas baseados em CPUs mono-core. E se não bastasse a falta de otimizações do sistema (muito pesado e consumidor voraz de recursos de hardware), muitas das aplicações também foram concebidas para rodar originalmente no Windows XP, em hardwares dotados de CPUs mono-nuclear. As coisas começaram a melhor mesmo somente a partir do Windows 7 (2009), que por sua vez trouxe diversas melhorias em relação ao suporte a CPUs multi-nucleares (que por sua vez passaram a ser mais comuns).
Quanto ao Linux, a situação foi bem diferente: com o suporte a multi-processamento já bem estabelecido desde tempos antigos (2.0, 1996), o kernel passou a mostrar mais flexibilidade na gestão de sistemas multi-processados a partir da versão 2.6, com destaque para o Completely Fair Scheduler (CFS). O CFS recebeu várias melhorias de código, em prol das CPUs multi-nucleares de diferentes fabricantes. Dada a sua natureza modular e flexível, o scheduler faz o uso de diferentes classes e políticas de escalonamento, possibilitando customizar o seu modo de funcionamento para diferentes tipos de processadores, extraindo o máximo em termos de performance. Por exemplo, ele permite agrupar processos-filhos juntamente com o processo-pai em uma mesma fila e vinculadas na mesma sessão, otimizando o tempo de resposta (latência) em sistemas multi-core e multi-CPU (SMP) quando eles estavam realizando outras tarefas que usam muitos Threads intensivos de CPU nessas tarefas.
Em tempo: recomendo o artigo “The Linux Scheduler: a Decade of Wasted Coresc”.
O que esperar do futuro?
Na minha opinião, o próximo estágio para a evolução das CPUs multi-nucleares, será a adoção de unidades dotadas núcleos heterogêneos não limitados a execuçar tarefas focadas em performance ou eficiência energética (tal como acontece atualmente com o design big.LITTLE), mas sim designados para a execução de tarefas específicas. Há tempos, defendo o conceito de uma 3a. CPU chamada HUB, otimizada exclusivamente para a execução de processos exclusivos do sistema operacional, provendo-lhe suporte para a gestão dos recursos disponibilizados pelo equipamento. Este por sua vez, pode operar com ênfase na eficiência (para os dispositivos móveis em geral), alta performance (para os PCs desktops e estações de alta performance) ou ainda, adotar um modo híbrido.
A partir de então, veremos o surgimento de unidades dedicadas exclusivamente para executar funções específicas. Por exemplo, a Inteligência Artificial e o Aprendizado de Máquinas já estão recebendo a devida atenção por parte de empresas como a Intel, a ARM e a nVidia, as quais já designam instruções e transistores extras em suas unidades, para otimizar o processamento de instruções com bases nestas tecnologias. Além disso, há tempos que as tecnologias voltadas para a segurança estão sendo implementadas a nível de hardware (como a criptografia e a detecção de ameaças), as quais certamente serão agraciadas com unidades computacionais à parte, preparadas especialmente para trabalhar em conjunto com os softwares de segurança disponíveis no mercado. Por fim, também veremos cada vez mais os IGPs sendo integrados ao SoC, auxiliando no processamento de cálculos matemáticos avançados (além do suporte para a criptografia e inteligência artifical), culminando de vez com o “fim” das CPUs para o “domínio” das APUs (embora bem “diferente” dos designs originais que conhecemos).
Quem viver (até lá), verá… &;-D
Referências
- “ARM big.LITTLE”, por Wikipedia.
- “Linux Kernel”, por Wikipedia.
- “Multi-core processor”, por Wikipedia.
- “The Linux Scheduler: a Decade of Wasted Cores”.
- “x86”, por Wikipedia.