Quando tento implementar a biblioteca de strings C, descobri que a glibc e o kernel do Linux têm uma maneira diferente de implementar algumas funções. Por exemplo, glibc memchr e glibc strchr usam algum truque para acelerar a função, mas o kernel memchr e o kernel strchr não. Por que as funções do kernel do Linux não são otimizadas como glibc?
relate perguntas
-
Bloqueando montagem syscall
-
Por que a versão 30 das ferramentas sem fio se tornou uma versão beta permanente?
-
tamanho da pilha do programa
-
Quais dongles WiFi 802.11ac (ou posteriores) funcionam com o kernel Linux 4.13
-
Parábola (semelhante ao Arch) - A atualização do ICU fez com que alguns programas exigissem duas versões diferentes da biblioteca do ICU. Ambos falham ao iniciar. Não pode se reproduzir
O kernel tem versões otimizadas de algumas dessas funções, nos diretórios específicos do arch; veja por exemplo a implementação x86 de
memchr
(veja todas asmemchr
definições e todas asstrchr
definições ). As versões que você encontrou são as versões genéricas de fallback; você pode identificá-los procurando o cheque de proteção,#ifndef __HAVE_ARCH_MEMCHR
paramemchr
e#ifndef __HAVE_ARCH_STRCHR
parastrchr
.As versões otimizadas da biblioteca C tendem a usar códigos mais sofisticados, então o que foi dito acima não explica por que o kernel não se esforça tanto para ser rápido. Se você puder encontrar cenários em que o kernel se beneficiaria de uma versão mais otimizada de uma dessas funções, imagino que um patch seria bem-vindo (com evidências de suporte apropriadas e desde que a função otimizada ainda seja compreensível - veja esta antiga discussão sobre
memcpy
). Mas eu suspeito que os usos dessas funções pelo kernel muitas vezes não farão valer a pena; por exemplomemcpy
e funções relacionadas tendem a ser usadas em pequenos buffers no kernel. E nunca desconte os ganhos de velocidade de uma função curta que cabe no cache ou pode ser incorporada...Além disso, como mencionado por Iwillnotexist Idonotexist , MMX e SSE não podem ser usados facilmente no kernel , e muitas versões otimizadas de funções de busca ou cópia de memória dependem delas.
Em muitos casos, a versão usada acaba sendo a versão interna do compilador de qualquer maneira, e estes são fortemente otimizados, muito mais do que até mesmo a biblioteca C pode ser (por exemplo,
memcpy
muitas vezes será convertida para um registro load and store, ou mesmo uma loja constante).Lembro-me que tive que corrigir um bug de despejo de núcleo do kernel no Solaris em 2006 que foi acionado com um sistema de arquivos ISO-9660 + Rock Ridge criado por algo diferente do
mkisofs
.Esse software de formatação ISO não incluiu o nome do arquivo Rock Ridge no meio da entrada do diretório ISO-9660 (como feito por
mkisofs
), mas no final da entrada do diretório ISO-9660. Agora você precisa saber que os nomes dos arquivos Rock Ridge não são terminados por um byte nulo...O que aconteceu foi que as rotinas de string (naquela época muito otimizadas) no kernel do Solaris poderiam ultrapassar um em alguns casos e se o nome do arquivo Rock Ridge terminasse exatamente no final de um setor de 2k e esse setor terminasse apenas no final de uma página de memória do kernel de 4k, esse acesso excessivo causou um pânico no kernel devido a um acesso ilegal à memória.
Precisávamos reescrever o código de acesso para ser muito conservador para evitar esse pânico do kernel no futuro.
Como você vê, às vezes é muito mais difícil escrever código seguro para o kernel e esse código às vezes é um pouco mais lento apenas para evitar um pânico no kernel.
BTW: o problema com uma pré-busca potencialmente imprevisível da CPU em programas de espaço do usuário pode ser tratado deixando o vinculador adicionar alguns bytes após os segmentos se houver a possibilidade de atingir o final de uma página MMU. Isso não funciona em um kernel que depende de áreas de mapeamento.