Segunda-feira, Agosto 31, 2009

Dualidade memória/dispositivo

Ainda pensando sobre linguagem de programação e sistema, e na possibilidade de se projetar uma API de dispositivos apenas com byte e address<>, me ocorreram os seguintes pensamentos sobre a relação entre os dispositivos e a memória.

A memória é uma sequência onde ocorrem símbolos, na máquina binária contemporânea esses símbolos são bits e a unidade de armazenagem prática aos programas é o byte.

Além disso, na máquina de von Neumann, toda a operação do programa ocorre sobre a memória, inclusive operação sobre dispositivos, que ocorrem ao programa na forma de intervalos especialmente posicionados na memória.

Programas no sistema Unix, por outro lado, vêem dispositivos na forma de arquivos, com o qual trocam dados; o dispositivo é uma origem de dados e um destino de dados. A API fundamental de dispositivos é read e write. A realização básica de um arquivo é o próprio arquivo de dados, ocorrendo em um sistema de arquivamento.

É claro que o Unix, aplicando sua filosofia de simplicidade, exibe tudo como arquivo, inclusive todos os dispositivos; programas podem trocar dados com qualquer dispositivo representável em /dev. De fato, existe /dev/mem que reflete como um dispositivo a própria memória.

Por fim, borrando a distinção entre o que o processo de usuário vê e o que o sistema vê, existem os mecanismo de mapeamento em memória, que representam dispositivos (entre outras coisas) como intervalos de memória ao processo.

É fácil observar que a memória, fisicamente, e o dispositivo, abstratamente, são elementos e conceitos que se substituem e se sobrepõe. A noção de character device no Unix parece nascer exatamente daqueles dispositivos cuja natureza é a de um intervalo de átomos, um conceito cuja necessidade surge após a decisão de representar tudo como arquivos.

A união de memória virtual e o aspecto memória de um dispositivo ocorre no mecanismo de mapeamento em memória; no projeto de uma API de I/O assíncrono, a necessidade de expor páginas da memória de um processo ao driver do dispositivo para DMA também ocorre.

Programas sintonizados à API de arquivos frequentemente desejam comunicar a subprogramas dados em memória, e então a necessidade de um pseudo-dispositivo cuja representação é memória surge.

Tudo isso implica que o projeto de uma API de dispositivos é o projeto de uma API de memória, e todo projeto de um abstract data type dispositivo implica o projeto de um abstract data type intervalo-de-memória.

Que um aspecto ofereça melhor desempenho a um programa é função das necessidades desse programa. Programas que lêem arquivos frequentemente mapeiam este arquivo na memória e o lêem como um intervalo de memória. Programas que computam na memória o digest SHA-1 de uma informação frequentemente operam um pseudo-dispositivo onde escrevem blocos fixos de dados iterativamente.

Fundamentalmente, eis a questão: um dispositivo deve ser convertível para um intervalo-de-memória e vice-versa. O desafio é projetar tal API segundo todos os critérios de boas práticas realisticamente em um sistema.

Mudando de assunto, eis o projeto 9.1 do Elements of Programming:

"Modern computing systems include highly optimized library procedures for copying memory; for example, memmove and memcpy, which use optimization techniques not discussed in this book. Study the procedures provided on your platform, determine the techniques they use (for example, loop unrolling and software pipelining), and design abstract procedures expressing as many of these techniques as possible. What type requirements and preconditions are necessary for each technique? What language extensions would allow a compiler full flexibility to carry out these optimizations?"

0 comentários: