Jump to content


Photo

[MULTILENGUAJE] GetTickNow


  • Please log in to reply
20 replies to this topic

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 09 January 2017 - 08:06 AM

La API de Winsows GetTickCount nos devuelve el número de microsegundos desde que se inició el sistema hasta 49.7 días. Este intervalo suele ser suficientemente amplio como para abarcar cualquier medida de tiempo en una aplicación. Pero contiene dos cosas que no son apetecibles:

1. La cuenta no comienza desde cero sino desde el inicio del sistema.

2. Si llegamos al valor de ‭4294967295‬ microsegundos ($FFFFFFFF) que representan los 49.7 días, obtendermos un acarreo que hay que tener en cuenta.

 
En un reciente proyecto multimedia, en el que la medida temporal era determinante hasta la precisión del microsegundo, solucioné los dos inconvenientes con una simple función que me permite poner a cero la cuenta de microsegundos teniendo en cuenta el acarreo y, además, me devuelve el número de microsegundos transcurridos desde la puesta a cero.
 
Esta es la versión C:


cpp
  1. DWORD GetTickNow(BOOL Start = FALSE)
  2. {
  3. static DWORD Old;
  4. if(Start) Old = GetTickCount();
  5.  
  6. if(GetTickCount() < Old)
  7. return GetTickCount() - Old + 0xFFFFFFFF;
  8. return GetTickCount() - Old;
  9. }

Y esta es la versión delphi:


delphi
  1. function GetTickNow(Start: BOOL = FALSE): DWORD;
  2. const
  3. {$J+}
  4. Old: DWORD = 0;
  5. {$J-}
  6. begin
  7. if Start then Old:= GetTickCount();
  8.  
  9. if GetTickCount() < Old then
  10. Result:= GetTickCount() - Old + $FFFFFFFF
  11. else Result:= GetTickCount() - Old;
  12. end;

De esta forma, aunque el límite siguen siendo 49.7 días, lo es desde la puesta a cero. Si necesitáramos un intervalo mayor, podemos usar como valor de vuelta un QWORD (unsigned int64).

El uso es bien simple. Para poner a cero la cuenta:


delphi
  1. GetTickNow(true);

 
Para obtener el tiempo desde la puesta a cero:


delphi
  1. // Delphi
  2. T:= GetTickNow;
  3. // C/C++
  4. T = GetTickNow();

Espero que sea de utilidad.


Saludos.


  • 2

#2 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 09 January 2017 - 11:12 AM

Hola Carlos,

Hay un detalle que no logro entender del todo bien en la operatoria... Veo que invocas a GetTickCount unas 2 o 3 veces... ¿Es realmente necesario? ¿No podría directamente usarse una variable y usarla para los cálculos?

 

Por otra parte, recuerdo que Ian Marteens en su sitio web de Delphi recomendaba no usar GetTickCount y en su lugar emplear QueryPerfomanceFrecuency y QueryPerfomanceCounter para tener precisión. Aquí el artículo en cuestión. Desconozco si al día de hoy sigue siendo igual de válido este punto, o si es que GetTickCount habrá sido mejorada. La ayuda (MSDN) sugiere otros timers para mejorar precisión asi que es posible que no haya cambiado mucho.

 

Del enlace que pusiste a la API, ahí mismo se sugiere otra alternativa a GetTickCount para evitar el problemas del acarreo tras los 49.7 días: GetTickCount64. Tengo que admitir que es la primera vez que conozco esta versión de la API, y ni recordaba de que GetTickCount tuviera ese problema de los 49.7 días. Yo recordaba de las palabras de Ian que simplemente GetTickCount no es precisa.

 

Me pregunto yo, ¿Porqué no directamente usas esta versión de la API? ¿O hay alguna restricción o limitación del tipo técnica a considerar? La MSDN dice que GetTickCount64 es soportada desde W. Vista. No se si es por eso, o hay algo más.

Como yo ignoro muchos aspectos de las APIs y tu eres el experto imagino que debes tener tus razones.

 

Saludos,


  • 0

#3 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 09 January 2017 - 12:46 PM

Hola Marcelo.

 

Uso llamadas repetidas a GetTickCount para no perder el acarreo que pudiera producirse en el transcurso de la función y devolver un tiempo exacto.

 

Tienes mucha razón en hacer la observación de APIs alternativas más precisas o que minimizan el acarreo. Elegí usar GetTickCount porque la precisión de unos pocos milisegundos (~10 a 16ms) me bastaba y no quería usar aritmética de 64bits en una App de 32bits que no me aportaba más precisión a la necesitada. Lo que si me resultaba molesto era el inicio de cuenta y el acarreo. Por eso implementé GetTickNow.

 

Las alternativas propuestas por M$ son correctas. Si te fijas, ellos mismos proponen QueryPerformanceFrequency y QueryPerformanceCounter además de GetTickCount64. Esta última tiene la misma resolución que su versión 32bits (~10 ms) pero con un acarreo enormemente mayor.

 

La elección depende de la precisión realmente necesitada. En mi caso se trataba de sincronizar fotogramas en relación al tiempo total transcurrido de video. Teniendo en cuenta que la frecuencia más alta de 60fps corresponden a un lapso de 16 ms, la precisión de GetTickCount era suficiente.

 

 

Saludos.


  • 2

#4 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 09 January 2017 - 01:04 PM

Muchas gracias por la aclaración amigo.

Vaya, eso de que aún usando GetTickCount64 tenemos el límite de 49 años pero con más acarreo es una sorpresa. No había visto que más abajo estaba la nota en la doc. :(

Con razón sugiere que se usen las API QueryPerfomance.

 

Sabía que habría alguna motivación y razón de tu parte para no ir por más precisión. Ahora entiendo.

Yo me he acostumbrado a seguir el consejo de Ian Marteens cuando lo necesito asi que me resultó "raro" encontrarme con tu propuesta.

 

Saludos,


  • 0

#5 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 09 January 2017 - 01:17 PM

El tema es que no hay un método mejor o peor. El bueno es el que te hace falta en un momento dado y te complica menos la vida. GetTickCount suele ser suficiente para casi todos los casos y su aritmética es simple. Es un caso parecido al uso de float, double u otros tipos más precisos para aritmética de punto flotante.

 

Al final siempre va a estar el límite del tamaño en bits del tipo usado, que generará un acarreo. El tema es conocerlo y ajustarse a la necesidad real, como tú has dicho varias veces.  :) 

 

 

Saludos.


  • 0

#6 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 09 January 2017 - 02:19 PM

El tema es que no hay un método mejor o peor. El bueno es el que te hace falta en un momento dado y te complica menos la vida. GetTickCount suele ser suficiente para casi todos los casos y su aritmética es simple. Es un caso parecido al uso de float, double u otros tipos más precisos para aritmética de punto flotante.
 
Al final siempre va a estar el límite del tamaño en bits del tipo usado, que generará un acarreo. El tema es conocerlo y ajustarse a la necesidad real, como tú has dicho varias veces.  :) 
 
 
Saludos.


Es como la eterna discusión de que motor de base de datos usar.... 

 

Como siempre yo digo depende, depende, depende

 

Quiero decir, la mejor base de datos es la que hace lo que necesitas, ni mas ni menos.  (h)

 

Saludos


  • 0

#7 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 09 January 2017 - 02:53 PM

El tema es que no hay un método mejor o peor. El bueno es el que te hace falta en un momento dado y te complica menos la vida. GetTickCount suele ser suficiente para casi todos los casos y su aritmética es simple. Es un caso parecido al uso de float, double u otros tipos más precisos para aritmética de punto flotante.

 

Al final siempre va a estar el límite del tamaño en bits del tipo usado, que generará un acarreo. El tema es conocerlo y ajustarse a la necesidad real, como tú has dicho varias veces.  :) 

 

 

Saludos.

 

A lo que apunto es que de que me sirve la versión 64 si al final tenemos el mismo período de tiempo (49 días) y se ve afectado por lo haga QueryUnbiasedInterruptTime. No supone gran cambio realmente.

Lo de compararlo con flotantes no es tan exacto en realidad. Pasar de single a double es un gran cambio, y lo mismo a extended. La precisión que nos da esos decimales y el rango numérico crece de manera exponencial. Obviamente que estos tipos tienen sus límites, su precisión a estos decimales, y que la aritemética de punto flotante requiere de ciertas consideraciones técnicas como por ejemplo que no todos los números son representables (sino aproximados) y hay que trabajar con márgenes de error de tolerancia absoluta y/o relativa.

 

En el caso de las GetTickCount, si ambas tienen la misma resolución entre 10 y 16ms y al final de una u otra ambas sufren el defecto de los 49 días, ¿para que la doc de GetTickCount sugiere ir por GetTickCount64?

 

¿O es que yo estoy entendiendo mal lo que dice el apartado Note de la doc de GetTickCount64?

 

Ian en su artículo aclara que se le puede dar uso a GetTickCount sin problemas para varias situaciones, claro está que para ciertas acciones un tanto más críticas o que requieran de una precisión fina hay que buscar algo más elaborado.

Eso no lo niego.

 

Saludos,


  • 0

#8 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 09 January 2017 - 04:55 PM

A lo que apunto es que de que me sirve la versión 64 si al final tenemos el mismo período de tiempo (49 días) y se ve afectado por lo haga QueryUnbiasedInterruptTime. No supone gran cambio realmente.
Lo de compararlo con flotantes no es tan exacto en realidad. Pasar de single a double es un gran cambio, y lo mismo a extended. La precisión que nos da esos decimales y el rango numérico crece de manera exponencial. Obviamente que estos tipos tienen sus límites, su precisión a estos decimales, y que la aritemética de punto flotante requiere de ciertas consideraciones técnicas como por ejemplo que no todos los números son representables (sino aproximados) y hay que trabajar con márgenes de error de tolerancia absoluta y/o relativa.
 
En el caso de las GetTickCount, si ambas tienen la misma resolución entre 10 y 16ms y al final de una u otra ambas sufren el defecto de los 49 días, ¿para que la doc de GetTickCount sugiere ir por GetTickCount64?
 
¿O es que yo estoy entendiendo mal lo que dice el apartado Note de la doc de GetTickCount64?
 
Ian en su artículo aclara que se le puede dar uso a GetTickCount sin problemas para varias situaciones, claro está que para ciertas acciones un tanto más críticas o que requieran de una precisión fina hay que buscar algo más elaborado.
Eso no lo niego.
 
Saludos,

 
Cuando hago la comparación con tipos de coma flotante me refiero a la precisión y no al acarreo, comparando GetTickCount con QueryPerformanceFrequency y QueryPerformanceCounter. No tengo claro que GetTickCount64 tenga el límite en 49 días. Si calculamos los días que da como máximo un DWORD ($FFFF FFFF) son 49,71026961805556 días. Un QWORD nos daría 584942421,57 años. En cualquier caso se puede hacer una función que devuelva un QWORD a partir de GetTickCount controlando el acarreo, la pregunta es si tiene sentido...

 

La precisión en ms de GetTickCount y GetTickCount64 es idéntica por lo que no tiene mucho sentido usar la versión 64 a no ser que pensemos en tiempos mayores de 49 días y asumamos que el acarreo de GetTickCount64 es en 584.942.421 años. ¿Alguien se anima a comprobar el resultado de la cuenta de GetTickCount64 pasados 50 días con el PC en marcha? Así salimos de dudas :D :D :D.

 

 

Saludos.


  • 0

#9 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 09 January 2017 - 05:40 PM

Si, entiendo el punto. Lo que me llama la atención es lo que leo en la documentación de la API GetTickCount64:

 

 

To obtain the time the system has spent in the working state since it was started, use the QueryUnbiasedInterruptTime function.

 

Note  The QueryUnbiasedInterruptTime function produces different results on debug ("checked") builds of Windows, because the interrupt-time count and tick count are advanced by approximately 49 days. This helps to identify bugs that might not occur until the system has been running for a long time. The checked build is available to MSDN subscribers through the Microsoft Developer Network (MSDN) Web site.

 

Ahí mismo dice que si desea obtener el timpo del sistema desde que se ha iniciado que se use QueryUnbiasedInterruptTime.

Pero en la nota misma dice que sufre el mismo "problema" de los 49 días.

 

Al final Moco$oft nos dice que GetTickCount64 soluciona el dilema de los 49 días, y se la puede usar en lugar de GetTickCount. Pero nos recomienda otra, que tiene el mismo problema.

¿Que debo pensar? ¿Usamos GetTickCount64 o que? ¿Cuál aconsejan y cual no? :o

 

Saludos,


  • 0

#10 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 09 January 2017 - 06:46 PM

Si, entiendo el punto. Lo que me llama la atención es lo que leo en la documentación de la API GetTickCount64:

 

 

Ahí mismo dice que si desea obtener el timpo del sistema desde que se ha iniciado que se use QueryUnbiasedInterruptTime.

Pero en la nota misma dice que sufre el mismo "problema" de los 49 días.

 

Al final Moco$oft nos dice que GetTickCount64 soluciona el dilema de los 49 días, y se la puede usar en lugar de GetTickCount. Pero nos recomienda otra, que tiene el mismo problema.

¿Que debo pensar? ¿Usamos GetTickCount64 o que? ¿Cuál aconsejan y cual no? :o

 

Saludos,

 

M$ es muy escueto en mucha información y en ocasiones difícil de entender. Estoy acostumbrado a realizar pruebas y encontrar que son dispares a la información dada. En este caso no me importa mucho puesto que ningún vídeo durará 50 días, pero si sería interesante saber el verdadero límite y me parece que o se hace la prueba de los 50 días o no lo sabremos con exactitud.

 

 

Saludos.


  • 0

#11 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 09 January 2017 - 07:01 PM

M$ es muy escueto en mucha información y en ocasiones difícil de entender. Estoy acostumbrado a realizar pruebas y encontrar que son dispares a la información dada. En este caso no me importa mucho puesto que ningún vídeo durará 50 días, pero si sería interesante saber el verdadero límite y me parece que o se hace la prueba de los 50 días o no lo sabremos con exactitud.

 

 

Saludos.

 

Lograr hacer esa prueba va a a ser duro... De existir un video que dure 50 días ocuparía varios Teras, y no creo que tengamos nosotros los de a pie algo de esa capacidad.

Es algo impracticable para nosotros.

 

Es bastante probable que sea lo que tu dices amigo. Con GetTickCount incluso aún siendo de 49 días es bastante...  y ni pensar en la cifra que le calculaste que nos permite la versión 64.

 

Esas cosas de la documentación que nos dejan ese sabor a que se lian... Al menos hay doc, y no como otras APIs que ni documentan *-)

 

Saludos,


  • 0

#12 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 09 January 2017 - 07:19 PM

Pues esta es la aplicación que nos va a salvar  :D :D :D
826334149e5548a2b5e589a084afd97bo.gif

Saludos.

Attached Files


  • 0

#13 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 09 January 2017 - 08:02 PM

¿No tendrás alguna máquina del tiempo que nos lleve 49 días al futuro? *-)  :D

 

Si alguien tiene una máquina miedo vieja a la que no tiene drama en dejarla encendida 50 días, bajo un iceberg que la mantenga fria, que haga la prueba. Salta, Argentina está descartado... nos están cortando la luz muy seguido 8o| y está más caliente que el infierno  :@ 

 

Saludos,


  • 0

#14 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 10 January 2017 - 04:42 AM

Es bastante probable que sea lo que tu dices amigo. Con GetTickCount incluso aún siendo de 49 días es bastante...  y ni pensar en la cifra que le calculaste que nos permite la versión 64.

 

Simplemente creo que hicieron un copia-pega de la nota sin saber muy bien lo que hacían. ^o|

 

 

Si alguien tiene una máquina miedo vieja a la que no tiene drama en dejarla encendida 50 días, bajo un iceberg que la mantenga fria, que haga la prueba. Salta, Argentina está descartado... nos están cortando la luz muy seguido 8o| y está más caliente que el infierno  :@

 
No seamos dramáticos, en realidad basta con no reiniciar el PC durante 50 días, basta con hibernarlo tras el trabajo. La cuenta sigue funcionando. :)


Saludos.


  • 0

#15 sir.dev.a.lot

sir.dev.a.lot

    Advanced Member

  • Miembros
  • PipPipPip
  • 545 posts
  • Location127.0.0.1

Posted 11 January 2017 - 03:26 PM

con M$ Windows bastara .... en menos de 15 Dias se reiniciara  : , ya sea por Actualizaciones o por cualquier programa tercero que se instale....

 

El sistema Operativo ayudara.... ;)

 

Saludos!


  • 0

#16 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 03 February 2017 - 07:16 AM

¿No tendrás alguna máquina del tiempo que nos lleve 49 días al futuro? *-)  :D


Problema resuelto. Aproveché un PC del trabajo que no se apaga nunca y coloqué un programa contador similar al mostrado en este hilo al que añadí una alerta de acarreo. Los contadores llegaron al la cuenta 0000-0000-FFFF-FFFF y se produjo acarreo en ambas APIs. El resultado no es el que esperaba, de modo que GetTickCount64 no lleva la cuenta en un int64 sino en un int32.

Tras esta prueba no que que narices pensaban los de Microsoft cuando escribieron la API GetTickCount64
  :|
 
 
Saludos.


  • 0

#17 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 03 February 2017 - 07:31 AM

Problema resuelto. Aproveché un PC del trabajo que no se apaga nunca y coloqué un programa contador similar al mostrado en este hilo al que añadí una alerta de acarreo. Los contadores llegaron al la cuenta 0000-0000-FFFF-FFFF y se produjo acarreo en ambas APIs. El resultado no es el que esperaba, de modo que GetTickCount64 no lleva la cuenta en un int64 sino en un int32.

Tras esta prueba no que que narices pensaban los de Microsoft cuando escribieron la API GetTickCount64  :|
 
 
Saludos.

 

¿Entonces yo estaba en lo cierto cuando decía que al final la versión 64 tenía el mismo período de tiempo?

Resulta ser que da lo mismo entonces usar una u otra. ¡Moco$oft haciendo honor otra vez a su apodo!

 

Salvo.... que te hayas equivocado y usarle DWORD y no QWORD cuando llamaste a la versión 64, o que por error en ambos contadores llamaste al de 32. Pero como se que eres cuidadoso, es muy poco probable esta pifia.

 

Saludos,


  • 0

#18 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 03 February 2017 - 09:37 AM

¿Entonces yo estaba en lo cierto cuando decía que al final la versión 64 tenía el mismo período de tiempo?

Resulta ser que da lo mismo entonces usar una u otra. ¡Moco$oft haciendo honor otra vez a su apodo!

 

Salvo.... que te hayas equivocado y usarle DWORD y no QWORD cuando llamaste a la versión 64, o que por error en ambos contadores llamaste al de 32. Pero como se que eres cuidadoso, es muy poco probable esta pifia.

 

Saludos,

 

Estabas en lo cierto. Esa nota de M$ no era un simple corta-pega sino realidad.

 

Saludos.


  • 0

#19 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 04 February 2017 - 12:24 PM

Me precipité al publicar el resultado. El PC donde puse el contador tuvo un reinicio que no advertí al estar cercano a cumplir la fecha de los 49 días lo que interpreté como un fin de cuenta sin acarreo.
 
Introduje una modificación en el código para que mostrase la palabra ACARREO si este ocurriese, de forma que tras un reinicio no aparecería la palabra. Coloqué el contador en otro PC cercano a cumplir la fecha pero no hizo falta esperar pues ya había pasado de los 49 días.
 
GetTickCount64 sobrepasa el límite de un DWORD sigue contando como era de esperar, así que M$ en su explicación metió la gamba y la API trabaja como se esperaba. De todas formas seguiré mirando el contador una temporada más mientras no se reinicie el PC
69f4c73ce58698ada99e4f2469029888o.gif

 

 

Saludos.


  • 0

#20 Delphius

Delphius

    Advanced Member

  • Administrador
  • 6295 posts
  • LocationArgentina

Posted 04 February 2017 - 12:32 PM

Me precipité al publicar el resultado. El PC donde puse el contador tuvo un reinicio que no advertí al estar cercano a cumplir la fecha de los 49 días lo que interpreté como un fin de cuenta sin acarreo.
 
Introduje una modificación en el código para que mostrase la palabra ACARREO si este ocurriese, de forma que tras un reinicio no aparecería la palabra. Coloqué el contador en otro PC cercano a cumplir la fecha pero no hizo falta esperar pues ya había pasado de los 49 días.
 
GetTickCount64 sobrepasa el límite de un DWORD sigue contando como era de esperar, así que M$ en su explicación metió la gamba y la API trabaja como se esperaba. De todas formas seguiré mirando el contador una temporada más mientras no se reinicie el PC
69f4c73ce58698ada99e4f2469029888o.gif

 

 

Saludos.

 

De todas formas Moco$oft debería hacer la documentación como la gente. Porque no se entiende muy mucho que digamos...

 

Saludos,


  • 0




IP.Board spam blocked by CleanTalk.