“Um erro típico - faça benchmarks sem pensar em tudo”: uma entrevista com Andrey Akinshin sobre benchmarking



No ano passado, Andrei Akinshin (Andarilho dos Sonhos) foi publicado o livro "Pro .NET Benchmarking" : um trabalho detalhado sobre benchmarking, útil para desenvolvedores .NET e especialistas em TI em outras áreas.

Alguns meses antes do seu lançamento, realizamos a conferência DotNext 2019 Piter, onde na transmissão on-line perguntamos a Andrei sobre o livro e, geralmente, sobre o benchmarking. Parece que, desde então, essa entrevista deveria estar desatualizada: lá eles falam sobre o livro no futuro, e agora já são seis meses. Mas, nos últimos seis meses, a humanidade não decidiu tomar o 99º percentil. Portanto, para todos que podem usar o benchmarking, as respostas de Andrei ainda têm muita relevância e interesse.

Ele vai realizarsobre o futuro do DotNext com o tópico “Vamos falar sobre análise de desempenho” - isto é, não sobre a criação de benchmarks, mas sobre a análise dos valores que eles coletaram. No momento, Andrey está estudando centenas de artigos sobre estatística matemática para falar sobre os métodos mais adequados para análise de desempenho na vida real. No livro, também é dada atenção a essa análise e, em uma entrevista, Andrey apenas explicou sua importância. Portanto, antecipando um novo relatório, abrimos um vídeo de entrevista para todos e fizemos uma transcrição de texto especificamente para Habr: agora ele pode não apenas ser visto, mas também lido.


A principal coisa sobre o livro


- Congratulamo-nos novamente com os telespectadores da transmissão DotNext. Desta vez, Andrey Akinshin está conosco.

- Olá a todos!

- Agora, as principais notícias relacionadas a você são o anúncio do livro, que será lançado em setembro ...

- Se tudo der certo, será lançado no final de junho.

Aqui você precisa entender como funcionam os prazos. Existem os mais extremos, que não podem ser violados em nenhum caso. Na Amazon, o livro agora tem uma data de lançamento por volta de 23 de agosto. E se você mudar essa data, todos os tipos de sanções serão aplicadas, a Amazon ficará infeliz. E se o livro sair mais cedo - bom, bom.

Portanto, espero realmente que, se não houver problemas em nenhum lugar, seja possível ler em junho. E assim, o final de agosto é o prazo final. Você também trabalha em TI, para entender como essas coisas funcionam.

- A maioria da platéia provavelmente já ouviu falar sobre o livro. Mas para quem não sabe, vamos começar com uma história sobre ela.

- O livro é chamado "Pro .NET Benchmarking" . Ela é da série Apress - a mesma em que o livro Pro .NET Memory Management de Conrad Coconut foi lançado recentemente . E havia o livro de Sasha Goldstein , "Pro .NET Performance", publicado - você provavelmente já ouviu falar sobre isso, ele é reproduzido de tempos em tempos no DotNext. E na mesma série vem o meu livro. É sobre como fazer comparações do início ao fim.

Eu tentei cobrir uma variedade de aspectos, começando pelas estatísticas, há um capítulo separado sobre isso. E não é assim que fomos ensinados na universidade, não tenho um único exemplo sobre "bolas que são colocadas em caixas". Concentre-se no que pode ser útil durante o benchmarking: métricas, desvio padrão, erros padrão, todos os tipos de intervalos de confiança e como interpretá-los. Ou seja, estamos falando do seguinte: se o BenchmarkDotNet condicional forneceu um milhão de números diferentes, o que devo fazer com eles? Recomendações práticas são dadas sobre como interpretar esses dados e tirar conclusões.

Há um capítulo, por exemplo, sobre benchmarks vinculados à CPU e sobre benchmarks vinculados à memória. Existem muitos estudos de caso diferentes, com exemplos de como você pode escrever uma referência para 3-4 linhas e ao mesmo tempo dar um tiro no pé devido a alguns efeitos microarquiteturais dos modernos processadores Intel.

E há um capítulo sobre análise de desempenho e teste de desempenho. O benchmarking é bom como um experimento separado, mas muitas pessoas desejam colocar benchmarks no IC, conduzi-los o tempo todo em algum servidor (idealmente o mesmo), coletar dados, por exemplo, para detectar degradações no desempenho. Portanto, há um capítulo sobre como trabalhar com esses dados e escrever diferentes tipos de testes de desempenho (existem muitos diferentes). Qual é, por exemplo, a diferença entre testes para uma partida a frio, uma partida a quente, como processar gráficos, como processar matrizes de dados inteiras.

Em um dos DotNext anteriores, faleisobre análise de desempenho, ele falou sobre diferentes métodos de pesquisa de anomalias de desempenho. A degradação não é o único problema que pode surgir. Por exemplo, existem distribuições multimodais quando o benchmark funciona por um segundo ou dez. Em um produto grande (especialmente com vários segmentos), esses casos certamente serão e, geralmente, ocultam o problema. Mesmo que não se trate de testes de desempenho executados nas máquinas correspondentes, mas dos testes usuais, o diabo sabe como "tremer" e dar muita variação; se você coletar e analisar todos esses dados, poderá encontrar muitos testes com esses problemas.

Em geral, há uma gama muito ampla de tarefas muito interessantes no benchmarking, e eu as organizei cuidadosamente nas prateleiras. Mas tentei fazê-lo da maneira mais prática possível, para que não fosse apenas uma teoria, mas algum conhecimento que eu pudesse usar e usar no meu produto na produção.

Sutilezas de benchmarking


- Lembro-me da frase que li em algum lugar que, para qualquer resultado de referência na Internet, você pode encontrar a interpretação errada desse resultado. Quanto você concorda com esta frase?

- Concordo absolutamente. Fala-se muito em benchmarks válidos e inválidos, mas se você observar de uma maneira geral, se mediu alguma coisa, coletou pelo menos algumas métricas de desempenho e as exibiu em um arquivo ou console, então este é um benchmark com um certo Do ponto de vista, é válido: algo mede e exibe alguns números. A questão principal é como você interpreta esses números e o que você fará a seguir.

Um dos primeiros erros das pessoas que estão imersas no tópico de benchmarking é que elas vão fazer benchmark de tudo sem se perguntar "por quê". Bem, comparamos, medimos - e depois o que? É muito importante determinar com que finalidade estamos fazendo o benchmarking.

Por exemplo, se queremos criar uma carga de trabalho estável, com a qual possamos avaliar o desempenho de certos casos e detectar a degradação do desempenho - esse é um caso. Outro caso: temos duas bibliotecas que fazem a mesma coisa, e somos a favor do desempenho e queremos escolher a mais rápida - como você compara isso?

Do ponto de vista das interpretações, qualquer um que leve à decisão certa de negócios pode ser considerado bom. Não é necessariamente correto, mas se você tiver sucesso, é bom.

E existe uma coisa que eu tenho exercícios especiais no meu livro. Digamos que existem dois algoritmos, e o exercício é este: primeiro você precisa fazer um benchmark que mostre que o primeiro algoritmo é 10 vezes mais rápido que o segundo e, em seguida, um benchmark que mostra o oposto. Você pode jogar com os dados de origem, com o ambiente, alterar o Mono para .NET Core ou executar no Linux em vez do Windows - há um milhão de opções para personalização. E a conclusão é a seguinte: se você pretende mostrar que um programa funciona mais rápido que outro, provavelmente existe uma maneira de fazê-lo.

Portanto, voltando à sua pergunta, é muito difícil traçar uma linha entre valores de referência válidos e inválidos e fornecer uma definição de inválido (ou seja, o que deve estar lá para que possamos reconhecer que é ruim). E o mesmo com a distinção entre a interpretação “correta” e a “incorreta”: você não consegue entender completamente o que está acontecendo no benchmark, não consegue explicar completamente todos os processos internos (o que não é muito bom, seria melhor fazer isso, mas você pode pular esta parte, se muito ocupado), mas, ao mesmo tempo, entenda em geral como é a imagem. E se você conseguiu fazer o certo (aqui novamente a questão é o que é "certo") e chegou à decisão de negócios certa, então está bem feito.

“Se você apenas ler e ler seu livro cuidadosamente, começará a tomar as decisões“ certas ”? Ou há muitas coisas fora do escopo do livro que também influenciam?

- O benchmarking é um tópico que, na minha opinião, só pode ser dominado na prática. Sim, no livro eu dou muitas metodologias, recomendações, descrevo armadilhas. No benchmarking, existem muitos problemas que, se você não os conhece, na vida nunca os adivinhará. Mas se você souber sobre eles, isso não garante absolutamente que seus benchmarks estarão corretos. Ou seja, este é um kit de ferramentas tão mínimo que ajuda a se orientar de alguma forma no campo.

Você pode escrever benchmarks normais e testes de desempenho apenas se você lidar sistematicamente com essa área. A grade neural no cabeçote treina para ler os relatórios de desempenho - quando você analisa as distribuições obtidas durante as medições de desempenho, analisa as tabelas de resumo, por exemplo, do BenchmarkDotNet (e não apenas a coluna "Média", mas também o desvio padrão) ), você analisa erros padrão, características adicionais, no mínimo, no máximo, em um quantil, no percentil 99.

Quando você olha para tudo isso, muito, muito, um certo volume mínimo é acumulado, permitindo realizar investimentos de desempenho muito mais rápido e ver o que as pessoas sem experiência (mesmo que leiam meu livro e um milhão de posts) não verão devido ao fato de que eles não têm experiência. Eles não verão nenhum problema ou não poderão interpretar os dados instantânea e corretamente.

- Sobre este DotNext em uma entrevista com Dmitry Nesteruk (mezastel), dissemos que geralmente os livros de TI rapidamente se tornam obsoletos, mas se ele escreve sobre padrões de design, tudo não muda lá todo ano. E quanto ao benchmarking: este livro também pode não estar desatualizado por muito tempo, ou você teria escrito algo mais dois anos atrás?

- É muito difícil dar uma resposta monossilábica. Há alguma base, algum material que não se torna obsoleto. As mesmas estatísticas: como o percentil 99 foi considerado há dois anos, ainda é considerado, e há uma suspeita de que nada mudará em dois anos.

A propósito, ao mesmo tempo, observo: acredito que o benchmarking deve ser uma disciplina separada. Por alguma razão, historicamente, ninguém prestou a devida atenção às medições sistemáticas. Bem, o que tem lá? Ele pegou, ligou o temporizador, desligou o temporizador e olhou quanto havia passado. E no livro, de acordo com estimativas preliminares, foram publicadas mais de 600 páginas e todos me perguntam: "O que poderia ser escrito em 600 páginas?"

E acredito que isso deve ser uma disciplina, uma área separada da ciência da computação. E essa é uma direção “independente da linguagem”, em que o equipamento geral permanece correto e não muda: é isso que a humanidade como um todo alcançou. Isso se aplica a quaisquer tempos de execução, idiomas e ecossistemas. Mas esta é apenas uma parte da resposta.

E a outra parte já está vinculada aos recursos do tempo de execução, aos recursos do .NET. No momento (temos muito sobre isso no livro), temos o .NET Framework, o .NET Core e o Mono. As medições de desempenho podem variar em diferentes tempos de execução ou mesmo em duas versões adjacentes do mesmo tempo de execução. Se você usar o .NET Core 2.2 e o próximo .NET Core 3.0, algumas cargas de trabalho diferem como dia e noite. Eles fazem otimizações tão legais que os cenários mais simples são simplesmente acelerados 10 vezes, 50 vezes.

É claro que, se você mudar para a nova versão do Core, o programa inteiro não começará a funcionar 50 vezes mais rápido, mas pequenos pedaços individuais, que geralmente se enquadram em benchmarks sintéticos, poderão sofrer overclock.

E aquilo que muda, muda principalmente em relação a todas essas versões, novas otimizações aparecem. Por exemplo, a execução de camadas aparecerá no .NET Core 3.0 . Ou seja, o tempo de execução pode primeiro gerar rapidamente uma implementação nativa simples (e não muito eficaz) para o método por código. E então, quando o tempo de execução perceber que você chama esse método muitas e muitas vezes, ele passará um pouco mais de tempo em segundo plano e regenerará um código mais produtivo. É sobre o fato de haver muitos anos em Java no HotSpot; no mundo .NET, ele aparecerá na versão incluída por padrão este ano na segunda metade do ano (nota do editor: lembramos que a entrevista foi feita em 2019) .

E para o BenchmarkDotNet, é um desafio lidar com esses casos normalmente. No mundo Java, Alexey Shipilev em seu JMHEu aprendi a lidar com isso há muito tempo, mas ainda precisamos. Sobre esse assunto também me comunico com os caras que viram o tempo de execução. Ou seja, precisarei de canetas especiais, APIs delas para lidar corretamente com tudo.

Essas coisas estão mudando. Em breve teremos todos os tempos de execução unidos, haverá um .NET 5. Suponho que ele será renomeado de alguma forma diferente, que este é um nome intermediário. Talvez não seja 5, mas 6, porque já tínhamos uma versão do .NET Core 5.0.

- Bem, como sabemos no Windows, não é um problema para a Microsoft pular o número na versão.

- Sim. Já na época do DNXhavia estruturas de destino com o quinto .NET Core, agora o “5.0” já foi muito utilizado, onde há muitas postagens antigas. Então, eu não sei, eles meio que farão a quinta após a terceira versão, mas eu teria perdido não apenas as quatro, mas as cinco também, e teria feito a sexta imediatamente. E levando em conta o fato de que agora eles querem tornar, na minha opinião, as versões ímpares estáveis ​​LTS e as pares não muito estáveis, seria possível sete imediatamente.

Bem, essa é a dor de cabeça deles. Mas é importante que você precise monitorar o desenvolvimento de tempos de execução, e é essa parte específica do .NET que está se tornando obsoleta - não tão rapidamente que é obsoleta, mas silenciosamente.

Já estou pensando em fazer a segunda edição de um livro em que tudo isso é atualizado. Os processadores Intel também não param, estão em desenvolvimento, aparecem novas otimizações, que também precisam ser tratadas de maneira esperta. A Skylake apresentou muitas surpresas desagradáveis; no mesmo BenchmarkDotNet, muito trabalho foi feito para contornar suas otimizações complicadas e obter resultados estáveis.

Interação com BenchmarkDotNet e Rider


- É claro que o trabalho na biblioteca BenchmarkDotNet lhe proporcionou muita experiência; portanto, é lógico que você foi quem escreveu o livro sobre o tópico de benchmarking. E aqui surge a pergunta: o livro está de alguma forma ligado ao BenchmarkDotNet, ou é “independente de ferramenta”?

- Tentei torná-la independente de ferramentas. Sobre o BenchmarkDotNet, eu tenho uma seção pequena e também a uso como exemplos em meus estudos de caso: quando preciso mostrar algum efeito microarquitetural, digo: “aqui escreveremos um benchmark usando o BenchmarkDotNet”. Apenas para não colocar um milhão de strappings em cada benchmark do livro, nenhum lugar para escrever separadamente a lógica do aquecimento. Já temos uma solução pronta que faz toda a rotina de benchmark para nós e não falamos mais sobre a metodologia (falamos sobre isso no início), mas falamos sobre os efeitos no nível da CPU.

Aqui estão dois casos de uso e tentei fazer o resto o mais abstraído possível do BenchmarkDotNet. Que o livro foi útil não apenas para desenvolvedores .NET, mas também, por exemplo, para desenvolvedores Java. Como todas as mecânicas comuns são facilmente transportadas para qualquer outra plataforma, ou seja, o .NET e o BenchmarkDotNet são usados ​​como uma ferramenta para ilustrar o conceito.

- E na outra direção foi a influência? O que, no processo de elaboração do livro, você finalmente entendeu o que precisa fazer no BenchmarkDotNet assim?

- Sim, eu escrevi todos os tipos de pequenas fichas, especialmente para elas estarem no livro. Por exemplo, a detecção legal de distribuições multimodais, sobre as quais eu já falei.

De uma maneira boa, ao analisar os resultados do benchmark, você deve sempre olhar para a distribuição, abrir a imagem, estudar o que aconteceu lá. Mas na prática, ninguém faz. Porque se eu executar, condicionalmente, 50 benchmarks em alguma base de código e alterar essa base de código 10 vezes por dia, e toda vez que reiniciar o conjunto completo, nem assistirei a 50 gráficos, é claro, preciso fazê-lo preguiçosamente. E isso, em geral, não faz sentido, não é uma tarefa humana, é uma tarefa de sintonia.

O BenchmarkDotNet possui um algoritmo interessante que determina automaticamente que a distribuição é multimodal e alerta o usuário: “Cara! Olhe para o gráfico! Tudo está ruim aqui! É aqui que o valor médio apareceu na coluna, não olhe para ele! Não corresponde a nada, veja o gráfico! ”

E isso é impresso apenas nos casos em que é realmente importante não distrair uma pessoa em gráficos em vão. Lá, uma abordagem baseada nos chamados valores m de Brendan Gregg, é um engenheiro de desempenho líder da Netflix.

Mas sua abordagem não foi suficiente para mim porque ele usa histogramas especialmente construídos com base na distribuição. Ou seja, um histograma é alimentado na entrada, o valor n é considerado e é magicamente determinado por ele, temos uma distribuição multimodal ou não. E como construir histogramas, Brendan Gregg não escreveu! Eu tive que inventar algum tipo de minha própria bicicleta, que surpreendentemente funcionou bem. Este algoritmo está resumido em um livro.

Havia algumas dessas histórias. Escrever um livro diretamente levou dois anos e meio. Em geral, coleciono conteúdo há cinco anos e dois anos e meio desde o momento em que entrei em um acordo com a editora. Durante esses dois anos e meio, graças ao livro, a biblioteca foi bombeada em muitos aspectos, muitas coisas apareceram lá.

- É difícil imaginar, mas além do livro e do BenchmarkDotNet, em sua vida também há trabalho no Rider - e provavelmente você também fará benchmark. Você pode falar sobre isso? Você tinha no Twitter fotos de um macbook no freezer e ao lado do aquecedor , verificando como isso afeta o desempenho - foi para o trabalho, para um livro ou para os dois ao mesmo tempo?

- Ao contrário, todos juntos. No pilotoUsamos o BenchmarkDotNet para investir em desempenho individual. Ou seja, quando você precisa descobrir a melhor forma de escrever código em algum item crítico de desempenho ou estudar como diferimos no comportamento de um pedaço de código no Mono no Linux e no .NET Framework no Windows. Tomamos o BenchmarkDotNet, projetamos um experimento, coletamos resultados, tiramos conclusões, tomamos decisões de negócios, como escrever código para que ele funcione rapidamente em qualquer lugar. E então essa referência é descartada.

Ou seja, não temos benchmarks sistemáticos no BenchmarkDotNet que funcionariam no CI. Mas, em vez disso, temos muitas outras áreas de trabalho de desempenho. Por exemplo, uma ferramenta interna que coleta números de todos os testes e procura diferentes anomalias de desempenho nelas, as mesmas distribuições multimodais, testa com algum desvio padrão grande e coleta tudo em um painel.

Outra abordagem em que trabalhamos há muito tempo, mas ainda não o fizemos, são os testes de desempenho confiáveis. Ou seja, queremos fazer uma abordagem na qual é impossível congelar a degradação do desempenho na ramificação principal.

E os benchmarks clássicos não são muito adequados, porque consomem muitos recursos. É necessário fazer muitas iterações para obter estatísticas normais e de alguma forma trabalhar com elas. E quando você tem centenas ou milhares de testes de desempenho, se executar cada teste 30 vezes, conforme o esperado, e isso é para todos os brunchs de todas as pessoas - nenhum ferro é suficiente.

Portanto, por um lado, quero fazer o menor número possível de iterações (idealmente uma, mas uma de cada vez, é muito difícil dizer se você tem degradação). A pior coisa que pode acontecer é o falso positivo, quando você não fez nada errado, mas o sistema fala sobre degradação do desempenho e não permite congelar o brunch no master. Se isso acontecer, eles atirarão pedras em mim e ninguém usará esse sistema.

Portanto, condicionalmente, se após uma iteração houver suspeita de degradação da perfomance, mas não houver 100% de confiança, vale a pena fazer a segunda iteração. Após o segundo, você pode decidir que está tudo bem conosco, apenas por acaso que algo aconteceu. Você pode dizer que agora temos certeza de degradação do desempenho e proibimos a marcha. E você pode dizer: "Não, duas iterações ainda não são suficientes, precisamos ir para a terceira". Bem e assim por diante.

E em um pequeno número de iterações (uma, duas, três), os testes padrão não funcionam. Aqui está o meu teste favorito de Mann-Whitney .começa a funcionar bem quando você tem pelo menos cinco iterações. Mas chegamos ao quinto apenas quando tudo está completamente ruim. Portanto, é necessário desenvolver um conjunto de heurísticas que nunca dê falso positivo, mas ao mesmo tempo detectará degradações quando elas existirem, com o número mínimo possível de iterações. E agora essa é uma tarefa bastante difícil para uma mistura de engenharia de programadores e fórmulas matemáticas. Ainda não terminamos, mas estamos indo para isso.

E sobre o macbook na geladeira - isso também é tudo para o trabalho. Agora, um dos miniprojetos que faço bastante é o estudo de modelos de regulagem térmica. A situação é a seguinte: quando o benchmark vinculado à CPU carrega muito o hardware, a temperatura da CPU aumenta e quando atinge um determinado valor limite, o processador ou o sistema operacional Intel diz: “Ay-yy-yy! Estamos superaquecendo! ” - e por um certo período de tempo reduz a frequência. E então, por exemplo, são obtidas 2-3 iterações, nas quais a degradação do desempenho é supostamente visível. E nós somos como: “Oh, oh, oh, oh! Tudo está mal! Não vamos realizar esse brunch. Mas, na verdade, temos apenas um agente de desempenho superaquecido.

Existem diferentes maneiras de lidar com isso. Temos nossa própria sala de servidores com estandes próprios, estamos tentando fornecer resfriamento suficiente para que essa limitação térmica não ocorra. Mas isso também nem sempre é bem sucedido. Ou seja, não podemos congelar completamente os agentes, eles não serão muito disso, mas de alguma forma precisamos lutar.

Outra opção é, por exemplo, desativar o turbo boost para que o processador nunca ultrapasse a frequência base. Isso, consequentemente, reduz a probabilidade de superaquecimento, o processador já não está tão quente. Em segundo lugar, obtemos uma frequência mais estável (em um turbo boost, ele costuma tremer bastante, e com um turbo boost na frequência base, ele fica muito reto e você obtém um resultado muito mais estável).

E os modelos de regulagem térmica são muito diferentes: em primeiro lugar, depende muito do processador e da configuração de todo o ferro e, em segundo lugar, do sistema operacional. Por exemplo, faça um Mac: temos muitos testes para Mac, porque há muitos usuários e eles não querem que o Rider diminua a velocidade. E existe um modelo de aceleração térmica muito agressivo.

Nos novos processadores Intel anunciados recentemente, existem piadas ainda mais complexas. Se a sua temperatura cair abaixo de um certo valor limite, como 50 graus, a frequência pode saltar ainda mais alto do que a frequência máxima em um turbo boost regular. Ou seja, eles fazem algo como overclock dinâmico "um pouco" a baixas temperaturas. O mesmo efeito. Nossos agentes ainda são processadores condicionalmente antigos, ainda não foram atualizados, mas os nerds que gostam de comprar a si mesmos tudo o que há de mais moderno podem entrar nisso.

Futuro


"Eu tenho que interrompê-lo, porque o tempo está acabando." Mas para aqueles que estão intrigados: você vai escrever um post sobre este material?

- Sim, enquanto coleciono material, tudo é muito interessante por lá, um modelo muito complexo de regulagem térmica. Há, por exemplo, limitação de energia no Windows, que permite economizar energia da bateria e muito mais. Enquanto estiver coletando dados, combinarei tudo em um post do blog, ou mesmo em um artigo científico, ou ele cairá na segunda edição do livro.

, . — , , .

DotNext 2020 Piter -. , , , . -, , . -, . — .

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


All Articles