zx81 escribió:Bueno, las primeras pruebas son un poco sorprendentes. De entrada, no se puede compilar con GCC, tiene que ser con G++, lo que no me gusta mucho porque por defecto enlaza con la libstdc++ aunque no la gaste.
Si, soy un trampas.
Tengo tropecientas versiones con múltiples características de pruebas, en concreto una con C POSIX, pero no la tengo pulida del todo. Es un milagro que haya subido una que funcione, pero esta usa C(no POSIX), o sea, es un C con alguna característica de C++.
Dame tiempo, y a ver si subo una C 100%.
zx81 escribió:Para comprobar tiempos de la forma más estable posible, he quitado la llamada a ShowTime por línea, me interesa el tiempo final, no lo que tarda cada línea, he cambiado el tipo de la variable 'tstates' de unsigned int a unsigned long, ya que con un entero simple se desborda y no da valores correctos (¿porqué no has usado los tipos de <stdint.h> que son más cortos de escribir y portables?). He compilado con -Wall -O2 con el G++ 11.1.1 que va con la Fedora 34, ejecutable de 64 bits.
Ok, añado un pragma para lo del tiempo para que se elija por línea o total. Usé el
time.h, pero no se si será el más multiplataforma. ¿Se te ocurre alguna otra? Igual hasta un pragma también para quitar tiempo de medición.
Lo de
stdin.h era porque no quería usarla para que valiera para más compiladores viejunos, pero era una cosa que empezé y luego dejé a la mitad, ya sabes como va esto, mientras que se hace, hay que sacar la basura, hay que sacar a pasear al perro, lo uno, lo otro, y queda todo a medias.
zx81 escribió:Al compilar con -O3, que es más proclive de por sí a meter inline muchas funciones, el tiempo se va a 1m43,670s, es decir, empeora en lugar de mejorar. Puede resultar contraintuitivo, pero un programa más grande son más fallos de caché y eso siempre cuesta tiempo.
Esto todo tengo pensado ponerlo en pragmas de prueba, pero tengo que pensar como dejarlo sin que quede todo complejo. Pero sí, la idea, sería tener muchas opciones de benchmark y así podriamos perder muy poco tiempo en pruebas, y elegir que core queremos, si C++, C o lo que sea.
zx81 escribió:Al final, después de insistir y pegar la chapa con el tema de ir haciendo tests poco a poco y ver los resultados, resulta que no iba tan desencaminado.
A ver, lo que has hecho a nivel técnico, no es que sea grande, es que es
nivel DIOS. Esto no es hacer la pelota, o sea, no hay palabras que definan, lo que has realizado, para que pueda servir para hacer luego test y demás modificaciones.
zx81 escribió:Lo que es a mi, me ha sido muy útil tu trabajo para despejar la duda de si el core sería mucho más rápido en C y la respuesta es *NO*. Tanta manía que le tienen los incondicionales del C al C++ por ser "más lento" y va a resultar que en este caso no lo es, al menos no tanto como para justificar lo que pierdes con el cambio a C (tu core es difícil de usar en un programa que necesite más de un Z80). Probablemente, podrías meter los registros y demás en una estructura Z80 como hacen otros sin pérdida apreciable de rendimiento.
Lo de C vs C++, no te lo compro, es más, no lo compraba en lo 90, como para comparlo en el 2021. Ahora mismo, es una primera plantilla. Está en pseudo C, para que los compiladores que no pueden optimizar más, pues tiren millas. Se puede hacer 2 y 3 podados más, pero claro, ese cambio, va unido al proyecto que estemos haciendo, dado que tener variables y funciones extern no es lo mismo que tenerlas static. Y luego no es lo mismo un GET SET o como lo tengo ahora en C, que:
Este acceso directo al registro, no quería dejarlo, porque por ejemplo, lo siguiente puede liarla parda:
Pero para un emulador que estemos nosotros controlando, la mejora es evidente.
La versión original tuya en C++ yo la tengo en normativa C++ clásica, que está sin override y con la reducción de métodos virtuales, de manera que eso ya incrementa velocidad. C++ no sólo es tema de velocidad, es de memoria. Los métodos virtuales estan en una tabla de objetos virtuales. Y los objetos estan en tabla de objetos, eso es más RAM para la saca.
Lo de dejarlo en variables en vez de estructura, es más pensado para si luego por dependencia de un proyecto queremos declararlas static, para que sea propagado a registro interno o cache en embebido, para si queremos seguir perfilando, con otro nivel de podado.
zx81 escribió:Por cierto, para tener una idea de cómo va esto en máquinas como la PI, hay que repetir todo lo que he hecho en una de ellas. El juego de instrucciones es muy diferente al de un PC, y lo ideal sería poder hacer lo mismo en el ESP32, cuyo juego de instrucciones Xtensa tampoco tiene nada que ver. Lo que se aplica en una arquitectura puede dar resultados diametralmente diferentes en otra. Cuidado con esto.
Correcto, por eso está genial lo de tu test.
zx81 escribió:De momento, no parece que hayas introducido ningún bug nuevo, pero el ZEXALL no comprueba absolutamente todas las instrucciones. Tiene buena pinta.
No nos engañemos, no es que puede que no tenga fallos, es que fijísimo que los he metido. Con tanto cambio aqui, copy y paste y demás, fijísimo que hay fallos, pero fijísimo. Con el tiempo, iran saliendo a la luz.
Pero eso, de entrada, no uso la opción de BIG ENDIAN, lo dejé para mis pruebas en Litte Endian, y el timer, lo dejé de 32 bits para mis pruebas en lugar de 64, que así me queda en un registro de 32 bits, así que añadiré pragmas también para que usar.
La idea de todo esto es tener una plantilla de C, e ir puliendo a partir de ese punto. Digamos que hemos conseguido quitar un escalón, para ir subiendo otro. Si tenemos que ponernos a hacer todo, da mucha pereza.
Muchas gracias por perder el tiempo probando. Lo que vayas encontrando, avisa, que va a servir de mucha ayuda
.