Ir para o conteúdo

Multithreading (arquitetura de computadores)

Origem: Wikipédia, a enciclopédia livre.
(Redirecionado de Multithreading simultâneo)
Um processo com duas threads de execução, executado num único processador. A thread 1 é executada primeiro, inicia a thread 2 e aguarda uma resposta. Quando a thread 2 termina, sinaliza à thread 1 que retome a execução até o fim, e então termina.
Um processo com duas threads de execução, executado num único processador.

Em arquitetura de computadores, multithreading é a capacidade de uma unidade central de processamento (CPU), ou de um único núcleo num processador multinúcleo, de executar várias threads de execução. Um processador multithread consegue manter duas ou mais threads ao mesmo tempo no seu pipeline, em geral com o contexto de cada uma num conjunto separado de registradores, e os intervalos deixados pelas latências de uma thread são preenchidos com instruções de outras.[1]:p. 29–30 Há três técnicas principais: o multithreading bloqueado (de grão grosso), o multithreading intercalado (de grão fino) e o multithreading simultâneo (SMT).[1]:p. 33–34 e 38

Visão geral

[editar | editar código]

O paradigma do multithreading ganhou importância à medida que ficou mais difícil acelerar os processadores explorando o paralelismo em nível de instrução: os fluxos de instruções típicos têm pouco paralelismo utilizável, e processadores superescalares capazes de emitir mais de cerca de quatro instruções por ciclo obtêm pouquíssimo ganho adicional na maioria das aplicações.[2][1]:p. 30 A computação voltada para a vazão (throughput computing) tornou-se a primeira área em que os chips com vários processadores tiveram impacto: as cargas de trabalho típicas de servidores têm muito pouco paralelismo em nível de instrução e muitas paradas à espera da memória, mas um servidor costuma ter dezenas ou centenas de pedidos em andamento ao mesmo tempo.[2] Embora seja cada vez mais difícil acelerar uma única thread, muitas dessas aplicações já têm grande número de threads independentes.[2] Assim, técnicas que melhoram a vazão do conjunto das tarefas resultam em ganhos gerais de desempenho: os processadores multithread explícitos otimizam a vazão de cargas de trabalho multiprogramadas ou multithread, e não o desempenho de uma única thread.[1]:p. 29 e 49

Duas grandes técnicas para a computação voltada para a vazão são o multithreading e o multiprocessamento, este último na forma de vários núcleos num mesmo chip; as duas podem ser combinadas, com várias threads em cada núcleo.[2][1]:p. 34

Vantagens

[editar | editar código]

Se uma thread sofre muitas falhas de cache, as outras threads podem continuar aproveitando os recursos computacionais não utilizados, o que pode levar a uma execução global mais rápida, já que esses recursos ficariam ociosos se apenas uma thread estivesse em execução.[1]:p. 29–30[2] Segundo a documentação da IBM, o multithreading simultâneo beneficia sobretudo ambientes comerciais em que importa mais o número total de transações do que a velocidade de cada uma, e cargas de trabalho com muitos ciclos por instrução, em geral causados por muitas falhas de cache; ele funciona melhor justamente quando o desempenho da cache é pior, e em cargas comerciais foram medidos ganhos de vazão de 25% a 40%.[3]

Além disso, se uma thread não consegue usar todos os recursos computacionais da CPU (porque as suas instruções dependem dos resultados umas das outras), executar outra thread pode evitar que esses recursos fiquem ociosos.[4]:p. 392–393[1]:p. 34 e 49

Desvantagens

[editar | editar código]

Várias threads podem interferir umas nas outras ao compartilhar recursos de hardware, como as caches: num núcleo com multithreading simultâneo, as threads compartilham quase todos os recursos do núcleo, o que causa interferência de desempenho entre elas, e algumas combinações de aplicações podem até reduzir a vazão total, por exemplo por disputa de cache.[5]:seç. 1–2 Em consequência, cada thread tende a ter latência um pouco maior quando todas estão ativas e competem pelo núcleo,[2] e o desempenho de uma thread é melhor quando a sua thread parceira está ociosa.[3] No multithreading intercalado, o desempenho de uma thread isolada é degradado,[1]:p. 35 ao passo que, no Hyper-Threading, uma única thread ativa deve ser executada à mesma velocidade que num processador sem essa tecnologia.[1]:p. 57 O hardware também fica mais complexo: o multithreading simultâneo pode complicar o estágio de emissão de instruções,[1]:p. 50 e ativá-lo aumenta a área e o consumo de energia de um núcleo em 5% a 20%.[5]:seç. 2

A eficiência global varia conforme a carga de trabalho. Segundo a IBM, cargas de trabalho intensivas em vírgula flutuante tendem a ganhar pouco com o multithreading simultâneo e são as que mais provavelmente perdem desempenho.[3] Na Intel, a tecnologia Hyper-threading acrescentou menos de 5% à área do chip e à potência máxima, e os primeiros testes mostraram ganhos de até 65% em aplicações de servidor de alto desempenho em relação ao Pentium III Xeon, em parte significativa graças a ela.[1]:p. 58

Ao contrário dos processadores convencionais, que dependem de espera ativa ou de uma troca de contexto demorada feita pelo sistema operativo, o processador multithread troca de thread automaticamente, por hardware, com custo de zero a poucos ciclos.[1]:p. 30–31 No Hyper-Threading, cada processador lógico mantém um conjunto completo do estado arquitetural, de modo que um processador físico aparece como dois processadores lógicos.[1]:p. 56 O escalonamento também é importante: escolher quais aplicações executar juntas num mesmo núcleo com multithreading simultâneo pode ter impacto considerável no desempenho.[5]:resumo e seç. 1

O tipo mais simples de multithreading ocorre quando uma thread é executada até ser bloqueada por um evento que pode causar uma parada de longa latência, como uma falha de cache, que exige um acesso demorado à memória. Esse evento provoca uma troca de contexto: em vez de esperar que a parada se resolva, o processador passa a executar outra thread. A thread original pode ser retomada quando a causa do bloqueio desaparece.[1]:p. 30 e 32–33

Por exemplo (num esquema semelhante aos diagramas de ocupação dos slots de emissão de Ungerer et al.):[1]:p. 34–35, figs. 2–3

  1. Ciclo i: é emitida a instrução j da thread A.
  2. Ciclo i + 1: é emitida a instrução j + 1 da thread A.
  3. Ciclo i + 2: é emitida a instrução j + 2 da thread A, uma instrução de carga que falha em todas as caches.
  4. Ciclo i + 3: o processador troca para a thread B.
  5. Ciclo i + 4: é emitida a instrução k da thread B.
  6. Ciclo i + 5: é emitida a instrução k + 1 da thread B.

Esse tipo de multithreading é conhecido como multithreading bloqueado (blocked multithreading) ou, às vezes, de grão grosso (coarse-grain). Em geral, a troca ocorre quando a execução chega a uma operação de longa latência; por isso, são necessárias menos threads que no multithreading intercalado, e uma thread isolada pode ser executada à velocidade máxima até a próxima troca. Se só uma thread estiver em execução, não há trocas, e o processador funciona como um processador comum, sem multithreading.[1]:p. 38 Exemplos comerciais são o IBM RS64 IV, usado em servidores comerciais, que adota duas threads com troca nas falhas de cache, por ter sido otimizado para cargas de trabalho como processamento de transações em linha, sistemas de gestão empresarial e serviços Web, e o Sun MAJC-5200, um chip com dois processadores de multithreading bloqueado.[1]:p. 40 e 47–48

O suporte de hardware ao multithreading deve permitir a troca rápida entre uma thread bloqueada e outra pronta para execução. Para isso, o processador precisa de dois ou mais contadores de programa independentes, de um mecanismo interno de marcação que distinga as instruções das diferentes threads no pipeline e de um mecanismo que dispare a troca de thread; com frequência, embora nem sempre, tem também vários conjuntos de registradores no chip — por exemplo, dois conjuntos para alternar rapidamente entre duas threads.[1]:p. 30 O custo da troca deve ser muito baixo, de zero a poucos ciclos; no multithreading bloqueado, pode chegar a vários ciclos.[1]:p. 30 e 34

Multithreading de grão fino

[editar | editar código]

No multithreading de grão fino, o processador troca de thread depois de cada busca de instrução, isto é, a cada ciclo, e a troca não tem custo.[1]:p. 33–35 Em princípio, uma instrução de uma thread só entra no pipeline depois que a instrução anterior da mesma thread foi concluída; por isso, deixam de existir dependências de controle e de dados entre as instruções no pipeline, não surgem conflitos (hazards) e não são necessários caminhos de encaminhamento (forwarding) de resultados, o que permite um pipeline simples e rápido. A latência da memória é tolerada não escalonando uma thread até que o seu acesso à memória termine.[1]:p. 35

Por exemplo (num esquema semelhante aos diagramas de Ungerer et al.):[1]:p. 34–35, figs. 2–3

  1. Ciclo i + 1: é emitida uma instrução da thread B.
  2. Ciclo i + 2: é emitida uma instrução da thread C.

Esse tipo também é chamado de multithreading intercalado (interleaved multithreading).[1]:p. 33–34 O modelo exige pelo menos tantas threads quanto os estágios do pipeline, e intercalar as instruções de muitas threads limita a capacidade de processamento disponível para cada uma, degradando o desempenho de uma thread isolada.[1]:p. 35 Os exemplos mais conhecidos são os processadores dos multiprocessadores HEP, projetado por Burton Smith e desenvolvido pela Denelcor entre 1978 e 1985, Horizon e Cray MTA, que admitem até 128 threads por processador.[1]:p. 36 e 45 A arquitetura multithread da Cray teve continuidade no Eldorado, a sua terceira geração, depois do MTA-1 (construído pela Tera Computer Company) e do MTA-2: o seu processador é semelhante ao do MTA-2 e, quando a thread em execução precisa esperar por uma operação de memória ou por um evento de sincronização, passa a executar outra thread.[6]

Como instruções de várias threads ficam ao mesmo tempo no pipeline, cada instrução precisa ser marcada com a identificação da sua thread, o que é um requisito de todo processador multithread.[1]:p. 30

Multithreading simultâneo

[editar | editar código]

O tipo mais avançado de multithreading aplica-se a processadores superescalares. Enquanto um processador superescalar comum emite várias instruções de uma única thread a cada ciclo, no multithreading simultâneo (SMT) um processador superescalar pode emitir instruções de várias threads a cada ciclo. Como cada thread isolada tem uma quantidade limitada de paralelismo em nível de instrução, esse tipo de multithreading procura explorar o paralelismo disponível entre várias threads para reduzir o desperdício associado aos slots de emissão não utilizados.[4]:p. 392–393[1]:p. 29 e 33 Nas simulações de Tullsen, Eggers e Levy, o SMT mostrou potencial para atingir quatro vezes a vazão de um processador superescalar e o dobro da vazão do multithreading de grão fino.[4]:p. 392

Por exemplo (num esquema semelhante aos diagramas de Ungerer et al.):[1]:p. 34–35, fig. 4

  1. Ciclo i: são emitidas simultaneamente as instruções j e j + 1 da thread A e a instrução k da thread B.
  2. Ciclo i + 1: são emitidas simultaneamente a instrução j + 2 da thread A, a instrução k + 1 da thread B e a instrução m da thread C.
  3. Ciclo i + 2: são emitidas simultaneamente a instrução j + 3 da thread A e as instruções m + 1 e m + 2 da thread C.

No SMT, todos os contextos de thread ficam ativos ao mesmo tempo e competem a cada ciclo por todos os recursos disponíveis, o que permite preencher tanto os ciclos ociosos quanto os slots de emissão não utilizados dentro de um ciclo.[1]:p. 49 Quando os recursos são compartilhados entre as threads, o que o SMT acrescenta a um superescalar convencional é a marcação de cada instrução interna com o identificador da sua thread, vários conjuntos de registradores e a capacidade das unidades de busca e de conclusão de tratar instruções de threads diferentes; o resultado é um hardware um pouco mais complexo.[1]:p. 49

Entre as implementações de SMT, estão:

  • o Alpha 21464 (EV8), apresentado pela Compaq em 1999, um projeto de SMT com quatro threads e oito instruções emitidas por ciclo, previsto para 2003 e abandonado quando a Compaq vendeu a tecnologia dos processadores Alpha à Intel;[1]:p. 56
  • a tecnologia Hyper-threading da Intel, um SMT de duas threads proposto para a família de processadores Xeon baseada no Pentium 4;[1]:p. 56
  • os processadores POWER5 e POWER6, da IBM, com SMT de duas threads em cada núcleo,[7][8] o POWER7, com SMT de quatro threads por núcleo,[9] e o POWER8, que admite os modos SMT2, SMT4 e SMT8;[5]:seç. 1
  • o microprocessador z13, dos mainframes IBM z Systems, com SMT de duas threads.[10]

Outros processadores adotam formas diferentes de multithreading: o UltraSPARC T2, da Sun Microsystems, tem oito núcleos de oito threads cada, num total de 64 threads,[11] e a microarquitetura Bulldozer, da AMD, adota uma abordagem própria de multithreading.[12]

Detalhes de implementação

[editar | editar código]

Uma área importante é o escalonamento das threads. Num processador com multithreading simultâneo, os núcleos compartilham a maior parte dos componentes da microarquitetura entre as aplicações em execução, o que causa interferência de desempenho entre elas; por isso, escalonar juntas aplicações com necessidades de recursos complementares pode melhorar muito a vazão do sistema.[5]:resumo O hardware também pode participar: no POWER5, o hardware aplica prioridades de thread definidas pelo software e faz um balanceamento dinâmico de recursos para que cada thread receba uma parte justa deles,[7] e, nos processadores POWER usados com o AIX, a diferença de prioridade entre threads irmãs determina a proporção dos slots de decodificação atribuídos a cada uma.[3]

Outra questão é que tipo de evento deve causar uma troca de thread no multithreading bloqueado. Nos modelos estáticos, a troca é codificada pelo compilador e ocorre sempre que uma dada instrução é executada — uma instrução explícita de troca ou, implicitamente, instruções de certas classes, como as de carga, de armazenamento ou de desvio. Nos modelos dinâmicos, a troca é provocada por um evento dinâmico, e as instruções que já entraram no pipeline depois dele precisam ser descartadas, o que aumenta o custo da troca; os eventos podem ser uma falha de cache, um sinal (como uma interrupção, uma exceção do tipo trap ou a chegada de uma mensagem), o uso de um valor de carga ainda não disponível ou uma instrução de troca condicional.[1]:p. 38–39

Uma terceira escolha de projeto é como organizar os recursos de um processador SMT: compartilhá-los entre as threads, o que acrescenta pouca complexidade a um superescalar convencional, ou replicar os seus buffers internos para cada thread, o que exige mais mudanças na organização do processador, mas simplifica os estágios de emissão e de conclusão. A principal desvantagem do SMT talvez seja complicar o estágio de emissão, que é central para todas as threads.[1]:p. 49–50

Ver também

[editar | editar código]

Referências

[editar | editar código]
  1. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 Ungerer, Theo; Robič, Borut; Šilc, Jurij (2003). «A survey of processors with explicit multithreading». ACM Computing Surveys (em inglês). 35 (1): 29–63. doi:10.1145/641865.641867
  2. 1 2 3 4 5 6 Olukotun, Kunle; Hammond, Lance (2005). «The Future of Microprocessors». ACM Queue (em inglês). 3 (7): 26–29. doi:10.1145/1095408.1095418
  3. 1 2 3 4 IBM (28 de novembro de 2025). «Simultaneous multithreading». AIX 7.3 documentation (em inglês). IBM. Consultado em 11 de novembro de 2026
  4. 1 2 3 Tullsen, Dean M.; Eggers, Susan J.; Levy, Henry M. (1995). «Simultaneous multithreading: maximizing on-chip parallelism». Proceedings of the 22nd Annual International Symposium on Computer Architecture (ISCA '95) (em inglês). Nova York: ACM Press. pp. 392–403. doi:10.1145/223982.224449
  5. 1 2 3 4 5 Feliu, Josué; Eyerman, Stijn; Sahuquillo, Julio; Petit, Salvador; Eeckhout, Lieven (2017). «Improving IBM POWER8 Performance Through Symbiotic Job Scheduling». IEEE Transactions on Parallel and Distributed Systems (em inglês). 28 (10): 2838–2851. doi:10.1109/TPDS.2017.2691708. Consultado em 11 de novembro de 2026
  6. ↑ Feo, John; Harper, David; Kahan, Simon; Konecny, Petr (2005). «ELDORADO». Proceedings of the 2nd Conference on Computing Frontiers (CF '05) (em inglês). Nova York: ACM. pp. 28–34. doi:10.1145/1062261.1062268
  7. 1 2 Sinharoy, B.; Kalla, R. N.; Tendler, J. M.; Eickemeyer, R. J.; Joyner, J. B. (2005). «POWER5 system microarchitecture». IBM Journal of Research and Development (em inglês). 49 (4/5): 505–521. doi:10.1147/rd.494.0505
  8. ↑ Le, H. Q.; Starke, W. J.; Fields, J. S.; O'Connell, F. P.; Nguyen, D. Q.; Ronchetti, B. J.; Sauer, W. M.; Schwarz, E. M.; Vaden, M. T.; et al. (2007). «IBM POWER6 microarchitecture». IBM Journal of Research and Development (em inglês). 51 (6): 639–662. doi:10.1147/rd.516.0639
  9. ↑ Kalla, Ron; Sinharoy, Balaram; Starke, William J.; Floyd, Michael (2010). «Power7: IBM's Next-Generation Server Processor». IEEE Micro (em inglês). 30 (2): 7–15. doi:10.1109/MM.2010.38
  10. ↑ Curran, B. W.; Jacobi, C.; Bonanno, J. J.; Schroter, D. A.; Alexander, K. J.; Puranik, A.; Helms, M. M.; et al. (2015). «The IBM z13 multithreaded microprocessor». IBM Journal of Research and Development (em inglês). 59 (4/5): 1:1–1:13. doi:10.1147/JRD.2015.2418591
  11. ↑ Nawathe, U. G.; Hassan, M.; Yen, K. C.; Kumar, A.; Ramachandran, A.; Greenhill, D.; et al. (2008). «Implementation of an 8-Core, 64-Thread, Power-Efficient SPARC Server on a Chip». IEEE Journal of Solid-State Circuits (em inglês). 43 (1): 6–20. doi:10.1109/JSSC.2007.910967
  12. ↑ Butler, Michael; Barnes, Leslie; Das Sarma, Debjit; Gelinas, Bob (2011). «Bulldozer: An Approach to Multithreaded Compute Performance». IEEE Micro (em inglês). 31 (2): 6–15. doi:10.1109/MM.2011.23