{"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\/es\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","title":{"rendered":"Una gran entrevista con Cliff Click, el padre de la compilaci\u00f3n JIT en Java","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Una gran entrevista con Cliff Click, el padre de la compilaci\u00f3n JIT en Java\" src=\"\/wp-content\/uploads\/2019\/07\/9ea9740ef74c0ae14d334482af115222.png\" style=\"display:block;margin: 0 auto;\" \/><strong>Cliff Click<\/strong> \u2014 CTO de Cratus (sensores IoT para mejorar procesos), fundador y cofundador de varias startups (incluyendo Rocket Realtime School, Neurensic y H2O.ai) con varios \u00e9xitos. Cliff escribi\u00f3 su primer compilador a los 15 a\u00f1os (Pascal para TRS Z-80). Es m\u00e1s conocido por su trabajo en C2 en Java (el IR Sea of Nodes). Este compilador mostr\u00f3 al mundo que JIT puede generar c\u00f3digo de calidad, lo que fue uno de los factores que ciment\u00f3 a Java como una de las principales plataformas de software moderno. Luego, Cliff ayud\u00f3 a Azul Systems a construir un mainframe de 864 n\u00facleos con software en Java puro, que soportaba pausas de GC en un mont\u00f3n de 500 gigabytes en alrededor de 10 milisegundos. En general, Cliff ha trabajado en todos los aspectos de la JVM.<br clear=\"all\"><br \/>\n\u00a0<br \/>\nEsta publicaci\u00f3n en Habr es una gran entrevista con Cliff. Hablaremos sobre los siguientes temas:<\/p>\n<p><\/p>\n<ul>\n<li>Transici\u00f3n a optimizaciones de bajo nivel<\/li>\n<li>C\u00f3mo realizar una gran refactorizaci\u00f3n<\/li>\n<li>Modelo de costos<\/li>\n<li>Aprendizaje de optimizaciones de bajo nivel<\/li>\n<li>Ejemplos pr\u00e1cticos de mejora del rendimiento<\/li>\n<li>Por qu\u00e9 crear su propio lenguaje de programaci\u00f3n<\/li>\n<li>Carrera como ingeniero de rendimiento<\/li>\n<li>Desaf\u00edos t\u00e9cnicos<\/li>\n<li>Un poco sobre la asignaci\u00f3n de registros y la multiprocesadoridad<\/li>\n<li>El mayor desaf\u00edo en la vida<\/li>\n<\/ul>\n<p><\/p>\n<p>La entrevista es conducida por:<\/p>\n<p><\/p>\n<ul>\n<li><strong>Andrei Satariin<\/strong> de Amazon Web Services. A lo largo de su carrera ha trabajado en proyectos muy diversos: prob\u00f3 una base de datos distribuida NewSQL en Yandex, un sistema de detecci\u00f3n en la nube en el Laboratorio Kaspersky, un juego multijugador en Mail.ru y un servicio de c\u00e1lculo de precios de divisas en Deutsche Bank. Le interesa la prueba de sistemas back-end a gran escala y distribuidos.<\/li>\n<li><strong>Vladimir Sitnikov<\/strong> de Netcracker. Ha trabajado durante diez a\u00f1os en el rendimiento y escalabilidad de NetCracker OS, un software utilizado por operadores de telecomunicaciones para automatizar procesos de gesti\u00f3n de red y equipo de red. Se interesa por el rendimiento de Java y Oracle Database. Es autor de m\u00e1s de una docena de mejoras en el rendimiento del controlador JDBC oficial de PostgreSQL.<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/li>\n<\/ul>\n<p><\/p>\n<h1 id=\"perehod-k-nizkourovnevym-optimizaciyam\">Transici\u00f3n a optimizaciones de bajo nivel<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Usted es una persona conocida en el mundo de la compilaci\u00f3n JIT, en Java y en el trabajo de rendimiento en general, \u00bfverdad?\u00a0<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: \u00a1As\u00ed es!<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Comencemos con preguntas generales sobre el trabajo en el rendimiento. \u00bfQu\u00e9 piensas sobre la elecci\u00f3n entre optimizaciones de alto nivel y de bajo nivel, como trabajar al nivel de la CPU?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Aqu\u00ed es bastante simple. El c\u00f3digo m\u00e1s r\u00e1pido es aquel que nunca se ejecuta. Por eso, siempre se debe comenzar desde un alto nivel, trabajando en los algoritmos. Una mejor notaci\u00f3n O superar\u00e1 a una peor notaci\u00f3n O, a menos que intervengan constantes suficientemente grandes. Las cosas de bajo nivel suelen llegar al final. Normalmente, si has optimizado bien el resto de la pila y a\u00fan queda algo interesante, eso es lo que se considera bajo nivel. Pero, \u00bfc\u00f3mo comenzar desde un alto nivel? \u00bfC\u00f3mo saber si se ha hecho suficiente trabajo en un alto nivel? Bueno\u2026 no hay f\u00f3rmulas listas. Necesitas entender el problema, decidir qu\u00e9 planeas hacer (para no dar pasos innecesarios) y entonces puedes sacar un perfilador, que pueda decir algo \u00fatil. En alg\u00fan momento, te das cuenta de que te has deshecho de las cosas innecesarias y es hora de hacer un ajuste fino a nivel bajo. Esto es, sin duda, un tipo especial de arte. Muchas personas hacen cosas innecesarias, pero se mueven tan r\u00e1pido que no tienen tiempo para preocuparse por el rendimiento. Pero esto sigue as\u00ed hasta que la cuesti\u00f3n se vuelve apremiante. Normalmente, el 99% del tiempo a nadie le interesa lo que estoy haciendo, hasta el momento en que en una ruta cr\u00edtica surge algo importante que a alguien le importa. Y en ese momento, todos comienzan a cuestionarte sobre por qu\u00e9 no funcion\u00f3 perfectamente desde el principio. En resumen, siempre hay algo que mejorar en el rendimiento. Pero el 99% del tiempo no tienes pistas. Simplemente intentas que algo funcione y en el proceso entiendes lo que es importante. Nunca se puede saber de antemano que este pedazo debe hacerse perfecto, por lo que, en esencia, tienes que ser perfecto en todo. Y eso no es posible y no lo haces. Siempre hay un mont\u00f3n de cosas que arreglar, y eso es completamente normal.<\/p>\n<p><\/p>\n<h1 id=\"kak-delat-bolshoy-refaktoring\">C\u00f3mo realizar una gran refactorizaci\u00f3n<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: \u00bfC\u00f3mo trabajas en el rendimiento? Es un problema transversal. Por ejemplo, \u00bfhas tenido que trabajar en problemas causados por la interacci\u00f3n de una gran cantidad de funcionalidades existentes?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Intento evitar esto. Si s\u00e9 que el rendimiento ser\u00e1 un problema, lo pienso antes de comenzar a programar, especialmente sobre las estructuras de datos. Pero a menudo descubres todo esto mucho m\u00e1s tarde. Y entonces tienes que recurrir a medidas extremas y hacer lo que yo llamo \u00abreescribir y dominar\u00bb: debes abarcar una parte lo suficientemente grande. Parte del c\u00f3digo a\u00fan tendr\u00e1 que ser reescrito por razones de rendimiento o por cualquier otra cosa. Cualquiera que sea la raz\u00f3n para reescribir el c\u00f3digo, casi siempre es mejor reescribir un bloque mayor que uno menor. En ese momento, todos comienzan a temblar de miedo: \u201c\u00a1Oh Dios, no se puede tocar tanto c\u00f3digo!\u201d. Pero, de hecho, este enfoque casi siempre funciona mucho mejor. Debes enfrentar un gran problema de inmediato, dibujar un gran c\u00edrculo alrededor de \u00e9l y decir: todo lo que est\u00e9 dentro del c\u00edrculo, lo reescribir\u00e9. La frontera es mucho m\u00e1s peque\u00f1a que el contenido que est\u00e1 dentro de ella, que debe ser reemplazado. Y si definir esos l\u00edmites permite que el trabajo interno sea perfecto, tienes las manos libres, haz lo que quieras. Una vez que entiendes el problema, el proceso de reescritura es mucho m\u00e1s f\u00e1cil, as\u00ed que \u00a1mu\u00e9rdete un gran trozo!<br \/>\nAl mismo tiempo, cuando haces una reescritura de gran tama\u00f1o y entiendes que el rendimiento ser\u00e1 un problema, puedes empezar a preocuparte por ello de inmediato. Generalmente, esto se convierte en cosas simples como \u00abno copies datos, gestiona los datos de la forma m\u00e1s simple posible, haz m\u00e1s peque\u00f1os\u00bb. En grandes reescrituras, hay formas est\u00e1ndar de mejorar el rendimiento. Y casi siempre giran en torno a los datos.<\/p>\n<p><\/p>\n<h1 id=\"model-stoimosti\">Modelo de costos<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: En uno de los podcasts mencionaste los modelos de costo en el contexto del rendimiento. \u00bfPuedes explicar qu\u00e9 quer\u00edas decir con eso?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Claro. Nac\u00ed en una \u00e9poca en la que el rendimiento del procesador era extremadamente importante. Y esa era vuelve a aparecer: el destino no est\u00e1 exento de iron\u00eda. Comenc\u00e9 a vivir en tiempos de m\u00e1quinas de ocho bits, mi primer computadora funcionaba con 256 bytes. Exactamente con bytes. Todo era muy peque\u00f1o. Ten\u00edas que contar instrucciones y, a medida que comenzamos a avanzar en el \u00e1mbito de los lenguajes de programaci\u00f3n, estos se encargaban de m\u00e1s y m\u00e1s. Primero fue Ensamblador, luego Basic, luego C, y C asumi\u00f3 la responsabilidad de muchos detalles, como la asignaci\u00f3n de registros y la selecci\u00f3n de instrucciones. Pero all\u00ed todo era bastante claro y si hac\u00eda un puntero a una instancia de una variable, obtendr\u00eda un load, y el costo de esa instrucci\u00f3n era conocido. El hardware entrega un n\u00famero conocido de ciclos de m\u00e1quina, as\u00ed que la velocidad de ejecuci\u00f3n de diferentes cosas se pod\u00eda calcular simplemente sumando todas las instrucciones que planeabas ejecutar. Cada compare\/test\/branch\/call\/load\/store se pod\u00eda sumar y decir: aqu\u00ed tienes el tiempo de ejecuci\u00f3n. Al trabajar en la mejora del rendimiento, definitivamente notar\u00e1s qu\u00e9 n\u00fameros corresponden a peque\u00f1os ciclos calientes.\u00a0<br \/>\nPero tan pronto como cambias a Java, Python y cosas similares, r\u00e1pidamente te alejas del hardware de bajo nivel. \u00bfCu\u00e1l es el costo de llamar a un getter en Java? Si el JIT en HotSpot lo hizo correctamente, <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.openjdk.java.net\/display\/HotSpot\/Inlining\">lo habr\u00e1 inlined<\/a><\/noindex>, eso ser\u00e1 un load, pero si no lo hizo, ser\u00e1 una llamada a funci\u00f3n. Dado que la llamada est\u00e1 en un ciclo caliente, cancelar\u00e1 todas las dem\u00e1s optimizaciones en ese ciclo. Por lo tanto, el costo real ser\u00e1 mucho mayor. Y de inmediato pierdes la capacidad de mirar un fragmento de c\u00f3digo y entender qu\u00e9 deber\u00edamos ejecutar en t\u00e9rminos de la frecuencia del procesador, memoria utilizada y cach\u00e9. Todo esto se vuelve interesante solo si realmente te sumerges en el rendimiento.<br \/>\nAhora nos encontramos en una situaci\u00f3n en la que la velocidad de los procesadores no ha crecido casi nada en una d\u00e9cada. \u00a1Los viejos tiempos han vuelto! Ya no puedes contar con un buen rendimiento de un solo hilo. Pero si de repente decides dedicarte a los c\u00e1lculos paralelos, eso es incre\u00edblemente complicado; todos te miran como si fueras James Bond. Aceleraciones de diez veces suelen ocurrir en aquellos lugares donde alguien ha pasado por alto algo. La paralelizaci\u00f3n requiere mucho trabajo. Para obtener esa aceleraci\u00f3n diez veces mayor, es necesario entender el modelo de costos. Qu\u00e9 cuesta y cu\u00e1nto. Y para eso, necesitas comprender c\u00f3mo el lenguaje se ajusta al hardware subyacente.<br \/>\nMartin Thompson encontr\u00f3 una excelente palabra para su blog <noindex><a rel=\"nofollow\" href=\"https:\/\/mechanical-sympathy.blogspot.com\/\">Simpat\u00eda Mec\u00e1nica<\/a><\/noindex>! Es fundamental entender qu\u00e9 se propone hacer el hardware, c\u00f3mo lo va a hacer y por qu\u00e9 hace lo que hace. Usando esto, es bastante simple empezar a contar instrucciones y averiguar d\u00f3nde se pierde el tiempo de ejecuci\u00f3n. Si no tienes la preparaci\u00f3n adecuada, simplemente est\u00e1s buscando un gato negro en una habitaci\u00f3n oscura. Constantemente veo a personas optimizando el rendimiento que no tienen la menor idea de lo que est\u00e1n haciendo. Ellos sufren mucho y no avanzan realmente. Y cuando yo tomo ese mismo trozo de c\u00f3digo, introduzco un par de peque\u00f1os hacks y obtengo una aceleraci\u00f3n de cinco o diez veces, ellos dicen: bueno, eso no es justo, ya sab\u00edamos que t\u00fa eras mejor. Asombroso. \u00bfDe qu\u00e9 estaba hablando... el modelo de costos es sobre qu\u00e9 c\u00f3digo est\u00e1s escribiendo y cu\u00e1n r\u00e1pido funciona en promedio dentro del panorama general.<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: \u00bfY c\u00f3mo se puede mantener tanto en la cabeza? \u00bfSe logra con mucha experiencia, o? \u00bfD\u00f3nde se adquiere esa experiencia?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Bueno, adquir\u00ed mi experiencia no de la manera m\u00e1s sencilla. Program\u00e9 en ensamblador en aquellos tiempos en que era posible comprender cada instrucci\u00f3n individual. Suena tonto, pero desde entonces tengo en mi cabeza, en mi memoria, un conjunto de instrucciones Z80 que perduran. No recuerdo los nombres de las personas un minuto despu\u00e9s de conversar, pero recuerdo el c\u00f3digo que escrib\u00ed hace 40 a\u00f1os. Curiosamente, se parece al 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\">genio loco<\/a><\/noindex>\u00bb.<\/p>\n<p><\/p>\n<h1 id=\"obuchenie-nizkourovnevym-optimizaciyam\">Aprendizaje de optimizaciones de bajo nivel<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>\": \u00bfHay alguna manera m\u00e1s sencilla de entrar en esto?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: S\u00ed y no. El hardware que todos utilizamos no ha cambiado tanto en este tiempo. Todos utilizan x86, excepto los tel\u00e9fonos inteligentes que usan Arm. Si no te dedicas a alg\u00fan embebido hardcore, tienes lo mismo. Bien, continuemos. Las instrucciones tampoco han cambiado en siglos. Necesitas ir y escribir algo en ensamblador. Un poco, pero suficiente para empezar a entender. Ustedes se r\u00eden, pero hablo muy en serio. Es necesario entender la relaci\u00f3n entre el lenguaje y el hardware. Despu\u00e9s de eso, debes ir y escribir un poco para crear un peque\u00f1o compilador para un lenguaje juguete. 'Juguete' significa que hay que hacerlo en un tiempo razonable. Puede ser s\u00faper simple, pero debe generar instrucciones. El acto de generaci\u00f3n de instrucciones permitir\u00e1 entender el modelo de costo para el puente entre el c\u00f3digo de alto nivel, que todos escriben, y el c\u00f3digo m\u00e1quina, que se ejecuta en el hardware. Esta relaci\u00f3n se grabar\u00e1 en la mente en el momento de escribir el compilador. Incluso un compilador muy simple. Despu\u00e9s de eso, puedes empezar a ver Java y c\u00f3mo su brecha sem\u00e1ntica es mucho m\u00e1s profunda, haciendo que construir puentes sobre ella sea mucho m\u00e1s complicado. En Java es mucho m\u00e1s dif\u00edcil entender si nuestro puente es bueno o malo, qu\u00e9 lo har\u00e1 colapsar y qu\u00e9 no. Pero necesitas alg\u00fan punto de partida cuando miras el c\u00f3digo y entiendes: 'claro, este getter debe inlinearse cada vez'. Y luego resulta que a veces s\u00ed lo es, excepto cuando el m\u00e9todo se vuelve demasiado grande, y el JIT comienza a inlinear todo. El rendimiento en esos casos se puede predecir de inmediato. Normalmente, los getters funcionan bien, pero despu\u00e9s miras grandes bucles calientes y te das cuenta de que hay llamadas a funciones que no entiendes qu\u00e9 hacen. Esa es la problem\u00e1tica del uso generalizado de getters, la raz\u00f3n por la cual no se inlinean: no est\u00e1 claro si es un getter. Si tienes una base de c\u00f3digo s\u00faper peque\u00f1a, simplemente puedes memorizarla y luego decir: este es un getter y este es un setter. En una gran base de c\u00f3digo, cada funci\u00f3n vive su propia historia, que en general no es conocida por nadie. El profiler dice que hemos perdido el 24% del tiempo en un ciclo y para entender qu\u00e9 hace ese ciclo, necesitas mirar cada funci\u00f3n dentro. No es posible comprenderlo sin estudiar la funci\u00f3n, lo cual ralentiza seriamente el proceso de entendimiento. Por eso no utilizo getters y setters, \u00a1he alcanzado un nuevo nivel!<br \/>\n\u00bfDe d\u00f3nde obtener un modelo de costos? Bueno, se puede leer algo, claro... Pero creo que la mejor manera es actuar. Crear un peque\u00f1o compilador es la mejor forma de comprender el modelo de costos y asimilarlo en tu mente. Un peque\u00f1o compilador que servir\u00eda para programar un microondas es una tarea para principiantes. Quiero decir, si ya tienes habilidades de programaci\u00f3n, deber\u00edas ser capaz de hacerlo. Todas esas cosas como analizar una cadena que ser\u00e1 alguna expresi\u00f3n algebraica, extraer de all\u00ed las instrucciones de operaciones matem\u00e1ticas en el orden correcto, obtener los valores correctos de los registros, todo eso se puede hacer sin problemas. Y mientras lo haces, se grabar\u00e1 en tu mente. Creo que todos saben lo que hace un compilador. Y esto ayudar\u00e1 a entender el modelo de costos.<\/p>\n<p><\/p>\n<h1 id=\"prakticheskie-primery-uluchsheniya-proizvoditelnosti\">Ejemplos pr\u00e1cticos de mejora del rendimiento<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: \u00bfEn qu\u00e9 m\u00e1s debes prestar atenci\u00f3n al trabajar en el rendimiento?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Estructuras de datos. Por cierto, hace tiempo que no daba esas clases... <noindex>Rocket School<\/noindex>. Fue divertido, pero requer\u00eda dedicar tanto esfuerzo, \u00a1y tambi\u00e9n tengo vida! Bien. En una de las clases grandes e interesantes, \"\u00bfA d\u00f3nde va tu rendimiento?\", di a los estudiantes un ejemplo: se le\u00edan dos terabytes y medio de datos fintech desde un archivo CSV y luego hab\u00eda que contar la cantidad de productos vendidos. Datos de mercado de tick habituales. Paquetes UDP convertidos a formato de texto desde los a\u00f1os 70. Chicago Mercantile Exchange, cosas como petr\u00f3leo, ma\u00edz, soja y similares. Ten\u00edas que contar estos productos, la cantidad de transacciones, el volumen promedio de movimiento de fondos y mercanc\u00edas, etc. Es matem\u00e1ticas comerciales bastante simples: encontrar el c\u00f3digo del producto (que son 1-2 caracteres en una tabla hash), obtener la suma, agregarla a uno de los conjuntos de transacciones, a\u00f1adir el volumen, a\u00f1adir el costo, y un par de cosas m\u00e1s. Matem\u00e1ticas muy simples. La implementaci\u00f3n a nivel juguete fue muy directa: todo est\u00e1 en un archivo, leo el archivo y avanzo en \u00e9l, separando los registros individuales en cadenas de Java, buscando las cosas necesarias y sumando seg\u00fan la matem\u00e1tica descrita anteriormente. Y esto funciona a una velocidad peque\u00f1a. <\/p>\n<p><\/p>\n<p>Con este enfoque, es obvio qu\u00e9 est\u00e1 sucediendo, y los c\u00e1lculos paralelos no ayudar\u00e1n en esto, \u00bfverdad? Resulta que se puede lograr un aumento de rendimiento cinco veces solo eligiendo las estructuras de datos adecuadas. \u00a1Esto sorprende incluso a los programadores experimentados! En mi caso espec\u00edfico, el enfoque estaba en no hacer asignaciones de memoria en el ciclo caliente. Bueno, esa no es toda la verdad, pero en general, no deber\u00edas asignar \"una vez cada X\", cuando X es lo suficientemente grande. Cuando X son dos mil quinientos megabytes, no deber\u00edas asignar nada \"una vez por letra\", o \"una vez por l\u00ednea\", o \"una vez por campo\", nada por el estilo. Eso es lo que realmente toma tiempo. \u00bfC\u00f3mo funciona esto? Imagina que estoy haciendo una llamada <code>String.split()<\/code> o <code>BufferedReader.readLine()<\/code>. <code>Readline<\/code> que convierte un conjunto de bytes que llegan por la red en una cadena, una vez por cada l\u00ednea, para cada una de las cientos de millones de l\u00edneas. Tomo esta l\u00ednea, la analizo y la descarto. \u00bfPor qu\u00e9 la descarto? Bueno, ya la he procesado, eso es todo. Entonces, para cada byte le\u00eddo de estos 2.7G, se escriben dos caracteres en la cadena, es decir, ya son 5.4G, y no los necesito m\u00e1s, as\u00ed que se descartan. Si miras el ancho de banda de la memoria, cargamos 2.7G que pasan a trav\u00e9s de la memoria y el bus de memoria en el procesador, y despu\u00e9s se env\u00edan el doble en la cadena que est\u00e1 en la memoria, y todo esto se desgasta al crear cada nueva cadena. Pero necesito leerla, el hardware la lee, incluso si luego todo ser\u00e1 desgastado. Y debo escribirla porque he creado una cadena y las cach\u00e9s se han saturado: la cach\u00e9 no puede contener 2.7G. Por lo tanto, para cada byte le\u00eddo, leo otros dos bytes adicionales y escribo otros dos bytes adicionales, y al final tienen una relaci\u00f3n de 4:1: as\u00ed de derrochadamente estamos utilizando el ancho de banda de la memoria. Y luego resulta que si hago <code>String.split()<\/code> \u2013 lo hago muy lejos de ser la \u00faltima vez, porque puede haber otros 6-7 campos dentro. Por lo tanto, el c\u00f3digo cl\u00e1sico para leer CSV con el posterior an\u00e1lisis de l\u00edneas conduce a p\u00e9rdidas de ancho de banda de memoria en un rango de 14:1 en comparaci\u00f3n con lo que realmente desear\u00edas tener. Si se eliminan estas asignaciones, se puede lograr una aceleraci\u00f3n de cinco veces. <\/p>\n<p><\/p>\n<p>Y no es que sea muy complicado. Si miras el c\u00f3digo desde el \u00e1ngulo correcto, todo se vuelve bastante simple, en cuanto comprendes la esencia del problema. No deber\u00edas dejar de asignar memoria en absoluto: el problema es que asignas algo y se agota de inmediato, y por el camino quema un recurso importante, que en este caso es el ancho de banda de la memoria. Y todo esto se traduce en una ca\u00edda del rendimiento. En x86, normalmente necesitas quemar ciclos de CPU activamente, y aqu\u00ed has quemado toda la memoria mucho antes. La soluci\u00f3n es reducir la cantidad de asignaciones.\u00a0<br \/>\nOtra parte del problema es que, si ejecutas el perfilador cuando se ha agotado el ancho de banda de la memoria, justo en el momento en que esto ocurre, generalmente esperas que el cach\u00e9 regrese, porque est\u00e1 lleno de basura que acabas de generar, con todas esas cadenas. Por lo tanto, cada operaci\u00f3n de carga o almacenamiento se vuelve lenta, ya que conducen a fallos en el cach\u00e9: todo el cach\u00e9 se ha vuelto lento, esperando a que se libere la basura. Entonces, el perfilador mostrar\u00e1 \u00fanicamente un ruido aleatorio tibio, disperso a lo largo de todo el ciclo; no habr\u00e1 ninguna instrucci\u00f3n o lugar caliente en el c\u00f3digo. Solo ruido. Y si miras los ciclos de GC, todos estar\u00e1n en Young Generation y ser\u00e1n s\u00faper r\u00e1pidos: microsegundos o milisegundos como m\u00e1ximo. Porque toda esta memoria muere instant\u00e1neamente. Asignas miles de millones de gigabytes, y \u00e9l los corta, y corta, y vuelve a cortar. Todo esto sucede muy r\u00e1pido. Resulta que hay ciclos de GC baratos, ruido tibio a lo largo de todo el ciclo, pero queremos obtener una aceleraci\u00f3n de 5 veces. En este momento, algo deber\u00eda\u00a0<\/p>\n<p><\/p>\n<p>El problema radica en la estructura de los datos: una estructura desnuda que subyace a todo lo que ocurre, es demasiado grande, son 2.7G en el disco, por lo que hacer una copia de esta cosa es muy indeseable; se desea cargarla directamente desde el b\u00fafer de bytes de la red a los registros, para no leer y escribir en la cadena de ida y vuelta cinco veces. Desafortunadamente, Java por defecto no ofrece una biblioteca as\u00ed en el JDK. Pero, en realidad, es trivial, \u00bfverdad? En esencia, son de 5 a 10 l\u00edneas de c\u00f3digo que servir\u00e1n para implementar tu propio cargador de cadenas con b\u00fafer, que replica el comportamiento de la clase String, siendo a la vez un envoltorio alrededor del b\u00fafer de bytes subyacente. Como resultado, parece que trabajas casi como si estuvieras manipulando cadenas, pero en realidad se est\u00e1n moviendo punteros en el b\u00fafer, y los bytes en bruto no se copian a ning\u00fan lado, reutiliz\u00e1ndose as\u00ed los mismos b\u00faferes una y otra vez, mientras que el sistema operativo est\u00e1 feliz de encargarse de las cosas para las que est\u00e1 dise\u00f1ado, como la doble amortiguaci\u00f3n oculta de esos b\u00faferes de bytes, y t\u00fa ya no procesas un flujo interminable de datos innecesarios. Por cierto, \u00bfentienden que cuando se trabaja con GC se garantiza que cada asignaci\u00f3n de memoria no ser\u00e1 visible para el procesador despu\u00e9s del \u00faltimo ciclo de GC? Por lo tanto, nada de esto puede estar en la cach\u00e9, y luego sucede un fallo garantizado al 100%. Cuando trabajas con un puntero, en x86 leer un registro de la memoria toma de 1 a 2 ciclos, y tan pronto como esto sucede, pagas, pagas, pagas, porque toda la memoria est\u00e1 <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Cache_inclusion_policy\">en NINE caches<\/a><\/noindex> \u2013 y esto es el costo de la asignaci\u00f3n de memoria. El verdadero costo.<\/p>\n<p><\/p>\n<p>En otras palabras, las estructuras de datos son lo m\u00e1s dif\u00edcil de cambiar. Y una vez que te das cuenta de que elegiste la estructura de datos incorrecta, la cual afectar\u00e1 el rendimiento m\u00e1s adelante, generalmente se requiere un trabajo considerable para corregirlo. Si no lo haces, las cosas empeorar\u00e1n. Primero que todo, debes pensar en las estructuras de datos, es importante. El costo principal recae en las estructuras de datos pesadas, que comienzan a usarse con la mentalidad de \u201ccopi\u00e9 la estructura de datos X en la estructura de datos Y, porque Y me gusta m\u00e1s visualmente\u201d. Pero la operaci\u00f3n de copiar (que parece barata) en realidad consume memoria y ah\u00ed es donde se pierde todo el tiempo de ejecuci\u00f3n. Si tengo una cadena gigantesca con JSON y quiero convertirla en un \u00e1rbol DOM estructurado de POJO o algo similar, la operaci\u00f3n de an\u00e1lisis de esa cadena y la construcci\u00f3n del POJO, y luego la nueva referencia al POJO en el futuro, tendr\u00e1n un costo adicional \u2013 no es barato. A menos que est\u00e9s accediendo a POJO con mucha m\u00e1s frecuencia que a la cadena. A simple vista, podr\u00edas intentar decodificar la cadena y extraer solo lo necesario, sin convertirlo en POJO. Si todo esto ocurre en una ruta que requiere el m\u00e1ximo rendimiento, nada de POJO, se necesita profundizar directamente en la cadena.<\/p>\n<p><\/p>\n<h1 id=\"zachem-sozdavat-svoy-yazyk-programmirovaniya\">Por qu\u00e9 crear su propio lenguaje de programaci\u00f3n<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Dijiste que para entender el modelo de costos, necesitas escribir tu propio peque\u00f1o lenguaje...<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: No un lenguaje, sino un compilador. Un lenguaje y un compilador son cosas diferentes. La principal diferencia est\u00e1 en tu mente.\u00a0<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Por cierto, hasta donde s\u00e9, est\u00e1s experimentando con la creaci\u00f3n de tus propios lenguajes. \u00bfPor qu\u00e9?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: \u00a1Porque puedo! Estoy semi-jubilado, as\u00ed que esto es mi hobby. He pasado toda mi vida realizando los lenguajes de otras personas. Adem\u00e1s, he trabajado mucho en el estilo de codificaci\u00f3n. Tambi\u00e9n porque veo problemas en otros lenguajes. Veo que hay mejores maneras de hacer las cosas habituales. Y me gustar\u00eda aprovecharlas. Estoy cansado de ver problemas en m\u00ed mismo, en Java, en Python, en cualquier otro lenguaje. Ahora estoy escribiendo en React Native, JavaScript y Elm como un hobby que no se trata de la jubilaci\u00f3n, sino de un trabajo activo. Tambi\u00e9n escribo en Python y, muy probablemente, seguir\u00e9 trabajando en el aprendizaje autom\u00e1tico para los backends en Java. Hay muchos lenguajes populares y todos tienen caracter\u00edsticas interesantes. Cada uno es bueno en algo y se pueden intentar combinar todas esas caracter\u00edsticas. As\u00ed que me estoy dedicando a estudiar cosas que me interesan, el comportamiento del lenguaje, intentando idear una sem\u00e1ntica razonable. \u00a1Y hasta ahora me va bien! En este momento estoy luchando con la sem\u00e1ntica de la memoria, porque quiero tenerla como en C y Java, y obtener un modelo de memoria fuerte y sem\u00e1ntica de memoria para cargas y almacenes. Al mismo tiempo, tener inferencia de tipos autom\u00e1tica como en Haskell. Aqu\u00ed estoy intentando mezclar la inferencia de tipos al estilo de Haskell con una memoria que funcione como en C y Java. En eso he estado trabajando los \u00faltimos 2-3 meses, por ejemplo.<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Si est\u00e1s construyendo un lenguaje que toma lo mejor de otros lenguajes, \u00bfhas considerado que alguien podr\u00eda hacer lo contrario: tomar tus ideas y usarlas en su propio lenguaje?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: As\u00ed es como surgen los nuevos lenguajes. \u00bfPor qu\u00e9 Java se parece a C? Porque C ten\u00eda una buena sintaxis que todos entend\u00edan y Java se inspir\u00f3 en esa sintaxis, a\u00f1adiendo seguridad de tipos, verificaciones de l\u00edmites de arreglos, GC, y adem\u00e1s mejoraron algunas cosas de C. Agregaron las suyas. Pero se inspiraron bastante fuerte, \u00bfverdad? Todos se apoyan en los hombros de gigantes que estuvieron antes que t\u00fa: as\u00ed es como se hace el progreso.<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Seg\u00fan entiendo, tu lenguaje ser\u00e1 seguro en cuanto al uso de memoria. \u00bfHas considerado implementar algo como el verificador de pr\u00e9stamos de Rust? \u00bfLo has visto, qu\u00e9 opinas de \u00e9l?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Bueno, he estado programando en C durante una eternidad, lidiando con todos esos malloc y free, y gestionando manualmente el ciclo de vida. Saben, el 90-95% del tiempo de vida gestionado manualmente tiene una estructura similar. Y es muy, muy doloroso manejarlo de esta manera. Me gustar\u00eda que el compilador simplemente me dijera qu\u00e9 est\u00e1 sucediendo y qu\u00e9 logr\u00e9 con mis acciones. Para algunas cosas, el verificador de pr\u00e9stamos lo hace autom\u00e1ticamente. Adem\u00e1s, deber\u00eda proporcionar autom\u00e1ticamente informaci\u00f3n, entender todo y no sobrecargarme con la necesidad de expresar ese entendimiento. Al menos deber\u00eda realizar un an\u00e1lisis de escape local, y solo si no puede lograrlo, entonces deber\u00eda agregar anotaciones de tipo que describan el ciclo de vida; este esquema es mucho m\u00e1s complicado que el verificador de pr\u00e9stamos, o cualquier verificador de memoria existente. La elecci\u00f3n entre 'todo est\u00e1 bien' y 'no entend\u00ed nada' \u2014 no, deber\u00eda haber algo mejor.\u00a0<br \/>\nAs\u00ed que, como alguien que ha escrito mucho c\u00f3digo en C, considero que tener soporte para la gesti\u00f3n autom\u00e1tica del ciclo de vida es fundamental. Adem\u00e1s, me ha frustrado mucho lo que Java usa de memoria y la principal queja es el GC. Al asignar memoria en Java, no recuperas la memoria que fue local en el \u00faltimo ciclo de GC. En lenguajes con gesti\u00f3n de memoria m\u00e1s precisa, esto no sucede. Si llamas a malloc, obtienes la memoria que generalmente acaba de ser utilizada. Normalmente, haces algunas cosas temporales con la memoria y la devuelves de inmediato. Y se devuelve de inmediato al grupo de malloc, y el siguiente ciclo de malloc la vuelve a extraer. Por lo tanto, el uso real de la memoria se reduce al conjunto de objetos vivos en un momento espec\u00edfico, m\u00e1s las fugas. Y si no se filtra de manera completamente inapropiada, la mayor parte de la memoria se asienta en cach\u00e9s y en el procesador, y esto funciona r\u00e1pido. Pero requiere mucha gesti\u00f3n manual de la memoria con malloc y free, llamados en el orden y lugar correctos. Rust puede manejar esto correctamente por s\u00ed mismo y en muchos casos puede incluso ofrecer un rendimiento mayor, ya que el consumo de memoria se reduce solo a los c\u00e1lculos actuales, en lugar de esperar el siguiente ciclo de GC que liberar\u00e1 la memoria. Al final, tenemos una forma muy interesante de mejorar el rendimiento. Y bastante poderosa; de hecho, he estado trabajando en cosas as\u00ed en el procesamiento de datos para fintech, y esto ha permitido obtener una aceleraci\u00f3n de aproximadamente cinco veces. Esto es una aceleraci\u00f3n considerable, especialmente en un mundo donde los procesadores no se vuelven m\u00e1s r\u00e1pidos, pero seguimos esperando mejoras.<\/p>\n<p><\/p>\n<h1 id=\"karera-performans-inzhenera\">Carrera como ingeniero de rendimiento<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Tambi\u00e9n me gustar\u00eda hacer algunas preguntas sobre la carrera en general. Te hiciste famoso gracias a tu trabajo en JIT en HotSpot, y luego te trasladaste a Azul, que tambi\u00e9n es una empresa de JVM. Pero te ocupaste m\u00e1s de hardware que de software. Y luego, de repente, te cambiaste a Big Data y Machine Learning, y luego a la detecci\u00f3n de fraudes. \u00bfC\u00f3mo sucedi\u00f3 esto? Son \u00e1reas de desarrollo muy diferentes.<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: He estado programando durante bastante tiempo y he tenido experiencias muy diversas. Y cuando la gente dice: \u00abOh, \u00a1t\u00fa eres el que hizo JIT para Java!\u00bb, siempre me parece gracioso. Antes de eso, trabaj\u00e9 en un clon de PostScript, el lenguaje que Apple us\u00f3 alguna vez para sus impresoras l\u00e1ser. Antes de eso, implement\u00e9 el lenguaje Forth. Creo que el tema com\u00fan para m\u00ed es el desarrollo de herramientas. He estado creando herramientas toda mi vida, las cuales permiten a otros escribir sus programas geniales. Pero tambi\u00e9n he trabajado en el desarrollo de sistemas operativos, controladores, depuradores a nivel de kernel, lenguajes para desarrollar sistemas operativos que comenzaban de manera trivial, pero que con el tiempo se volv\u00edan cada vez m\u00e1s complejos. Sin embargo, el tema principal sigue siendo el desarrollo de herramientas. Gran parte de mi vida transcurri\u00f3 entre Azul y Sun, y estuvo relacionada con Java. Pero cuando empec\u00e9 con Big Data y Machine Learning, volv\u00ed a ponerme mi sombrero de gala y dije: \u00abOh, ahora tenemos un problema no trivial, y aqu\u00ed est\u00e1 ocurriendo una gran cantidad de cosas interesantes y personas haciendo algo\u00bb. Es un camino excelente para el desarrollo que vale la pena recorrer. <\/p>\n<p><\/p>\n<p>S\u00ed, me encantan los c\u00e1lculos distribuidos. Mi primer trabajo fue durante la universidad en C, en un proyecto publicitario. Era un trabajo de c\u00e1lculos distribuidos en chips Zilog Z80, que recolectaban datos para el reconocimiento \u00f3ptico anal\u00f3gico de textos, realizado por un verdadero analizador anal\u00f3gico. Era un tema incre\u00edble y completamente extra\u00f1o. Pero hab\u00eda problemas; algunas partes no se reconoc\u00edan correctamente, as\u00ed que hab\u00eda que obtener la imagen y mostrarla a una persona que la hubiera le\u00eddo y que informara sobre lo que dec\u00eda, y as\u00ed hab\u00eda trabajos con datos, y esos trabajos ten\u00edan su propio lenguaje. Hab\u00eda un backend que procesaba todo esto: Z80 trabajando en paralelo con terminales vt100 en uso, uno por persona, y hab\u00eda un modelo de programaci\u00f3n paralela en Z80. Un cierto bloque de memoria com\u00fan que compart\u00edan todos los Z80 dentro de una configuraci\u00f3n en estrella; se compart\u00eda tanto el backplane como la mitad de la RAM dentro de la red, mientras que la otra mitad era privada o se usaba para otra cosa. Un sistema paralelo distribuido complejo de manera significativa con memoria compartida... semi-compartida. \u00bfCu\u00e1ndo fue esto? Ya no lo recuerdo, por ah\u00ed en la mitad de los a\u00f1os 80. Hace bastante tiempo.\u00a0<br \/>\nS\u00ed, digamos que 30 a\u00f1os es bastante tiempo. Las tareas relacionadas con los c\u00e1lculos distribuidos existen desde hace bastante tiempo, la gente ha estado luchando con <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>-cl\u00fasteres. Estos cl\u00fasteres se ven como\u2026 Por ejemplo: hay Ethernet y tu r\u00e1pido x86 est\u00e1 conectado a este Ethernet, y ahora quieres obtener memoria compartida simulada, porque en ese momento nadie pod\u00eda dedicarse a la codificaci\u00f3n de computaci\u00f3n distribuida, era demasiado complicado y por eso hab\u00eda memoria compartida simulada con protecci\u00f3n de p\u00e1ginas de memoria en x86, y si escrib\u00edas en esa p\u00e1gina, le dec\u00edamos a los otros procesadores que si acced\u00edan a la misma memoria compartida, deb\u00edan cargarla de ti, y as\u00ed surgi\u00f3 algo similar a un protocolo de soporte de coherencia de cach\u00e9s y software para ello. Una idea interesante. El verdadero problema, por supuesto, estaba en otro lugar. Todo esto funcionaba, pero r\u00e1pidamente te encontrabas con problemas de rendimiento, ya que nadie entend\u00eda el modelo de rendimiento a un nivel suficientemente bueno \u2013 cu\u00e1les eran los patrones de acceso a la memoria, c\u00f3mo hacer para que los nodos no se pingen eternamente entre s\u00ed, y as\u00ed sucesivamente. <\/p>\n<p><\/p>\n<p>En H2O, se me ocurri\u00f3 lo siguiente: los propios desarrolladores son responsables de determinar d\u00f3nde se encuentra el paralelismo y d\u00f3nde no. He ideado un modelo de codificaci\u00f3n que hace que escribir c\u00f3digo de alto rendimiento sea f\u00e1cil y simple. Sin embargo, escribir c\u00f3digo que funcione lentamente es complicado; se ver\u00e1 mal. Se necesita un gran esfuerzo para escribir c\u00f3digo lento, tendr\u00e1 que usarse m\u00e9todos no est\u00e1ndar. El c\u00f3digo que causa retrasos se ve de inmediato. Como resultado, generalmente se escribe c\u00f3digo que funciona r\u00e1pido, pero luego hay que lidiar con lo que hacer en caso de memoria compartida. Todo esto est\u00e1 ligado a grandes arreglos y el comportamiento all\u00ed es similar al de los grandes arreglos no vol\u00e1tiles en Java paralelo. En otras palabras, imagina que dos hilos escriben en un arreglo paralelo, uno de ellos gana y el otro, por consiguiente, pierde, y no sabes qui\u00e9n es qui\u00e9n. Si no son vol\u00e1tiles, el orden puede ser cualquier cosa, y realmente funciona bien. A la gente realmente le importa el orden de las operaciones; colocan correctamente los vol\u00e1tiles y en los lugares adecuados anticipan problemas de rendimiento relacionados con la memoria. De lo contrario, simplemente escribir\u00edan el c\u00f3digo en forma de bucles del 1 al N, donde N son algunos billones, con la esperanza de que todos los casos complejos se vuelvan autom\u00e1ticamente paralelos, y eso no funciona. Pero en H2O, no es Java ni Scala; se podr\u00eda considerar como \u00abJava menos menos\u00bb, si se quiere. Es un estilo de programaci\u00f3n muy comprensible y se asemeja a escribir c\u00f3digo simple en C o Java con bucles y arreglos. Pero al mismo tiempo, se puede manejar memoria en terabytes. Todav\u00eda utilizo H2O. De vez en cuando lo empleo en diferentes proyectos, y sigue siendo la cosa m\u00e1s r\u00e1pida, superando a sus competidores por decenas de veces. Si est\u00e1s trabajando con Big Data con datos en columnas, es muy dif\u00edcil superar a H2O.<\/p>\n<p><\/p>\n<h1 id=\"tehnicheskie-chellenzhi\">Desaf\u00edos t\u00e9cnicos<\/h1>\n<p><\/p>\n<p><strong>Andrei<\/strong>: \u00bfCu\u00e1l ha sido el mayor desaf\u00edo en toda su carrera?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: \u00bfEstamos discutiendo la parte t\u00e9cnica o la no t\u00e9cnica de la cuesti\u00f3n? Yo dir\u00eda que los mayores desaf\u00edos son los no t\u00e9cnicos.\u00a0<br \/>\nEn cuanto a los desaf\u00edos t\u00e9cnicos, simplemente los super\u00e9. Ni siquiera s\u00e9 cu\u00e1l fue el m\u00e1s grande, pero hubo varios bastante interesantes que tomaron mucho tiempo y lucha mental. Cuando ingres\u00e9 a Sun, estaba seguro de que har\u00eda un compilador r\u00e1pido, mientras que un mont\u00f3n de personas mayores me dec\u00edan que nunca lo lograr\u00eda. Pero segu\u00ed por ese camino, escrib\u00ed un compilador hasta el asignador de registros, y fue bastante r\u00e1pido. Era tan r\u00e1pido como el moderno C1, pero en ese entonces el asignador era mucho m\u00e1s lento, y mirando hacia atr\u00e1s, esa fue una gran problema de la estructura de datos. La necesitaba para escribir un asignador gr\u00e1fico de registros y no entend\u00eda la dilema entre la expresividad del c\u00f3digo y la velocidad, que exist\u00eda en esa \u00e9poca y era muy importante. Result\u00f3 que la estructura de datos a menudo superaba el tama\u00f1o de la cach\u00e9 en los x86 de ese tiempo, as\u00ed que, si inicialmente supuse que el asignador de registros ocupar\u00eda el 5-10% de todo el tiempo de compilaci\u00f3n JIT, en realidad result\u00f3 ser el 50%. <\/p>\n<p><\/p>\n<p>Con el tiempo, el compilador se volvi\u00f3 cada vez m\u00e1s claro y eficiente, dej\u00f3 de generar c\u00f3digo horrible en m\u00e1s casos, y el rendimiento se asemej\u00f3 m\u00e1s a lo que produce un compilador de C. A menos que, por supuesto, est\u00e9s escribiendo algo tan malo que ni siquiera C puede acelerar. Si escribes c\u00f3digo como en C, obtendr\u00e1s un rendimiento similar al de C en m\u00e1s casos. Y a medida que pasaba el tiempo, m\u00e1s frecuente es que el c\u00f3digo coincidiera asint\u00f3ticamente con el nivel de C, el asignador de registros comenz\u00f3 a parecerse a algo terminado... independientemente de si tu c\u00f3digo se ejecuta r\u00e1pido o lento. Continu\u00e9 trabajando en el asignador para que hiciera mejores asignaciones. Se volv\u00eda m\u00e1s y m\u00e1s lento, pero proporcionaba un rendimiento cada vez mejor en aquellos casos donde nadie m\u00e1s pod\u00eda. Pod\u00eda sumergirme en el asignador de registros, dedicar un mes de trabajo, y de repente todo el c\u00f3digo comenzaba a ejecutarse un 5% m\u00e1s r\u00e1pido. Esto suced\u00eda una y otra vez y el asignador de registros se convirti\u00f3 en una especie de obra de arte: todos lo amaban o lo odiaban, y las personas de la academia hac\u00edan preguntas sobre por qu\u00e9 todo se hac\u00eda de esa manera, por qu\u00e9 no <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Register_allocation#Linear_Scan\">b\u00fasqueda lineal<\/a><\/noindex>, y cu\u00e1l es la diferencia. La respuesta sigue siendo la misma: un asignador basado en el grafo de coloraci\u00f3n m\u00e1s un manejo muy cuidadoso del c\u00f3digo de b\u00fafer equivale a un arma de victoria, la mejor combinaci\u00f3n que nadie puede vencer. Y esto es algo bastante poco obvio. Todo lo dem\u00e1s que hace el compilador son cosas bastante estudiadas, aunque tambi\u00e9n han sido llevadas a un nivel art\u00edstico. Siempre he hecho cosas que deber\u00edan convertir el compilador en una obra de arte. Pero nada de esto fue algo extraordinario, excepto el asignador de registros. La clave es que hay que manejarlo con cuidado. <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Register_allocation\">recortar<\/a><\/noindex> bajo carga y, si esto ocurre (puedo explicar con m\u00e1s detalle si es interesante), significa que se puede hacer inlining de manera m\u00e1s agresiva, sin el riesgo de superar el quiebre en el gr\u00e1fico de rendimiento. En aquellos tiempos hab\u00eda un mont\u00f3n de compiladores completos, adornados con chucher\u00edas y bocinas, que ten\u00edan asignadores de registros, pero nadie pudo hacerlo as\u00ed nuevamente. <\/p>\n<p><\/p>\n<p>El problema es que, si agregas m\u00e9todos que deben ser in-lined, aumentando cada vez m\u00e1s el \u00e1rea de inlining, el conjunto de valores utilizados supera instant\u00e1neamente la cantidad de registros, y es necesario hacer un spill. El nivel cr\u00edtico generalmente ocurre cuando el allocador se rinde, y un buen candidato para el spill sustituye a otro, lo que lleva a unos spills bastante extra\u00f1os. El valor del inlining aqu\u00ed es que pierdes parte de la sobrecarga, la sobrecarga de la llamada y el almacenamiento; puedes ver los valores internamente y puedes seguir optimiz\u00e1ndolos. El costo del inlining radica en que se genera una gran cantidad de valores vivos, y si tu allocador de registros hace spill de m\u00e1s de lo necesario, pierdes inmediatamente. Por eso, la mayor\u00eda de los allocadores tienen el problema de que, cuando el inlining sobrepasa un cierto l\u00edmite, todo empieza a hacer spill y el rendimiento puede irse por el desag\u00fce. Aquellos que implementan compiladores a\u00f1aden algunas heur\u00edsticas: por ejemplo, para detener el inlining cuando llega a un tama\u00f1o suficientemente grande, ya que las asignaciones arruinar\u00edan todo. As\u00ed se forma una quiebra en el gr\u00e1fico de rendimiento: inlines, inlines, el rendimiento incrementa lentamente, y luego \u00a1bam! \u2013 cae en picada debido a que has inlined demasiado. As\u00ed funcion\u00f3 todo hasta la llegada de Java. Java requiere mucho m\u00e1s inlining, por lo que tuve que hacer que mi allocador fuera mucho m\u00e1s agresivo, para que se estabilizara y no cayera, y si inlines demasiado, comienza a hacer spill, pero luego llega el momento de \"no m\u00e1s spills\". Esta es una observaci\u00f3n interesante y me lleg\u00f3 de la nada, no era obvio, pero vali\u00f3 la pena. Me embarqu\u00e9 en un inlining agresivo y eso me llev\u00f3 a lugares donde el rendimiento de Java y C van de la mano. Realmente son cercanos: puedo escribir c\u00f3digo en Java que es significativamente m\u00e1s r\u00e1pido que el c\u00f3digo en C y cosas por el estilo, pero en t\u00e9rminos generales, en el gran esquema de las cosas, son comparables. Creo que parte de este cr\u00e9dito se debe al allocador de registros, que me permite inlining de manera muy tonta. Simplemente inlineo todo lo que veo. La cuesti\u00f3n aqu\u00ed es si el allocador funciona bien, si como resultado se obtiene un c\u00f3digo razonablemente eficiente. Ese fue un gran desaf\u00edo: entender todo esto y hacer que funcionara.<\/p>\n<p><\/p>\n<h1 id=\"nemnogo-pro-allokaciyu-registrov-i-mnogoyadernost\">Un poco sobre la asignaci\u00f3n de registros y la multiprocesadoridad<\/h1>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: Problemas como la asignaci\u00f3n de registros parecen ser un tema eterno e interminable. Es interesante, \u00bfhubo alguna vez una idea que parec\u00eda prometedora y luego fracas\u00f3 en la pr\u00e1ctica?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: \u00a1Por supuesto! La asignaci\u00f3n de registros es un \u00e1rea en la que, para resolver un problema NP-completo, intentas encontrar algunas heur\u00edsticas. Y nunca podr\u00e1s lograr una soluci\u00f3n perfecta, \u00bfverdad? Simplemente es imposible. Mira, la compilaci\u00f3n Ahead of Time tambi\u00e9n funciona mal. Aqu\u00ed se habla de algunos casos promedio. De un rendimiento t\u00edpico, as\u00ed que puedes ir y medir algo que consideras un buen rendimiento t\u00edpico; al final, \u00a1est\u00e1s trabajando en mejorar eso! La asignaci\u00f3n de registros es un tema completamente dedicado al rendimiento. Una vez que tienes el primer prototipo, que funciona y hace lo que necesita, comienza el trabajo sobre el rendimiento. Hay que aprender a medir bien. \u00bfPor qu\u00e9 es importante? Si tienes datos claros, puedes ver diferentes partes y notar: ah, esto ayud\u00f3 aqu\u00ed, \u00a1pero all\u00ed todo fall\u00f3! Surgen buenas ideas, agregas una nueva heur\u00edstica y de repente todo empieza a funcionar un poco mejor en promedio. O no lo hace. Tuve un mont\u00f3n de casos en los que luchamos por cinco por ciento de rendimiento que diferenciaban nuestro desarrollo del asignador anterior. Y cada vez se ve as\u00ed: en alg\u00fan lugar gan\u00e9, en alg\u00fan lugar perd\u00ed. Si tienes buenas herramientas de an\u00e1lisis de rendimiento, puedes encontrar ideas perdedoras y entender por qu\u00e9 est\u00e1n fallando. Quiz\u00e1s debas dejar todo como est\u00e1, o tal vez tomarte m\u00e1s en serio la afinaci\u00f3n, o ir y arreglar algo m\u00e1s. \u00a1Es toda una serie de cosas! Hice este genial truco, pero necesito tambi\u00e9n esto, y esto, y esto; y la combinaci\u00f3n total da algunas mejoras. A veces, las soluciones aisladas pueden fracasar. Esa es la naturaleza de trabajar en problemas de rendimiento NP-completos.<\/p>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: Da la impresi\u00f3n de que cosas como la pintura en los asignadores es una tarea ya resuelta. Bueno, para ustedes parece resuelta, seg\u00fan lo que cuentan, entonces, \u00bfvale la pena\u2026?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: No est\u00e1 resuelta como tal. Eres t\u00fa quien debe convertirla en 'resuelta'. Hay tareas dif\u00edciles y hay que resolverlas. Una vez hecho esto, llega el momento de trabajar en el rendimiento. Hay que tratar este trabajo de manera apropiada: hacer benchmarks, recopilar m\u00e9tricas, explicar situaciones en las que al regresar a una versi\u00f3n anterior tu viejo truco volvi\u00f3 a funcionar (o viceversa, dej\u00f3 de funcionar). Y no retroceder hasta que consigas algo. Como ya he mencionado, si hay grandes ideas que no funcionaron, en el \u00e1mbito de la asignaci\u00f3n de registros las ideas son pr\u00e1cticamente infinitas. Por ejemplo, se pueden leer publicaciones cient\u00edficas. Aunque ahora este campo se ha movido mucho m\u00e1s lento y es m\u00e1s claro que en su juventud. Sin embargo, en este campo trabajan una infinidad de personas y vale la pena probar todas sus ideas; todas est\u00e1n esperando su momento. Y no puedes decir cu\u00e1n buenas son si no las pruebas. Cu\u00e1n bien se integran con todo lo dem\u00e1s en tu asignador, ya que el asignador realiza m\u00faltiples tareas y algunas ideas en tu asignador espec\u00edfico pueden no funcionar, mientras que en otro asignador s\u00ed lo har\u00edan. La principal forma de triunfar para un asignador es sacar la parte lenta fuera del camino principal y forzar la divisi\u00f3n en los l\u00edmites de los caminos lentos. Por lo tanto, si deseas iniciar GC, ir por el camino lento, desoptimizar, lanzar una excepci\u00f3n, todo en ese sentido, sabes que esas cosas son relativamente raras. Y realmente son raras, lo he comprobado. Haces trabajo adicional y gracias a esto desaparecen muchas restricciones en esos caminos lentos, pero no es muy importante porque son lentos y rara vez se utilizan. Por ejemplo, un puntero nulo: nunca ocurre, \u00bfverdad? Necesitas tener varios caminos para diferentes cosas, pero no deben interferir en el principal.\u00a0<\/p>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: \u00bfQu\u00e9 opinas sobre la multicore, cuando hay miles de n\u00facleos? \u00bfEs algo \u00fatil?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: \u00a1El \u00e9xito de las GPU demuestra que s\u00ed, es bastante \u00fatil!<\/p>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: Son bastante especializadas. \u00bfY qu\u00e9 hay de los procesadores de prop\u00f3sito general?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Bueno, este era el modelo de negocio de Azul. La respuesta lleg\u00f3 en una era en la que a la gente le encantaba la previsibilidad en el rendimiento. En aquel entonces, era un poco complicado escribir c\u00f3digo paralelo. El modelo de codificaci\u00f3n H2O se escala bien, pero no es un modelo de uso general. Es solo un poco m\u00e1s general que el uso de GPU. \u00bfEstamos hablando de la complejidad de desarrollar algo as\u00ed o de la complejidad de su uso? Por ejemplo, una lecci\u00f3n interesante que me ense\u00f1\u00f3 Azul, bastante no obvia: las cach\u00e9s peque\u00f1as est\u00e1n bien.\u00a0<\/p>\n<p><\/p>\n<h1 id=\"samyy-bolshoy-chellenzh-v-zhizni\">El mayor desaf\u00edo en la vida<\/h1>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: \u00bfQu\u00e9 hay de los desaf\u00edos no t\u00e9cnicos?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: El mayor desaf\u00edo fue no ser\u2026 amable y bueno con la gente. Como consecuencia, me encontraba constantemente en situaciones de conflicto extremo. Situaciones en las que sab\u00eda que todo iba mal, pero no sab\u00eda c\u00f3mo avanzar en la soluci\u00f3n de esos problemas y no pude manejarlos. Muchas de las dificultades a largo plazo, que duraron d\u00e9cadas, surgieron de esta manera. El hecho de que en Java existen compiladores C1 y C2 es una consecuencia directa de esto. Tambi\u00e9n es una consecuencia directa que en Java no hubo compilaci\u00f3n multinivel durante diez a\u00f1os. Es evidente que necesit\u00e1bamos un sistema as\u00ed, pero no est\u00e1 claro por qu\u00e9 no exist\u00eda. Tuve problemas con un ingeniero\u2026 o un grupo de ingenieros. Hace mucho tiempo, cuando comenc\u00e9 a trabajar en Sun, yo era\u2026 Bueno, no solo en ese momento, siempre he tenido mi propia opini\u00f3n sobre todo. Y consideraba que era verdad que pod\u00eda simplemente presentar mi verdad de forma directa. Sobre todo porque, sorprendentemente, ten\u00eda raz\u00f3n la mayor parte del tiempo. Y si a alguien no le gusta este enfoque\u2026 especialmente si est\u00e1 claramente equivocado y hace tonter\u00edas\u2026 En general, pocas personas podr\u00edan soportar este tipo de comunicaci\u00f3n con tolerancia. Aunque algunas s\u00ed podr\u00edan, como yo. He basado toda mi vida en principios meritocr\u00e1ticos. Si me muestras que algo est\u00e1 mal, me dar\u00e9 la vuelta y dir\u00e9: dijiste tonter\u00edas. Al mismo tiempo, por supuesto, me disculpo y cosas as\u00ed, reconozco los m\u00e9ritos, si los hay, y tomo otras acciones correctas. Por otro lado, tengo raz\u00f3n sorprendentemente en un porcentaje sorprendentemente alto de tiempo. Y eso no funciona muy bien en las relaciones con las personas. No intento ser amable, sino que planteo las preguntas directamente. \"Esto nunca funcionar\u00e1, porque uno, dos y tres\". Y ellos responden: \"\u00a1Oh!\". Hubo otras consecuencias, que probablemente es mejor omitir: por ejemplo, las que llevaron a mi divorcio y a una d\u00e9cada de depresi\u00f3n despu\u00e9s de eso.<\/p>\n<p><\/p>\n<p>El desaf\u00edo es luchar contra las personas y su percepci\u00f3n de lo que puedes o no puedes hacer, de lo que es importante y lo que no. Ha habido muchos desaf\u00edos sobre el estilo de codificaci\u00f3n. Todav\u00eda escribo mucho c\u00f3digo, y en esos tiempos tuve que incluso desacelerarme porque estaba haciendo demasiadas tareas en paralelo y las estaba haciendo mal, en lugar de enfocarme en una sola. Mirando hacia atr\u00e1s, escrib\u00ed la mitad del c\u00f3digo del equipo de Java JIT, del equipo C2. El siguiente programador m\u00e1s r\u00e1pido escrib\u00eda la mitad de lento, el siguiente, a\u00fan la mitad m\u00e1s lento, y eso fue una ca\u00edda exponencial. La s\u00e9ptima persona en esta fila era muy, muy lenta; \u00a1eso siempre sucede! Toqu\u00e9 un mont\u00f3n de c\u00f3digo. Observ\u00e9 lo que cada uno escrib\u00eda, sin excepciones, mir\u00e9 su c\u00f3digo, revis\u00e9 a cada uno de ellos, y a\u00fan continu\u00e9 escribiendo m\u00e1s que cualquiera de ellos. Este enfoque no funciona muy bien con las personas. A algunos no les gusta. Y cuando no pueden manejarlo, comienzan a surgir todo tipo de quejas. Por ejemplo, una vez me dijeron que dejara de escribir c\u00f3digo porque escribo demasiado c\u00f3digo, y eso pone en peligro al equipo; para m\u00ed, todo eso sonaba a broma: amigo, si todo el resto del equipo desaparece y yo sigo escribiendo c\u00f3digo, solo perder\u00e1s la mitad del equipo. Por otro lado, si contin\u00fao escribiendo c\u00f3digo y t\u00fa pierdes la mitad del equipo, eso suena a una muy mala gesti\u00f3n. Nunca realmente pens\u00e9 en eso, nunca lo mencion\u00e9, pero a\u00fan as\u00ed estaba en alg\u00fan lugar de mi cabeza. En el fondo de mi conciencia, la idea giraba: '\u00bfEst\u00e1n todos de broma?'. As\u00ed que, el mayor problema era yo y mis relaciones con las personas. Ahora me entiendo mucho mejor; fui l\u00edder de equipo con programadores por un tiempo, y ahora les digo directamente a las personas: sabes, soy como soy, y tendr\u00e1n que lidiar conmigo; \u00bfest\u00e1 bien si me quedo aqu\u00ed? Y cuando empezaron a manejarlo, todo funcion\u00f3. En realidad, no soy ni bueno ni malo, no tengo malas intenciones ni aspiraciones ego\u00edstas, simplemente es mi esencia, y hay que vivir con eso.<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Recientemente, todos han comenzado a hablar sobre la autoconciencia para introvertidos y, en general, sobre las habilidades blandas. \u00bfQu\u00e9 se puede decir al respecto?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: S\u00ed, fue una comprensi\u00f3n y una lecci\u00f3n que saqu\u00e9 de mi divorcio con mi esposa. Lo que aprend\u00ed de la separaci\u00f3n fue el entendimiento de m\u00ed mismo. As\u00ed comenc\u00e9 a entender a los dem\u00e1s. Comprender c\u00f3mo funciona esa interacci\u00f3n. Esto condujo a descubrimientos uno tras otro. Surgi\u00f3 la conciencia de qui\u00e9n soy y qu\u00e9 represento. Lo que hago: o estoy preocupado por la tarea, evito el conflicto, o algo m\u00e1s; y ese nivel de autoconciencia realmente ayuda a mantenerme en control. Despu\u00e9s de esto, todo se vuelve mucho m\u00e1s f\u00e1cil. Una cosa que descubr\u00ed, no solo en m\u00ed mismo, sino tambi\u00e9n en otros programadores, es la incapacidad de verbalizar pensamientos cuando est\u00e1s bajo estr\u00e9s emocional. Por ejemplo, est\u00e1s codificando, en un estado de flujo, y de repente vienen corriendo y gritando hist\u00e9ricamente que algo se ha roto, y que se tomar\u00e1n medidas dr\u00e1sticas. Y no puedes decir una palabra, porque est\u00e1s en un estado de estr\u00e9s emocional. Los conocimientos adquiridos permiten prepararse para ese momento, vivirlo y pasar al plan de escape, despu\u00e9s del cual ya puedes hacer algo. As\u00ed que s\u00ed, cuando comienzas a darte cuenta de c\u00f3mo funciona todo esto, es un gran acontecimiento que cambia la vida.\u00a0<br \/>\nNo pude encontrar las palabras correctas, pero memoric\u00e9 la secuencia de acciones. La esencia es que esta reacci\u00f3n es tan f\u00edsica como verbal, y necesitas espacio. Un espacio as\u00ed, en el sentido zen. Eso es lo que hay que explicar, y luego apartarse enseguida, f\u00edsicamente. Cuando estoy en silencio verbalmente, puedo procesar la situaci\u00f3n en t\u00e9rminos de emociones. A medida que la adrenalina llega al cerebro y te coloca en el modo de 'pegar o huir', ya no puedes hablar; no, ahora eres un idiota, un ingeniero para golpear, incapaz de dar una respuesta digna o al menos detener el ataque, y el atacante puede volver a atacar una y otra vez. Primero tienes que volver a ser t\u00fa mismo, recuperar el control, salir del modo de 'pegar o huir'. <\/p>\n<p><\/p>\n<p>Y para esto es necesario un espacio verbal. Simplemente un espacio libre. Si se va a hablar de algo, se puede afirmar exactamente eso y luego salir y realmente encontrar un \u00abespacio\u00bb: dar un paseo por el parque, encerrarse en la ducha, no importa. Lo principal es desconectarse temporalmente de la situaci\u00f3n. Tan pronto como te desconectas aunque sea por unos segundos, el control regresa, comienzas a pensar con claridad. \u00abBien, no soy alg\u00fan idiota, no estoy haciendo cosas tontas, soy una persona bastante \u00fatil\u00bb. Una vez que logras convencerte a ti mismo, es momento de pasar a la siguiente etapa: entender lo que ocurri\u00f3. Te atacaron, el ataque vino de donde no lo esperabas, fue una emboscada deshonesta y vil. Eso es malo. El siguiente paso es entender por qu\u00e9 el atacante necesitaba hacer eso. De verdad, \u00bfpor qu\u00e9? \u00bfTal vez porque \u00e9l mismo est\u00e1 furioso? \u00bfPor qu\u00e9 est\u00e1 furioso? Por ejemplo, porque cometi\u00f3 un error y no puede asumir la responsabilidad. As\u00ed es como se debe procesar cuidadosamente toda la situaci\u00f3n. Pero para esto necesitas un espacio para maniobrar, un espacio verbal. El primer paso es romper el contacto verbal. Alejarse de la discusi\u00f3n verbalmente. Cancelarlo, irse lo m\u00e1s r\u00e1pido posible. Si es una llamada telef\u00f3nica, simplemente cuelga \u2014 esta es una habilidad que adquir\u00ed de mi comunicaci\u00f3n con mi exesposa. Si la conversaci\u00f3n no lleva a nada bueno, simplemente di \u00abadi\u00f3s\u00bb y cuelga. Del otro lado del tel\u00e9fono: \u00abbla-bla-bla\u00bb, t\u00fa respondes: \u00abaj\u00e1, \u00a1hasta luego!\u00bb y cuelgas. Simplemente cortas la conversaci\u00f3n. Cinco minutos despu\u00e9s, cuando recuperas la capacidad de pensar con claridad, te calmas un poco, es posible reflexionar sobre lo que realmente ocurri\u00f3 y qu\u00e9 pasar\u00e1 despu\u00e9s. Y comenzar a formular una respuesta reflexionada, en lugar de simplemente reaccionar emocionalmente. Para m\u00ed, un avance en la autoconciencia fue precisamente eso: en caso de estr\u00e9s emocional no puedo hablar. Salir de ese estado, pensar y planificar c\u00f3mo responder y compensar los problemas \u2014 esos son los pasos correctos cuando no puedes hablar. La manera m\u00e1s simple es escapar de la situaci\u00f3n en la que se manifiesta el estr\u00e9s emocional y simplemente dejar de participar en ese estr\u00e9s. Despu\u00e9s de esto, recuperas la capacidad de pensar, cuando puedes pensar, surge la posibilidad de hablar, y as\u00ed sucesivamente.<\/p>\n<p><\/p>\n<p>Por cierto, en la corte, el abogado de la parte opuesta intenta hacer esto contigo, ahora ya se entiende por qu\u00e9. Porque tiene la capacidad de aplastarte hasta un punto en el que no puedes ni siquiera pronunciar tu nombre, por ejemplo. En el sentido m\u00e1s literal, no puedes hablar. Si esto te est\u00e1 sucediendo y si sabes que estar\u00e1s en un lugar donde estallan batallas verbales, como en la corte, puedes acudir con tu abogado. El abogado te defender\u00e1 y detendr\u00e1 el ataque verbal de manera completamente legal, y te devolver\u00e1 el espacio zen perdido. Por ejemplo, en un par de ocasiones necesit\u00e9 llamar a mi familia, el juez fue bastante amigable al respecto, pero el abogado de la parte contraria gritaba y gritaba, ni siquiera pod\u00eda interrumpir. En tales casos, lo que mejor funciona para m\u00ed es utilizar un intermediario. El intermediario detiene toda esa presi\u00f3n que fluye sobre ti de forma continua, descubres el espacio zen necesario, y junto con \u00e9l regresa la capacidad de hablar. Es todo un campo de conocimiento en el que hay mucho por aprender, mucho por descubrir dentro de uno mismo, y todo se convierte en decisiones estrat\u00e9gicas de alto nivel, diferentes para distintas personas. Algunos no tienen los problemas descritos anteriormente, por lo general, no los tienen las personas que se dedican profesionalmente a las ventas. Todas estas personas que se ganan la vida con palabras: cantantes conocidos, poetas, figuras religiosas y pol\u00edticos, siempre tienen algo que decir. No tienen esos problemas, pero yo s\u00ed.<\/p>\n<p><\/p>\n<p><strong>Andrei<\/strong>: Fue\u2026 inesperado. Bien, hemos hablado bastante y es hora de concluir esta entrevista. Nos encontraremos en la conferencia y podremos continuar este di\u00e1logo. \u00a1Nos vemos en Hydra!<\/p>\n<p><\/p>\n<blockquote><p>Se podr\u00e1 continuar la comunicaci\u00f3n con Cliff en la conferencia Hydra 2019, que se llevar\u00e1 a cabo los d\u00edas 11 y 12 de julio de 2019 en San Petersburgo. Vendr\u00e1 con una presentaci\u00f3n <noindex><a rel=\"nofollow\" href=\"https:\/\/hydraconf.com\/2019\/talks\/2jix5mst7iduyp9linqhfj\/?utm_source=habr&amp;utm_medium=45871\">\u00abLa experiencia de memoria transaccional de hardware Azul\u00bb<\/a><\/noindex>. Las entradas se pueden adquirir <noindex><a rel=\"nofollow\" href=\"https:\/\/hydraconf.ru\/?utm_source=habr&amp;utm_medium=458718\">en el sitio oficial<\/a><\/noindex>.<\/p><\/blockquote>\n<p>Fuente: <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.2 - 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\/es\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"es_ES\" \/>\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\/es\/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\udd47Gran entrevista con Cliff Click \u2014 el padre de la compilaci\u00f3n JIT en Java | ProHoster","description":"Cliff Click \u2014","canonical_url":"https:\/\/prohoster.info\/es\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"es_ES","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\/es\/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\/es\/wp-json\/wp\/v2\/posts\/35851","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/comments?post=35851"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/posts\/35851\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/media?parent=35851"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/categories?post=35851"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/es\/wp-json\/wp\/v2\/tags?post=35851"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}