Ir para o conteúdo principal

Entrada e Saída: Como o Computador Se Comunica com o Mundo

Autor
Francisco Bustamante
Um químico trabalhando com Ciência de Dados e Programação em Python.
Tabela de conteúdos
Por Dentro do Computador - Este artigo faz parte de uma série de artigos.
Parte 11: Esse Artigo

Até aqui nesta série exploramos memória, CPU, pipeline, representação de dados e execução de programas — todos os componentes internos do computador. Mas um computador sem entrada e saída seria apenas uma calculadora fechada: incapaz de receber dados do mundo e incapaz de devolver resultados. Este artigo trata do problema que torna a E/S tão desafiadora, das três estratégias para resolvê-lo e de como calcular o impacto de cada uma no desempenho da CPU.

O problema fundamental da E/S

Dispositivos externos são ordens de grandeza mais lentos do que a CPU e a memória principal. A CPU opera em nanosegundos (GHz); um disco rígido responde em milissegundos; um teclado humano gera eventos a cada centenas de milissegundos. Toda a arquitetura de E/S existe para gerenciar essa incompatibilidade de velocidade sem desperdiçar os ciclos preciosos da CPU.

Dispositivos externos: da variedade à velocidade
#

A primeira complicação de qualquer sistema de E/S é a diversidade dos dispositivos — cada um com velocidade, protocolo e comportamento completamente diferentes:

Categoria Exemplos Taxa de transferência típica
Muito lentos Teclado bytes por segundo a poucas dezenas de B/s
Lentos Mouse, impressora, UART dezenas de B/s a KB/s
Médios Disco rígido (HDD), USB 2.0 MB/s a dezenas de MB/s
Rápidos SSD SATA, rede Gigabit centenas de MB/s
Muito rápidos SSD NVMe, redes de alta velocidade GB/s
Faixas de taxa são apenas ordens de grandeza

As taxas acima servem como referência didática. Em sistemas reais, elas variam muito conforme interface, geração do barramento, controlador, protocolo, tamanho de bloco e padrão de acesso.

Quanto à função:

Tipo Exemplos
Entrada Teclado, mouse, scanner, microfone, câmera
Saída Monitor, impressora, alto-falante
Entrada/Saída Disco rígido, pendrive USB, placa de rede, memória flash

A figura abaixo mostra o modelo geral de um dispositivo de E/S, com seus componentes e a interface com o módulo de E/S da CPU:

modelo geral
Modelo geral de E/S

A interface com o módulo de E/S ocorre na forma de sinais de controle, de dados e de estado. Os sinais de controle determinam a função que o dispositivo realizará, como enviar dados ao módulo de E/S (INPUT ou READ), aceitar dados do módulo de E/S (OUTPUT ou WRITE), informar o estado ou realizar alguma função de controle particular ao dispositivo (por exemplo, posicionar uma cabeça de disco). Os dados estão na forma de um conjunto de bits a serem enviados ou recebidos do módulo de E/S. Os sinais de estado indicam o estado do dispositivo. Alguns exemplos são READY/NOT-READY, para indicar se o dispositivo está pronto para uma transferência de dados. A lógica de controle, associada ao dispositivo, controla a operação do dispositivo em resposta ao módulo de E/S. O transdutor converte dados elétricos para outras formas de energia durante a saída e de outras formas para elétrico durante a entrada. Em geral, um buffer é associado ao transdutor para manter temporariamente os dados sendo transferidos entre o módulo de E/S e o ambiente externo.

A interface de E/S: o intermediário
#

Entre a CPU e o dispositivo físico fica a interface de E/S (também chamada de controlador ou módulo de E/S). Na prática, a CPU não fala com o disco rígido; ela fala com o controlador do disco rígido. Esse circuito intermediário assume cinco responsabilidades vitais para isolar a CPU do caos do mundo exterior:

  1. Controle e temporização: Sincroniza o tráfego de dados entre recursos internos rápidos e dispositivos externos lentos.
  2. Comunicação com a CPU: Decodifica comandos, troca dados pelo barramento do sistema e relata o status.
  3. Comunicação com o dispositivo: Envia sinais elétricos ou comandos específicos do protocolo do periférico.
  4. Armazenamento temporário (Buffering): Acumula bits lentos que chegam do dispositivo até formar uma palavra de tamanho adequado (8, 16, 32 bits) para enviar à memória de uma só vez, compensando a diferença de velocidade.
  5. Detecção de erros: Checa problemas mecânicos (ex: papel preso) ou falhas de transmissão (bits corrompidos) e avisa a CPU.

Para realizar essas tarefas, toda interface possui ao menos três registradores internos mapeados para a CPU:

Registrador Função
Dados Armazena o dado a ser transferido entre CPU ↔ dispositivo
Estado (status) Indica a condição atual: pronto (ready), ocupado (busy) ou erro
Controle Recebe comandos da CPU: iniciar operação, selecionar modo
CPU  ←————————————→    [ Interface de E/S  ]  ←————————→  Dispositivo
       barramento      [ Reg. Dados        ]   cabo/protocolo
                       [ Reg. Estado       ]
                       [ Reg. Controle     ]

A figura abaixo oferece um diagrama de blocos geral de um módulo de E/S. O módulo conecta-se ao restante do computador por meio de um conjunto de linhas de sinal (por exemplo, linhas de barramento do sistema). Os dados transferidos de e para o módulo são armazenados em um ou mais registradores de dados. Também pode haver um ou mais registradores de estado que oferecem informações do estado atual.

diagrama de blocos de E/S
Diagrama de blocos de E/S

Um registrador de estado também pode funcionar como um registrador de controle, para aceitar informações de controle detalhadas do processador. A lógica dentro do módulo interage com o processador por meio de um conjunto de linhas de controle. O processador usa as linhas de controle para enviar comandos ao módulo de E/S. Algumas das linhas de controle podem ser usadas pelo módulo de E/S (por exemplo, para sinais de arbitração e de estado). O módulo também precisa ser capaz de reconhecer e gerar endereços associados aos dispositivos que ele controla. Cada módulo de E/S tem um endereço exclusivo ou, se controlar mais de um dis- positivo externo, um conjunto exclusivo de endereços. Por fim, o módulo de E/S contém uma lógica específica à interface com cada dispositivo que ele controla.

Transmissão serial × paralela
#

Os dados precisam trafegar de alguma forma entre interface e dispositivo. Dois paradigmas:

Característica Paralela Serial
Bits por ciclo 8, 16 ou 32 simultaneamente 1 bit por vez
Distância típica Curta (dentro do gabinete) Longa (metros a km)
Número de fios Muitos Poucos (2 a 4)
Custo Maior Menor
Exemplos Barramento interno, porta LPT USB, RS-232, Ethernet, SATA

A transmissão serial pode ser ainda:

  • Síncrona: transmissor e receptor operam com uma referência temporal comum; no modelo clássico, isso aparece como um clock compartilhado. É mais eficiente, pois evita bits extras de sincronização por caractere.
  • Assíncrona: não há clock compartilhado explícito entre as pontas; cada caractere é delimitado por bits especiais de início (start bit) e parada (stop bit) — padrão da UART (Universal Asynchronous Receiver-Transmitter).

Endereçamento de E/S: como a CPU acessa a interface
#

Como a CPU acessa os registradores da interface de E/S? Há dois paradigmas:

E/S mapeada em memória (Memory-Mapped I/O): os registradores de E/S recebem endereços dentro do mesmo espaço de endereçamento usado pela memória principal. A CPU usa as mesmas instruções de acesso à memória (LDA, STR, MOV…) para ler e escrever registradores de E/S. É simples e flexível. Desvantagem: parte do mapa de endereços passa a ser ocupada por E/S, e não por memória principal.

E/S independente (Port-Mapped I/O): existe um espaço de endereçamento separado e exclusivo para E/S — as portas de E/S. Requer instruções dedicadas (IN para leitura, OUT para escrita). Não consome endereços de memória; é o modelo da arquitetura Intel x86 (portas de 0x0000 a 0xFFFF).

As três técnicas de E/S
#

O problema central é: como a CPU sabe quando o dispositivo terminou uma operação e está pronto para transferir dados? Três estratégias evoluíram historicamente, cada uma mais eficiente que a anterior.

A figura abaixo ilustra as três técnicas de E/S: Polling, Interrupção e DMA. Cada técnica tem um modelo de interação distinto entre CPU, interface e dispositivo, com trade-offs claros em termos de eficiência e overhead. Serão exploradas em detalhes a seguir.

tres técnicas de E/S
Três técnicas de E/S

Polling — E/S programada (Busy-Wait)
#

A CPU verifica continuamente o registrador de estado do dispositivo em um laço de espera ativa:

repita:
    leia Reg_Estado do dispositivo
    se Reg_Estado == PRONTO:
        leia/escreva Reg_Dados
        saia do laço
    senão:
        continue verificando  (não faz nada útil)

✅ Extremamente simples de implementar em software.
Busy-wait: a CPU desperdiça todos os seus ciclos aguardando — não executa nenhum trabalho útil.

Desperdício catastrófico com polling

Em um sistema com clock de 1 GHz aguardando um disco com latência de 10 ms:

$$\text{Ciclos desperdiçados} = 10 \times 10^{-3}\,\text{s} \times 10^9\,\frac{\text{ciclos}}{\text{s}} = 10^7\text{ ciclos}$$

Dez milhões de ciclos completamente ociosos — apenas esperando. Em sistemas de propósito geral com multitarefa, isso é inaceitável.

Interrupção — E/S por interrupção (Interrupt-Driven I/O)
#

A CPU inicia a operação de E/S e retorna imediatamente ao seu trabalho. Quando o dispositivo conclui, ele envia um sinal de interrupção (IRQ — Interrupt Request). A CPU salva o estado atual, executa a rotina de tratamento (ISR) e retoma exatamente de onde parou:

sequenceDiagram
    participant UCP
    participant Dispositivo
    participant ISR as ISR (Rotina de Tratamento)

    UCP->>Dispositivo: Inicia operação (escreve em Reg. Controle)
    UCP->>UCP: Continua executando outros processos
    Dispositivo-->>UCP: Gera sinal IRQ ao concluir
    UCP->>UCP: Salva contexto (PC, registradores)
    UCP->>ISR: Desvia para rotina de tratamento
    ISR->>ISR: Lê dado do Reg. Dados / trata resultado
    ISR->>UCP: Restaura contexto
    UCP->>UCP: Retoma execução de onde parou

✅ CPU não desperdiça ciclos em espera; executa trabalho útil em paralelo com E/S.
❌ Overhead de salvar e restaurar contexto a cada interrupção; muitas interrupções por segundo podem saturar a CPU.

Dois tipos de interrupção merecem atenção:

  • Mascaráveis: podem ser desabilitadas temporariamente (CLI no x86) — útil para seções críticas que não devem ser interrompidas.
  • Não-mascaráveis (NMI): sempre atendidas, mesmo com interrupções desabilitadas — reservadas para erros críticos de hardware (falha de energia, erro de memória).

DMA — Acesso Direto à Memória
#

O controlador DMA é um circuito dedicado capaz de transferir blocos inteiros de dados entre a interface do dispositivo e a memória principal, sem que a CPU precise intervir a cada palavra transferida. A CPU apenas programa a operação (endereço, tamanho, direção), e o controlador DMA assume a movimentação do bloco pelo barramento.

O diagrama abaixo detalha as etapas da operação DMA, mostrando como a CPU programa o controlador, como o DMA rouba o barramento para transferir os dados e como a CPU é notificada ao final da transferência. O resultado é que a CPU fica praticamente livre durante toda a operação, exceto por um pequeno overhead inicial e uma interrupção final.

sequenceDiagram
    participant UCP
    participant DMA as Controlador DMA
    participant MP as Memória Principal
    participant IF as Interface / Dispositivo

    UCP->>DMA: Programa DMA (endereço MP, tamanho, direção)
    UCP->>UCP: Continua executando outras tarefas
    DMA->>UCP: Solicita uso do barramento
    UCP->>DMA: Concede o barramento
    Note over UCP,DMA: Cycle stealing / cessão temporária do barramento
    DMA->>IF: Coordena leitura/escrita do dispositivo
    DMA->>MP: Transfere o bloco pela memória
    DMA-->>UCP: Interrupção ao final da transferência

O diagrama acima detalha as oito etapas da operação DMA. Nas duas primeiras, a CPU ainda está no controle: ela programa o controlador DMA informando o endereço de destino na memória principal, a quantidade de dados a transferir e a direção da operação (leitura ou escrita). A partir daí, ela simplesmente continua executando outras tarefas — esse é o ganho fundamental em relação às técnicas anteriores.

Quando o controlador DMA está pronto para iniciar a transferência, ele precisa usar o barramento do sistema, que pertence à CPU. Por isso ele solicita o barramento (passo 3), e a CPU o concede (passo 4), suspendendo temporariamente seu próprio acesso a ele — o chamado cycle stealing, indicado pela nota no diagrama. Concedido o barramento, o DMA age de forma autônoma: coordena a leitura ou escrita junto à interface do dispositivo (passo 5) e transfere o bloco diretamente para a memória principal (passo 6), sem que a CPU participe palavra por palavra. Ao final, o controlador DMA envia uma interrupção à CPU (passo 7), sinalizando que a transferência terminou e que o dado já está disponível na memória.

Vale notar que o diagrama é uma simplificação intencional: ele representa a transferência como um único bloco contínuo, ocultando o fato de que, no cycle stealing real, a solicitação e a concessão do barramento se repetem para cada palavra transferida. A nota a seguir detalha essa distinção.

Roubo de ciclo — Cycle Stealing vs. Modo Rajada (Burst Mode)

O DMA pode operar em dois modos distintos de controle do barramento:

  • Cycle stealing (roubo de ciclo): o controlador DMA solicita o barramento, rouba 1 ciclo, transfere 1 palavra e devolve o barramento imediatamente. A CPU retoma brevemente, e o processo se repete para cada palavra do bloco. O impacto sobre a CPU é pulverizado ao longo do tempo, mas ela nunca fica completamente livre durante a transferência.

  • Modo rajada (burst mode): o DMA toma o barramento uma única vez e mantém o controle por toda a duração da transferência. A CPU fica suspensa durante todo o bloco, mas o barramento é usado de forma muito mais eficiente (sem a sobrecarga de múltiplas negociações).

O diagrama acima representa, de forma simplificada, o modo rajada — a solicitação e concessão aparecem uma única vez. No cycle stealing real, essa negociação se repete palavra por palavra. Em ambos os casos, a CPU não participa da transferência em si e é notificada apenas ao final, via interrupção.

A eficiência desse “roubo” depende de como o DMA está fisicamente conectado à placa-mãe. Existem três configurações arquiteturais clássicas:

  • Barramento Único (Controlador Solto): O DMA e o dispositivo compartilham o mesmo barramento do sistema. Para ler um dado do disco para a RAM, o dado trafega do Disco para o DMA e, em seguida, do DMA para a RAM. Isso usa o barramento duas vezes, suspendendo a CPU em ambos os momentos.
  • Barramento Único (Controlador Integrado): O DMA e a interface de E/S formam um único componente. O dado vai direto desse controlador para a RAM. A CPU é suspensa apenas uma vez.
  • Barramento de E/S Dedicado: O sistema possui o barramento principal (CPU-Memória) e um barramento secundário específico para periféricos (como o PCI Express). O DMA atua como uma “ponte” entre os dois. Transferências entre dispositivos no barramento secundário não afetam a CPU, e o envio para a RAM rouba o mínimo de ciclos possível.

✅ CPU praticamente livre durante a transferência de blocos grandes.
❌ Requer hardware dedicado (controlador DMA); maior custo e complexidade.

Tabela comparativa
#

Característica Polling Interrupção DMA
Complexidade de HW Mínima Média Alta
Complexidade de SW Baixa Média Média
Eficiência da CPU Muito baixa Boa Muito alta para blocos grandes
Velocidade de E/S Limitada Média Alta
Overhead por transferência Alto (laço contínuo) Médio (contexto por evento) Baixo (CPU não participa de cada palavra)
Aplicações típicas MCUs simples Teclado, mouse, temporizadores Disco, rede, áudio/vídeo
Como escolher a técnica certa
  • Polling: dispositivo com resposta muito rápida (< 1 µs) onde o custo de uma interrupção seria maior que a espera, ou sistemas embarcados muito simples sem multitarefa.
  • Interrupção: maioria dos dispositivos de propósito geral — teclado, mouse, UART, temporizadores.
  • DMA: transferências grandes e frequentes — discos rígidos, SSDs, placas de rede, áudio e vídeo.

Calculando o overhead de E/S
#

O overhead de E/S mede a fração dos ciclos de CPU consumida para tratar operações de E/S:

$$\text{Overhead (\%)} = \frac{\text{operações/s} \times \text{ciclos/operação}}{\text{ciclos totais/s}} \times 100$$

Onde:

$$\text{operações/s} = \frac{\text{taxa de transferência (B/s)}}{\text{tamanho da unidade transferida (B)}}$$$$\text{ciclos totais/s} = f_{\text{clock}}$$

Os passos para resolver qualquer problema de overhead:

  1. Calcular quantas operações de E/S ocorrem por segundo (taxa ÷ tamanho da unidade)
  2. Multiplicar pelo número de ciclos de CPU gastos por operação
  3. Dividir pela frequência do clock
  4. Multiplicar por 100 para obter o percentual
Exemplo — Overhead de interrupções de um mouse

Um mouse USB envia 40 relatórios por segundo, cada um com 4 bytes. A CPU (1 GHz) gasta 1000 ciclos por interrupção.

Com interrupção:

$$\text{Overhead} = \frac{40 \times 1000}{1 \times 10^9} = \frac{40.000}{10^9} = 0{,}004\%$$

Praticamente desprezível — a CPU gasta apenas 4 em cada 100.000 ciclos tratando o mouse.

Com polling a 1 kHz (1000 verificações/s), 100 ciclos por verificação:

$$\text{Overhead}_{\text{polling}} = \frac{1000 \times 100}{10^9} = 0{,}01\%$$

Também pequeno para o mouse — mas imagine aplicar polling a um disco SSD NVMe lendo a GB/s: o polling seria catastrófico.

Observação didática sobre o exemplo a seguir

O cálculo abaixo usa um modelo simplificado e historicamente clássico: uma interrupção por bloco pequeno e tamanho fixo de transferência. Isso é útil para comparar as três técnicas de E/S, mas dispositivos modernos — especialmente SSDs NVMe e redes de alta velocidade — usam mecanismos mais sofisticados de fila, agrupamento de interrupções e transferência.

Exemplo — Lendo 1 MB do disco: comparação das três técnicas

Sistema com CPU de 1 GHz lendo 1 MB de um disco com latência de 5 ms e taxa de 100 MB/s.

Com Polling: Tempo de transferência: \(1\,\text{MB} / 100\,\text{MB/s} = 10\,\text{ms}\)

$$\text{Ciclos desperdiçados} = (5 + 10) \times 10^{-3} \times 10^9 = 15 \times 10^6\text{ ciclos}$$

CPU praticamente bloqueada durante toda a operação.

Com Interrupção (modelo didático: 1 interrupção por setor de 512 B):

$$\text{Interrupções} = \frac{1\,\text{MB}}{512\,\text{B}} = 2048\text{ interrupções}$$

$$\text{Overhead} = 2048 \times 100\,\text{ciclos} = 204.800\text{ ciclos}$$

CPU livre durante a maior parte da operação, mas ainda precisa tratar muitas interrupções.

Com DMA: CPU programa o DMA uma única vez (custo ≈ dezenas de ciclos), DMA transfere todo o bloco autonomamente, 1 única interrupção ao final.

$$\text{Overhead}_{\text{DMA}} \approx \text{programação} + 100\text{ ciclos (1 IRQ)} \ll 204.800$$
Técnica Overhead estimado
Polling 15.000.000 ciclos (CPU bloqueada)
Interrupção ~204.800 ciclos
DMA ~dezenas + 100 ciclos
Exemplo — Identificando técnicas a partir de pseudo-código

Três implementações distintas para transferir dados de um dispositivo:

Implementação 1: Configurar dispositivo → Iniciar leitura → aguardar em laço até concluir → Armazenar → Processar. → Polling — a palavra-chave é o laço de espera ativa antes do armazenamento.

Implementação 2: Configurar dispositivo → Configurar rotina de ISR → Continuar executando; quando IRQ chegar, ISR armazena dados e retorna → Processar. → Interrupção — a palavra-chave é a rotina de tratamento (ISR) disparada pelo dispositivo.

Implementação 3: Configurar controlador DMA (endereços, tamanho) → Habilitar → Controlador transfere sem intervenção da CPU → Interrupção ao fim → Processar. → DMA — a palavra-chave é “sem intervenção da CPU” durante a transferência.

Cenários recomendados:

  • Polling: controle exato do momento de leitura sem latências de interrupção (aquisição de dados em tempo real crítico).
  • Interrupção: dispositivos assíncronos de velocidade moderada (mouse, teclado, UART).
  • DMA: altos volumes de dados contínuos (vídeo, disco, rede).

Conclusão e próximos artigos
#

A E/S é o ponto onde o computador encontra o mundo físico — e gerenciar essa fronteira é fundamentalmente um problema de diferença de velocidade. Polling desperdiça CPU em espera ativa; interrupções delegam a notificação ao hardware, liberando a CPU para trabalho útil; DMA libera a CPU completamente para blocos grandes. A escolha certa depende do volume de dados, da frequência dos eventos e da tolerância ao overhead.

No próximo artigo, vamos explorar as arquiteturas avançadas de processadores — RISC vs CISC, métricas de desempenho, a taxonomia de Flynn e como os processadores modernos partem para o paralelismo em múltiplos níveis. Fique ligado!

Até lá!

Por Dentro do Computador - Este artigo faz parte de uma série de artigos.
Parte 11: Esse Artigo

Relacionados