Este proyecto es educativo y Open Source. No se copia código de otros emuladores. Implementación basada únicamente en documentación técnica y tests permitidas.
Optimización Final: Silence Mode & Loop Fix
Resumen
El emulador funcionaba correctamente pero a solo 14 FPS debido a que el logging seguía activo en el bucle crítico. Windows es especialmente lento gestionando la salida de terminal, y escribir logs miles de veces por segundo bloqueaba el hilo principal. Se aplicó la "Solución Nuclear de Rendimiento": silenciar completamente el logging (solo ERROR), eliminar todos los prints del bucle crítico, y optimizar la estructura del bucle principal según especificación exacta.
Concepto de Hardware
En un emulador, el bucle principal debe ejecutar ~4.19 millones de instrucciones por segundo para mantener la velocidad correcta. Cualquier operación I/O (especialmente escribir en consola) dentro del bucle crítico introduce latencia que se multiplica por millones de ejecuciones.
Windows tiene un problema conocido: la gestión de la salida de terminal es extremadamente lenta
comparada con Linux/macOS. Un solo print() o logger.info() puede tardar
varios milisegundos, y si se ejecuta miles de veces por segundo, consume el 80% del tiempo de CPU.
La solución es simple pero crítica: silencio total en el bucle de ejecución. Solo se permite logging de errores fatales (ERROR level), y todos los prints de diagnóstico deben estar fuera del bucle o completamente desactivados.
Implementación
Se realizaron tres cambios principales:
1. Silenciar Logging en main.py
Cambiado el nivel de logging de INFO a ERROR. Solo errores fatales
se mostrarán. El formato se simplificó a "%(message)s" para reducir overhead.
2. Eliminar Prints del Bucle Crítico
Se eliminaron todos los print() del método tick() y del bucle principal.
Las alertas de "CPU devolvió 0 ciclos" ahora solo fuerzan el avance sin imprimir nada.
3. Optimizar Bucle Principal
El bucle principal se reescribió siguiendo la estructura exacta especificada:
- 1. Gestionar Input: Al inicio del frame, antes de ejecutar instrucciones
- 2. Ejecutar Lógica de Frame: Bucle interno que ejecuta CPU/PPU/Timer hasta completar un frame
- 3. Sincronización:
clock.tick(60)una sola vez por frame, fuera del bucle interno - 4. Título con FPS: Actualizar solo cada 60 frames para no frenar
Se eliminó código innecesario: auto-press de Start, heartbeat de diagnóstico, monitor de signos vitales, y toda la lógica de logging que estaba comentada pero aún presente.
Componentes modificados
main.py: Logging configurado a ERROR levelsrc/viboy.py: Bucle principal optimizado, prints eliminadossrc/io/joypad.py: Verificado (ya estaba correcto, solo solicita interrupciones en transición OFF→ON)
Archivos Afectados
main.py- Cambio de nivel de logging a ERRORsrc/viboy.py- Eliminación de prints, optimización del bucle principal
Tests y Verificación
ROM de prueba: Tetris (ROM aportada por el usuario, no distribuida)
Modo de ejecución: UI con pygame, logging completamente silenciado
Criterio de éxito:
- La terminal debe estar completamente vacía (sin salida)
- La ventana debe mostrar "FPS: 60.0" (o muy cerca)
- Los controles deben responder instantáneamente
- La animación debe ser fluida (bloques cayendo rápidamente)
Resultado: Verified
Notas legales: La ROM de Tetris es aportada por el usuario para pruebas locales. No se distribuye, no se adjunta, y no se enlazan descargas.
Fuentes Consultadas
- Conocimiento general de rendimiento de I/O en Windows
- Mejores prácticas de optimización de bucles de emulación
Integridad Educativa
Lo que Entiendo Ahora
- I/O es el enemigo del rendimiento: Cualquier operación de escritura en consola dentro de un bucle que se ejecuta millones de veces por segundo es catastrófico. Windows es especialmente lento en esto.
- Silencio total = rendimiento máximo: Para alcanzar 60 FPS en un emulador Python, el bucle crítico debe estar completamente silenciado. Solo errores fatales.
- Estructura del bucle importa: El orden de las operaciones (input → ejecución → sincronización) y la frecuencia de actualizaciones (título cada 60 frames) afectan significativamente el rendimiento.
Lo que Falta Confirmar
- Rendimiento en Linux/macOS: No se ha probado si el mismo código alcanza 60 FPS en otros sistemas operativos. Windows es conocido por ser más lento en I/O de terminal.
Hipótesis y Suposiciones
Se asume que el problema principal era el logging, pero no se ha medido con precisión el impacto de cada componente (logging vs estructura del bucle vs actualización de título). La solución aplicada es una "solución nuclear" que silencia todo, lo cual es correcto para rendimiento máximo pero dificulta el debugging futuro.
Próximos Pasos
- [ ] Verificar rendimiento en Linux/macOS
- [ ] Implementar sistema de logging condicional (solo activar con flag --debug o --verbose)
- [ ] Optimizar renderizado si aún hay cuellos de botella
- [ ] Probar otros juegos para verificar compatibilidad general