Então eu fui para a fonte, e parece que a lentidão está no tratamento de caracteres de byte duplo. Essencialmente, para cada caractere lido, ele precisa chamar mbrtowc() para tentar convertê-lo em um caractere largo, então esse caractere largo é testado para ver se é um separador de palavras, um separador de linhas, etc.
De fato, se eu alterar minha variável de local LANG do padrão en_US.UTF-8 (UTF-8 é um conjunto de caracteres multibyte) e defini-la como " C " (conjunto de caracteres simples de byte único), wc é capaz de usar otimizações de byte único, o que acelera consideravelmente, levando apenas cerca de um quarto do tempo anterior.
Além disso, ele só precisa verificar se cada caractere está em andamento ( -w ), o comprimento da linha ( -L ) ou o caractere ( -m ) conta. Se estiver apenas fazendo contagem de bytes e / ou linhas, ele pode ignorar o tratamento de caracteres amplo e, em seguida, é executado com extrema rapidez - mais rápido do que md5sum .
Eu o executei através de gprof , e as funções que são usadas para manipular os caracteres multibyte ( mymbsinit() , mymbrtowc() , myiswprint() , etc) estão ocupando cerca de 30% do tempo de execução sozinho, e o código que percorre o buffer é muito mais complexo porque ele tem que manipular etapas de tamanhos variáveis através do buffer para caracteres de tamanho variável, bem como preencher quaisquer caracteres parcialmente completos que abranjam o buffer de volta ao início do buffer para que ele possa ser tratou da próxima vez.
Agora que sei o que procurar, encontrei alguns posts mencionando a lentidão do utf-8 com alguns utilitários: