FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin para Harbour/xHarbour Conseguir la maxima velocidad del EXE creado por Harbour
Posts: 729
Joined: Tue Oct 18, 2005 06:49 PM
Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Tue Mar 13, 2012 05:07 PM

Hola foro,
Basado en sus experiencias, 驴cu谩les son los procedimientos a seguir para conseguir la velocidad m谩xima del EXE generado por Harbour + FWH?
Por ejemplo, estoy pensando en lo siguiente:
1. Sustituir c贸digo Harbour por c贸digo C (en funciones que pueden ser, o deber铆an ser, optimizadas mediante el uso de c贸digo C).
2. Usar variables locales en lugar de variables globales.
3. Para bases de datos usar ADS/ADT en lugar de DBF (no estoy seguro cual sera mas rapido).
4. Uso de tablas HASH en lugar de arrays
5. Uso de los bloques de c贸digo y funciones eval()

Algunas preguntas:
Fivetechsoft o algun compa帽ero del foro han hecho pruebas comparando las velocidades de EXE de harbour vs. EXE de lenguaje C?
Seria posible llamar codigo "assembler" desde Harbour?
Es el P-Code, generado por Harbour, una gran limitaci贸n para obtener EXE que corran rapido, comparable a los EXE generados por el lenguage C?
Se pudiera anular (o disminuir notablemente) , esta limitaci贸n, llamando a funciones escritas en lenguaje C (o assembler) desde el codigo Harbour?

Saludos,

George

Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Tue Mar 13, 2012 06:28 PM

George,

La velocidad del .exe depende MUCHO del compilador C que utilices. Te hablo sobre lo que he le铆do en el foro de Harbour.

Saludos

Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Tue Mar 13, 2012 06:44 PM
George,

Una aplicaci贸n en Harbour finalmente genera un EXE a partir de lenguaje C, luego no hay diferencia, salvo que usamos una m谩quina virtual que interpreta pcode, pero esa m谩quina virtual est谩 programada en C y es muy eficiente, posiblemente de las m谩s r谩pidas que existan :-)

Pero tu pregunta me hace pensar en por que te planteas esto ? Es que tu aplicaci贸n va "lenta" ? De ser asi, en que va lenta ? Que partes de ella ?

Y aqui es en donde aparece el concepto de "profiling": http://en.wikipedia.org/wiki/Profiling_(computer_programming)

Para acelerar la ejecuci贸n de una aplicaci贸n hay que identificar los "cuellos de botella" que enlentecen la aplicaci贸n. Harbour implementa un profiler (yo lo dise帽茅) que basicamente mide los tiempos de ejecuci贸n de cada funci贸n (贸 m茅todo) y adem谩s informa de cuantas veces cada proceso es llamado. Los que se llamen m谩s veces obviamente son los mejores candidatos a ser optimizados, para ganar en velocidad de ejecuci贸n.

Otra posible raz贸n de lentitud es el consumo de memoria. Los sistemas operativos usan "memoria virtual" que basicamente se traduce en usar tanto la ram como los discos duros para almacenar informaci贸n. A mayor consumo de memoria, mayor necesidad de memoria virtual y mayor lentitud. Hoy en d铆a parecer铆a que esto es "improbable" pero, por ejemplo, estos dias estoy probando la nueva versi贸n Mountain Lion de OSX y uno puede experimentar esto perfectamente. A mayor complejidad de los sistemas operativos, m谩s consumo de memoria y mayor lentitud. De ahi que se hace necesario el usar de hardware m谩s r谩pido.
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 729
Joined: Tue Oct 18, 2005 06:49 PM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Tue Mar 13, 2012 10:09 PM
Antonio,
Como siempre, te agradezco tu pronta respuesta asi como tus consejos tecnicos y tu disposicion de ayuda.
Pero antes de seguir quiero aclararte que TODAS las aplicaciones que he desarrollado con Harbour + Fivewin NO son lentas en modo alguno.
Por el contrario son mas rapidas que todos los otros entornos de desarrollo (IDE) que he utilizado y que no lo voy a mencionar para no entrar en discusiones irrelevantes.

Lo que me refiero es a la *optimizacion* del codigo EXE generado por Harbour (aunque gracias al comentario der hmpaquito y al tuyo creo que entiendo mejor ahora).

Por ejemplo si tenemos una database con decenas de millones de records donde los campos pueden ser tratados como un 'string" de bits, talvez podemos usar FWH64 para representar una informacion "binaria" de longitud 64 bits almacenado como un numero entero en formato hexadecimal.
En este caso podemos aplicar el concepto de Bit Map (como expresado en el libro "Clipper 5.2 - Power Programmer Guide", autor Rick Spencer, pags. 688-694), para accesar directamente (y manipular) esta informacion a nivel de bits.

Supongamos que en nuestra database tenemos un tipo de producto X particular, representado por el string de 64 bits expresado en hexadecimal, y que la posicion No. 32 (dentro de ese string de 64 bits) representa un atributo especifico (del producto X) cuando esta "1" y la carencia de ese atributo cuando esta "0". Aqui podemos, de forma muy rapida, mediante operaciones bitwise (AND, OR, o XOR) investigar cuales productos tienen esa caracteristicas y cuales no,
Lo anterior es posible ya que estas operaciones "bitwise" se ejecutan en "computer's clock cycle" asi que nuestros programas realizarian millones de estas operaciones por segundo.

La pregunta mia es, si debido al factor P-Code, que tipo de limitaciones tendremos al usar las operaciones bitwise desde Harbour64 + FWH64?
Si hay limitaciones, en lo que se refiere a la velocidad, podemos evitarlas desarrollando funciones escritas en lenguaje C y llamandolas desde nuestro programas Harbour64?

Cual es tu opinion referente al codigo siguiente que esta siendo llamado desde Harbour64 + FWH64?
Se estaria ejecutando a una velocidad diferente (menor) que si lo llamaramos desde un programa escrito enteramente en C, aunque utilizemos el mismo compilador?
Code (fw): Select all Collapse
#pragma BEGINDUMP
#include <hbapi.h>
#include <math.h>

// Bitwise XOR C Function
HB_FUNC( C_XOR )
{

聽 聽 long long int nHexadecimal1, nHexadecimal2;
聽 聽 long long int nXor;

聽 聽 nHexadecimal1 = hb_parnll(1);
聽 聽 nHexadecimal2 = hb_parnll(2);

聽 聽 nXor = nHexadecimal1 ^ nHexadecimal2;

聽 聽 hb_retnll( nXor );

}

#pragma ENDDUMP


Saludos,

George
Posts: 883
Joined: Tue Oct 11, 2005 11:57 AM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Tue Mar 13, 2012 11:47 PM

George...

Si, lo mas problabe es que tengas un optimizacion de 0.00000001 segundo... que lo vas a perder 1.000.000 de veces en el siguiente Do While.. que no esta optimizado.

Lo mejor cuando trabajas con compiladores, especialmente con aquellos que generan codigo C puro y duro, es la optimizacion del procedimiento o funcion que ejecuta ciclos, ahi es donde los problemas aparecen, no en la ejecucion lineal de tu programa.

1.-Evita lo que mas puedas las escrituras y lecturas a disco.
2.-Optimiza al maximo los ciclos. (Do While...End / For...Next etc)
3.-Controla al maximo las excepciones (calculos o recuperaciones de divisiones por cero por ej) Aqui en el foro habia un post muy interesante sobre eso.
4.-Cuida el flujo de tu programa, evita pasos innecesarios, respuestas del usuario.
5.-Menos es mas
6.-Crea consultas inteligentes (en el caso de SQL)
7.-Crea indices de acuerdo a lo que vas a necesitar. Con la seguridad de usarlos y de que te permitan mejorar la respuesta de la DB.

Con eso tienes mas que suficiente para "acelerar" tu exe.
Los internals de C, pueden mejorar tu velocidad, pero en cuanto.. casi imperceptible para el usuario.

Saludos desde Chile
Adolfo

;-) Ji,ji,ji... buena la cosa... "all you need is code"

http://www.xdata.cl - Desarrollo Inteligente
----------
Asus TUF F15, 32GB Ram, 2 * 1 TB NVME M.2, GTX 1650
Posts: 729
Joined: Tue Oct 18, 2005 06:49 PM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Wed Mar 14, 2012 12:40 AM

Adolfo,
Muy clara tu respuesta.
Estoy de acuerdo contigo en tus sugerencias y sobretodo en que las instrucciones tipo "loops" y de toma de decisiones nos hacen perder en mucho lo poco que gananos.

Por otro lado imaginate un escenario donde usemos unicamente operaciones bitwise, no "for-next" , no "do while - enddo", no "if-else-endif"
Lo que me gustaria saber es como las operaciones "bitwise" se verian afectadas por P-Code.
Bueno, creo que tendria yo mismo que hacer estas pruebas :|

Saludos,

George

Posts: 731
Joined: Fri Oct 07, 2005 07:42 AM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Thu Mar 15, 2012 01:07 PM
Bueno , algunas mejoras, es insignificante pero, te aseguro que esto es una cuello de botella enorme;

Code (fw): Select all Collapse
aArray := Array( 1000000 )
For x := 1 to len( aArray )   // MALO MALISIMO


Optimizado;

Code (fw): Select all Collapse
nLen := Len( aArray )
for x := 1 to nLen


La explicaci贸n es simple, en el primero , evalua LEN() por cada vuelta, en el otro, no.

Lo mejor que puedes hacer es poner el PROFILE , pero para ello tienes que construir Harbour con ese soporte, porque la aplicaci贸n no estar谩 pensada para el cliente final, si no para encontrar los cuellos de botella.
Saludos

Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)
Posts: 729
Joined: Tue Oct 18, 2005 06:49 PM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Thu Mar 15, 2012 04:51 PM

Gracias thefull.
Ire tomando notas de todos los "tips".

Saludos,

George

Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Thu Mar 15, 2012 05:15 PM
George,

Como ha quedado inaugurada la temporada de tips, a vuela pluma va uno:

Code (fw): Select all Collapse
Tip. Cuidado con  Aadd() !
// No hacer:
a:= {}
for ni:= 1 to 1000
   Aadd(a, "algo")
next

// Sino hacer mejor asi:
a:= asize(1000)
for ni:= 1 to 1000
   a[ni]:= "algo"
next


A ver si la gente se anima a poner aqui sus tips de velocidad.

Saludos
Posts: 1380
Joined: Fri Oct 14, 2005 01:28 PM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Fri Mar 16, 2012 12:43 PM
Pues ac谩 les dejo un interesante tip "del dia"
http://forums.fivetechsupport.com/viewtopic.php?f=6&t=23671&p=127486#p127481

Y otros del 2005, publicados por el amigo Walter Negro en su blog
Optimizacion I: http://cosadenegro.blogspot.com/2005/02/optimizacion-i.html
Optimizacion II: http://cosadenegro.blogspot.com/search? ... izacion+II
Optimizacion III: (parece que se perdio, pero les pego el texto, porque "el que guarda siempre tiene" :-) )
Optimizaci贸n IV - Walter Negro
605 palabras totales en este texto (24 Lecturas) Versi贸n Imprimible
<modules.php?name=Sections&op=printpage&artid=13>
------------------------------------------------------------------------

Comando With Object

WITH OBJECT ... END

Esta es otro de los nuevos comandos de xHarbour que permiten ahorrar
tiempo en tareas repetitivas.

Este comando realiza una cache de un objeto y junto con algunos PCODEs
permite acelerar el acceso a metodos y datas de un objeto.

La sint谩xis m谩s com煤n es:

WITH OBJECT oGet
...:Name := "Nombre"
...:VarPut( "Walter" )
END

Tambi茅n se puede usar la funci贸n HB_SetWith().
Al pasarle el dato, lo guarda en la cache, y al llamar a esta funci贸n
sin par谩metros, lo quita.
Para acceder al objeto en el cache se usa la funci贸n HB_QWith().
Hay que destacar, que tanto HB_SetWith() como HB_QWith() no son
funciones reales, sino que en tiempo de compilaci贸n se transforman en
los mismos PCODEs usados en WITH OBJECT.

HB_SetWith( oGet )
...HB_QWith():Name := "Nombre"
...HB_QWith():VarPut( "Walter" )
HB_SetWith()

Este c贸digo genera el mismo PCODE que el ejemplo anterior.

Es posible usar HB_QWith() dentro de WITH OBJECT, pero no es posible
usar la sint谩xis reducida (:Name), con HB_SetWith().

WITH OBJECT oGet
...oOtro := HB_QWith() // Correcto
END

HB_SetWith( oGet )
...? :Name // Error
HB_SetWith()

Tambi茅n es posible usar el WITH OBJECT dentro de una macro.

WITH OBJECT oGet
...&(":Name := 'Nombre'")
...&(":VarPut( 'Walter' )")
END

Y el HB_SetWith() tambi茅n en una macro

&("HB_SetWith( oGet )")
...HB_QWith():Name := "Nombre"
...HB_QWith():VarPut( "Walter" )
&("HB_SetWith()")

WITH OBJECT y HB_SetWith() soportan hasta 32 niveles de anidamiento.
Cada END y cada HB_SetWith() sin par谩metros o con par谩metro NIL,
"desanidan" un nivel.

Aqu铆 hay un ejemplo de los usos, tomado desde el CVS de xHarbour
xharbour estswith.prg
<http://cvs.sourceforge.net/viewcvs.py/*checkout*/xharbour/xharbour/tests/with.prg?rev=1.3>

Fuente: Blog "Cosa de Negro" por Walter Negro

Optimizacion IV: http://cosadenegro.blogspot.com/search? ... izacion+IV
Optimizacion IV:
Optimizaci贸n V - Walter Negro
1107 palabras totales en este texto (31 Lecturas) Versi贸n Imprimible
<modules.php?name=Sections&op=printpage&artid=14>
------------------------------------------------------------------------

FOR EACH
Acelerando los recorridos sobre un array.

Es muy com煤n que tengamos que recorrer arrays para hacer diferentes
tipos de tareas, buscar, imprimir, copiar, modificar masivamente, etc.

Adem谩s de poder hacerlo con un AEVAL(), podemos usar un bucle FOR-NEXT o
un bucle DO WHILE-ENDDO.

En xHarbour se agrega un nuevo bucle exclusivo para la tarea de recorrer
arrays, el FOR EACH-NEXT.

Veremos m谩s adelante que este bucle tiene algunas particularidades muy
interesantes que son su punto fuerte y raz贸n de ser.

La sint谩xis de uso es la siguiente:

FOR EACH _var_ IN _array_
[LOOP]
[HB_ENUMINDEX()]
[EXIT]
NEXT

_array_ puede ser cualquier expresi贸n que retorne un array, un objeto o
una cadena de caracteres.

_var_ puede ser cualquier variable previamente declarada, pero es
recomendable que sea una variable local.
Esta variable va a apuntar a una posici贸n del array, comenzando por la
primera posici贸n.

El FOR EACH va a recorrer todo el array completamente, a menos que se
fuerze la salida anticipada con el comando EXIT.
Tambi茅n es posible usar el comando LOOP de la misma forma que se usa en
el comando FOR-NEXT.

La pseudo-funci贸n HB_ENUMINDEX() retorna el n煤mero de posici贸n del array
que se est谩 procesando en ese momento.


Funcionamiento:

El comando FOR EACH recorre todo el array _array_ y en cada iteraci贸n
guarda en la variable _var_ una referencia a la posici贸n actual del array.

Al finalizar el bucle FOR EACH, la variable _var_ queda con valor NIL,
asi que si necesitamos preservar el valor de dicha variable para usarlo
fuera del bucle, debemos copiarla a otra variable antes de salir.


Qu茅 es eso de que la variable es una referencia ?

La variable del FOR EACH funciona de forma similar a los par谩metros de
una funci贸n que reciben los datos por referencia.

Es como si fuera algo as铆: (la siguiente sint谩xis es de ejemplo, no es
v谩lida)

_var_ := @_array_[n]


Qu茅 ventajas tiene ?

La ventaja de tener en _var_ una referencia a la posici贸n del array es
que para modificar la posici贸n del array, solo es necesario asignar el
dato que queremos a la variable _var_, y lo que realmente estaremos
haciendo, es modificar el contenido del array.


Donde aplicarlo?

Este comando est谩 especialmente dise帽ado para recorrer arrays
r谩pidamente y poder usar o modificar su contenido tambi茅n de la forma
m谩s r谩pida posible.

Todas los bucles que recorren un array pueden beneficiarse con el uso de
For each.
Cualquier construcci贸n del tipo:

for n:=1 to Len(aArray)
...
next

puede ser convertida a

for each x in aArray
...
next


Los que usan Fivewin, encontrar谩n muchas construcciones que pueden
optimizarse usando FOR EACH, en muchos de los fuentes del sistema.
Tambi茅n en otras clases como TSBrowse el desempe帽o mejora notablemente
al usar FOR EACH.

Encontrar谩n ejemplos y pruebas aqu铆: foreach.prg
<http://cvs.sourceforge.net/viewcvs.py/*checkout*/xharbour/xharbour/tests/foreach.prg?rev=1.1>
objlist.prg
<http://cvs.sourceforge.net/viewcvs.py/*checkout*/xharbour/xharbour/tests/objlist.prg?rev=1.1>
ivarref.prg
<http://cvs.sourceforge.net/viewcvs.py/*checkout*/xharbour/xharbour/tests/ivarref.prg?rev=1.3>

Los siguientes ejemplos producen el mismo resultado, pero con tiempos de
ejecuci贸n diferentes.
El for-next y el aeval, tardan aproximadamente lo mismo, pero el for
each demora la mitad de tiempo.

aArray := arrray(500000)
nLen := Len(aArray)

for n:=1 to nLen
...aArray[n] := n
next

for n:=1 to nLen
...nSum += aArrray[n]
next

------------------------

aeval( aArray, {|a,n| aArray[n]:=n} )
aeval( aArray, {|a,n| nSum += a} )

------------------------

for each x in aArray
...x := HB_EnumIndex()
next

for each x in aArray
...nSum += x
next

Fuente: Blog "Cosa de Negro" por Walter Negro
Resistencia - "Ciudad de las Esculturas"

Chaco - Argentina
Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Sat Mar 17, 2012 08:30 AM
Amigos,

Me gustan mucho los tips que van al grano, sencillitos y directos...

Aqu铆 va lo que espero que sea uno del estilo

Code (fw): Select all Collapse
// 2潞 Tip de velocidad: Unlock s贸lo al final del proceso.
// Teniendo un bucle DO WHILE de evaluaci贸n de datos con replace, el 
// unlock lo haremos al final del bucle y no en cada iteraci贸n

do while !eof()
聽 聽rlock()
聽 聽replace x with y
   skip
enddo
unlock


驴 Alguien se atreve a aportar sus tips de velocidad fruto de su ya mucha experiencia en las lides xprogram谩ticas ?
saludos
Posts: 654
Joined: Mon May 29, 2006 03:14 PM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Sat Mar 17, 2012 02:46 PM
thefull wrote:
Code (fw): Select all Collapse
aArray := Array( 1000000 )
For x := 1 to len( aArray ) 聽 // MALO MALISIMO


Y como lo hariamos si dependiendo de un criterio dado tenemos que ir BORRANDO algunos elementos del array.

Yo hago esto:
Code (fw): Select all Collapse
for x = 1 to len( aArray )
聽 聽if << Aqu铆 la condicion deseada >>
聽 聽 聽 adel( aArray , x , .T. )
聽 聽endif
next x
Mi abuelo dec铆a: Los aviones vuelan porque Dios quiere, y los helic贸pteros ni Dios sabe porque vuelan.

FWH 16.02, xHarbour 1.2.3, Harbour 3.2.0, WorkShop 4.5, AJ Make 0.30, Borlan BCC 7.00, VisualStudio 2013
Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Sat Mar 17, 2012 03:38 PM
jm,

lo har铆amos as铆:
Code (fw): Select all Collapse
nLen:= Len( aArray)
nBorrados:= 0
for x = 1 to nLen- nBorrados
聽 聽if << Aqu铆 la condicion deseada >>
聽 聽 聽 adel( aArray , x )
聽 聽 聽 nBorrados++
      x--
聽 聽endif
next x
aSize(aArray, nLen- nBorrados)


Y en este caso la mejora de velocidad ser铆a doble: primero el Len(aArray) y luego que s贸lo se hace una operaci贸n de redimensionado del array al final del proceso.
Saludos
Posts: 1380
Joined: Fri Oct 14, 2005 01:28 PM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Sat Mar 17, 2012 04:29 PM

jm;
Si el array es de muchos registros, como tu sample, te sugiero usar FOR EACH (la explicaci贸n en Optimizacion IV).

Saludos

Resistencia - "Ciudad de las Esculturas"

Chaco - Argentina
Posts: 654
Joined: Mon May 29, 2006 03:14 PM
Re: Conseguir la maxima velocidad del EXE creado por Harbour
Posted: Sun Mar 18, 2012 10:39 AM
MarioG wrote:Si el array es de muchos registros, como tu sample, te sugiero usar FOR EACH (la explicaci贸n en Optimizacion IV).
S铆, mis array suelen ser "monstruosos".

He probado el m茅todo IV con ForNext, Aeval y ForEach y los resultados sobre un array de 10.000.000 de elementos son estos:
ForNext 5.7 seg.
Aeval 6.8 seg.
ForEach 3.1 seg. (casi la mitad del tiempo)

Aqui el ejemplo probado:
Code (fw): Select all Collapse
function main()
local nSegundos , x , n:=0 , nSum:=0 , aArray := array(10000000) , nLen := Len(aArray)
*---
nSegundos:=seconds()
for n:=1 to nLen
聽 聽aArray[n] := n
next
for n:=1 to nLen
聽 聽nSum += aArray[n]
next
nSegundos:=seconds()-nSegundos
? nSegundos
*---
nSegundos:=seconds()
aeval( aArray, {|a,n| aArray[n]:=n} )
aeval( aArray, {|a,n| nSum += a} )
nSegundos:=seconds()-nSegundos
? nSegundos
*---
nSegundos:=seconds()
for each x in aArray
聽 聽x := HB_EnumIndex()
next
for each x in aArray
聽 聽nSum += x
next
nSegundos:=seconds()-nSegundos
? nSegundos
*---
return nil
Mi abuelo dec铆a: Los aviones vuelan porque Dios quiere, y los helic贸pteros ni Dios sabe porque vuelan.

FWH 16.02, xHarbour 1.2.3, Harbour 3.2.0, WorkShop 4.5, AJ Make 0.30, Borlan BCC 7.00, VisualStudio 2013