Es/FlightGear Newsletter November 2013: Difference between revisions

Jump to navigation Jump to search
Nasal Internals for hackers: Intern'ing symbols: traducido
(Getting involved as a programmer: traducido)
(Nasal Internals for hackers: Intern'ing symbols: traducido)
Line 182: Line 182:
Si estás interesado en aportar como un desarrollador del núcleo, por favor lee [[Howto:Start core development|Comenzar como desarrollador del núcleo]].
Si estás interesado en aportar como un desarrollador del núcleo, por favor lee [[Howto:Start core development|Comenzar como desarrollador del núcleo]].


== Nasal Internals for hackers: Intern'ing symbols ==
== Internals de Nasal para hackers: internando símbolos ==
''Contributed by Philosopher''
''Aportado por Philosopher''


As some of you experienced Nasal/C-code hackers should recall, or even those familiar with scripting languages internals, namespaces are just hashes, with keys representing symbols - right? Well yes, mostly, but each of those symbols are unique in a way from all of the other strings out there: they're interned. (Interning is a process that takes strings and a dictionary and returns a matching string, adding one if needed. That means equal strings are substituted so they have the same pointer, i.e. one string represents all instances of "io", stored in a pool/hash of all used symbols.) Though these interned strings appear at runtime in the keys in namespaces, they get created during code generation (codegen), where the symbols (TOK_SYMBOL) get converted to Nasal strings, are interned to get the correct string (using the globals->symbols hash), and are stored in the naCode's constants' block. From there, the symbol-strings are used to set and get various lvalues (both local/global symbols and objects' members) in an optimized way (that's the whole point of the exercise). Looking at hash.c, there are some specialized functions that make use of the potential optimizations:
Como algunos de ustedes, experimentados hackers de Nasal/C podrán recordar, o incluso aquellos familiarizados con los detalles de los lenguajes de script, los namespaces son sólo tablas de hashing con llaves que representan símbolos - correcto? Ok bien, practicamente, pero cada uno de esos símbolos son únicos en una forma distinta a todos los otros strings que hay ahí afuera: ellos son internos. (El interning es un proceso que toma strings y un diccionario y retorna una cadena coincidente, añadiendo uno si es necesario). Eso significa que las cadenas iguales son sustituidas tal que tienen el mismo puntero, por ejemplo, un string representa todas las instancias de "io", almacenado en un pool/hash de todos los símbolos usados.) Aunque estas cadenas internadas aparecen en tiempo de ejecución en las keys de los namespaces, ellas se crean durante la generación del código (codegen), donde los símbolos (TOK_SYMBOL) que son convertidos a cadenas Nasal, son internadas para obtener la cadena correcta (usando el globals->symbols hash), y son almacenadas en el bloque de constantes de naCode. Desde allí, los symbol-strings son usados para establecer y obtener varios lvalues (ambos simbolos locales/globales y miembros de objeto) en una forma optimizada (esa es la idea principal del ejercicio). Mirando el hash.c, hay varias funciones especializadas que hacen uso de potenciales optimizaciones:


* naiHash_sym (looks up an interned symbol)
* naiHash_sym (busca un símbolo internado)
* naiHash_newsym (adds a symbol in the first empty slot for the hashcode)
* naiHash_newsym (añade un símbolo en el primer slot vacío del hashcode)


(There's another that looks similar, naiHash_tryset, but it does not deal with interned symbols: it uses the findkey() method, which in turn uses the equals() method that checks for more general key equality instead of simple pointer equality.)
(Hay otro que se parece, naiHash_tryset, pero este no maneja símbolos internados: este usa el método findkey(), el cual a su vez usa el método equals() que comprueba una llave de igualdad más general en vez de simplemente la igualdad de punteros.)


The first, naiHash_sym, is pretty neat and the prime example of the optimization: it runs through a hashcode's potential slots, checking only pointer equality (note that interned symbols' hashcodes are computed during interning, so that's another step that doesn't have to be done are runtime). naiHash_newsym is another nice optimization but a little problematic, due to its assumption that the key doesn't exist already. It's basically used for adding another argument as a local key, but it doesn't care about if it exists already, it just sees an occupied slot and keeps going. Consider the following example that illustrates calling with an argument into a hash that already has the argument's key in it:
Lo primero, naiHash_sym, es bastante claro y el supremo ejemplo de la optimización: este corre los slots del hashcode, comprobando sólo la igualdad de punteros (nótese que el hashcode de los símbolos internados son calculados durante la internación, por lo que es otro paso que no es necesario realizar en tiempo de ejecución). naiHash_newsym es otra buena optimización pero un poco problemática, debido a que asume que la llave ya no existe. Básicamente se utiliza para añadir otro argumento como una llave local, pero no le importa si ya existe, sólo ve un slot ocupado y continúa. Considera el siguiente ejemplo que ilustra la llamada con un argumento en un hash que ya tiene la llave del argumento en él:


<syntaxhighlight lang="nasal">
<syntaxhighlight lang="nasal">
Line 203: Line 203:
</syntaxhighlight>
</syntaxhighlight>


This should print:
Esto mostraría:
<pre>
<pre>
arg
arg
Line 210: Line 210:
</pre>
</pre>


This shows that the key is being set twice (which violates a normal precondition of hashes): once as an argument and once to create an existing key in the namespace. The one set first is the one being picked up (e.g. the arg in {arg:nil} versus the arg... that equals []). And this behavior persists even through resizing: hashset() (which is used to reinitialize a hash after reallocation) only keeps appending keys in empty slots, so the number of keys doesn't change (even if there are multiple of the same keys).
Esto muestra que la llave está siendo establecida dos veces (lo cual viola la condición de las tablas de hashing): una vez como argumento y otra vez para crear una llave existente en el espacio de nombres. El primer set es el que está siendo recogido (por ejemplo, el arg en {arg:nil} versus el arg... que iguala []). Y este comportamiento persiste incluso a través del redimensionado: hashset() (el cual es usado para reiniciar un hash después de la redistribución) sólo sigue añadiendo llaves en slots vacíos, tal que el número de llaves no cambia (incluso si hay varias de la mismas llaves).  


For this reason, I would suggest amending naiHash_newsym to check keys' pointer equality before continuing; that way symbols aren't "trodden" over like this. (Please note that if "arg" exists in the hash as non-interned, then it will be trodden over anyways; having to look for non-interned symbols would mainly violate the point of the optimization at this step, and doesn't actually matter in the long run.) I would argue that finding an existing key (a few simple pointer comparisons!) would be more efficient generally, because the hash would never need to be resized if an existing one is found, whereas the old version would append regardless. (I think I once counted well over a hundred "arg" symbols in the __js0 namespace from the continual firing of bindings, which obviously isn't good.)
Por esta razón, sugeriría modificar el naiHash_newsym para comprobar la igualdad de punteros de las llaves antes de continuar; de esa forma los símbolos no son "pisados" como acá. (Por favor considera que si "arg" existe en el hash como un no-internado, entonces éste será pisado de todos modos; tener que buscar símbolos no internados principalmente violaría el punto de la optimización en este paso, y a la larga realmente no importa.) Yo sostendría que encontrar una llave existente (¡unas simples comparaciones de punteros!) generalmente sería más eficiente, porque el hash nunca necesitaría ser redimensionado si encuentra uno existente, mientras que la vieja versión añadiría de todas formas. (Creo que una vez conté más de cien símbolos "arg" in the namespace __js0 desde el continuo lanzamiento de vínculos, lo cual obviamente no es bueno.)


Continue reading at [http://forum.flightgear.org/viewtopic.php?f=30&t=21308&p=193935#p193935].
Continúa leyendo en [http://forum.flightgear.org/viewtopic.php?f=30&t=21308&p=193935#p193935].


== FlightGear addons and mods ==
== FlightGear addons and mods ==
99

edits

Navigation menu