Pular para o conteúdo principal

Recursos computacionais e gerenciamento de recursos

Modelo de recursos e recursos clássicos

Nesta seção, vamos apresentar um framework para pensar sobre ambientes de computação que pode ser aplicado tanto a um laptop quanto escalado até supercomputadores. Ao final desta seção, você vai entender os componentes fundamentais de um ambiente de computação e como eles se relacionam entre si. Tudo isso é apresentado por Iskandar Sitdikov no vídeo a seguir.

Modelo de recursos

Qualquer ambiente de computação clássica é construído a partir de vários recursos interligados que trabalham juntos para executar aplicações de forma eficiente. Os principais recursos geralmente incluem:

  • CPU (Unidade Central de Processamento): A CPU é a unidade de processamento central que interpreta e executa as instruções dos programas. Ela lida com operações lógicas, aritméticas e de controle, atuando essencialmente como o "cérebro" do sistema.

  • Cache da CPU (L1, L2, L3): É a memória mais rápida do sistema, construída diretamente no núcleo da CPU ou muito próxima a ele. Armazena pequenas porções de dados e instruções que a CPU precisa imediatamente. Os diferentes níveis (L1, L2, L3) representam um tradeoff: o L1 é o menor e mais rápido, enquanto o L3 é o maior e mais lento, mas ainda assim ordens de magnitude mais rápido que a RAM.

  • RAM (Memória de Acesso Aleatório): Memória volátil que fornece armazenamento temporário e de grande capacidade para as instruções dos programas e os dados em uso ativo. Ela garante que a CPU possa acessar rapidamente as informações de que precisa durante a execução, sem depender constantemente de dispositivos de armazenamento mais lentos.

  • Armazenamento (local e em rede): O armazenamento retém dados e software mesmo quando o sistema está desligado, oferecendo persistência de longo prazo para grandes conjuntos de dados e aplicações. Em computação de alto desempenho, as soluções de armazenamento precisam lidar com enormes volumes de dados científicos ou analíticos com velocidade e confiabilidade. O armazenamento local inclui unidades de estado sólido (SSDs) e discos rígidos (HDDs), com os SSDs sendo preferidos por sua menor latência e maior throughput. Para o gerenciamento de dados em grande escala, sistemas de arquivos paralelos, armazenamento em rede compartilhado e sistemas baseados em objetos permitem acesso rápido em muitos nós de computação, enquanto camadas de armazenamento em nuvem e de arquivo suportam retenção de longo prazo e escalabilidade.

  • GPU (Unidade de Processamento Gráfico): Embora originalmente projetadas para renderização gráfica, as GPUs modernas são poderosos processadores paralelos. São amplamente usadas para tarefas que exigem muitos cálculos simultâneos, como aprendizado profundo, simulações físicas e análise de big data. É importante notar que as GPUs não estão substituindo as CPUs; as CPUs direcionam a lógica de nível mais alto do programa e as GPUs aceleram as etapas altamente paralelas.

  • Conexões/Barramentos: São os caminhos de comunicação que ligam a CPU, a memória, o armazenamento e os periféricos. Os barramentos permitem a transferência de dados e a coordenação entre os componentes do sistema, garantindo uma comunicação fluida em todo o ambiente de computação. Em sistemas HPC, componentes como CPUs, GPUs e dispositivos de armazenamento são conectados por interconexões de alta velocidade que permitem troca rápida de dados. As GPUs geralmente se conectam ao sistema via PCIe, uma interface padrão com múltiplas vias de dados para comunicação eficiente. Para maior desempenho, o NVLink fornece uma conexão direta de alta largura de banda entre GPUs ou entre GPUs e CPUs, reduzindo a latência e acelerando cargas de trabalho paralelas.

  • Sistema de arquivos: O sistema de arquivos organiza os dados nos dispositivos de armazenamento. Ele fornece estrutura para armazenar, recuperar e gerenciar arquivos, permitindo que programas e usuários acessem as informações de forma consistente e lógica.

Cada tipo de recurso tem suas próprias unidades de medida relacionadas ao desempenho. Por exemplo, as CPUs são tipicamente medidas por "núcleos" e "velocidade de clock". Ao comprar um laptop, suas especificações geralmente incluem o número de núcleos. Um conceito semelhante se aplica aos nós computacionais em um data center, onde cada nó está associado a um número específico de núcleos. Ambientes de computação que incluem múltiplos tipos de recursos (CPUs, GPUs e até QPUs) são chamados de ambientes de computação heterogêneos. Essas configurações lidam com cargas de trabalho diversas de forma mais eficiente, aproveitando os pontos fortes de cada tipo de processador. Por exemplo, as CPUs seriam usadas para tarefas gerais e as GPUs para processamento paralelo. No contexto de gerenciamento e agendamento de recursos — especialmente para ambientes de computação heterogêneos — unidades de medida adicionais podem ser necessárias além das descritas aqui.

Para memória, a unidade de medida seria Mega/Giga/Terabytes.

Para placas gráficas e outros aceleradores, a unidade de medida depende do contexto. Embora sua capacidade computacional real seja medida por métricas detalhadas — número de núcleos de processamento, tamanho da memória e largura de banda da memória —, em discussões de alto nível sobre recursos de cluster ou agendamento de jobs, GPUs e aceleradores similares podem ser quantificados no nível do dispositivo pelo número de dispositivos inteiros atribuídos (por exemplo, três GPUs).

Rede/conectividade/barramentos são aspectos cruciais de qualquer infraestrutura de computação, pois determinam a velocidade com que os dados são transferidos entre os componentes de computação. Da CPU ao cache da CPU, à RAM, às placas PCI, aos dispositivos conectados em rede: tudo é comunicação, e é fundamental ter um modelo mental preciso disso para projetar algoritmos altamente otimizados para HPC.

Uma imagem mostrando que cada nó de computação pode incluir muitos tipos de recursos.

Escalando recursos clássicos

A Computação de Alto Desempenho (HPC) envolve o escalonamento desses recursos clássicos para alcançar tempos de processamento mais rápidos ou aumentar o volume de dados que podem ser manipulados simultaneamente (por exemplo, para aumentar o tamanho dos espaços de solução que podem ser pesquisados). Isso pode ser alcançado por meio de:

  • Escalonamento vertical: Aumentar o poder dos recursos individuais, como usar uma CPU mais poderosa ou adicionar mais memória em um único nó físico, onde um nó é uma unidade de um cluster de computação que encapsula múltiplos recursos de computação.

  • Escalonamento horizontal: Adicionar mais recursos, como múltiplas CPUs ou GPUs, para trabalharem juntos em um único nó ou, mais comumente, em múltiplos nós, permitindo a computação distribuída.

Uma imagem mostrando o escalonamento vertical de recursos ao colocar mais recursos, como memória, em um único nó, e o escalonamento horizontal ao aumentar o número de nós conectados, incluindo diferentes tipos de recursos.

Alguns dos conceitos de escalonamento desta seção serão aplicáveis à próxima seção sobre recursos de computação quântica. Alguns outros aspectos dos recursos quânticos serão quantificados de novas maneiras.

Teste seu entendimento

Use as descrições acima para inferir algumas vantagens e desvantagens das diferentes abordagens de escalonamento: vertical e horizontal?

Resposta:

Pode haver muitas respostas corretas. O escalonamento vertical costuma ser mais simples, especialmente se você tem cargas de trabalho previsíveis que vão precisar de uma quantidade fixa de recursos. Mas o escalonamento vertical pode ser mais caro de atualizar, já que a unidade fundamental de computação não pode ser dividida tão facilmente quanto no escalonamento horizontal. O escalonamento horizontal é mais complexo de gerenciar e às vezes há dificuldades ou latências relacionadas às conexões entre nós. Mas é muito mais adaptável a requisitos de recursos variáveis e é modular quando atualizações são necessárias.

Novo tipo de recurso: QPU (Unidade de Processamento Quântico)

Nesta seção, vamos apresentar um novo tipo de recurso — um recurso quântico — e explorar sua definição, unidades de medida e conectividade com a infraestrutura clássica.

Definição de QPU

  • Unidade de processamento quântico (QPU): Uma QPU inclui todo o hardware responsável por aceitar um conjunto de instruções quânticas executáveis, ou um circuito quântico, e retornar uma resposta precisa.

Isso significa que a QPU inclui um ou mais chips quânticos (por exemplo, o Heron), os múltiplos componentes adicionais no refrigerador de diluição, como os amplificadores quânticos, a eletrônica de controle e a computação clássica necessária para tarefas como manter as instruções e formas de onda na memória, acumular resultados e futura decodificação de correção de erros. Embora um refrigerador de diluição seja necessário para realizar essas tarefas, ele é excluído desta definição para permitir o caso de múltiplas QPUs no mesmo refrigerador.

  • Computador quântico: Um computador quântico é composto pela QPU mais a computação clássica que hospeda o ambiente de runtime.

  • Ambiente de runtime: A combinação de hardware e software que torna possível executar um programa.

Camadas em circuitos quânticos

Tanto na computação clássica quanto na quântica, os processos podem ser executados sequencialmente ou em paralelo. Como os qubits têm um espaço de estados muito mais rico em comparação com os bits clássicos, às vezes faz sentido que múltiplas portas de um qubit sejam executadas em sequência (como uma porta R_x seguida de uma porta R_z). Como o entrelaçamento entre qubits é fundamental para a computação quântica, também é comum que um circuito quântico tenha um conjunto de portas de entrelaçamento agindo em muitos qubits. Esses e outros fatores tornam comum identificar processos que podem ser executados em paralelo na escala de operações individuais de portas em um circuito quântico. Na computação clássica, o paralelismo no nível de bits também é possível, mas é menos comum considerá-lo no nível de portas; é mais comum se referir a processos paralelos e sequenciais em uma escala maior.

Na computação quântica, fala-se de uma "camada" de portas que podem ser executadas simultaneamente. Em muitas aplicações, é útil realizar um conjunto de rotações em todos os qubits e depois portas de entrelaçamento entre pares de qubits. Nesses contextos, fala-se de uma "camada de rotação" (uma camada de portas como R_x, R_y e/ou R_z) e uma "camada de entrelaçamento" (como uma com portas CNOT). O número de camadas em um circuito é a "profundidade do circuito", uma medida importante, pois maior profundidade significa mais camadas de ruído e erros acumulados.

Pode ser difícil identificar camadas de portas visualmente quando elas não estão alinhadas com barreiras. No Qiskit, uma barreira funciona como uma instrução em circuitos quânticos que age como um separador visual e uma restrição durante a compilação. Tanto ao desenhar o circuito quanto ao executá-lo, nenhuma porta será movida através da barreira. Isso pode ser importante em contextos como o desacoplamento dinâmico, no qual se implementam intencionalmente portas que simplificam para uma identidade para suprimir certos tipos de erro. Para mais informações sobre desacoplamento dinâmico, veja este guia. Para ver o efeito visual das barreiras, compare estas duas imagens do mesmo circuito: a primeira sem barreiras e a segunda com barreiras para forçar o alinhamento das camadas.

Circuito quântico de quatro qubits sem barreiras para forçar o alinhamento das camadas; as portas aparecem de forma um pouco aleatória.

Circuito quântico de quatro qubits com barreiras para forçar o alinhamento das camadas. Contar as camadas fica muito mais fácil agora.

São o mesmo circuito e têm o mesmo número de camadas. Mas no segundo, o alinhamento torna fácil ver que o circuito possui:

  • Duas camadas de rotação: uma em torno do eixo Y por π/5\pi/5, uma em torno do eixo Z por π/4\pi/4.
  • Três camadas de entrelaçamento. Note que cada CNOT pode ser chamado de uma "camada" por si só, já que os CNOTs não podem ser reordenados para serem paralelos sem alterar a operação lógica.
  • Mais duas camadas de rotação: uma em torno do eixo Y por π/3\pi/3, uma em torno do eixo Z por π/2\pi/2.
  • Mais duas camadas de entrelaçamento. Note que desta vez a primeira camada foi ligeiramente mais paralelizada do que no primeiro conjunto de camadas de entrelaçamento.

A profundidade de cada circuito é 9.

Unidades de medida

Na computação quântica, as capacidades de um sistema quântico são tipicamente avaliadas usando três métricas de desempenho principais: escala, qualidade e velocidade. Essas métricas não apenas descrevem o potencial computacional de um dispositivo quântico, mas também informam como os recursos são gerenciados e agendados em aplicações práticas.

  • Escala refere-se ao número de bits quânticos (qubits) no sistema, representando a quantidade de informação quântica que o dispositivo pode armazenar. No gerenciamento de recursos, isso impacta diretamente a largura do circuito — o número de qubits necessários para executar uma determinada tarefa quântica. Uma unidade quântica deve ter qubits suficientes para suportar a tarefa atribuída.

  • Qualidade descreve a precisão com que as operações quânticas são realizadas. Ela é frequentemente quantificada pela fidelidade de camada, que mede a precisão de executar uma camada completa de portas quânticas em todos os qubits. Do ponto de vista do agendamento, maior fidelidade permite que circuitos mais profundos sejam executados de forma confiável, afetando a necessidade de mitigação de erros ou decomposição de tarefas.

  • Velocidade é medida por CLOPS (Operações de Camada de Circuito por Segundo), indicando quantas camadas de operações quânticas o sistema pode executar por segundo. Isso afeta o throughput e a latência na execução de tarefas, e ajuda a determinar com que rapidez uma unidade quântica pode completar uma determinada carga de trabalho. Essa velocidade é especialmente importante em um computador quântico, pois os qubits sofrem com ruído e erros em maior grau do que seus equivalentes clássicos. O tempo durante o qual eles podem manter suas informações quânticas de forma útil é descrito pelo tempo de coerência, tipicamente na ordem de 200–300 μs\mu\text{s} para processadores Heron r3.

Diferenças entre métricas quânticas e clássicas

Você pode pensar em CLOPS como um análogo quântico aproximado do FLOPS, mas com algumas diferenças importantes. O CLOPS mede a velocidade com que um processador quântico pode executar circuitos quânticos, especificamente camadas de operações dentro dos circuitos, incluindo tanto as computações quânticas quanto as computações clássicas necessárias para executar os circuitos. Ele foi desenvolvido pela IBM Quantum como uma medida holística da velocidade de execução de um computador quântico, cobrindo o tempo de execução quântica e o processamento clássico em tempo real necessário para atualizações de circuitos, ao contrário do FLOPS que mede puramente a capacidade aritmética de ponto flutuante em processadores clássicos.

O CLOPS fornece uma métrica de desempenho mensurável que pode ser comparada em hardware existente. A IBM Quantum usou o CLOPS para comparar diferentes processadores quânticos e os valores podem ser encontrados na página Compute resources na IBM Quantum Platform. Os valores de CLOPS dependem das capacidades do hardware, velocidades de portas, velocidade de processamento clássico e integração entre eles.

A contagem de qubits é um número fixo para uma determinada QPU. O CLOPS e a qualidade dependem de calibração e manutenção regulares e podem variar ligeiramente ao longo do tempo, mesmo para uma única QPU.

Juntas, essas métricas orientam como os sistemas quânticos são alocados e agendados. Em muitos casos, o sistema quântico inteiro é tratado como uma única unidade. No entanto, quando uma tarefa excede a capacidade de uma unidade — seja em termos de contagem de qubits, profundidade do circuito ou velocidade de execução — técnicas como corte/costura de circuitos podem ser usadas. O corte de circuito é o processo de dividir grandes tarefas quânticas em subtarefas menores e gerenciáveis que podem ser distribuídas em múltiplos chips quânticos, permitindo computação quântica escalável apesar das limitações de hardware. A costura de circuito refere-se ao processo que vem após o corte do circuito — a etapa de pós-processamento clássico que "costura" ou combina os resultados dos subcircuitos menores de volta juntos.

Os computadores quânticos não têm memória tradicional, no sentido de armazenamento persistente e endereçável como a RAM ou a memória de GPU. Os recursos de computação clássica têm bits discretos armazenados na memória, permitindo que os dados sejam salvos, recuperados e reutilizados durante a computação. Os recursos quânticos usam qubits que não armazenam memória no sentido clássico. Em vez disso, os qubits existem em estados quânticos que representam superposições de 0 e 1 simultaneamente, permitindo paralelismo exponencial no espaço de estados. No entanto, os estados dos qubits são frágeis e não podem ser clonados ou lidos deterministicamente em etapas intermediárias sem colapsar o estado quântico, portanto, o comportamento semelhante à memória persistente durante a computação não existe. Os qubits devem ser mantidos em um estado coerente durante toda a execução, e a "memória" é essencialmente o próprio estado quântico. A memória clássica só pode ser usada ao lado de um processador quântico, não como memória quântica interna. Isso tem implicações significativas: os recursos de computação clássica podem reutilizar e armazenar resultados intermediários livremente; os recursos quânticos não conseguem fazer isso sem medições que perturbam a computação.

Conectividade com a infraestrutura clássica

As QPUs podem ser conectadas à infraestrutura clássica por meio de redes e várias interfaces de programação de aplicações (APIs) que permitem que desenvolvedores de software interajam com QPUs de forma programática. Essas APIs geralmente ficam ocultas por trás de kits de desenvolvimento de software (SDKs) e bibliotecas (como o Qiskit) e são expostas a cientistas computacionais na forma de abstrações de programação (como as Primitivas do Qiskit, sobre as quais falaremos no Capítulo 3: modelos de programação).

Vale destacar a distinção entre integração estreita e solta de recursos quânticos e clássicos. Atualmente, as QPUs não estão no mesmo nó que os recursos de computação clássica. Na verdade, as QPUs atualmente não estão conectadas via PCIe, mas via rede. Isso pode mudar no futuro, mas há desafios de engenharia relacionados às condições ambientais ideais para QPUs e recursos de computação clássica.

Escalando recursos quânticos

O escalonamento dos recursos quânticos também pode ser categorizado em vertical e horizontal.

  • Escalonamento vertical seria aumentar o número de qubits por chip ou melhorar a fidelidade dos dispositivos.
  • Escalonamento horizontal seria conectar chips com acopladores ou com interconexões clássicas.

Uma imagem mostrando o escalonamento vertical de recursos quânticos como mais qubits em um chip, e o escalonamento horizontal de recursos quânticos como a conexão de muitos chips juntos com acopladores.

Teste seu entendimento

Quais são os análogos quânticos dos (a) bits de informação clássicos e (b) velocidade do processador?

Resposta:

(a) Bits quânticos ou qubits — unidades de informação que, ao contrário de seus equivalentes clássicos (que só podem adotar o estado 0 ou 1), podem estar em uma superposição de 0 e 1 simultaneamente.

(b) Operações de camada de circuito por segundo ou CLOPS — número de operações sequenciais que a QPU pode realizar a cada segundo, incluindo alguma interface com recursos de computação clássica, como ao carregar parâmetros do circuito.

Gerenciamento de recursos

Tanto os recursos HPC quanto os recursos quânticos são preciosos e complexos; eles precisam ser gerenciados com cuidado. Nesta seção, vamos explicar como gerenciar recursos para programas de usuário. O gerenciamento de recursos em infraestrutura de computação se refere ao processo de (1) planejamento, (2) alocação e (3) controle/gerenciamento do uso de recursos de computação, como CPUs, memória, armazenamento e largura de banda de rede, para garantir uma utilização eficiente e efetiva dos recursos.

Planejamento — estimativa de recursos

Qualquer programa consome recursos, e estimar os recursos necessários é crucial para um gerenciamento eficiente. Isso inclui estimar a quantidade de CPU, memória e outros recursos necessários para executar um programa. O mesmo se aplica aos recursos quânticos. No entanto, os recursos quânticos existem em uma escala completamente diferente. Os processadores quânticos IBM Quantum® Heron r3 têm 156 qubits, em comparação com os muitos bilhões de bits clássicos em um laptop comum. Tempo e custo também são considerações. Atualmente, a IBM Quantum tem um plano gratuito, o Open Plan, que permite aos usuários explorar a computação quântica usando 10 minutos de tempo de QPU por mês. Algumas organizações de pesquisa precisam de tanto tempo de QPU que possuem um computador quântico IBM dedicado nas suas instalações.

Uma etapa na estimativa de recursos que é exclusiva da computação quântica é a profundidade do circuito. Como mencionado anteriormente, cada porta quântica e cada tempo de atraso entre operações vem com ruído e uma certa probabilidade de erro. Quanto mais profundo o circuito quântico, maior o ruído. Há duas sutilezas nisso: as portas de dois qubits têm taxas de erro muito mais altas do que as portas de um qubit, portanto, muitas vezes pode-se ignorar a profundidade de um qubit. Além disso, nem todos os qubits em um chip quântico estão diretamente conectados. Às vezes, as informações precisam ser trocadas de qubit em qubit para realizar os entrelaçamentos necessários, e esse processo de troca em si requer portas de dois qubits. Essa troca é tratada em um processo chamado "transpilação", um processo complexo que serve a outros propósitos também; isso é discutido em mais detalhes na próxima lição. A quantidade limitante relevante é, portanto, a profundidade transpilada de dois qubits. A profundidade máxima exata na qual resultados de alta fidelidade podem ser obtidos depende do circuito. Mas aproveitando as modernas técnicas de mitigação de erros, pode-se obter resultados de alta fidelidade com profundidades transpiladas de dois qubits de 80 ou mais.

Alocação — agendamento

O agendamento é o processo de alocar recursos para programas e gerenciar sua execução. Isso envolve:

  • Submissão de job: O processo pelo qual um usuário envia uma solicitação (job) ao sistema HPC, especificando qual trabalho computacional e quais recursos são necessários para a execução.
  • Alocação de recursos: A atribuição dos recursos disponíveis do sistema HPC (como nós, CPUs, memória) a um job submetido com base em seus requisitos.
  • Execução do job: A execução real das tarefas computacionais definidas pelo job nos recursos HPC alocados.

Existem análogos de todos esses processos para computadores quânticos.

  • Os jobs são submetidos pelo usuário, usando o Qiskit Runtime, e tipicamente usando uma primitiva do Qiskit Runtime, como Sampler, Estimator ou outras.
  • O usuário seleciona de uma lista de backends aos quais tem acesso. A lista completa de backends disponíveis pode ser vista na página Compute resources na IBM Quantum Platform. É comum simplesmente usar o computador quântico menos ocupado. Mas há casos em que pode ser importante usar um específico por causa de considerações sobre o layout do dispositivo, replicação de cálculos anteriores, e assim por diante.
  • A execução de jobs quânticos é similar ao caso HPC. Embora algumas diferenças já tenham sido descritas, algumas merecem ser repetidas aqui. As QPUs atualmente não estão geralmente localizadas no mesmo nó que os recursos de computação clássica, mas são conectadas por uma rede. Isso pode ter implicações de agendamento. Além disso, os computadores quânticos podem ter tempos de fila substanciais, e esses tempos de fila variam, tornando o controle preciso de temporização difícil. Essa situação pode ser diferente para sistemas dedicados; isso depende da administração interna do computador quântico.

Controle/Gerenciamento — gerenciamento de carga de trabalho

O gerenciamento de carga de trabalho, também conhecido como orquestração, é o processo de gerenciar múltiplos programas e seus requisitos de recursos. Isso envolve:

  • Provisionamento de recursos: O processo de preparar e disponibilizar os recursos HPC para uso pelos jobs, incluindo a configuração de hardware e software. Como veremos mais adiante, as QPUs são recursos de computação que podem ser provisionados de forma semelhante aos recursos HPC clássicos, com as ressalvas da seção anterior.
  • Agendamento de jobs: A atividade do software agendador ao decidir quais jobs são executados, quando e em quais recursos, gerenciando prioridades e filas para utilizar o sistema HPC de forma eficiente. Embora essa afirmação ampla se aplique aos recursos quânticos, pode haver menos controle sobre o timing do que com outros recursos.

Uma imagem mostrando cargas de trabalho (representadas como caixas) sendo organizadas e dispostas para se encaixar de forma otimizada em uma grade bidimensional, com um eixo representando o tempo e o outro representando os recursos. Exemplo:

Considere uma tarefa bem conhecida como contexto para entender o gerenciamento de recursos: encontrar os fatores primos de números grandes. Vamos assumir ainda que o algoritmo sendo usado se baseia na verificação por força bruta de cada divisor potencial. Embora esse geralmente não seja o método mais eficiente, é fácil entender como a carga de trabalho pode ser gerenciada.

Planejamento — estimativa de recursos

  • Estime quanto tempo de CPU e memória a fatoração prima pode exigir.
  • Planeje a paralelização da sua tarefa — quantas CPUs/núcleos você vai usar?

Alocação — agendamento

  • Após a submissão do job, o agendador atribui núcleos de CPU e memória à tarefa de fatoração prima. Por exemplo, pode alocar todos os divisores potenciais terminando nos dígitos 1, 3, 7, 9 para um de quatro núcleos, respectivamente.
  • Execução do job: O algoritmo de fatoração prima é executado, realizando divisões ou outras etapas de fatoração nos recursos alocados até que a tarefa seja concluída.

Controle/Gerenciamento — gerenciamento de carga de trabalho

  • O sistema orquestra a ordem e o timing dos jobs de fatoração prima para otimizar o throughput.
  • O caso mais fácil de imaginar é que um dos núcleos encontra o fator primo alvo. Isso deve parar o cálculo nos outros núcleos para que possam ser usados para a próxima tarefa.

Ambientes de computação de alto desempenho usam software especial para executar essas etapas e gerenciar recursos. Na próxima seção, vamos aprender sobre um sistema de software de gerenciamento de recursos amplamente adotado: o Slurm.

Exemplo com recursos quânticos:

Um fluxo de trabalho que será o assunto de outras lições neste curso é a determinação de estados fundamentais e energias químicas usando a diagonalização quântica baseada em amostras (SQD). Isso é abordado em mais detalhes na Lição 4, e você também pode visitar este curso sobre SQD e métodos relacionados no IBM Quantum Learning. Tudo o que precisamos saber para esta discussão é que o fluxo de trabalho envolve o seguinte:

  • Preparar um circuito quântico
  • Medir o circuito quântico
  • Usar os resultados das medições para projetar o problema em um subespaço útil
  • Diagonalizar uma matriz menor e projetada usando recursos de computação clássica
  • Iteração, seja para garantir a autoconsistência por meio de considerações como a conservação de carga, e possíveis iterações do circuito quântico se ele tiver parâmetros variacionais.

Planejamento — estimativa de recursos

  • Mapeie os orbitais eletrônicos para qubits para estabelecer o número de qubits necessários.
  • Combine o Hamiltoniano mapeado do sistema e o estado (possivelmente variacional) em um circuito quântico e verifique a profundidade transpilada de dois qubits. Certifique-se de que é razoável.
  • Estime o tamanho do subespaço no qual você vai projetar; a partir disso, estime quanto tempo de CPU e memória a diagonalização pode exigir.
  • Planeje a paralelização da sua tarefa — quantas CPUs/núcleos você vai usar?

Alocação — agendamento

  • O usuário seleciona a QPU; o processo de transpilação mapeia automaticamente os qubits do seu circuito quântico abstrato para qubits físicos na QPU. Isso é importante pois o circuito abstrato pode assumir conectividade direta que não existe no chip, entre outros motivos.
  • Após a submissão do job via Qiskit Runtime, o job entra na fila da QPU selecionada. O usuário não tem controle sobre o tempo de fila, embora isso possa ser diferente para sistemas dedicados.
  • Os recursos de computação clássica aguardam os resultados quânticos.
  • Um job de diagonalização é submetido aos recursos HPC; após a submissão do job, o agendador atribui núcleos de CPU e memória à tarefa de diagonalização.
  • Execução do job: O algoritmo de diagonalização é executado, diagonalizando a matriz projetada menor até que a tarefa seja concluída.

Controle/Gerenciamento — gerenciamento de carga de trabalho

  • O sistema orquestra a ordem e o timing das etapas quânticas e clássicas ao longo de todo o processo. Por exemplo, uma vez que a matriz projetada tenha sido diagonalizada e uma energia do estado fundamental obtida, dependendo dos critérios de convergência, o fluxo de trabalho pode voltar a um novo circuito quântico (com um novo parâmetro variacional).
  • Quando os critérios de convergência são atendidos pela energia do estado fundamental, o cálculo em todos os núcleos para.

Ambientes de computação de alto desempenho usam software especial para executar essas etapas e gerenciar recursos. Na próxima seção, vamos aprender sobre um sistema de software de gerenciamento de recursos amplamente adotado: o Slurm. É importante notar que o Slurm não possui ferramentas para todas as etapas descritas acima. O Slurm não fornece suporte para planejamento de jobs, nem para gerenciamento detalhado de carga de trabalho, como a comunicação entre componentes da carga de trabalho. Isso é bem adequado ao estado atual da computação quântica em HPC, já que as QPUs são tipicamente acessadas pela rede.

Teste seu entendimento

Suponha que você está tentando pesquisar um banco de dados não ordenado para encontrar um elemento que chamaremos de "alvo". Para cada uma das ações a seguir, indique a qual etapa do gerenciamento de recursos ela corresponde: (a) Estimar o tamanho do banco de dados e o tempo necessário para verificar cada elemento (b) Garantir que encontrar o alvo em uma GPU pare o processo nas outras GPUs para liberá-las para o próximo problema. (c) Dividir o espaço de busca em regiões para cada uma das suas (digamos, 10) GPUs pesquisarem

Resposta:

(a) Planejamento (b) Controle/gerenciamento (c) Alocação/agendamento,

Software: Slurm

Nesta seção, vamos aplicar os conceitos aprendidos neste capítulo para praticar o uso do popular sistema de gerenciamento de recursos, o Slurm.

Introdução ao Slurm

O Slurm é um sistema de gerenciamento de recursos de código aberto amplamente utilizado em ambientes de computação de alto desempenho. Ele oferece um conjunto abrangente de ferramentas para gerenciar recursos, agendar jobs e monitorar o desempenho do sistema.

Vamos cobrir os conceitos básicos do uso do Slurm, incluindo:

  • Submissão de jobs
  • Alocação de recursos
  • Monitoramento de jobs

Como é muito difícil fornecer recursos de HPC para cada estudante deste curso, vamos usar um atalho e disponibilizar um repositório com imagens Docker que simulam um cluster HPC real com Slurm, mas em pequena escala. Isso nos ajudará a praticar os conceitos aprendidos em ambientes seguros e reproduzíveis.

Vale observar que, atualmente, todos os recursos quânticos e clássicos são alocados pela duração de todo o experimento. No momento, não há alocação intercalada de recursos mistos. Uma ressalva importante é que, mesmo depois que o job é iniciado, o sistema quântico não será controlado diretamente como um usuário HPC frequente poderia esperar. O job é iniciado em um nó x86 arbitrário, que executa o serviço Qiskit Runtime, e esse serviço de runtime se conecta a outro agendador sobre o qual o usuário não tem controle direto. Esse fluxo de trabalho e os problemas relacionados podem ser familiares para usuários de HPC que tiveram experiência inicial buscando acesso exclusivo a nós de GPU (o uso original do gres).

Instruções de instalação e visão geral da configuração

Para praticar a combinação de recursos quânticos e de HPC, você precisará ter acesso a um ambiente HPC real ou simular um ambiente HPC na sua máquina local. Um guia de instalação para configuração local usando Docker pode ser encontrado neste repositório. O guia inclui links para suporte na criação de uma conta IBM Cloud® e na instalação do plugin SPANK para QRMI. Também nesse repositório há vários arquivos Python para testar seu ambiente.

Após concluir a instalação, vamos usar o comando abaixo para verificar os recursos computacionais do Slurm no seu terminal. Se a instalação foi bem-sucedida, você deve conseguir confirmar um total de três nós virtuais.

$ sinfo

PARTITION AVAIL TIMELIMIT NODES STATE NODELIST
normal up 5-00:00:00 2 idle c[1-2]
quantum* up infinite 1 idle q1
$ scontrol show node

NodeNAME=q1 Arch=x86_64 CoresPerSocket=1
CPUAlloc=0 CPUTot=1 CPULoad=0.34
AvailableFeatures=(null)
ActiveFeatures=(null)
Gres=qpu:1
NodeAddr=q1 NodeHostName=q1 Version=21.08.6
...

Temos duas partições ou grupos de nós: normal e quantum. A partição normal é composta por nós que têm acesso apenas a recursos clássicos. A partição quantum tem acesso a recursos quânticos. Você pode ver os detalhes de cada nó executando scontrol show nodes.

Executar um exemplo simples de hello world no Slurm

Vamos primeiro executar um exemplo clássico simples de hello world com o Slurm. Usaremos Python nos exemplos. Vamos criar o arquivo hello_world.py, que é bastante autoexplicativo.

$ vim hello_world.py

import time
time.sleep(10)
print("Hello, World!")
~

Agora precisamos informar ao gerenciador de recursos quais recursos precisamos para executar este programa. O Slurm oferece uma forma de especificar todos os metadados do job por meio de um script de submissão, que é simplesmente um shell script com anotações específicas do Slurm. Essas anotações permitem especificar requisitos de recursos, parâmetros de agendamento e muito mais. Vamos criar um shell script hello_world.sh para isso.

$ vim hello_world.sh

#SBATCH --job-name=hello-world
#SBATCH --output=hello-world.out
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=1
#SBATCH --partition=normal

srun hello_world.py
~

Vamos analisar o arquivo de submissão e entender o que está acontecendo.

As diretivas #SBATCH são anotações específicas para informar quais requisitos temos para a execução do programa. Aqui você pode especificar a quantidade de recursos — o número de nós, o número de tarefas por nó, o número de tarefas e CPUs por nó e por tarefa — e outras opções como o nome do arquivo de saída. Uma lista completa de opções está disponível na documentação do Slurm.

Agora é hora de executar nosso job no Slurm. sbatch é um comando que aceita um arquivo de submissão e coloca o job na fila para execução no Slurm.

$ sbatch hello_world.sh

Submitted batch job 63

Vamos verificar o status do nosso programa usando o comando squeue.

$ squeue

# JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
# 1 main hello_world root R 0:01 1 c1

Assim que o job terminar, podemos verificar o resultado olhando o arquivo de saída.

$ cat hello_world_logs.txt
Hello, World!

Verifique seu entendimento

Dado o shell script Slurm abaixo, qual é (a) o nome do job, (b) o nome do arquivo Python, e (c) o nome do arquivo de saída? (d) Por fim, esse script poderia usar recursos quânticos ou não?

vim hello_learner.sh

#SBATCH --job-name=hello-learner
#SBATCH --output=hello-learner.out
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=1
#SBATCH --partition=quantum

srun hello_learner_qm.py

Resposta:

(a) hello-learner (b) hello-learner_qm.py (c) hello-learner.out (d) Sim, poderia. Está usando a partição quantum.

Executar um exemplo simples de Qiskit hello world no Slurm

A seguir, vamos tentar usar recursos quânticos também. Vamos criar e executar um programa simples "Hello, Qiskit" que utiliza recursos quânticos.

$ vim hello_qiskit.py

# hello_qiskit.py
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime import EstimatorV2 as Estimator

# Create a new circuit with two qubits
qc = QuantumCircuit(2)

# Add a Hadamard gate to qubit 0
qc.h(0)

# Perform a controlled-X gate on qubit 1, controlled by qubit 0
qc.cx(0, 1)

observables_labels = ["IZ", "IX", "ZI", "XI", "ZZ", "XX"]
observables = [SparsePauliOp(label) for label in observables_labels]

# switch to QRMI service
from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()

backend = service.backend("...")

# Convert to an ISA circuit and layout-mapped observables.
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)

# Construct the Estimator instance.

estimator = Estimator(mode=backend)
estimator.options.resilience_level = 1
estimator.options.default_shots = 5000

mapped_observables = [
observable.apply_layout(isa_circuit.layout) for observable in observables
]

# One pub, with one circuit to run against five different observables.
job = estimator.run([(isa_circuit, mapped_observables)])

job_result = job.result()

pub_result = job.result()[0]

print("Result", pub_result)

Aqui usaremos a interface de gerenciamento de recursos quânticos (QRMI), um plugin SPANK do Slurm para suporte a recursos e jobs quânticos, desenvolvido em conjunto pela IBM, Pasqal, The Hartree Center e RPI. Criamos um circuito pauli-2-design simples com valores iniciais aleatórios e um observável simples, e vamos executá-lo usando o Estimator para obter o valor esperado. Para executá-lo, vamos precisar novamente do script de submissão hello_qiskit.sh, que terá recursos quânticos como requisito.

$ vim hello_qiskit.sh

#SBATCH --job-name=hello-qiskit
#SBATCH --output=hello_qiskit.out
#SBATCH --nodes=1
#SBATCH --ntasks-per-nodes=1
#SBATCH --cpus-per-task=1
#SBATCH --partition=quantum
#SBATCH --gres=qpu:1

srun python /data/ch2/hello_qiskit/hello_qiskit.py
~

Vamos analisar o arquivo de submissão e entender o que está acontecendo. Temos uma nova opção, que é o gres. gres é uma opção do Slurm para definir recursos computacionais extras. No nosso caso, esse novo recurso seria nosso recurso quântico. Como especificamos os recursos e a partição do nosso cluster onde os recursos quânticos estão disponíveis, nossas primitivas do Qiskit usarão esses recursos alocados para executar a carga útil quântica.

Agora é hora de executar nosso job no Slurm.

$ sbatch hello_qiskit.sh

Em seguida, vamos verificar o status do nosso programa usando o comando squeue.

$ squeue
# JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
# 1 main hello_qiskit root R 0:01 1 q1

Podemos explorar os logs e resultados após o término do job.

$ cat hello_qiskit.out | grep Exp
Expectation Value: 0.8372900070983516

Resumo

Até agora, aprendemos o que são recursos computacionais e como usá-los para executar programas em ambientes heterogêneos. Também criamos e executamos dois programas simples de "Hello World": um para o recurso clássico e outro para um recurso quântico, e aprendemos como criar shell scripts para submeter tarefas e visualizar resultados.

Na próxima lição, vamos ampliar esse conhecimento sobre controle de recursos para aplicar modelos de programação aos recursos que adquirimos durante a execução dos jobs.

Todo o código e os scripts usados neste capítulo estão disponíveis para você em nosso repositório no GitHub.