{"id":35851,"date":"2019-10-31T22:07:03","date_gmt":"2019-10-31T19:07:03","guid":{"rendered":"https:\/\/prohoster.info\/blog\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java\/"},"modified":"2019-10-31T22:07:03","modified_gmt":"2019-10-31T19:07:03","slug":"bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","title":{"rendered":"A pot\u00eancia de um computador qu\u00e2ntico \u00e9 medida em cubits, a unidade b\u00e1sica de medida em um computador qu\u00e2ntico. Fonte.","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"A pot\u00eancia de um computador qu\u00e2ntico \u00e9 medida em cubits, a unidade b\u00e1sica de medida em um computador qu\u00e2ntico. Fonte.\" src=\"\/wp-content\/uploads\/2019\/07\/9ea9740ef74c0ae14d334482af115222.png\" style=\"display:block;margin: 0 auto;\" \/><strong>Cliff Click<\/strong> \u2014 CTO da Cratus (sensores IoT para aprimorar processos), fundador e cofundador de v\u00e1rias startups (incluindo Rocket Realtime School, Neurensic e H2O.ai) com v\u00e1rias sa\u00eddas bem-sucedidas. Cliff escreveu seu primeiro compilador aos 15 anos (Pascal para TRS Z-80)! \u00c9 mais conhecido pelo trabalho no C2 em Java (o Sea of Nodes IR). Este compilador mostrou ao mundo que o JIT podia gerar c\u00f3digo de qualidade, o que se tornou um dos fatores para o Java se tornar uma das principais plataformas de software modernas. Depois, Cliff ajudou a Azul Systems a construir um mainframe de 864 n\u00facleos com software em Java puro, que suportava pausas de GC em um heap de 500 gigabytes dentro de 10 milissegundos. No geral, Cliff conseguiu trabalhar em todos os aspectos da JVM.<br clear=\"all\"><br \/>\n\u00a0<br \/>\nEsta postagem no Habr \u00e9 uma grande entrevista com Cliff. Vamos discutir os seguintes t\u00f3picos:<\/p>\n<p><\/p>\n<ul>\n<li>Transi\u00e7\u00e3o para otimiza\u00e7\u00f5es de baixo n\u00edvel<\/li>\n<li>Como fazer um grande refatoramento<\/li>\n<li>Modelo de custo<\/li>\n<li>Aprendizado sobre otimiza\u00e7\u00f5es de baixo n\u00edvel<\/li>\n<li>Exemplos pr\u00e1ticos de melhoria de desempenho<\/li>\n<li>Por que criar sua pr\u00f3pria linguagem de programa\u00e7\u00e3o<\/li>\n<li>Carreira de engenheiro de desempenho<\/li>\n<li>Desafios t\u00e9cnicos<\/li>\n<li>Um pouco sobre aloca\u00e7\u00e3o de registradores e multiprocessamento<\/li>\n<li>O maior desafio da vida<\/li>\n<\/ul>\n<p><\/p>\n<p>Entrevista conduzida por:<\/p>\n<p><\/p>\n<ul>\n<li><strong>Andrei Satarin<\/strong> da Amazon Web Services. Em sua carreira, trabalhou em projetos bastante diversos: testou um banco de dados distribu\u00eddo NewSQL no Yandex, um sistema de detec\u00e7\u00e3o em nuvem no Kaspersky Lab, um jogo multiplayer na Mail.ru e um servi\u00e7o de c\u00e1lculo de pre\u00e7os em moedas no Deutsche Bank. Tem interesse em testar sistemas backend de larga escala e sistemas distribu\u00eddos.<\/li>\n<li><strong>, que participa de comit\u00eas de programas de uma quantidade insana de confer\u00eancias\u2026 parece que atualmente s\u00e3o cinco ao mesmo tempo. Na BOF ao lado sobre 'CS Moderna no mundo real', tamb\u00e9m discutiram NVM e chegaram a isso completamente sozinhos.<\/strong> da Netcracker. Trabalhou por dez anos em desempenho e escalabilidade do NetCracker OS \u2014 software usado por operadores de telecomunica\u00e7\u00f5es para automatizar processos de gerenciamento de rede e equipamentos de rede. \u00c9 interessado nas quest\u00f5es de desempenho do Java e da Oracle Database. Autor de mais de uma dezena de melhorias de desempenho no driver oficial PostgreSQL JDBC.<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/li>\n<\/ul>\n<p><\/p>\n<h1 id=\"perehod-k-nizkourovnevym-optimizaciyam\">Transi\u00e7\u00e3o para otimiza\u00e7\u00f5es de baixo n\u00edvel<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Voc\u00ea \u00e9 uma figura conhecida no mundo da compila\u00e7\u00e3o JIT, do Java e do desempenho em geral, certo?\u00a0<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Correto!<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Vamos come\u00e7ar com perguntas gerais sobre o trabalho em desempenho. O que voc\u00ea acha sobre a escolha entre otimiza\u00e7\u00f5es de alto n\u00edvel e baixo n\u00edvel, como trabalhar no n\u00edvel do CPU?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Aqui tudo \u00e9 simples. O c\u00f3digo mais r\u00e1pido \u00e9 aquele que nunca \u00e9 executado. Portanto, voc\u00ea sempre deve come\u00e7ar em um n\u00edvel alto, trabalhando nos algoritmos. Uma nota\u00e7\u00e3o O melhor deve superar uma nota\u00e7\u00e3o O pior, a menos que intervenham algumas constantes grandes o suficiente. As coisas de baixo n\u00edvel v\u00eam por \u00faltimo. Geralmente, se voc\u00ea otimizou todo o resto da pilha bem o suficiente e ainda h\u00e1 algo interessante, isso \u00e9 o que se chama de baixo n\u00edvel. Mas como come\u00e7ar em um n\u00edvel alto? Como saber que voc\u00ea fez trabalho suficiente em um n\u00edvel alto? Bem... n\u00e3o h\u00e1 como. N\u00e3o existem receitas prontas. Voc\u00ea precisa entender o problema, decidir o que pretende fazer (para n\u00e3o dar passos desnecess\u00e1rios) e ent\u00e3o voc\u00ea pode pegar a ferramenta de perfilagem, que pode te dar alguma informa\u00e7\u00e3o \u00fatil. Chega um momento em que voc\u00ea mesmo percebe que se livrou de coisas desnecess\u00e1rias e chegou a hora de se concentrar nos ajustes finos de baixo n\u00edvel. Isso \u00e9, sem d\u00favida, uma forma especial de arte. Muitas pessoas fazem coisas desnecess\u00e1rias, mas se movimentam t\u00e3o rapidamente que n\u00e3o t\u00eam tempo para se preocupar com o desempenho. Mas isso dura at\u00e9 que a quest\u00e3o se torne cr\u00edtica. Normalmente, 99% do tempo ningu\u00e9m se interessa pelo que estou fazendo, at\u00e9 o momento em que algo importante surge no caminho cr\u00edtico, algo com que algu\u00e9m se importa. E \u00e9 a\u00ed que todos come\u00e7am a question\u00e1-lo sobre<\/p>\n<p><\/p>\n<h1 id=\"kak-delat-bolshoy-refaktoring\">Como fazer um grande refatoramento<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Como voc\u00ea trabalha no desempenho? Essa \u00e9 uma quest\u00e3o abrangente. Por exemplo, voc\u00ea j\u00e1 teve que lidar com problemas que surgem da sobreposi\u00e7\u00e3o de muitas funcionalidades j\u00e1 existentes?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Eu tento evitar isso. Se eu sei que o desempenho ser\u00e1 um problema, come\u00e7o a refletir sobre isso antes de come\u00e7ar a codificar, especialmente sobre as estruturas de dados. Mas muitas vezes voc\u00ea descobre tudo isso muito mais tarde. E ent\u00e3o voc\u00ea tem que tomar medidas dr\u00e1sticas e fazer o que eu chamo de 'reescrever e dominar': \u00e9 preciso pegar uma parte suficientemente grande. Parte do c\u00f3digo ter\u00e1 que ser reescrita devido a problemas de desempenho ou por algum outro motivo. Qualquer que seja a raz\u00e3o para reescrever o c\u00f3digo, quase sempre \u00e9 melhor reescrever uma parte maior do que uma parte menor. Neste momento, todos come\u00e7am a ficar apavorados: 'oh Deus, n\u00e3o podemos tocar em tanto c\u00f3digo!'. Mas, na verdade, essa abordagem quase sempre funciona muito melhor. \u00c9 preciso enfrentar um grande problema, desenhar um grande c\u00edrculo ao seu redor e dizer: tudo o que estiver dentro do c\u00edrculo, eu vou reescrever. O limite \u00e9 muito menor do que o conte\u00fado dentro dele que deve ser substitu\u00eddo. E se essa demarca\u00e7\u00e3o permitir que o trabalho interno seja feito perfeitamente \u2013 voc\u00ea tem liberdade, fa\u00e7a o que quiser. Assim que voc\u00ea entende o problema, o processo de reescrita se torna muito mais f\u00e1cil, ent\u00e3o morda um peda\u00e7o grande!<br \/>\nAo mesmo tempo, quando voc\u00ea faz a reescrita de um grande peda\u00e7o e percebe que o desempenho se tornar\u00e1 um problema, pode come\u00e7ar a se preocupar com isso imediatamente. Normalmente, isso se transforma em coisas simples como 'n\u00e3o copie os dados, gerencie os dados da forma mais simples poss\u00edvel, fa\u00e7a-os menores'. Em reescritas grandes, h\u00e1 maneiras padr\u00e3o de melhorar o desempenho. E elas quase sempre giram em torno dos dados.<\/p>\n<p><\/p>\n<h1 id=\"model-stoimosti\">Modelo de custo<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Em um dos podcasts, voc\u00ea falou sobre modelos de custo no contexto de desempenho. Voc\u00ea pode explicar o que quis dizer com isso?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Claro. Eu nasci em uma \u00e9poca em que o desempenho do processador era extremamente importante. E essa era est\u00e1 retornando novamente \u2013 o destino n\u00e3o \u00e9 desprovido de ironia. Eu comecei a viver na \u00e9poca das m\u00e1quinas de oito bits, meu primeiro computador funcionava com 256 bytes. Isso mesmo, bytes. Tudo era muito pequeno. Era necess\u00e1rio contar instru\u00e7\u00f5es e, assim que come\u00e7amos a avan\u00e7ar nas pilhas de linguagens de programa\u00e7\u00e3o, as linguagens assumiram cada vez mais responsabilidades. Havia Assembly, depois Basic, depois C, e o C lidava com muitos detalhes, como a aloca\u00e7\u00e3o de registradores e a otimiza\u00e7\u00e3o de instru\u00e7\u00f5es. Mas tudo era bastante claro, e se eu fizesse um ponteiro para uma inst\u00e2ncia de vari\u00e1vel, teria um load, e o custo dessa instru\u00e7\u00e3o \u00e9 conhecido. O hardware fornece um n\u00famero conhecido de ciclos de m\u00e1quina, ent\u00e3o a velocidade de execu\u00e7\u00e3o de diferentes tarefas pode ser calculada apenas somando todas as instru\u00e7\u00f5es que voc\u00ea planejou executar. Cada compare\/test\/branch\/call\/load\/store podia ser somado e voc\u00ea poderia dizer: aqui est\u00e1 o seu tempo de execu\u00e7\u00e3o. Ao melhorar o desempenho, voc\u00ea certamente notar\u00e1 quais n\u00fameros correspondem a pequenos ciclos quentes.\u00a0<br \/>\nMas assim que voc\u00ea muda para Java, Python e coisas parecidas, voc\u00ea rapidamente se afasta do hardware de baixo n\u00edvel. Qual \u00e9 o custo de chamar um getter em Java? Se o JIT no HotSpot fez tudo certo <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.openjdk.java.net\/display\/HotSpot\/Inlining\">inlined<\/a><\/noindex>, isso ser\u00e1 um load, mas, se ele n\u00e3o fez \u2013 ser\u00e1 uma chamada de fun\u00e7\u00e3o. Como a chamada est\u00e1 em um ciclo quente, ela anular\u00e1 todas as outras otimiza\u00e7\u00f5es nesse ciclo. Portanto, o custo real ser\u00e1 muito maior. E voc\u00ea imediatamente perde a capacidade de olhar para um peda\u00e7o de c\u00f3digo e entender que devemos execut\u00e1-lo em termos de frequ\u00eancia do processador, mem\u00f3ria utilizada e cache. Tudo isso se torna interessante apenas se realmente voc\u00ea se aprofundar no desempenho.<br \/>\nAtualmente, nos encontramos em uma situa\u00e7\u00e3o em que a velocidade dos processadores quase n\u00e3o cresce h\u00e1 uma d\u00e9cada. Os velhos tempos est\u00e3o de volta! Voc\u00ea j\u00e1 n\u00e3o pode contar com um bom desempenho em um \u00fanico n\u00facleo. Mas se voc\u00ea decidir realizar c\u00e1lculos paralelos - isso \u00e9 extremamente complicado, todos olham para voc\u00ea como se voc\u00ea fosse James Bond. Acelera\u00e7\u00f5es de dez vezes geralmente acontecem onde algu\u00e9m deixou passar alguma coisa. A paralelidade exige muito trabalho. Para obter essa acelera\u00e7\u00e3o de dez vezes, \u00e9 preciso entender o modelo de custo. O que e quanto custa. E para isso, \u00e9 preciso entender como a linguagem se relaciona com o hardware subjacente.<br \/>\nMartin Thompson encontrou uma \u00f3tima palavra para seu blog <noindex><a rel=\"nofollow\" href=\"https:\/\/mechanical-sympathy.blogspot.com\/\">Simpatia Mec\u00e2nica<\/a><\/noindex>! \u00c9 necess\u00e1rio entender o que o hardware est\u00e1 prestes a fazer, como exatamente ele far\u00e1 isso e por que ele faz o que faz. Usando isso, \u00e9 bem simples come\u00e7ar a contar instru\u00e7\u00f5es e descobrir para onde o tempo de execu\u00e7\u00e3o est\u00e1 indo. Se voc\u00ea n\u00e3o tem a prepara\u00e7\u00e3o adequada, voc\u00ea est\u00e1 apenas procurando um gato preto em um quarto escuro. Eu vejo constantemente pessoas otimizando desempenho, que n\u00e3o t\u00eam a menor ideia do que est\u00e3o fazendo. Elas ficam muito frustradas e n\u00e3o conseguem avan\u00e7ar. E quando eu pego o mesmo peda\u00e7o de c\u00f3digo, insiro alguns pequenos truques e obtenho um aumento de cinco ou dez vezes, elas dizem: bem, isso n\u00e3o \u00e9 justo, n\u00f3s j\u00e1 sab\u00edamos que voc\u00ea era melhor. Impressionante. Sobre o que eu estava falando\u2026 o modelo de custo \u00e9 sobre o c\u00f3digo que voc\u00ea escreve e qu\u00e3o r\u00e1pido ele, em m\u00e9dia, funciona no quadro geral.<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: E como manter essa quantidade em mente? Isso \u00e9 alcan\u00e7ado com uma grande quantidade de experi\u00eancia, certo? Onde se pode adquirir tal experi\u00eancia?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Bem, minha experi\u00eancia n\u00e3o foi adquirida da maneira mais simples. Eu programei em Assembly na \u00e9poca em que era poss\u00edvel entender cada instru\u00e7\u00e3o individual. Isso pode parecer bobagem, mas desde ent\u00e3o, na minha cabe\u00e7a, ficou gravado um conjunto de instru\u00e7\u00f5es Z80. Eu n\u00e3o lembro os nomes das pessoas um minuto ap\u00f3s a conversa, mas lembro do c\u00f3digo que escrevi h\u00e1 40 anos. Engra\u00e7ado, isso parece uma forma de s\u00edndrome de '<noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A1%D0%B8%D0%BD%D0%B4%D1%80%D0%BE%D0%BC_%D1%81%D0%B0%D0%B2%D0%B0%D0%BD%D1%82%D0%B0\">cientista idiota<\/a><\/noindex>\u00bb.<\/p>\n<p><\/p>\n<h1 id=\"obuchenie-nizkourovnevym-optimizaciyam\">Aprendizado sobre otimiza\u00e7\u00f5es de baixo n\u00edvel<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Existe um caminho mais f\u00e1cil para entrar nesse campo?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Sim, e n\u00e3o. O hardware que todos usamos n\u00e3o mudou tanto ao longo do tempo. Todos utilizam x86, exceto smartphones com Arm. Se voc\u00ea n\u00e3o est\u00e1 envolvido com algum tipo de embedded hardcore, tem tudo igual. Certo, vamos continuar. Instru\u00e7\u00f5es tamb\u00e9m n\u00e3o mudaram ao longo dos s\u00e9culos. \u00c9 preciso ir e escrever algo em Assembly. Um pouco, mas o suficiente para come\u00e7ar a entender. Voc\u00ea pode estar sorrindo, mas eu falo isso muito a s\u00e9rio. \u00c9 necess\u00e1rio entender a correspond\u00eancia entre a linguagem e o hardware. Depois disso, \u00e9 preciso ir, escrever um pouco e fazer um pequeno compilador para uma linguagem pequena e simples. 'Simples' significa que \u00e9 necess\u00e1rio faz\u00ea-lo em um tempo razo\u00e1vel. Ele pode ser ultra simples, mas deve gerar instru\u00e7\u00f5es. O ato de gerar instru\u00e7\u00f5es permitir\u00e1 entender o modelo de custo para a ponte entre o c\u00f3digo de alto n\u00edvel, que todos escrevem, e o c\u00f3digo de m\u00e1quina, que \u00e9 executado no hardware. Essa correspond\u00eancia ficar\u00e1 gravada nas mentes no momento em que se escreve o compilador. Mesmo um compilador bem simples. Depois disso, voc\u00ea pode come\u00e7ar a olhar para Java e perceber que sua lacuna sem\u00e2ntica \u00e9 muito mais profunda, e construir pontes sobre isso \u00e9 muito mais dif\u00edcil. Em Java, \u00e9 muito mais dif\u00edcil entender se nossa ponte \u00e9 boa ou ruim, o que far\u00e1 com que ela desmorone e o que n\u00e3o far\u00e1. Mas voc\u00ea precisa de algum ponto de partida, quando olha para o c\u00f3digo e entende: 'ah, este getter deve ser inlinado toda vez'. E ent\u00e3o voc\u00ea percebe que, \u00e0s vezes, isso acontece, exceto quando o m\u00e9todo se torna muito grande, e o JIT come\u00e7a a inlinar tudo. O desempenho desses lugares pode ser previsto instantaneamente. Normalmente, getters funcionam bem, mas depois voc\u00ea olha para grandes ciclos quentes e percebe que h\u00e1 algumas chamadas de fun\u00e7\u00f5es ali, e n\u00e3o est\u00e1 claro o que elas fazem. Esse \u00e9 o problema com o uso excessivo de getters, a raz\u00e3o pela qual eles n\u00e3o s\u00e3o inlinados - n\u00e3o est\u00e1 claro se \u00e9 um getter. Se voc\u00ea tem uma base de c\u00f3digo super pequena, pode simplesmente memoriz\u00e1-la e depois dizer: este \u00e9 um getter, e este \u00e9 um setter. Em uma grande base de c\u00f3digo, cada fun\u00e7\u00e3o vive sua pr\u00f3pria hist\u00f3ria, que, na verdade, ningu\u00e9m conhece. O profiler diz que perdemos 24% do tempo em algum ciclo, e para entender o que esse ciclo faz, voc\u00ea precisa olhar para cada fun\u00e7\u00e3o dentro. \u00c9 imposs\u00edvel entender isso sem estudar a fun\u00e7\u00e3o, e isso desacelera seriamente o processo de compreens\u00e3o. Por isso n\u00e3o uso getters e setters; eu avancei para um novo n\u00edvel!<br \/>\nDe onde pegar o modelo de custos? Bem, \u00e9 poss\u00edvel ler algo, claro... Mas eu acho que a melhor maneira \u00e9 agir. Fazer um pequeno compilador \u00e9 a melhor forma de compreender o modelo de custos e assimil\u00e1-lo na sua pr\u00f3pria mente. Um pequeno compilador que funcionasse para programar um micro-ondas \u00e9 um desafio para iniciantes. Quero dizer, se voc\u00ea j\u00e1 tem habilidades de programa\u00e7\u00e3o, isso deve ser suficiente. Todas essas coisas, como analisar uma string que ser\u00e1 alguma express\u00e3o alg\u00e9brica, extrair de l\u00e1 as instru\u00e7\u00f5es das opera\u00e7\u00f5es matem\u00e1ticas na ordem correta, obter os valores corretos dos registradores - tudo isso \u00e9 feito rapidamente. E enquanto voc\u00ea faz isso, fica gravado na sua mente. Acho que todos sabem o que um compilador faz. E isso proporcionar\u00e1 uma compreens\u00e3o do modelo de custos.<\/p>\n<p><\/p>\n<h1 id=\"prakticheskie-primery-uluchsheniya-proizvoditelnosti\">Exemplos pr\u00e1ticos de melhoria de desempenho<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Em que mais devemos prestar aten\u00e7\u00e3o ao trabalhar na performance?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Estruturas de dados. Ali\u00e1s, j\u00e1 faz um bom tempo que n\u00e3o dou essas aulas... <noindex>Rocket School<\/noindex>. Isso foi divertido, mas exigiu tanto esfor\u00e7o, e eu ainda tenho a minha vida! Ok. Assim, em uma das grandes e interessantes aulas, \"Para onde vai seu desempenho\", eu dei aos alunos um exemplo: dois terabytes e meio de dados fintech lidos de um arquivo CSV, e depois era preciso calcular a quantidade de produtos vendidos. Dados de mercado normais em ticks. Pacotes UDP transformados em formato de texto desde os anos 70. Chicago Mercantile Exchange - coisas como petr\u00f3leo, milho, soja, e por a\u00ed vai. Era necess\u00e1rio contar esses produtos, o n\u00famero de transa\u00e7\u00f5es, o volume m\u00e9dio de movimento de fundos e mercadorias, e assim por diante. Matem\u00e1tica comercial bastante simples: encontrar o c\u00f3digo do produto (que s\u00e3o 1-2 caracteres em uma tabela hash), obter a soma, adicion\u00e1-la a um dos conjuntos de transa\u00e7\u00f5es, adicionar o volume, adicionar o pre\u00e7o, e mais algumas outras coisas. Matem\u00e1tica muito simples. A implementa\u00e7\u00e3o prot\u00f3tipo era muito direta: tudo estava em um arquivo, eu lia o arquivo e andava por ele, separando os registros individuais em strings Java, procurando as coisas necess\u00e1rias e somando de acordo com a matem\u00e1tica mencionada acima. E isso funcionava com uma velocidade razo\u00e1vel. <\/p>\n<p><\/p>\n<p>Com essa abordagem, est\u00e1 claro o que est\u00e1 acontecendo, e os c\u00e1lculos paralelos n\u00e3o ajudar\u00e3o, certo? Descobriu-se que um aumento de cinco vezes no desempenho pode ser alcan\u00e7ado simplesmente escolhendo as estruturas de dados corretas. E isso surpreende at\u00e9 os programadores mais experientes! No meu caso espec\u00edfico, o foco estava em n\u00e3o fazer aloca\u00e7\u00f5es de mem\u00f3ria no loop cr\u00edtico. Bem, essa n\u00e3o \u00e9 toda a verdade, mas, no geral, n\u00e3o se deve alocar \"uma vez a cada X\", quando X \u00e9 suficientemente grande. Quando X \u00e9 de dois a meio gigabytes, n\u00e3o se deve alocar nada \"uma vez por caractere\", ou \"uma vez por linha\", ou \"uma vez por campo\", nada desse tipo. \u00c9 isso que consome tempo. Como isso funciona na pr\u00e1tica? Imagine que estou fazendo uma chamada <code>String.split()<\/code> ou <code>BufferedReader.readLine()<\/code>. <code>Readline<\/code> e transforma a string de um conjunto de bytes recebidos pela rede, uma vez para cada linha, para cada uma das centenas de milh\u00f5es de linhas. Eu pego essa string, analiso e descarto. Por que descarto? Bem, eu j\u00e1 a processei, ent\u00e3o, \u00e9 isso. Portanto, para cada byte lido desses 2.7G, ser\u00e3o gravados dois caracteres na string, ou seja, j\u00e1 5.4G, e eu n\u00e3o preciso mais deles, por isso s\u00e3o descartados. Se olharmos para a largura de banda da mem\u00f3ria, estamos carregando 2.7G, que passam pela mem\u00f3ria e pelo barramento de mem\u00f3ria no processador, e, em seguida, o dobro \u00e9 enviado para a string que est\u00e1 na mem\u00f3ria, e tudo isso \u00e9 manipulado na cria\u00e7\u00e3o de cada nova string. Mas eu preciso l\u00ea-la, o hardware a l\u00ea, mesmo que depois tudo seja processado. E eu devo grav\u00e1-la, porque criei uma string e os caches ficaram cheios - o cache n\u00e3o pode conter 2.7G. Portanto, para cada byte lido, estou lendo mais dois bytes adicionais e escrevendo dois bytes adicionais, e no final, temos uma rela\u00e7\u00e3o de 4:1 - assim estamos desperdi\u00e7ando a largura de banda da mem\u00f3ria. E ent\u00e3o, descobre-se que se eu fizer <code>String.split()<\/code> \u2013 eu certamente n\u00e3o farei isso pela \u00faltima vez, pois pode haver mais 6-7 campos por dentro. Portanto, o c\u00f3digo cl\u00e1ssico de leitura de CSV seguido do parsing das strings leva a perdas de largura de banda da mem\u00f3ria na faixa de 14:1 em rela\u00e7\u00e3o ao que voc\u00ea realmente gostaria de ter. Se descartarmos essas aloca\u00e7\u00f5es, podemos obter um aumento de cinco vezes. <\/p>\n<p><\/p>\n<p>E n\u00e3o \u00e9 que seja muito dif\u00edcil. Se voc\u00ea olhar para o c\u00f3digo do \u00e2ngulo certo, tudo isso se torna bastante simples, assim que voc\u00ea percebe a ess\u00eancia do problema. N\u00e3o deve parar de alocar mem\u00f3ria: o problema \u00e9 que voc\u00ea est\u00e1 alocando algo e ele morre imediatamente, queimando um recurso importante pelo caminho, que neste caso \u00e9 a largura de banda da mem\u00f3ria. E tudo isso resulta na queda de desempenho. No x86, normalmente \u00e9 necess\u00e1rio queimar ciclos de CPU ativamente, mas aqui voc\u00ea queimou toda a mem\u00f3ria muito antes. A solu\u00e7\u00e3o \u00e9 reduzir o n\u00famero de aloca\u00e7\u00f5es.\u00a0<br \/>\nOutra parte do problema \u00e9 que, se voc\u00ea executar o perfilador quando a largura de banda da mem\u00f3ria se esgotou, exatamente no momento em que isso acontece, voc\u00ea costuma esperar que o cache retorne, porque ele est\u00e1 cheio de lixo que voc\u00ea acabou de gerar com todas essas aloca\u00e7\u00f5es. Portanto, cada opera\u00e7\u00e3o de load ou store se torna lenta, pois elas resultam em falhas no cache \u2013 todo o cache ficou lento, esperando que o lixo sa\u00edsse dele. Assim, o perfilador apenas mostrar\u00e1 um ru\u00eddo aleat\u00f3rio quente, espalhado ao longo de todo o ciclo \u2013 n\u00e3o haver\u00e1 uma instru\u00e7\u00e3o ou local quente no c\u00f3digo. Apenas ru\u00eddo. E se voc\u00ea olhar para os ciclos de GC, todos eles estar\u00e3o na Young Generation e super r\u00e1pidos \u2013 microssegundos ou milissegundos no m\u00e1ximo. Porque toda essa mem\u00f3ria morre instantaneamente. Voc\u00ea aloca bilh\u00f5es de gigabytes, e ele os corta, e corta, e corta de novo. Tudo isso acontece muito rapidamente. Assim, temos ciclos de GC baratos, ru\u00eddo quente ao longo de todo o ciclo, mas queremos obter uma acelera\u00e7\u00e3o de 5 vezes. Nesse momento, algo deve se conectar em sua cabe\u00e7a e soar: 'por que isso?!'. O estouro da largura de banda da mem\u00f3ria n\u00e3o \u00e9 exibido no depurador cl\u00e1ssico, voc\u00ea precisa iniciar o depurador de contadores de desempenho de hardware e ver isso por conta pr\u00f3pria e diretamente. E n\u00e3o diretamente isso pode ser suspeitado a partir desses tr\u00eas sintomas. O terceiro sintoma \u00e9 quando voc\u00ea olha o que est\u00e1 alocando, pergunta ao perfilador, e ele responde: 'Voc\u00ea fez um bilh\u00e3o de aloca\u00e7\u00f5es, mas o GC trabalhou de gra\u00e7a'. Assim que isso acontece, voc\u00ea entende que criou objetos demais e queimou toda a largura de banda da mem\u00f3ria. Existe uma maneira de resolver isso, mas n\u00e3o \u00e9 \u00f3bvia.\u00a0<\/p>\n<p><\/p>\n<p>O problema est\u00e1 na estrutura dos dados: a estrutura bruta por tr\u00e1s de tudo isso \u00e9 muito grande, s\u00e3o 2,7 GB no disco, portanto, fazer uma c\u00f3pia dessa coisa \u00e9 extremamente indesej\u00e1vel - queremos carreg\u00e1-la diretamente do buffer de bytes da rede para os registradores, sem ler e escrever na linha de um lado para o outro cinco vezes. Infelizmente, o Java, por padr\u00e3o, n\u00e3o oferece tal biblioteca no JDK. Mas isso \u00e9 trivial, n\u00e3o \u00e9? Basicamente, s\u00e3o de 5 a 10 linhas de c\u00f3digo que implementar\u00e3o o seu pr\u00f3prio carregador de linhas em buffer, que replicar\u00e1 o comportamento da classe String, funcionando como um wrapper ao redor do buffer de bytes subjacente. Como resultado, voc\u00ea acaba trabalhando quase como se estivesse lidando com strings, mas, na verdade, os ponteiros est\u00e3o se movendo para o buffer, e os bytes brutos n\u00e3o s\u00e3o copiados em lugar nenhum, assim, os mesmos buffers s\u00e3o reutilizados repetidamente, enquanto o sistema operacional felizmente assume tarefas para as quais foi projetado, como a dupla bufferiza\u00e7\u00e3o oculta desses buffers de bytes, e voc\u00ea n\u00e3o fica mais processando um fluxo infinito de dados desnecess\u00e1rios. A prop\u00f3sito, voc\u00ea sabe que ao trabalhar com GC garante-se que cada aloca\u00e7\u00e3o de mem\u00f3ria n\u00e3o ser\u00e1 vis\u00edvel para o processador ap\u00f3s o \u00faltimo ciclo de GC? Portanto, nada disso pode estar no cache, e ent\u00e3o ocorre uma falha garantida de 100%. Quando se trata de um ponteiro, na arquitetura x86, ler um registrador da mem\u00f3ria leva de 1 a 2 ciclos, e assim que isso acontece, voc\u00ea paga, paga, paga, porque toda a mem\u00f3ria est\u00e1 <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Cache_inclusion_policy\">nos caches NINE<\/a><\/noindex> \u2013 e essa \u00e9 a verdadeira custo da aloca\u00e7\u00e3o de mem\u00f3ria. O custo real.<\/p>\n<p><\/p>\n<p>Em outras palavras, estruturas de dados s\u00e3o a parte mais dif\u00edcil de mudar. E assim que voc\u00ea percebe que escolheu a estrutura de dados errada, que acabar\u00e1 comprometendo a performance, geralmente \u00e9 preciso fazer um trabalho substancial. Se isso n\u00e3o for feito, a situa\u00e7\u00e3o s\u00f3 tende a piorar. Primeiramente, \u00e9 preciso pensar nas estruturas de dados, isso \u00e9 crucial. O maior custo est\u00e1 nas estruturas de dados pesadas, que come\u00e7am a ser usadas no estilo \"copiarei a estrutura de dados X para a estrutura de dados Y, porque Y me agrada mais visualmente\". Mas a opera\u00e7\u00e3o de c\u00f3pia (que parece barata) na verdade consome largura de banda de mem\u00f3ria e aqui est\u00e1 enterrado todo o tempo de execu\u00e7\u00e3o perdido. Se eu tiver uma enorme string JSON e quiser transform\u00e1-la em uma \u00e1rvore DOM estruturada de POJO ou algo assim, a opera\u00e7\u00e3o de an\u00e1lise dessa string e a constru\u00e7\u00e3o do POJO, e depois o novo acesso ao POJO, se transformar\u00e3o em um custo adicional \u2013 n\u00e3o \u00e9 barato. Exceto se voc\u00ea acessar o POJO muito mais frequentemente do que a string. De forma pr\u00e1tica, pode-se tentar decifrar a string e extrair apenas o que \u00e9 necess\u00e1rio, sem convert\u00ea-la em POJO. Se tudo isso estiver acontecendo em um percurso que requer m\u00e1xima performance, nada de POJO \u2013 \u00e9 preciso mexer diretamente na string.<\/p>\n<p><\/p>\n<h1 id=\"zachem-sozdavat-svoy-yazyk-programmirovaniya\">Por que criar sua pr\u00f3pria linguagem de programa\u00e7\u00e3o<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Voc\u00ea disse que para entender o modelo de custo, \u00e9 necess\u00e1rio escrever uma pequena linguagem...<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: N\u00e3o \u00e9 uma linguagem, mas um compilador. Linguagem e compilador s\u00e3o coisas diferentes. A principal diferen\u00e7a est\u00e1 na sua cabe\u00e7a.\u00a0<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: A prop\u00f3sito, pelo que sei, voc\u00ea est\u00e1 experimentando com a cria\u00e7\u00e3o de suas pr\u00f3prias linguagens. Por qu\u00ea?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Porque posso! Estou semi-aposentado, ent\u00e3o isso \u00e9 meu hobby. Passei a vida realizando os idiomas de outras pessoas. Tamb\u00e9m trabalhei muito no estilo de codifica\u00e7\u00e3o. E porque vejo problemas em outras linguagens. Vejo que existem maneiras melhores de fazer coisas comuns. E eu gostaria de us\u00e1-las. Estou apenas cansado de ver problemas em mim mesmo, em Java, em Python, em qualquer outra linguagem. Atualmente estou escrevendo em React Native, JavaScript e Elm como um hobby, que n\u00e3o \u00e9 sobre aposentadoria, mas sobre trabalho ativo. E tamb\u00e9m escrevo em Python e provavelmente continuarei trabalhando com aprendizado de m\u00e1quina para backends Java. Existem muitas linguagens populares, todas com caracter\u00edsticas interessantes. Cada uma \u00e9 boa por algo espec\u00edfico e \u00e9 poss\u00edvel tentar unir todas essas funcionalidades. Ent\u00e3o, estou explorando coisas que me interessam, o comportamento da linguagem, tentando inventar uma sem\u00e2ntica razo\u00e1vel. E at\u00e9 agora, est\u00e1 funcionando! No momento, estou lidando com a sem\u00e2ntica de mem\u00f3ria, porque quero t\u00ea-la como em C e Java, e obter um modelo de mem\u00f3ria forte e a sem\u00e2ntica de mem\u00f3ria para cargas e armazenamentos. Ao mesmo tempo, ter infer\u00eancia de tipos autom\u00e1tica como em Haskell. Aqui, estou tentando misturar a infer\u00eancia de tipos semelhante a Haskell com uma mem\u00f3ria que funcione como em C e Java. \u00c9 isso que venho fazendo nos \u00faltimos 2-3 meses, por exemplo.<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Se voc\u00ea est\u00e1 construindo uma linguagem que extrai os melhores aspectos de outras linguagens, voc\u00ea j\u00e1 pensou que algu\u00e9m poderia fazer o contr\u00e1rio: pegar suas ideias e utiliz\u00e1-las em seu pr\u00f3prio projeto?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: \u00c9 assim que novas linguagens surgem! Por que Java \u00e9 semelhante a C? Porque C tinha uma boa sintaxe que todos entendiam e Java se inspirou nessa sintaxe, adicionando seguran\u00e7a de tipos, verifica\u00e7\u00f5es de limites de arrays, GC, e tamb\u00e9m melhoraram algumas coisas de C. Mas eles se inspiraram bastante, certo? Todos estamos em cima dos ombros de gigantes que vieram antes de n\u00f3s \u2013 \u00e9 assim que se faz progresso.<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Pelo que entendi, sua linguagem ser\u00e1 segura em rela\u00e7\u00e3o ao uso de mem\u00f3ria. Voc\u00ea j\u00e1 considerou implementar algo como o borrow checker de Rust? Voc\u00ea j\u00e1 olhou para ele, o que achou?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Bem, eu estou programando em C h\u00e1 uma eternidade, com todas essas chamadas de malloc e free, e gerenciando manualmente o tempo de vida. Sabe, 90-95% do tempo de vida gerenciado manualmente tem uma estrutura semelhante. E \u00e9 muito, muito doloroso lidar com isso manualmente. Gostaria que o compilador apenas informasse o que est\u00e1 acontecendo e o que voc\u00ea alcan\u00e7ou com suas a\u00e7\u00f5es. Para algumas coisas, o borrow checker faz isso por padr\u00e3o. E ele tamb\u00e9m deve automaticamente fornecer informa\u00e7\u00f5es, entender tudo e nem me sobrecarregar com o que \u00e9 necess\u00e1rio para entender. Ele deve realizar, no m\u00ednimo, uma an\u00e1lise de escape local, e apenas se isso falhar \u00e9 que seria necess\u00e1rio adicionar anota\u00e7\u00f5es de tipo que descrevam o tempo de vida \u2013 e esse tipo de esquema \u00e9 muito mais complicado do que o borrow checker, ou qualquer checker de mem\u00f3ria existente. A escolha entre 'tudo certo' e 'n\u00e3o entendi nada' \u2014 n\u00e3o, deveria haver algo melhor.\u00a0<br \/>\nAssim, como algu\u00e9m que escreveu muito c\u00f3digo em C, acredito que ter suporte para gerenciamento autom\u00e1tico de lifetime \u00e9 a coisa mais importante. Al\u00e9m disso, estou cansado de como Java utiliza mem\u00f3ria e a principal reclama\u00e7\u00e3o \u00e9 sobre o GC. Quando se aloca mem\u00f3ria em Java, voc\u00ea n\u00e3o recebe de volta a mem\u00f3ria que foi local na \u00faltima execu\u00e7\u00e3o do ciclo GC. Em linguagens com gerenciamento de mem\u00f3ria mais preciso, isso n\u00e3o acontece. Se voc\u00ea chama malloc, recebe imediatamente uma mem\u00f3ria que geralmente foi utilizada h\u00e1 pouco. Normalmente, voc\u00ea faz alguns trabalhos tempor\u00e1rios com a mem\u00f3ria e a devolve imediatamente. E ela retorna ao pool de malloc, e o pr\u00f3ximo ciclo de malloc a utiliza novamente. Portanto, o uso real de mem\u00f3ria \u00e9 reduzido ao conjunto de objetos vivos em um determinado momento, mais as vazamentos. E se n\u00e3o haver vazamentos de forma vergonhosa, a maior parte da mem\u00f3ria se instala em caches e no processador, e isso funciona rapidamente. Mas requer muito gerenciamento manual de mem\u00f3ria usando malloc e free, chamadas na ordem correta, no local certo. Rust consegue cuidar disso por si s\u00f3 e, em muitos casos, pode at\u00e9 fornecer um desempenho maior, pois o consumo de mem\u00f3ria se reduz apenas para os c\u00e1lculos atuais - ao contr\u00e1rio da expectativa de um pr\u00f3ximo ciclo de GC que liberar\u00e1 a mem\u00f3ria. No final, conseguimos uma maneira muito interessante de melhorar o desempenho. E bastante poderosa - quero dizer, trabalhava com coisas assim no processamento de dados para fintech, e isso permitia um aumento de desempenho de aproximadamente cinco vezes. Isso \u00e9 um aumento consider\u00e1vel, especialmente em um mundo onde os processadores n\u00e3o ficam mais r\u00e1pidos, enquanto ainda esperamos melhorias.<\/p>\n<p><\/p>\n<h1 id=\"karera-performans-inzhenera\">Carreira de engenheiro de desempenho<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Tamb\u00e9m gostaria de perguntar sobre a carreira como um todo. Voc\u00ea se tornou famoso por seu trabalho no JIT no HotSpot, e depois se transferiu para a Azul - que tamb\u00e9m \u00e9 uma empresa de JVM. Mas voc\u00ea passou a trabalhar mais com hardware do que com software. E ent\u00e3o, de repente, se mudou para Big Data e Machine Learning, e depois para detec\u00e7\u00e3o de fraudes. Como isso aconteceu? Estas s\u00e3o \u00e1reas de desenvolvimento muito diferentes.<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Eu j\u00e1 trabalho com programa\u00e7\u00e3o h\u00e1 bastante tempo e consegui me destacar em diversas atividades. Quando as pessoas dizem: 'oh, voc\u00ea \u00e9 aquele que fez o JIT para Java!', isso sempre me faz rir. Antes disso, trabalhei em um clone do PostScript \u2013 a linguagem que a Apple usava para suas impressoras a laser. Antes disso, implementei a linguagem Forth. Acredito que o tema central para mim sempre foi o desenvolvimento de ferramentas. Passei a vida criando ferramentas que permitem que outras pessoas escrevam seus programas incr\u00edveis. Mas tamb\u00e9m trabalhei no desenvolvimento de sistemas operacionais, drivers, depuradores de n\u00edvel de n\u00facleo e linguagens para desenvolvimento de SOs, que come\u00e7aram simples, mas foram se tornando cada vez mais complexas. Contudo, o foco principal, ainda assim, \u00e9 a cria\u00e7\u00e3o de ferramentas. Uma parte significativa da minha vida se passou entre a Azul e a Sun, e foi dedicada ao Java. Mas quando comecei a trabalhar com Big Data e Machine Learning, coloquei meu chap\u00e9u de festa e disse: 'Oh, agora temos um problema n\u00e3o trivial, e muitas coisas interessantes est\u00e3o acontecendo com pessoas que est\u00e3o fazendo algo'. Este \u00e9 um excelente caminho para o desenvolvimento que vale a pena seguir. <\/p>\n<p><\/p>\n<p>Sim, eu realmente amo computa\u00e7\u00e3o distribu\u00edda. Meu primeiro trabalho foi durante a faculdade, em C, em um projeto publicit\u00e1rio. Era computa\u00e7\u00e3o distribu\u00edda em chips Zilog Z80, que coletavam dados para reconhecimento \u00f3ptico anal\u00f3gico de textos, realizado por um verdadeiro analisador anal\u00f3gico. Era um tema incr\u00edvel e totalmente fora do comum. Mas havia problemas, algumas partes n\u00e3o eram reconhecidas corretamente, ent\u00e3o precis\u00e1vamos extrair a imagem e mostr\u00e1-la a uma pessoa que pudesse ler e informar o que estava escrito, e assim havia jobs de dados, e esses jobs tinham sua pr\u00f3pria linguagem. Havia um backend que processava tudo isso \u2013 Z80s funcionando em paralelo com terminais vt100 \u2013 um para cada pessoa, e havia um modelo de programa\u00e7\u00e3o paralela em Z80. Um peda\u00e7o comum de mem\u00f3ria que era compartilhado por todos os Z80 dentro de uma configura\u00e7\u00e3o em estrela; o backplane era compartilhado, e metade da RAM era compartilhada dentro da rede, enquanto a outra metade era privada ou usada para outra coisa. Uma sistema paralelo distribu\u00eddo complexamente significativo com mem\u00f3ria compartilhada\u2026 semi-compartilhada. Quando foi isso\u2026 J\u00e1 n\u00e3o me lembro, em algum lugar no meio dos anos 80. Faz bastante tempo.\u00a0<br \/>\nSim, vamos considerar que 30 anos \u00e9 bastante tempo. As tarefas relacionadas \u00e0 computa\u00e7\u00e3o distribu\u00edda existem h\u00e1 muito tempo, as pessoas t\u00eam lutado com <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/Beowulf_(%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80)\">Beowulf<\/a><\/noindex>-clusters. Esses clusters parecem como\u2026 Por exemplo: h\u00e1 Ethernet e seu r\u00e1pido x86 conectado a esse Ethernet, e agora voc\u00ea deseja obter uma fake shared memory, porque ningu\u00e9m poderia ent\u00e3o trabalhar na programa\u00e7\u00e3o de computa\u00e7\u00e3o distribu\u00edda, isso era muito complexo e, por isso, havia uma fake shared memory com prote\u00e7\u00e3o de p\u00e1ginas de mem\u00f3ria em x86, e se voc\u00ea gravasse nessa p\u00e1gina, n\u00f3s inform\u00e1vamos aos outros processadores que, se eles acessassem a mesma shared memory, precisariam carreg\u00e1-la de voc\u00ea, e assim surgiu algo parecido com um protocolo de suporte \u00e0 coer\u00eancia de cache e software para isso. Uma ideia interessante. O verdadeiro problema, \u00e9 claro, estava em outro lugar. Tudo isso funcionava, mas voc\u00ea rapidamente enfrentava problemas de desempenho, pois ningu\u00e9m entendia o modelo de desempenho em um n\u00edvel suficientemente bom \u2013 quais eram os padr\u00f5es de acesso \u00e0 mem\u00f3ria, como fazer com que os n\u00f3s n\u00e3o se pingssem interminavelmente, e assim por diante. <\/p>\n<p><\/p>\n<p>No H2O, eu concebi o seguinte: os pr\u00f3prios desenvolvedores s\u00e3o respons\u00e1veis por identificar onde est\u00e1 o paralelismo e onde n\u00e3o est\u00e1. Eu criei um modelo de codifica\u00e7\u00e3o que torna f\u00e1cil e simples escrever c\u00f3digo de alto desempenho. Escrever c\u00f3digo que funcione lentamente \u00e9 dif\u00edcil; ele ser\u00e1 mal estruturado. \u00c9 necess\u00e1rio esfor\u00e7o consider\u00e1vel para escrever c\u00f3digo lento, e m\u00e9todos n\u00e3o convencionais ser\u00e3o necess\u00e1rios. C\u00f3digo que desacelera \u00e9 vis\u00edvel \u00e0 primeira vista. Como resultado, normalmente se escreve c\u00f3digo que funciona rapidamente, mas voc\u00ea precisa descobrir o que fazer em caso de mem\u00f3ria compartilhada. Tudo isso est\u00e1 atrelado a grandes arrays, e o comportamento \u00e9 semelhante aos arrays grandes n\u00e3o vol\u00e1teis em Java paralelo. Ou seja, imagine que dois threads escrevem em um array paralelo, um deles vence, e o outro, por consequ\u00eancia, perde, e voc\u00ea n\u00e3o sabe quem \u00e9 quem. Se eles n\u00e3o forem vol\u00e1teis, a ordem pode ser qualquer uma \u2013 e isso realmente funciona bem. As pessoas se preocupam com a ordem das opera\u00e7\u00f5es, elas corretamente estabelecem o volatile e, nos locais certos, antecipam problemas de desempenho relacionados \u00e0 mem\u00f3ria. Caso contr\u00e1rio, elas simplesmente escreveriam c\u00f3digo em loops de 1 a N, onde N s\u00e3o trilh\u00f5es, na esperan\u00e7a de que todos os casos complexos se tornassem automaticamente paralelos \u2013 e isso n\u00e3o funciona. Mas no H2O, isso n\u00e3o \u00e9 Java, nem Scala; pode-se considerar como um 'Java menos menos', se quiser. \u00c9 um estilo de programa\u00e7\u00e3o muito compreens\u00edvel e se assemelha \u00e0 escrita de c\u00f3digo simples em C ou Java com loops e arrays. Contudo, a mem\u00f3ria pode ser manipulada em terabytes. Eu ainda uso o H2O. O uso \u00e9 ocasional em diferentes projetos \u2013 e at\u00e9 hoje, \u00e9 a coisa mais r\u00e1pida, estando dezenas de vezes \u00e0 frente dos concorrentes. Se voc\u00ea est\u00e1 lidando com Big Data e dados em colunas, \u00e9 muito dif\u00edcil superar o H2O.<\/p>\n<p><\/p>\n<h1 id=\"tehnicheskie-chellenzhi\">Desafios t\u00e9cnicos<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Qual foi o maior desafio que voc\u00ea enfrentou em toda a sua carreira?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Estamos discutindo a parte t\u00e9cnica ou a n\u00e3o t\u00e9cnica da quest\u00e3o? Eu diria que os maiores desafios s\u00e3o os n\u00e3o t\u00e9cnicos.\u00a0<br \/>\nQuanto aos desafios t\u00e9cnicos. Eu simplesmente os superei. Nem mesmo sei qual foi o maior, mas houve v\u00e1rios bastante interessantes que consumiram bastante tempo e luta mental. Quando fui para a Sun, estava certo de que faria um compilador r\u00e1pido, enquanto um monte de seniores dizia que eu nunca conseguiria nada. Mas segui esse caminho, escrevi um compilador at\u00e9 o alocador de registradores, e bastante r\u00e1pido. Ele era t\u00e3o r\u00e1pido quanto o moderno C1, mas na \u00e9poca o alocador era muito mais lento, e olhando para tr\u00e1s \u2013 foi um problema de grandes estruturas de dados. Eu precisava disso para escrever um alocador gr\u00e1fico de registradores e n\u00e3o entendia a dilema entre a expressividade do c\u00f3digo e a velocidade, que existia naquela \u00e9poca e era muito importante. Descobri que a estrutura de dados geralmente superava o tamanho do cache nos x86 da \u00e9poca, e portanto, se eu inicialmente supus que o alocador de registradores levaria de 5 a 10 por cento de todo o tempo de JIT, na realidade isso se traduziu em 50 por cento. <\/p>\n<p><\/p>\n<p>O tempo passava, o compilador tornava-se cada vez mais claro e eficiente, parou de gerar c\u00f3digo horr\u00edvel na maioria dos casos, e o desempenho come\u00e7ou a se assemelhar ao que um compilador C produce. Se voc\u00ea, \u00e9 claro, n\u00e3o est\u00e1 escrevendo alguma porcaria que nem mesmo C pode otimizar. Se voc\u00ea escreve c\u00f3digo como em C, obt\u00e9m desempenho similar ao de C na maioria dos casos. E quanto mais avan\u00e7\u00e1vamos, mais frequentemente resultava em c\u00f3digo que coincidencialmente se igualava ao n\u00edvel de C, o alocador de registradores come\u00e7ou a se assemelhar a algo completo... independentemente de seu c\u00f3digo estar r\u00e1pido ou devagar. Eu continuei a trabalhar no alocador para que ele fizesse aloca\u00e7\u00f5es melhores. Ele estava ficando mais lento, mas produzia desempenhos cada vez melhores em casos onde ningu\u00e9m mais conseguia. Eu podia mergulhar no alocador de registradores, enterrar um m\u00eas de trabalho l\u00e1, e de repente todo o c\u00f3digo come\u00e7ava a rodar 5% mais r\u00e1pido. Isso acontecia repetidamente, e o alocador de registradores se tornou uma esp\u00e9cie de obra de arte - todos o amavam ou o odiavam, e as pessoas da academia faziam perguntas sobre o porqu\u00ea de tudo ser feito daquela forma, por que n\u00e3o <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Register_allocation#Linear_Scan\">varredura linear<\/a><\/noindex>, e qual \u00e9 a diferen\u00e7a. A resposta continua a mesma: o alocador baseado em colora\u00e7\u00e3o de grafos mais um trabalho muito cuidadoso com o c\u00f3digo de buffer resulta em uma ferramenta vencedora, a melhor combina\u00e7\u00e3o que ningu\u00e9m consegue superar. E isso \u00e9 algo bastante n\u00e3o \u00f3bvio. Tudo o mais que o compilador faz s\u00e3o coisas bastante conhecidas, embora tamb\u00e9m tenham sido elevadas ao n\u00edvel da arte. Sempre fiz coisas que deveriam transformar o compilador em uma obra de arte. Mas nada disso era algo extraordin\u00e1rio \u2013 exceto o alocador de registros. O foco \u00e9 que \u00e9 preciso lidar com cuidado <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Register_allocation\">despachar<\/a><\/noindex> sob carga e, se isso acontecer (eu posso explicar em mais detalhes, se estiver interessado), isso significa que \u00e9 poss\u00edvel fazer inlining de forma mais agressiva, sem o risco de ultrapassar o ponto de inflex\u00e3o da performance. Naquela \u00e9poca, havia uma infinidade de compiladores de grande escala, repletos de firulas e apetrechos, que tinham alocadores de registros, mas ningu\u00e9m mais conseguiu isso. <\/p>\n<p><\/p>\n<p>O problema \u00e9 que, se voc\u00ea adicionar m\u00e9todos que devem ser inlined, aumentando e aumentando a \u00e1rea de inlining, o conjunto de valores utilizados ultrapassa instantaneamente o n\u00famero de registros, e voc\u00ea precisa fazer spill. O n\u00edvel cr\u00edtico geralmente ocorre quando o alocador falha, e um bom candidato para spill vale mais do que o outro, voc\u00ea faz spill de algumas coisas realmente absurdas. O valor do inlining aqui est\u00e1 no fato de que voc\u00ea perde parte da sobrecarga, a sobrecarga na chamada e na preserva\u00e7\u00e3o, voc\u00ea pode ver os valores internamente e pode otimiz\u00e1-los ainda mais. O custo do inlining \u00e9 que se forma uma grande quantidade de valores vivos, e se seu alocador de registros faz spill de mais do que o necess\u00e1rio, voc\u00ea imediatamente perde. Portanto, a maioria dos alocadores enfrenta um problema: quando o inlining ultrapassa um certo limite, tudo come\u00e7a a fazer spill e o desempenho pode ser arrastado para o ralo. Aqueles que implementam um compilador adicionam algumas heur\u00edsticas: por exemplo, para parar o inlining ao atingir um tamanho grande o suficiente, pois as aloca\u00e7\u00f5es estragam tudo. Surge assim uma quebra na curva de desempenho - voc\u00ea inlining, inlining, o desempenho aumenta lentamente - e ent\u00e3o, bum! - ele despenca com um colapso r\u00e1pido, porque voc\u00ea inlinou demais. Tudo funcionou assim at\u00e9 a chegada do Java. O Java requer muito mais inlining, ent\u00e3o tive que fazer meu alocador muito mais agressivo para que ele se equilibrasse em vez de cair, e se voc\u00ea inlinou demais - ele come\u00e7a a fazer spill, mas ainda assim chega um momento em que \"n\u00e3o h\u00e1 mais spill\". Essa \u00e9 uma observa\u00e7\u00e3o interessante que me veio do nada, n\u00e3o \u00f3bvia, mas muito recompensadora. Eu me envolvi com inlining agressivo e isso me levou a lugares onde o desempenho do Java e do C est\u00e3o lado a lado. Eles s\u00e3o realmente pr\u00f3ximos - posso escrever c\u00f3digo em Java que ser\u00e1 significativamente mais r\u00e1pido do que o c\u00f3digo em C e coisas assim, mas em m\u00e9dia, na grande vis\u00e3o das coisas, eles s\u00e3o aproximadamente compar\u00e1veis. Acredito que parte deste m\u00e9rito se deve ao alocador de registros, que me permite inlining de maneira muito simples. Eu simplesmente inline tudo que vejo. A quest\u00e3o \u00e9 se o alocador funciona bem, se o c\u00f3digo resultante \u00e9 razoavelmente eficiente. Esse foi um grande desafio: entender tudo isso e fazer funcionar.<\/p>\n<p><\/p>\n<h1 id=\"nemnogo-pro-allokaciyu-registrov-i-mnogoyadernost\">Um pouco sobre aloca\u00e7\u00e3o de registradores e multiprocessamento<\/h1>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: Problemas como a aloca\u00e7\u00e3o de registradores parecem um tema eterno e intermin\u00e1vel. \u00c9 interessante saber se alguma ideia parecia promissora e, depois, falhou na pr\u00e1tica?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Certamente! A aloca\u00e7\u00e3o de registradores \u00e9 uma \u00e1rea em que, para resolver um problema NP-completo, voc\u00ea tenta encontrar algumas heur\u00edsticas. E voc\u00ea nunca conseguir\u00e1 uma solu\u00e7\u00e3o perfeita, certo? Isso simplesmente \u00e9 imposs\u00edvel. Veja, a compila\u00e7\u00e3o Ahead of Time tamb\u00e9m n\u00e3o funciona bem. A conversa aqui gira em torno de casos m\u00e9dios. Sobre a performance t\u00edpica, de modo que voc\u00ea pode ir e medir algo que considera uma boa performance t\u00edpica - afinal, voc\u00ea est\u00e1 trabalhando para melhor\u00e1-la! A aloca\u00e7\u00e3o de registradores \u00e9 um tema inteiramente dedicado \u00e0 performance. Assim que voc\u00ea tem o primeiro prot\u00f3tipo, ele funciona e realiza o que precisa, come\u00e7a o trabalho de performance. \u00c9 preciso aprender a medir bem. Por que isso \u00e9 importante? Se houver dados claros, voc\u00ea pode olhar para diferentes partes e ver: ah, isso ajudou aqui, mas ali tudo quebrou! Surgem boas ideias, voc\u00ea adiciona uma nova heur\u00edstica e, de repente, tudo come\u00e7a a funcionar um pouco melhor em m\u00e9dia. Ou n\u00e3o come\u00e7a. Tive v\u00e1rias situa\u00e7\u00f5es em que lutamos por cinco por cento de performance, que distinguiam nosso desenvolvimento do alocador anterior. E cada vez \u00e9 assim: em algum lugar voc\u00ea ganhou, em algum lugar voc\u00ea perdeu. Se voc\u00ea tiver boas ferramentas de an\u00e1lise de performance, pode encontrar ideias perdedoras e entender por que elas falharam. Talvez seja melhor manter tudo como est\u00e1, ou talvez seja hora de se dedicar mais \u00e0 afina\u00e7\u00e3o, ou ir e corrigir outra coisa. \u00c9 um conjunto inteiro de coisas! Eu fiz esse hack incr\u00edvel, mas preciso disso, e disso, e disso \u2013 e a combina\u00e7\u00e3o total delas traz algumas melhorias. Ideias isoladas podem falhar. Essa \u00e9 a natureza do trabalho em tarefas NP-completas relacionadas \u00e0 performance.<\/p>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: Tem a impress\u00e3o de que tarefas como pintura em alocadores \u00e9 um problema j\u00e1 resolvido. Bem, para voc\u00ea, parece resolvido, considerando o que voc\u00ea relata, ent\u00e3o vale a pena\u2026<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: N\u00e3o est\u00e1 resolvido como tal. Voc\u00ea deve transform\u00e1-la em \"resolvida\". Existem problemas dif\u00edceis que precisam ser resolvidos. Quando isso \u00e9 feito, chega a hora de trabalhar na performance. \u00c9 preciso levar esse trabalho a s\u00e9rio - fazer benchmarks, coletar m\u00e9tricas, explicar situa\u00e7\u00f5es quando, ao voltar para uma vers\u00e3o anterior, seu antigo hack come\u00e7ou a funcionar novamente (ou vice-versa, parou de funcionar). E n\u00e3o desista at\u00e9 conseguir algo. Como j\u00e1 mencionei, se h\u00e1 ideias legais que n\u00e3o funcionaram, na \u00e1rea de aloca\u00e7\u00e3o de registradores, as ideias s\u00e3o praticamente infinitas. Voc\u00ea pode, por exemplo, ler publica\u00e7\u00f5es cient\u00edficas. Embora agora essa \u00e1rea tenha avan\u00e7ado muito mais devagar e tenha se tornado mais clara do que em seus prim\u00f3rdios. No entanto, nesse campo trabalha uma infinidade de pessoas e todas as suas ideias merecem ser testadas, todas aguardando sua oportunidade. E voc\u00ea n\u00e3o pode dizer qu\u00e3o boas elas s\u00e3o se n\u00e3o as experimentar. Qu\u00e3o bem elas se integram com o resto do seu alocador, pois o alocador faz muitas coisas, e algumas ideias podem n\u00e3o funcionar muito bem no seu alocador espec\u00edfico, enquanto em outro alocador funcionariam perfeitamente. O principal modo de vit\u00f3ria para o alocador \u00e9 retirar as coisas lentas do caminho principal e for\u00e7ar a divis\u00e3o nas fronteiras dos caminhos lentos. Portanto, se voc\u00ea quer iniciar o GC, seguir pelo caminho lento, desotimizar, lan\u00e7ar exce\u00e7\u00f5es, tudo nesse sentido - voc\u00ea sabe que essas coisas s\u00e3o relativamente raras. E elas realmente s\u00e3o raras, eu cheguei a verificar. Voc\u00ea faz trabalho adicional e, gra\u00e7as a isso, muitas limita\u00e7\u00f5es nesses caminhos lentos desaparecem, mas isso n\u00e3o \u00e9 muito importante, porque eles s\u00e3o lentos e raramente utilizados. Por exemplo, um ponteiro nulo - isso nunca acontece, certo? \u00c9 preciso ter v\u00e1rios caminhos para diferentes situa\u00e7\u00f5es, mas eles n\u00e3o devem se sobrepor no principal.\u00a0<\/p>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: O que voc\u00ea pensa sobre a multicore, quando voc\u00ea tem milhares de n\u00facleos de uma vez? Isso \u00e9 algo \u00fatil?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: O sucesso das GPUs mostra que \u00e9 bastante \u00fatil!<\/p>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: Elas s\u00e3o bastante especializadas. E quanto aos processadores de uso geral?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Bem, esse era o modelo de neg\u00f3cios da Azul. A resposta veio em uma era em que as pessoas realmente apreciavam desempenho previs\u00edvel. Naquela \u00e9poca, era um desafio escrever c\u00f3digo paralelo. O modelo de codifica\u00e7\u00e3o H2O escala bem, mas n\u00e3o \u00e9 um modelo de uso geral. No entanto, \u00e9 um pouco mais geral do que usar uma GPU. Estamos falando sobre a complexidade de desenvolver algo assim ou sobre a complexidade de us\u00e1-lo? Por exemplo, uma li\u00e7\u00e3o interessante que aprendi com a Azul, bastante n\u00e3o \u00f3bvia: caches pequenos s\u00e3o aceit\u00e1veis.\u00a0<\/p>\n<p><\/p>\n<h1 id=\"samyy-bolshoy-chellenzh-v-zhizni\">O maior desafio da vida<\/h1>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: E quanto aos desafios n\u00e3o t\u00e9cnicos?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: O maior desafio foi n\u00e3o ser... gentil e bom com as pessoas. E como consequ\u00eancia, eu frequentemente me encontrava em situa\u00e7\u00f5es extremamente conflituosas. Aqueles em que eu sabia que tudo estava indo na dire\u00e7\u00e3o errada, mas n\u00e3o sabia como avan\u00e7ar na resolu\u00e7\u00e3o desses problemas e n\u00e3o conseguia lidar com eles. Muitas quest\u00f5es prolongadas, que duraram v\u00e1rias d\u00e9cadas, apareceram exatamente dessa maneira. O fato de que no Java existem compiladores C1 e C2 \u00e9 uma consequ\u00eancia direta disso. O fato de que no Java por mais de uma d\u00e9cada n\u00e3o houve compila\u00e7\u00e3o em m\u00faltiplos n\u00edveis tamb\u00e9m \u00e9 uma consequ\u00eancia direta. \u00c9 \u00f3bvio que precis\u00e1vamos de um sistema assim, mas n\u00e3o estava claro o motivo de sua aus\u00eancia. Eu tive problemas com um engenheiro... ou um grupo de engenheiros. H\u00e1 muito tempo, quando comecei a trabalhar na Sun, eu era... Bem, n\u00e3o s\u00f3 naquela \u00e9poca, eu sempre tive minha pr\u00f3pria opini\u00e3o sobre tudo. E eu acreditava ser verdade que poderia simplesmente apresentar essa minha verdade de forma direta. Especialmente porque fiquei chocantemente certo na maior parte do tempo. E se voc\u00ea n\u00e3o gosta dessa abordagem... especialmente se voc\u00ea est\u00e1 claramente errado e fazendo bobagens... Enfim, poucas pessoas podiam suportar pacientemente esse estilo de comunica\u00e7\u00e3o. Embora alguns pudessem, por exemplo, eu. Eu constru\u00ed minha vida inteira com base em princ\u00edpios meritocr\u00e1ticos. Se voc\u00ea me mostrar algo errado, imediatamente vou me voltar e dizer: voc\u00ea disse uma besteira. E, claro, pe\u00e7o desculpas, e tudo mais, reconhe\u00e7o os m\u00e9ritos, se houver, e tomo outras a\u00e7\u00f5es corretas. Por outro lado, eu estou chocantemente certo em uma porcentagem chocantemente alta do tempo geral. E isso n\u00e3o funciona muito bem nas rela\u00e7\u00f5es com as pessoas. Eu n\u00e3o estou tentando ser gentil, mas coloco a quest\u00e3o de forma direta. 'Isto nunca vai funcionar, porque um, dois e tr\u00eas'. E eles ficam: 'Oh!'. Houve outras consequ\u00eancias que \u00e9 melhor talvez ignorar: por exemplo, resultaram em um div\u00f3rcio e uma d\u00e9cada de depress\u00e3o ap\u00f3s isso.<\/p>\n<p><\/p>\n<p>O desafio \u00e9 lutar contra as percep\u00e7\u00f5es que as pessoas t\u00eam sobre o que voc\u00ea pode ou n\u00e3o fazer, o que \u00e9 importante e o que n\u00e3o \u00e9. Houve muitos desafios sobre estilo de codifica\u00e7\u00e3o. Eu ainda escrevo muito c\u00f3digo, e naquelas \u00e9pocas eu at\u00e9 precisei desacelerar, porque estava fazendo muitas tarefas paralelas e as fazia mal, em vez de me concentrar em uma s\u00f3. Olhando para tr\u00e1s, escrevi metade do c\u00f3digo da equipe Java JIT, da equipe C2. O pr\u00f3ximo codificador mais r\u00e1pido escrevia a metade da velocidade, o seguinte escrevia ainda mais devagar e isso era uma queda exponencial. O s\u00e9timo da fila era muito, muito lento \u2013 isso sempre acontece! Eu analisei uma tonelada de c\u00f3digo. Observei quem estava escrevendo o qu\u00ea, sem exce\u00e7\u00f5es, estive de olho no c\u00f3digo deles, revisei cada um deles e ainda assim continuei escrevendo mais do que qualquer um deles. Com as pessoas, essa abordagem n\u00e3o funciona muito bem. Alguns n\u00e3o gostam disso. E quando n\u00e3o conseguem lidar, come\u00e7am a surgir todos os tipos de reclama\u00e7\u00f5es. Por exemplo, uma vez me disseram para parar de escrever c\u00f3digo, porque eu estava escrevendo c\u00f3digo demais, e isso colocava a equipe em risco, e tudo isso soou como uma piada para mim: cara, se toda a equipe restante desaparecer e eu continuar escrevendo c\u00f3digo, voc\u00ea vai perder apenas metade da equipe. Por outro lado, se eu continuar escrevendo c\u00f3digo e voc\u00ea perder metade da equipe \u2013 isso soa como uma gest\u00e3o muito ruim. Eu nunca pensei muito sobre isso, nunca falei sobre isso, mas estava de alguma forma na minha cabe\u00e7a. Na parte de tr\u00e1s da minha mente, a ideia girava: 'Voc\u00eas est\u00e3o brincando, n\u00e3o \u00e9?'. Assim, o maior problema era eu e meus relacionamentos com as pessoas. Agora, eu me entendo muito melhor; fui l\u00edder de equipe por muito tempo, e agora eu digo diretamente \u00e0s pessoas: sabe, eu sou como sou, e voc\u00eas v\u00e3o ter que lidar comigo \u2013 tudo bem se eu ficar aqui? E quando eles come\u00e7aram a lidar com isso, tudo funcionou. Na verdade, eu n\u00e3o sou nem bom nem ruim, n\u00e3o tenho m\u00e1s inten\u00e7\u00f5es ou ambi\u00e7\u00f5es ego\u00edstas, \u00e9 apenas a minha ess\u00eancia, e precisamos lidar com isso de alguma forma.<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Recentemente, todos estavam falando sobre autoconsci\u00eancia para introvertidos e, de maneira geral, sobre soft skills. O que se pode dizer sobre isso?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Sim, isso foi um entendimento e uma li\u00e7\u00e3o que tirei do meu div\u00f3rcio com minha esposa. O que extra\u00ed do div\u00f3rcio foi a compreens\u00e3o de mim mesmo. Assim, comecei a entender outras pessoas. Entender como essa intera\u00e7\u00e3o funciona. Isso resultou em descobertas uma ap\u00f3s a outra. Surgiu a consci\u00eancia de quem sou e o que represento. O que fa\u00e7o: ou fico obcecado com a tarefa, ou evito conflitos, ou algo mais \u2013 e esse n\u00edvel de autoconsci\u00eancia realmente ajuda a manter o controle. Depois disso, tudo se torna muito mais f\u00e1cil. Uma coisa que descobri n\u00e3o apenas em mim, mas tamb\u00e9m em outros programadores \u2013 \u00e9 a incapacidade de verbalizar pensamentos quando se est\u00e1 em estado de estresse emocional. Por exemplo, voc\u00ea est\u00e1 codificando, est\u00e1 em um estado de fluxo, e ent\u00e3o algu\u00e9m corre at\u00e9 voc\u00ea e come\u00e7a a gritar em p\u00e2nico que algo quebrou, que medidas extremas ser\u00e3o tomadas. E voc\u00ea n\u00e3o consegue dizer uma palavra, porque est\u00e1 sob estresse emocional. O conhecimento adquirido permite se preparar para esse momento, passar por ele e passar para o plano de retirada, a partir do qual voc\u00ea pode come\u00e7ar a agir. Ent\u00e3o, sim, quando voc\u00ea come\u00e7a a perceber como tudo isso funciona \u2013 \u00e9 um grande evento que muda a vida.\u00a0<br \/>\nEu mesmo n\u00e3o consegui encontrar as palavras certas, mas me lembrei da sequ\u00eancia de a\u00e7\u00f5es. A ess\u00eancia \u00e9 que essa rea\u00e7\u00e3o \u00e9 t\u00e3o f\u00edsica quanto verbal, e voc\u00ea precisa de espa\u00e7o. Um espa\u00e7o desse tipo, no sentido do zen. \u00c9 isso que precisa ser explicado, e ent\u00e3o se afastar imediatamente \u2013 fisicamente. Quando estou em sil\u00eancio, consigo processar a situa\u00e7\u00e3o em termos de emo\u00e7\u00f5es. \u00c0 medida que a adrenalina chega ao c\u00e9rebro, coloca voc\u00ea no modo 'lutar ou fugir', voc\u00ea j\u00e1 n\u00e3o consegue dizer nada, n\u00e3o \u2013 agora voc\u00ea \u00e9 um idiota, um engenheiro vulner\u00e1vel, incapaz de uma resposta digna ou de, pelo menos, parar a agress\u00e3o, e o agressor pode atacar livremente novamente e novamente. Primeiramente, \u00e9 preciso se tornar novamente voc\u00ea mesmo, recuperar o controle, sair do modo 'lutar ou fugir'. <\/p>\n<p><\/p>\n<p>E \u00e9 por isso que \u00e9 necess\u00e1rio ter um espa\u00e7o verbal. Apenas um espa\u00e7o livre. Se for para falar de algo, \u00e9 isso que se pode afirmar, e depois sair para realmente encontrar seu 'espa\u00e7o': passear no parque, fechar-se no chuveiro \u2013 n\u00e3o importa. O importante \u00e9 desconectar-se temporariamente da situa\u00e7\u00e3o. Assim que voc\u00ea se desconecta, mesmo que por alguns segundos, o controle retorna, voc\u00ea come\u00e7a a pensar de forma clara. 'Bem, eu n\u00e3o sou algum idiota, n\u00e3o fa\u00e7o coisas est\u00fapidas, sou uma pessoa bastante \u00fatil'. Assim que voc\u00ea consegue convencer a si mesmo, \u00e9 hora de passar para a pr\u00f3xima etapa: entender o que aconteceu. Voc\u00ea foi atacado, o ataque veio de onde voc\u00ea menos esperava, foi uma emboscada trai\u00e7oeira. Isso \u00e9 ruim. O pr\u00f3ximo passo \u00e9 entender por que o atacante fez isso. Realmente, por qu\u00ea? Talvez porque ele mesmo esteja furioso? Por que ele est\u00e1 furioso? Por exemplo, porque cometeu um erro e n\u00e3o consegue assumir a responsabilidade? \u00c9 dessa forma que voc\u00ea precisa lidar cuidadosamente com toda a situa\u00e7\u00e3o. Mas para isso, \u00e9 necess\u00e1rio ter espa\u00e7o para manobras, um espa\u00e7o verbal. O primeiro passo \u00e9 romper o contato verbal. Sair da discuss\u00e3o em palavras. Cancel\u00e1-la, sair o mais r\u00e1pido poss\u00edvel. Se for uma conversa telef\u00f4nica \u2013 simplesmente desligue \u2013 \u00e9 uma habilidade que aprendi ao lidar com minha ex-esposa. Se a conversa n\u00e3o leva a coisa alguma boa, apenas diga 'tchau' e desligue. Do outro lado do telefone: 'bl\u00e1-bl\u00e1-bl\u00e1', voc\u00ea responde: 'certo, tchau!' e desliga. Apenas interrompa a conversa. Cinco minutos depois, quando sua capacidade de pensar claramente retorna, voc\u00ea se acalma um pouco, e \u00e9 poss\u00edvel refletir sobre o que aconteceu e o que vir\u00e1 a seguir. E come\u00e7ar a formular uma resposta ponderada, em vez de apenas reagir emocionalmente. Para mim, a descoberta em termos de autoconsci\u00eancia foi que, em situa\u00e7\u00f5es de estresse emocional, n\u00e3o consigo falar. Sair desse estado, pensar e planejar como responder e compensar os problemas - esses s\u00e3o os passos corretos quando voc\u00ea n\u00e3o consegue se expressar. O modo mais simples \u00e9 fugir da situa\u00e7\u00e3o que causa estresse emocional e simplesmente parar de participar desse estresse. Depois disso, voc\u00ea Recupera a capacidade de pensar, quando consegue pensar, surgem a possibilidade de falar e assim por diante.<\/p>\n<p><\/p>\n<p>A prop\u00f3sito, no tribunal, o advogado da parte contr\u00e1ria tenta fazer isso com voc\u00ea \u2013 agora est\u00e1 claro por qu\u00ea. Porque ele tem a capacidade de te suprimir a ponto de voc\u00ea n\u00e3o conseguir nem pronunciar seu pr\u00f3prio nome, por exemplo. No sentido mais literal, voc\u00ea n\u00e3o consegue falar. Se isso est\u00e1 acontecendo com voc\u00ea e se voc\u00ea sabe que vai estar em um lugar onde palavras ser\u00e3o um campo de batalha, como um tribunal, \u00e9 recomend\u00e1vel ir com seu advogado. O advogado ir\u00e1 defend\u00ea-lo e interromper a agress\u00e3o verbal, e far\u00e1 isso de maneira totalmente legal, permitindo que voc\u00ea retome seu espa\u00e7o zen perdido. Por exemplo, em algumas ocasi\u00f5es eu precisei ligar para minha fam\u00edlia, o juiz foi bastante amig\u00e1vel, mas o advogado da parte contr\u00e1ria gritava e gritava comigo, e eu n\u00e3o conseguia nem intervir. Nesses casos, o que funciona melhor para mim \u00e9 usar um intermedi\u00e1rio. O intermedi\u00e1rio interrompe toda essa press\u00e3o que vem sobre voc\u00ea de forma constante, e voc\u00ea redescobre o espa\u00e7o zen necess\u00e1rio, junto com a habilidade de falar. \u00c9 um campo de conhecimento onde \u00e9 preciso aprender muito, descobrir muitas coisas dentro de si mesmo, e isso se transforma em decis\u00f5es estrat\u00e9gicas de alto n\u00edvel, diferentes para cada pessoa. Algumas pessoas n\u00e3o t\u00eam os problemas descritos acima, geralmente, elas n\u00e3o ocorrem em pessoas que trabalham profissionalmente com vendas. Todas essas pessoas que ganham a vida com palavras \u2013 cantores famosos, poetas, l\u00edderes religiosos e pol\u00edticos, sempre t\u00eam algo a dizer. Eles n\u00e3o enfrentam esses problemas, mas eu enfrento.<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Isso foi\u2026 inesperado. \u00d3timo, j\u00e1 falamos bastante e \u00e9 hora de encerrar essa entrevista. Certamente nos encontraremos na confer\u00eancia e poderemos continuar esse di\u00e1logo. Nos vemos na Hydra!<\/p>\n<p><\/p>\n<blockquote><p>O contato com Cliff poder\u00e1 ser continuado na confer\u00eancia Hydra 2019, que ocorrer\u00e1 nos dias 11 e 12 de julho de 2019 em S\u00e3o Petersburgo. Ele vir\u00e1 com uma apresenta\u00e7\u00e3o <noindex><a rel=\"nofollow\" href=\"https:\/\/hydraconf.com\/2019\/talks\/2jix5mst7iduyp9linqhfj\/?utm_source=habr&amp;utm_medium=45871\">\u00abA experi\u00eancia da Mem\u00f3ria Transacional de Hardware Azul\u00bb<\/a><\/noindex>. Os ingressos podem ser adquiridos <noindex><a rel=\"nofollow\" href=\"https:\/\/hydraconf.ru\/?utm_source=habr&amp;utm_medium=458718\">no site oficial<\/a><\/noindex>.<\/p><\/blockquote>\n<p>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/jugru\/blog\/458718\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041a\u043b\u0438\u0444\u0444 \u041a\u043b\u0438\u043a \u2014 CTO \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 Cratus (IoT \u0441\u0435\u043d\u0441\u043e\u0440\u044b \u0434\u043b\u044f \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432), \u043e\u0441\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0438 \u0441\u043e\u043e\u0441\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0441\u0442\u0430\u0440\u0442\u0430\u043f\u043e\u0432 (\u0432\u043a\u043b\u044e\u0447\u0430\u044f Rocket Realtime School, Neurensic \u0438 H2O.ai) \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u043c\u0438 \u044d\u043a\u0437\u0438\u0442\u0430\u043c\u0438. \u041a\u043b\u0438\u0444\u0444 \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0432\u043e\u0439 \u043f\u0435\u0440\u0432\u044b\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0432 15 \u043b\u0435\u0442 (Pascal \u0434\u043b\u044f TRS Z-80)! \u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u0437\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430\u0434 \u04212 \u0432 Java (the Sea of Nodes IR). \u042d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u043f\u043e\u043a\u0430\u0437\u0430\u043b [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-35851","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041a\u043b\u0438\u0444\u0444 \u041a\u043b\u0438\u043a \u2014.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_PT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0411\u043e\u043b\u044c\u0448\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0432\u044c\u044e \u0441 \u041a\u043b\u0438\u0444\u0444\u043e\u043c \u041a\u043b\u0438\u043a\u043e\u043c \u2014 \u043e\u0442\u0446\u043e\u043c JIT-\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0432 Java | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041a\u043b\u0438\u0444\u0444 \u041a\u043b\u0438\u043a \u2014.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:07:03+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:07:03+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Grande entrevista com Cliff Click \u2014 o pai da compila\u00e7\u00e3o JIT em Java | ProHoster","description":"Cliff Click \u2014.","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0411\u043e\u043b\u044c\u0448\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0432\u044c\u044e \u0441 \u041a\u043b\u0438\u0444\u0444\u043e\u043c \u041a\u043b\u0438\u043a\u043e\u043c \u2014 \u043e\u0442\u0446\u043e\u043c JIT-\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0432 Java | ProHoster","og:description":"\u041a\u043b\u0438\u0444\u0444 \u041a\u043b\u0438\u043a \u2014.","og:url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:07:03+00:00","article:modified_time":"2019-10-31T19:07:03+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"35851","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-22 01:01:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:55:25","updated":"2026-01-22 01:01:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/35851","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=35851"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/35851\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=35851"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=35851"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=35851"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}