Runtime: CoreCLR falha ao executar quando o mlock está indisponível

Criado em 25 jun. 2018  ·  3Comentários  ·  Fonte: dotnet/runtime

CoreCLR usa mlock durante a inicialização e falha se mlock falhar com EPERM . Geralmente, isso não é um problema.

No entanto, muitas distribuições Linux estão começando a usar systemd-nspawn para construir código. Isso cria um chroot onde os programas têm recursos restritos. Especificamente, eles não têm CAP_IPC_LOCK , o que significa que eles não podem usar mlock .

Quando mlock não funciona, o coreclr não inicia. Isso aparece em um strace como algo como:

mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fbd542bb000
mlock(0x7fbd542bb000, 4096)       = -1 EPERM (Operation not permitted)
write(2, "Failed to initialize CoreCLR, HR"..., 49) = 49

Como resultado, isso torna basicamente impossível construir o coreclr em alguns sistemas de compilação de distribuição Linux.

area-PAL-coreclr os-linux

Comentários muito úteis

O mlock é necessário para o comportamento adequado da função FlushProcessWriteBuffers PAL que é crucial para garantir a suspensão confiável do tempo de execução para o GC. Veja https://github.com/dotnet/coreclr/blob/e6ebea25bea93eb4ec07cbd5003545c4805886a8/src/pal/src/thread/process.cpp#L3095 -L3098 para descrição do motivo.
No Linux 4.3 e superior, há um syscall sys_membarrier que podemos usar como um mecanismo alternativo para implementar FlushProcessWriteBuffers. O problema dotnet/runtime#4501 está rastreando isso. @sdmaclea tentou implementá-lo e testou no ARM64 . Ele descobriu que o desempenho foi muito ruim e que o tempo de execução de nossos ~11.000 testes coreclr foi cerca de 50% maior. No entanto, nenhum teste foi feito em outro hardware, portanto, não ficou claro se o problema de desempenho é específico do ARM64 ou um problema geral.
Curiosamente, acabei de descobrir o seguinte artigo descrevendo problemas de desempenho com o sys_membarrier: https://lttng.org/blog/2018/01/15/membarrier-system-call-performance-and-userspace-rcu/. A razão é que o syscall internamente espera até que todos os threads em execução no sistema tenham passado por uma troca de contexto, o que pode levar dezenas de milissegundos. Mas a boa notícia mencionada neste artigo é que a partir do Linux 4.14, há um novo sinalizador que pode ser passado para o sys_membarrier syscall e que o faz usar IPI para implementar a semântica de barreira de memória. E isso é muito mais rápido. Portanto, devemos experimentá-lo.

Todos 3 comentários

cc @tmds @alucryd

Consulte https://github.com/dotnet/source-build/issues/285#issuecomment -399949984 e https://github.com/rpm-software-management/mock/issues/186 para alguns exemplos em que isso está atingindo alguns constrói

O mlock é necessário para o comportamento adequado da função FlushProcessWriteBuffers PAL que é crucial para garantir a suspensão confiável do tempo de execução para o GC. Veja https://github.com/dotnet/coreclr/blob/e6ebea25bea93eb4ec07cbd5003545c4805886a8/src/pal/src/thread/process.cpp#L3095 -L3098 para descrição do motivo.
No Linux 4.3 e superior, há um syscall sys_membarrier que podemos usar como um mecanismo alternativo para implementar FlushProcessWriteBuffers. O problema dotnet/runtime#4501 está rastreando isso. @sdmaclea tentou implementá-lo e testou no ARM64 . Ele descobriu que o desempenho foi muito ruim e que o tempo de execução de nossos ~11.000 testes coreclr foi cerca de 50% maior. No entanto, nenhum teste foi feito em outro hardware, portanto, não ficou claro se o problema de desempenho é específico do ARM64 ou um problema geral.
Curiosamente, acabei de descobrir o seguinte artigo descrevendo problemas de desempenho com o sys_membarrier: https://lttng.org/blog/2018/01/15/membarrier-system-call-performance-and-userspace-rcu/. A razão é que o syscall internamente espera até que todos os threads em execução no sistema tenham passado por uma troca de contexto, o que pode levar dezenas de milissegundos. Mas a boa notícia mencionada neste artigo é que a partir do Linux 4.14, há um novo sinalizador que pode ser passado para o sys_membarrier syscall e que o faz usar IPI para implementar a semântica de barreira de memória. E isso é muito mais rápido. Portanto, devemos experimentá-lo.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

Timovzl picture Timovzl  ·  3Comentários

GitAntoinee picture GitAntoinee  ·  3Comentários

v0l picture v0l  ·  3Comentários

sahithreddyk picture sahithreddyk  ·  3Comentários

matty-hall picture matty-hall  ·  3Comentários