- A Cosmopolitan Libc é famosa por fornecer binários executáveis em vários sistemas operacionais e é uma biblioteca C capaz de entregar excelente desempenho também em ambientes de produção.
- Benchmark de mutex para comprovar o desempenho: a implementação de mutex foi comparada por meio de um teste em que 30 threads incrementam o mesmo inteiro 100.000 vezes
- Windows
- O
pthread_mutex_t da Cosmopolitan é 2,75 vezes mais rápido que o SRWLOCK da Microsoft e usa 18 vezes menos recursos de CPU
- O mutex do Cygwin tem desempenho muito baixo, a ponto de ser melhor usar um spin lock.
- Linux
- O
pthread_mutex_t da Cosmopolitan é 3 vezes mais rápido que o glibc e 11 vezes mais rápido que o musl libc
- O uso de CPU é 42 vezes menor que o do glibc e 178 vezes menor que o do musl libc
- MacOS
- O Apple Libc apresenta desempenho ligeiramente melhor que o mutex da Cosmopolitan
- A Cosmopolitan otimiza o desempenho com um algoritmo baseado no artigo "Futexes Are Tricky", de Ulrich Drepper
Como isso é possível?
- O excelente desempenho vem do uso da biblioteca nsync, escrita pelo renomado engenheiro do Google Mike Burrows
- Ele foi quem programou o Altavista, antigo concorrente do Google
- Truques e análise do nsync
- O nsync usa imediatamente um CAS (compare and swap) otimista para que o bloqueio ocorra rapidamente quando não há contenção
- Quando não consegue adquirir o bloqueio, o nsync adiciona a thread chamadora a uma lista duplamente encadeada de esperadores
- Cada esperador recebe seu próprio semáforo em uma linha de cache separada e independente
- Quando a thread entra em espera, ela não toca mais no bloqueio base
- O motivo da importância disso pode ser visto no documento "What Every Programmer Should Know About Memory", de Ulrich Drepper
- Quando vários núcleos tocam a mesma linha de cache, isso gera muito overhead de comunicação dentro do processador
- O nsync usa futex para obter ajuda do sistema operacional
- O futex é uma excelente abstração inventada no Linux há alguns anos e que rapidamente passou a ser usada em outros sistemas operacionais
- No MacOS ele se chama ulock, e no Windows,
WaitOnAddress()
- Entre os sistemas operacionais suportados pelo Cosmo, o único sem futex é o NetBSD (ele implementa semáforos POSIX no espaço do kernel, e cada semáforo precisa criar um novo descritor de arquivo)
- O ponto importante do futex e dos semáforos é que o sistema operacional pode colocar a thread para dormir. Com isso, o nsync não precisa consumir tempo de CPU quando não há trabalho a fazer
- O nsync evita starvation com o conceito de "espera longa (long wait)"
- Se um esperador é acordado 30 vezes e falha internamente em adquirir o bloqueio, um bit é adicionado ao bloqueio para impedir que threads que ainda não esperaram o adquiram
- O CAS inicial falha para todos os outros até que a fila seja desafogada em certo nível
- O nsync usa o conceito de "despertador designado (designated waker)" para acelerar o caso de uso analisado no benchmark (bloqueios contenciosos com seções críticas pequenas)
- Esse bit é definido no bloqueio base quando a thread que tenta adquirir o bloqueio está acordada
- No nsync, a função de desbloqueio é responsável por acordar a próxima thread que está esperando pelo bloqueio
- Com esse bit, a thread que libera o bloqueio sabe que não precisa acordar uma segunda thread, porque já existe um lock waiter acordado
Prova online
- É possível verificar o desempenho por meio de uma demonstração ao vivo de software usando mutexes da Cosmopolitan.
- O servidor web http://ipv4.games/ mostra desempenho capaz de resistir até mesmo a grandes ataques DDOS.
1 comentários
Comentários do Hacker News
Sempre é interessante ver novas implementações de mutex e comparações de desempenho entre elas. Mas este benchmark parece um microbenchmark. O normal é testar o desempenho usando um programa multithread de grande porte. Em cargas de trabalho complexas, o desempenho de um mutex se comporta de forma diferente
O motivo de os Cosmopolitan Mutexes serem bons é o uso de uma biblioteca chamada nsync. Essa biblioteca foi escrita por Mike Burrows, um engenheiro renomado do Google. Mas fico curioso sobre por que essa implementação de mutex não foi incluída no benchmark
__ulockno macOS, isso pode ser implementado de forma mais simples com as funçõeswait()enotify_one()da biblioteca atomic do libc++Há muitas opiniões positivas sobre Cosmo/ape/redbean, mas nunca vi ninguém usando isso de fato. Fico curioso se essas ferramentas são realmente inovadoras, mas ainda não amplamente adotadas
Tenho grande apreço pelo projeto Cosmopolitan, mas desconfio de alegações exageradas de superioridade. O motivo de nem toda biblioteca C adotar o mesmo truque pode ser que ele só seja sempre mais rápido em arquiteturas, modelos de CPU ou cargas de trabalho específicas
Em produção, confiabilidade é mais importante do que velocidade ou eficiência. O mais importante é garantir que o sistema não quebre
Já tive a experiência de corrigir um bug encontrado na função de unlock do mutex do nsync. Estou vendo melhorias no nsync dentro do projeto Cosmopolitan. Fico curioso se usar o nsync upstream é seguro
Threads e mutexes são um dos elementos mais complexos da ciência da computação. Sempre sou cético até que uma nova implementação seja usada em larga escala. Quando o Java surgiu, muitos bugs de threads e mutexes apareceram no Solaris
Fiquei surpreso com o fato de o nsync ser muito mais rápido que o SRWLOCK. Já tive experiência em fazer engenharia reversa dos SRWLOCKs do win32
Toda vez que vejo mutexes, sinto algo negativo. Já trabalhei removendo locks de muito código e substituindo-os por abstrações de fila ou mensageria. Ultimamente, venho explorando vários algoritmos de locking. Quero experimentar ferramentas de locking eficientes como o nsync