[blog] Kernels monolíticos e microkernels

«in my proudy opinion, as an architecat, we should put a middleware under the application layer»

Sistema operativo e kernel

Antes, uma ligeira digressão: onde termina o sistema operativo e começa o kernel? Conceituá-lo como o núcleo do SO fatalmente amarra esta diferenciação ao sistema. Eu diria quem nem todo kernel é um sistema operativo, mas todo sistema operativo tem um kernel. Devido à hardware-dependência, a discussão sobre a estrutura do SO/kernel não pode ser desvinculada do hardware em que este sistema está implantado. Do ponto de vista do programador da aplicação, um SO provê uma forma de acessar o hardware (abstração), além dos mecanismos para gerenciar recursos que as aplicações demandam.

Para microprocessadores mais simples, as possíveis escolhas arquiteturais podem (e muitas vezes devem) fazer uma diferenciação entre kernel/SO e aplicação. Entretanto se na prática não houver diferenciação entre usuário e supervisor, o sistema todo é um único objeto, e a vantagem advinda desta diferenciação é majoritariamente do ponto de vista de modelagem, manutenção e reuso do software.

Durante o desenvolvimento de um sistema desta natureza, se o programador desejar, a aplicação pode acessar recursos do hardware sem passar pelo sistema operacional, como ilustra a Figura 1. Aliás, o mais simples bare-metal é conceitualmente um sistema operativo.

Figura 1. Sistema operativo baseado em bibliotecas [1]

Em microprocessadores mais complexos, nos quais existe separação entre espaço de supervisor e usuário o acesso ao hardware pela aplicação pode ser limitado por um mecanismo supervisor. Para acessar o hardware as threads da aplicação precisam executar system calls: pedir acesso aos recursos de sistema.

Na Figura 2 (a), o sistema operativo é dito “monolítico” porque é um objeto à parte, entretanto existe ainda uma simbiose entre aplicação e sistema operativo. Perceba que esta simbiose já não ocorre entre aplicação e hardware.

Figura 2. Sistemas operativos (a) monolítico (b) em camadas [1]

Na Figura 2 (b), o SO em camadas é uma arquitetura padrão para sistemas de uso mais generalista, atingido através da definição de camadas de software com o menor acoplamento possível. O layer logo abaixo da camada de aplicação poderia ser um AAL (Application Abstraction Layer), por exemplo. Também, a camada logo acima do hardware poderia ser um BSP (Board Support Package). As representações na Figura 2 entretanto, não dizem nada sobre o kernel.

Kernel Monolítico e Microkernel

Em linhas gerais, dois modelos de kernel constam na literatura: monolítico e microkernel. A diferença crucial entre ambos está no volume de recursos do sistema que correm no espaço do supervisor e no espaço do usuário.

A Figura 3 ilustra conceitualmente as duas abordagens. No microkernel um conjunto menor de abstrações corre em kernel space. Assim, programas de sistema, como o sistema de arquivos, device drivers, etc., estarão também no domínio de usuário e operam como servidores. No domínio do kernel ficam os módulos mais essenciais, o escalonador e a comunicação inter-processos, por exemplo. A função primordial do microkernel é gerenciar recursos, e em menor parte abstrair o hardware. A modularidade é um ponto forte da arquitetura, normalmente descrita como um conjunto de layers com baixo acoplamento, no modelo cliente-servidor.

Figura 3. Kernel Monolítico vs Microkernel [2]

O kernel monolítico por sua vez concentra todos os serviços em uma única unidade de compilação, e somente a aplicação estará a correr no espaço de usuário. Neste tipo de sistema o kernel além de um gerenciador de recursos é também uma extensão da máquina (“extended machine”), porque abstrai completamente o hardware para o usuário.

Kernel + SO

Na Figura 4 uma ilustração conceitual famosa do GNU/Linux (Linus Torvalds é um grande defensor dos monolíticos). As bibliotecas (glibc) e as aplicações estão em user space. No kernel space existe uma parte que é “universal” para todos os Linuxes, e outra que depende da plataforma em hardware.

Figura 4. GNU/Linux [4]

Ainda em domínios de aplicação mais generalistas, o Minix do Prof. Tanembaum é um microkernel raíz. Os layers bem definidos correm a maior parte do sistema no espaço de usuário. Uma alegada vantagem deste tipo de arquitetura é que caso o driver de um dispositivo entre em deadlock, o kernel pode resetar o sistema. Em um sistema com kernel monolítico isto não seria possível porque o sistema estaria trancado já em modo supervisor. Os microkernels são entretanto conhecidos por serem mais lentos – em sistemas de uso generalista, principalmente – além de adicionarem complexidade à comunicação inter-processos, que pode ser eventualmente explorada por código malicioso.

Figura 5. Minix 3 [5]

Outros flavours para microkernel são possíveis. Na Figura 6a, o SO monolítico significa que todos os servidores estão concentrados em um único programa, e as aplicações utilizam-se de clientes para acessar estes serviços concentrados. Na Figura 6b, os servidores estão distribuídos modularmente. Na Figura 6c., uma aplicação especializada (dedicada) interage diretamente com o microkernel, sem um SO propriamente dito.

Figura 6. Sistemas com microkernel: a) SO monolítico com Microkernel b) SO distribuído com microkernel c) Sistema monolítico com microkernel [3]

[1] RANKL, Wolfgang. Smart Card Handbook. 2010

[2] KEN, Yu. RTOS Model and Simulation using System C. 2010

[3] HERDER, Jorrit. Torwards a true Microkernel Operating System. 2005

[4] Anatomy of the Linux kernel – IBM Developer

[5] https://upload.wikimedia.org/wikipedia/commons/7/7d/The_MINIX_3_Microkernel_Architecture.png

[blog] Group working: constructive and destructive behaviors

4x100m Medley Relay: even though they perform alone in the pool, the overall result is what matters. In a pretty well balanced team, like this, each swimmer can go for his best style. If the team was heavily unbalanced, at the limit, for instance, Adrian happens to be competitive only on butterfly – Phelps could give up his best stroke (butterfly) for the overall goal – since Phelps’ crawl could deliver at least enough contribution for a medal.

During my career I have had the opportunity to work with different people, from different cultures (5 cities, 3 countries) and I think I can talk about my very own impressions of what is a functional working group.

I believe in a very straight way to work in group: comradery. If you can provide what others need – do it. I am not saying you need to sacrifice yourself, but the overall result should be more important than your very own result, as in any system. Frustrated colleagues will, even if they try to avoid, create a frustrating environment, and that is language – not a mystical energy as one could suggest. The size of your RAM memory does not mean too much if the throughput is damaged at a certain frequency.

But it all comes down to language: human language. It is such a complex mechanism: a biopsychosocial product from the structure of your bones, passing through the consequences of the most joyful or painful events you went through and the positions you someway have occupied on the groups you once belonged or still belong to (family, school, sports, etc.). And of course, everyone has different bones and a life story, therefore, different ways to communicate. By communication, I mean transferring, receiving and processing information. This is even more clear when working with people from different cultures.

Being helpful makes who helps feel fine – mainly if recognized. Being helped makes people feel included, and not apart or ignored. An ideal system has fully functional decoupled components that communicate well. No noise, no jitters, no heavy dependence between them, but if one component malfunctions/fails, the overall system will eventually malfunctions/fails, otherwise it is not a system at all.

The tricky thing in all of this is the balance. There will be times when a person will need to provide more than receive, and another times, this very same person will need to receive more than provide. This sending+receiving addend, should integrate in time to an ideal value, as a contribution to the ideal system value, i.e, a goal. It seems the value for the overall system is more meaningful and easier to assess than the value for each component, but the stability of the system depends on the harmony between the components1. And there are deadlocks: helpless people cannot help. And the capacity of anyone to help is also limited. If someone is not receiving, it is very probable he will not be able to provide. What comes first? That is the tricky balance.

Anyway, as individuals the best we can do is to be self-aware. Some psychologists say behaviors can generally be classified as constructive or destructive. Below some attitudes are listed2. It is worth to think about how you are doing.

Constructive Behaviors:
Cooperating: Is interested in the views and perspectives of the other group members and is willing to adapt for the good of the group.

Clarifying: Makes issues clear for the group by listening, summarizing and focusing discussions.

Inspiring: Enlivens the group, encourages participation and progress.

Harmonizing: Encourages group cohesion and collaboration. For example, uses humor as a relief after a particularly difficult discussion.

Risk Taking: Is willing to risk possible personal loss or embarrassment for the group or project success.

Process Checking: Questions the group on process issues such as agenda, time frames, discussion topics, decision methods, use of information, etc.


Destructive Behaviors:
Dominating: Takes much of meeting time expressing self views and opinions. Tries to take control by use of power, time, etc.

Rushing: Encourages the group to move on before task is complete. Gets “tired” of listening to others and working as a group.

Withdrawing: Removes self from discussions or decision-making. Refuses to participate.

Discounting: Disregards or minimizes group or individual ideas or suggestions. Severe discounting behavior includes insults, which are often in the form of jokes.

Digressing: Rambles, tells stories, and takes group away from primary purpose.

Blocking: Impedes group progress by obstructing all ideas and suggestions. “That will never work because…”

1 We are not that predictable, although being predictable is an essential good social adaptive response.

2 https://cns.utexas.edu/images/CNS/TIDES/teaching-portal/Constructive_and_Destructive_Group_Behaviors.pdf

[blog] O Amplificador Diferencial

Comentários básicos sobre este workhorse em eletrônica. O conceito de amplificador diferencial é elemento-chave em uma infinidade de aplicações analógicas: buffers, filtros, osciladores, reguladores de tensão, referências de tensão/corrente, processamento de sinais, PLLs, etc., devido às suas propriedades úteis. As figuras foram retiradas do livro CMOS Circuit, Design, Layout and Simulation (Baker).

Figura retirada de analog.com

O Par diferencial

O conceito de diferencial é comum em engenharia e consiste na ideia de que determinado fluxo de energia é distribuído entre dois ramos ‘complementares’ de um dispositivo (no automóvel, isto permite que uma roda gire mais rápido que a oposta para que possamos fazer uma curva – cada uma das rodas vai percorrer diferentes comprimentos de arco no mesmo tempo). Em eletrônica o par diferencial nos permite principalmente eliminar ruídos de modo-comum (neste caso especificamente aqueles provindos de uma mesma fonte DC que alimenta os circuitos que geram os sinais AC de entrada, e possivelmente o amp-op).

O Amplificador Diferencial

A apresentação clássica do amplificador diferencial é assim:

Vout = (V+ – V)*Ganho [V]

Também sempre é dito que idealmente temos:

  • impedância de entrada infinita
  • impedância de saída nula
  • ganho infinito em malha aberta
  • rejeição de modo comum infinita

Vou tentar mostrar aqui porque estas características são importantes, utilizando circuitos analógicos CMOS básicos e análises intuitivas.

Talvez a primeira coisa que vem à mente de quem é introduzido ao assunto é que se o ganho é muito grande (como deve ser), a tensão Vout vai explodir. Primeiramente, esta equação está em malha aberta, sem a realimentação negativa, quando parte do sinal de saída é subtraído do sinal de entrada. Depois, na maior parte das vezes estamos interessados em trabalhar em pequenos sinais AC – centésimos ou milésimos de Vdd (v+, v-). Cabe ainda dizer que ganho mede-se em V/V (é um número sem dimensão), e independente do seu tamanho a máxima tensão alcançada será sempre Vdd.

Os pequenos sinais (v+,- v-) variam em torno da polarização DC (V+, V-). Polarizar significa determinar um ponto de operação do circuito, de cada transistor na verdade (em elementos semicondutores, as características elétricas variam conforme às tensões elétricas a que o dispositivo é submetido).  Na figura acima o ganho de malha aberta (open-loop) é mostrado como função da frequência do sinal de entrada. Uma topologia clássica do circuito amplificador diferencial em CMOS é assim:

(PS: transistores NMOS estarão em região linear se VGS >= Vth, e PMOS com VSG >= Vth. IDS = f(VDS,VGS), assume formas distintas a depender da região de operação)

A corrente Iss é resultado da tensão de gate em M6, que estará com a corrente estável em um range de tensão dreno-fonte. Supondo uma tensão Vn, de modo comum aplicada aos gates de M1 e M2, a corrente drenada por M6 seja um valor Iss = Id1 + Id2.

Se extrairmos a tensão de saída no dreno de cada um dos transistores M1 e M2, Vout1,2= Id1,2*RCarga1,2. Isto basicamente diz que o ganho Av=Vout/Vin é proporcional à transcondutância do transistor em determinado ponto de polarização multiplicado pela carga, pois ID/Vin = Gm = 1/(Rds).

A saída Vout diferencial é VD1-VD2 ou ao contrário, a depender do que estabelecermos como saída positiva e negativa. Com a topologia acima é impossível dizer qualquer coisa sobre qual será a entrada positiva e qual será a negativa. Só podemos dizer isto quando definirmos qual a entrada que aumenta a tensão de saída, e a entrada que a diminui.

Para tanto, completa-se o par diferencial com uma carga espelho de corrente do tipo PMOS, uma carga ativa.

Se a tensão do gate M1 aumenta, mais corrente é drenada, maior a tensão VSG de M3 e M4 (ou menor a tensão VGS, se preferir). Se ambos M1 e M2 tiverem a mesma tensão de gate, a corrente no sentido dreno-fonte de cada elemento do par será ID1 = ID2 = Iss/2 [A]. Se tensão de gate em M1 aumenta em relação à tensão de gate M2, menos corrente é drenada por M2 e portanto menor a queda dreno-fonte em M2. Se M2 continuar no ponto de operação desejável, sua (trans)condutância é constante. Se a condutância de M2 mantém-se constante, mas sua corrente diminui, a tensão Vout = VDD – VSD4 obrigatoriamente aumenta. Então VG1 = V+. O raciocínio inverso vale para V: quanto maior a corrente drenada em M2, menor a tensão Vout. É este balanço na entrada que nos permite reduzir drasticamente o ruído de modo comum, se comparado a um amplificador de entrada única. Se adicionarmos mais um estágio de amplificação teremos ganho suficiente para chamá-lo de amplificador operacional. Tradicionalmente, o próximo estágio seria um amplificador PMOS, dreno-comum, com carga NMOS.

Ainda nesta topologia de só um estágio, a curva de transferência assume o seguinte, sendo o eixo horizontal a tensão de modo comum Vin nos gates do par diferencial, e no eixo vertical, Vout a tensão medida nos drenos de M2 e M4.

A derivada no ponto de polarização é o ganho do amplificador quando polarizado com a tensão correspondente Vin. Um bom ponto de polarização é aquela cuja derivada em relação ao pequeno sinal vin mantenha o maior intervalo em vout sem perturbar a transcondutância de M2 // M4. Idealmente é um ponto com derivada infinita. Pois para o sinal vout não remover M2 e M4 do ponto de operação desejável, as correntes drenadas não podem causar quedas de tensão que retire os transistores do ponto de operação, o que no limite significa impedância nula no nodo vout. Para a impedância de entrada ser infinita, a variação da tensão vgs de M1 e M2, não deve causar variação de tensão vgs + Vgs que retire o transistor da região de operação desejada. Se for saturado na região linear, a tensão dreno-fonte precisa manter-se em Vds >= tensão de overdrive (Vgs – Vth). A rejeição de modo comum será tão boa quanto a precisão do espelhamento de corrente – o mais iguais o módulo das correntes de dreno de M3 e M4, mais ruídos do sinal de tensão de modo-comum Vin estarão subtraídos no nodo Vout = Iout*RLout.