Con Sieve en Javascript optimizado, había dado por cerrado el ciclo de rendimientos basados en Sieve en Java, BASIC, Pascal, y C.

Sin embargo después del buen sabor de boca con C3 (Clipper Compatible Compiler), me quedaba por comprobar como de bueno sería su rendimiento.

La clave de Clipper, era que generaba ejecutables nativos, pero que contenían un runtime de p-code para el código, que era interpretado. Esperaba por tanto que fuera menos eficiente que los lenguajes compilados tradicionales: C, Pascal, Basic, … Pero no sabía que tal se comportaría frente a Java o Javascript.

Tanto Java, como Javascript, son ejecutados actualmente con un compilador JIT, es decir, el sistema lee el código fuente, o bytecode, y genera código nativo en memoria, que es el que al final se acaba ejecutando.

El rendimiento obtenido ha sido bastante malo, y malísimo si tenemos en cuenta las buenas expectativas que tenía al ver lo compactos que eran los ejecutables. Ello me ha obligado a reducir las iteraciones a 10.000, las mismas que usé para Javascript, pero incluso con eso, ha resultado mucho menos veloz.

Incluso me planteé la posibilidad de que mis oxidados conocimientos de C3 hubieran causado que cometiese un error en la conversión del código.

He obtenido una medición de 136,83 segundos para el ejecutable x86, y de 149,17 segundos para el x64. Como digo, me ha sorprendido su falta de agilidad, con un desempeño 50 veces peor que el de Javascript, o lo que es lo mismo, 2.500 veces peor que C/C++.

Soy consciente que xBase no es el entorno ideal para el desarrollo de aplicaciones de cálculo intensivo, pero por esa misma regla de tres, tampoco lo es Javascript, y ahí están sus resultados más que dignos, que choca con el rendimiento ágil de la GUI, que también está escrita en C3.

Otro punto contradictorio es el hecho que la compilación de 64 bits resulte más lenta que la de 32 bits. Es obvio que no son necesarios grandes números en el algoritmo de Sieve, y que los punteros largos tendrán cierta sobrecarga, pero también es verdad que tenemos más registros de CPU disponibles, y una convención de llamada más eficiente, que deberían igualar ambas plataformas. Quizás el problema venga por el generador de código de Visual C++ 2005 con el que está implementado el núcleo de C3, que no sea demasiado eficaz en 64 bits. Valdría la pena actualizar a 2013 o 2014 CTP, y ver si la cosa mejora.

Como es habitual, os dejo el código aquí para que lo reviséis vosotros mismos:

#define MAXITER 10000
 
procedure main
   local i, k
   local found, iter
   local flags[MAXITER]
   local start, finish
 
   ? str(MAXITER) + " iterations"
   start := seconds()
   for iter := 1 to MAXITER
           found := 0
           for i := 1 to MAXITER
                  flags[i] := 0
           next i
           for i := 2 to MAXITER
         if flags[i] = 0      // found a prime
                      found++
            for k := i+i to MAXITER step i
               flags[k] := 1
            next
                  endif
           next
   next
   finish := seconds()
   ? str(found) + " primes in " + str((finish-start)*1) + " seconds "
return

Y os dejo el proyecto, los fuentes, y los binarios de 32 y 64 bits aquí (195 Kb. en formato ZIP).

Esperemos que poco a poco el runtime vaya mejorando en eficiencia.