Compatibilidade binária: agora ou nunca

Tradução da publicação de Titus Winters no Grupo de Trabalho 21 (WG21) - Comitê de Padronização de Idiomas C ++. O autor discute uma questão importante: suporte à compatibilidade binária com versões anteriores ou ABI (interface binária do aplicativo).

Nos últimos anos no WG21, promovi ativamente que o progresso é mais importante do que a compatibilidade com versões anteriores. Mas eu mesmo não acredito mais nisso, principalmente no que diz respeito à manutenção da compatibilidade binária (ABI). Nos últimos três lançamentos (C ++ 14, C ++ 17 e C ++ 20), a ABI foi a mais estável possível. Mesmo que o WG21 decida interromper a compatibilidade com versões anteriores da ABI no C ++ 23, fornecemos compatibilidade binária em muitas plataformas há mais de 10 anos. Na minha opinião, a lei da Hyrum domina as alterações em larga escala dos sistemas de software. Agora você não pode dizer quantos usuários assumem que a biblioteca padrão da ABI é estável (por mais sábia ou explícita ou implícita) que ela seja "costurada no subcórtex", talvez metade dos desenvolvedores de C ++ no mundo.


Eu mantenho uma lista do que o WG21 poderia corrigir no idioma se decidirmos "quebrar" a ABI. E não posso dizer com confiança que o custo total do retrabalho, que implicará a implementação apenas dessa lista, é comparável ao custo da violação da ABI em todo o ecossistema. Vimos muitas pequenas melhorias na consistência da API, na qualidade do código da biblioteca padrão etc., mas sem dúvida não há uma única mudança "inovadora" que justificaria esse custo para o desenvolvedor médio. Talvez tenhamos melhores implementações do padrão, dando a chance de resolver problemas para implementações que atualmente não atendem às especificações do padrão. Mas nenhuma melhoria na minha lista vale claramente o custo.


Mais importante, devido às limitações da ABI, não podemos eliminar perdas significativas de desempenho. Não podemos nos livrar do custo significativo de transmitir unique_ptr por valor [desempenho de Chandler no CppCon 2019, a ser publicado posteriormente], não podemos alterar std :: hash ou a colocação da classe na memória para unordered_map sem forçar todos a recompilar tudo em qualquer lugar. O desempenho dos hashes foi extensivamente estudado ao longo dos anos e, levando em consideração a otimização das pesquisas na tabela e o hash adequado, estamos confiantes de que podemos fornecer uma implementação unordered_map / std :: hash compatível com a API e com aumento de desempenho de 200 a 300%. Mas as restrições da ABI não permitem isso. Estudos adicionais sobre como otimizar e ajustar o SSO para std :: string sugerem um aumento não trivial no desempenho (1% em marcas e escalonamento) - a API não é afetada, mas as restrições ABI não permitem isso.

A perda total de produtividade bloqueada exclusivamente pela ABI atinge vários pontos percentuais - possivelmente até 5-10%. Isso não é algo que o ecossistema como um todo não pode prescindir, mas pode não ser aceitável para algumas organizações (entre elas o Google). Obviamente, essa é uma grande perda de desempenho que é aceitável para C ++: lembre-se de que essa é uma linguagem que afirma que não deixa espaço para um concorrente mais produtivo. A maioria dos usuários não parece preocupada com essa degradação do desempenho: existem outras implementações de tabela de hash para aqueles preocupados com o desempenho absoluto. A ineficiência geral associada à transmissão de unique_ptr em valor e outros problemas da linguagem ABI vêm à tona em um número muito pequeno de tarefas. As organizações que precisam de produtividade máxima podem seguir seu próprio caminho (e fazê-lo), usando bibliotecas não padrão e ferramentas de configuração não padrão. Isso é natural e deve ser claramente entendido.



Uma mudança na ABI afetará um número relativamente maior de usuários. Suspeito que uma proporção significativa desses usuários não suspeite de quão forte é sua dependência da ABI. No ecossistema dos servidores do Google, quase tudo é coletado da fonte, existem poucas dependências externas e há uma oportunidade melhor que a média para realizar a refatoração em larga escala. Mas, mesmo para nós, as recentes mudanças na ABI na biblioteca padrão custam de 5 a 10 anos de engenharia.

O custo total de quebrar a compatibilidade com versões anteriores da ABI para todo o ecossistema C ++ pode ser estimado de forma conservadora no “ Millennium Engineer ”: coordenar a reconstrução para cada provedor de plug-ins, .so ou dll no mundo exigirá recursos humanos enormes. Juntamente com a separação do ecossistema devido aos módulos C ++ 20, a alteração da ABI no cronograma de desenvolvimento e implementação do C ++ 23 pode levar a uma forte separação do ecossistema.



Há muitas perguntas que não podem ser respondidas com esta discussão. Por quanto tempo podemos continuar até o ponto em que mudar a ABI de apenas útil se tornará uma necessidade crítica? Se escolhermos explicitamente o suporte à estabilidade da ABI, qual será o custo da mudança quando e quando surgir uma necessidade tão crítica? Se problemas de segurança como Spectre e Meltdown exigirem uma alteração na convenção de chamada, quanto C ++ custará para superar esse marco? Qual a proporção de desenvolvedores que usam C ++ porque afirmamos colocar o desempenho acima de tudo? Pior: quanto tempo o C ++ pode reivindicar ser a linguagem mais rápida e não precisa fazer essas otimizações?


Se conscientemente não podemos permitir ou não queremos alterar a ABI, essa decisão deve ser dublada em voz alta. Devemos dizer claramente que essa é uma linguagem que coloca a estabilidade da ABI acima dos últimos percentuais de produtividade. Estou disposto a argumentar que, na prática, esse foi o caso nos últimos anos. Precisamos informar aos usuários o que esperar de nós e informar que bibliotecas como Boost, Folly ou Absail devem fazer a escolha certa se for necessário desempenho. Mas isso não ajuda em nada com as restrições relacionadas à ABI no próprio idioma, como o custo da transmissão de unique_ptr. A biblioteca padrão mantém significância neste modelo de desenvolvimento: a biblioteca padrão é o que usamos para compatibilidade e estabilidade. Isso pode exigir uma mudança no foco e na direção do desenvolvimento: podemos querer projetar para ter mais flexibilidade nas condições de mudança e não para um desempenho "limpo".


Se argumentarmos que o desempenho é mais importante que a estabilidade da ABI, devemos decidir imediatamente quando exatamente “quebraremos” a compatibilidade com versões anteriores e faremos todo o possível para que o ecossistema aceite tais mudanças. E declarar claramente e em voz alta que estamos indo por esse caminho. Você precisa entender que quanto mais tempo passa entre essas alterações, mais caras elas se tornam - porque, com o tempo, haverá cada vez mais uma dependência não suportada da ABI. Nossos "implementadores" deixaram muito claro que as mudanças no C ++ 11 que quebram a compatibilidade eram dolorosas e caras. O desejo de evitar a repetição de tais custos é natural, mas você precisa escolher: ou não os repetimos, porque não alteramos o ITB ou diminuímos os custos.


Em essência, existem três possibilidades para o WG21:

  1. Decidir em qual versão a ABI será alterada não importa em C ++ 23 ou C ++ 26. Avise as pessoas e desenvolva imediatamente ferramentas e diagnósticos para ajudar a identificar lugares que irão se romper. Concentra-se em práticas e ferramentas mais consistentes para apoiar mudanças futuras da ABI. Não é do interesse de um implementador específico expor seus usuários às conseqüências da alteração da ABI; se outras implementações não o fizerem, a alteração da ABI deve ser uma atividade coordenada em benefício de futuros usuários. Idealmente, você precisa quebrar tudo - para deixar claro que o código compilado no modo C ++ 23 é incompatível com o código compilado nos modos anteriores. Se alguém puder passar sem reconstruir e outros tiverem erros no layout ou no tempo de execução - isso só aumentará mal-entendidos e decepções.
  2. Decida que lutamos pela estabilidade da ABI formalizando a prática de hoje. Esse é o caso há muitos anos em que os implementadores padrão têm o direito de vetar as alterações da ABI - já definimos a compatibilidade com versões anteriores da ABI acima da pureza e desempenho do projeto. Se reconhecermos isso e informarmos claramente os usuários, o ecossistema será melhor. O valor de bibliotecas adicionais aumentará para aqueles que precisam reduzir as últimas quedas de desempenho, mas não exigem a estabilidade fornecida pelo padrão. Outras linguagens orientadas para o desempenho podem desafiar nossa posição no futuro.
  3. Não é possível escolher uma direção e salvar o status quo. Este é o pior cenário para mim: continuamos prestando mais atenção implicitamente à compatibilidade com versões anteriores da ABI. Dizemos "desempenho" e votamos "compatibilidade binária". Essa dissonância prejudica o ecossistema e implica uma falta de acordo sobre as prioridades da linguagem. Espero sinceramente que, através dos esforços dos implementadores e da DG, cheguemos ao consenso necessário.

Acredito que a opção nº 1 é mais adequada para usuários que precisam de desempenho máximo, mas tem um custo incrível para o ecossistema e pode levar à fragmentação do idioma no futuro. A opção número 2 é uma escolha chata, responsável e digna: é triste admitir que nos pintamos no canto da sala e tentamos minimizar as perdas associadas a isso. Escolher a opção 3 significa não administrar, e rezo para que isso seja evitado: qualquer escolha explícita é melhor do que a dissonância atual e a incapacidade de chegar a um acordo sobre a escolha de objetivos de longo prazo.

Entendo que alcançamos nossa posição atual por meio de muitos pequenos atos de inação aparentemente razoável. Nos últimos 10 anos, nenhuma alteração foi feita para justificar uma violação da compatibilidade binária, mas a política implícita de manter a compatibilidade com versões anteriores se tornou destrutiva para o ecossistema. No entanto, ao adotar explicitamente essa política, abriremos outra possibilidade para o C ++ sair gradualmente do palco: você não pode ser uma linguagem orientada ao sistema e orientada ao desempenho, deixando muito espaço para uma linguagem mais produtiva. Em teoria, cada fornecedor pode decidir “quebrar” a ABI em qualquer versão futura, mas a direção geral do pensamento parece diferente. Estou certo de que a discussão e o consenso entre os implementadores da norma e o GT21 são necessários: que prioridades devo escolher?

Source: https://habr.com/ru/post/pt474294/


All Articles