nanosegundos a segundos java
¿System.nanoTime() es completamente inútil? (14)
Absolutamente no inútil. Los aficionados a la sincronización puntualizan correctamente el problema de núcleos múltiples, pero en las aplicaciones de palabras reales a menudo es radicalmente mejor que el actualTimeMillis ().
Al calcular las posiciones de los gráficos en las renovaciones de cuadros, nanoTime () conduce a MUCHO movimiento más suave en mi programa.
Y solo pruebo en máquinas multi-core.
Como se documenta en la publicación del blog Cuidado con System.nanoTime () en Java , en sistemas x86, System.nanoTime () de Java devuelve el valor del tiempo utilizando un contador específico de la CPU . Ahora considere el siguiente caso que uso para medir el tiempo de una llamada:
long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;
Ahora, en un sistema de núcleo múltiple, podría ser que después de medir el tiempo1, el hilo esté programado para un procesador diferente cuyo contador sea menor que el de la CPU anterior. Por lo tanto, podríamos obtener un valor en time2 que es menor que time1. Por lo tanto, obtendríamos un valor negativo en el tiempo. Arrepentidos.
Teniendo en cuenta este caso, ¿no es que System.nanotime es bastante inútil por el momento?
Sé que cambiar el tiempo del sistema no afecta el nanotiempo. Ese no es el problema que describo arriba. El problema es que cada CPU mantendrá un contador diferente desde que se activó. Este contador puede ser inferior en la segunda CPU en comparación con la primera CPU. Dado que el hilo puede ser programado por el sistema operativo a la segunda CPU después de obtener el tiempo1, el valor de timeSpent puede ser incorrecto e incluso negativo.
Además, System.currentTimeMillies()
cambia cuando cambia el reloj de su sistema, mientras que System.nanoTime()
no lo hace, por lo que este último es más seguro para medir duraciones.
Esa publicación es incorrecta, y nanoTime
es segura. Hay un comentario en la publicación que enlaza a una publicación del blog de David Holmes , un tipo de concurrencia en tiempo real en Sun. Dice:
System.nanoTime () se implementa utilizando QueryPerformanceCounter / QueryPerformanceFrequency API [...] El mecanismo predeterminado utilizado por QPC está determinado por la capa de abstracción de hardware (HAL) [...] Este valor predeterminado cambia no solo en el hardware sino también en todo el sistema operativo versiones. Por ejemplo, Windows XP Service Pack 2 cambió las cosas para usar el temporizador de administración de energía (PMTimer) en lugar del contador de marca de tiempo del procesador (TSC) debido a problemas con el TSC no sincronizado en diferentes procesadores en sistemas SMP, y debido a su frecuencia puede variar (y por lo tanto su relación con el tiempo transcurrido) en función de la configuración de administración de energía.
Entonces, en Windows, este fue un problema hasta WinXP SP2, pero no es ahora.
No puedo encontrar una parte II (o más) que trate sobre otras plataformas, pero ese artículo sí incluye una observación de que Linux se ha encontrado y ha resuelto el mismo problema de la misma manera, con un enlace a las preguntas frecuentes de clock_gettime (CLOCK_REALTIME) , que dice:
- ¿Clock_gettime (CLOCK_REALTIME) es consistente en todos los procesadores / núcleos? (¿El arco es importante? Por ejemplo, ppc, brazo, x86, amd64, sparc).
Debería o se considera con errores.
Sin embargo, en x86 / x86_64, es posible ver que los TSC de frecuencia variable o no sincronizados causan incoherencias de tiempo. 2.4 los núcleos realmente no tenían protección contra esto, y los primeros kernels 2.6 tampoco funcionaron bien aquí. A partir de 2.6.18 y más, la lógica para detectar esto es mejor y generalmente recurriremos a un código de acceso seguro.
ppc siempre tiene una base de tiempo sincronizada, por lo que no debería ser un problema.
Entonces, si el enlace de Holmes puede interpretarse como que implica que nanoTime
llama a clock_gettime(CLOCK_REALTIME)
, entonces es seguro a partir del núcleo 2.6.18 en x86, y siempre en PowerPC (porque IBM y Motorola, a diferencia de Intel, realmente saben cómo diseñar microprocesadores).
No hay mención de SPARC o Solaris, por desgracia. Y, por supuesto, no tenemos idea de lo que hacen las JVM de IBM. Pero las JVM de Sun en Windows y Linux modernos tienen este derecho.
EDITAR: Esta respuesta se basa en las fuentes que cita. Pero todavía me preocupa que en realidad podría estar completamente equivocado. Alguna información más actualizada sería realmente valiosa. Acabo de encontrar un enlace a un artículo nuevo de cuatro años sobre los relojes de Linux que podría ser útil.
Esto no parece ser un problema en un Core 2 Duo con Windows XP y JRE 1.5.0_06.
En una prueba con tres hilos, no veo que System.nanoTime () vaya hacia atrás. Los procesadores están ocupados y los hilos van a dormir ocasionalmente para provocar el movimiento de los hilos.
[EDIT] Supongo que solo ocurre en procesadores físicamente separados, es decir, que los contadores están sincronizados para múltiples núcleos en el mismo dado.
He visto un tiempo transcurrido negativo informado al usar System.nanoTime (). Para ser claros, el código en cuestión es:
long startNanos = System.nanoTime();
Object returnValue = joinPoint.proceed();
long elapsedNanos = System.nanoTime() - startNanos;
y la variable ''elapsedNanos'' tenía un valor negativo. (Estoy seguro de que la llamada intermedia tomó menos de 293 años también, que es el punto de desbordamiento para los nanos almacenados en longs :)
Esto ocurrió utilizando un hardware IBM v1.5 JRE de 64 bits en IBM P690 (multi-core) que ejecuta AIX. Solo he visto este error una vez, por lo que parece extremadamente raro. No sé la causa: ¿es un problema específico del hardware, un defecto de JVM? No lo sé. Tampoco sé las implicaciones para la precisión de nanoTime () en general.
Para responder a la pregunta original, no creo que nanoTime sea inútil, proporciona un tiempo de menos de milisegundos, pero existe un riesgo real (no solo teórico) de que sea impreciso, lo cual debe tener en cuenta.
Hice un poco de búsqueda y descubrí que si uno es pedante, entonces sí puede considerarse inútil ... en situaciones particulares ... depende de cuán apremiantes sean sus requisitos ...
Vea esta cita del sitio de Java Sun:
El reloj en tiempo real y System.nanoTime () se basan en la misma llamada al sistema y, por lo tanto, en el mismo reloj.
Con Java RTS, todas las API basadas en tiempo (por ejemplo, temporizadores, subprocesos periódicos, monitoreo de fecha límite, etc.) se basan en el temporizador de alta resolución. Y, junto con las prioridades en tiempo real, pueden garantizar que el código apropiado se ejecutará en el momento adecuado para las restricciones en tiempo real. Por el contrario, las API Java SE comunes ofrecen solo unos pocos métodos capaces de manejar tiempos de alta resolución, sin garantía de ejecución en un momento dado. El uso de System.nanoTime () entre varios puntos en el código para realizar mediciones de tiempo transcurrido siempre debe ser preciso.
Java también tiene una advertencia para el método nanoTime () :
Este método solo se puede usar para medir el tiempo transcurrido y no está relacionado con ninguna otra noción de sistema o tiempo de reloj de pared. El valor devuelto representa nanosegundos desde algún tiempo fijo pero arbitrario (tal vez en el futuro, por lo que los valores pueden ser negativos). Este método proporciona una precisión de nanosegundos, pero no necesariamente una precisión de nanosegundos. No se hacen garantías sobre la frecuencia con la que cambian los valores. Las diferencias en las llamadas sucesivas que abarcan más de aproximadamente 292,3 años (2 63 nanosegundos) no calcularán con precisión el tiempo transcurrido debido al desbordamiento numérico.
Parecería que la única conclusión que se puede extraer es que nanoTime () no se puede confiar como un valor preciso. Como tal, si no necesita medir los tiempos que están separados por nanosegundos, entonces este método es lo suficientemente bueno incluso si el valor devuelto resultante es negativo. Sin embargo, si necesita una mayor precisión, parecen recomendarle que use JAVA RTS.
Entonces para responder a su pregunta ... no nanoTime () no es inútil ... simplemente no es el método más prudente para usar en cada situación.
Java es una plataforma cruzada, y nanoTime depende de la plataforma. Si usa Java, cuando no use nanoTime. Encontré errores reales en diferentes implementaciones de jvm con esta función.
La documentación de Java 5 también recomienda el uso de este método para el mismo propósito.
Este método solo se puede usar para medir el tiempo transcurrido y no está relacionado con ninguna otra noción de sistema o tiempo de reloj de pared.
Linux corrige las discrepancias entre CPU, pero Windows no lo hace. Sugiero que suponga que System.nanoTime () solo tiene una precisión de alrededor de 1 micro segundo. Una forma simple de obtener un tiempo más largo es llamar a foo () 1000 o más veces y dividir el tiempo entre 1000.
Me estoy vinculando a lo que esencialmente es la misma discusión en la que Peter Lawrey está brindando una buena respuesta. ¿Por qué obtengo un tiempo transcurrido negativo usando System.nanoTime ()?
Mucha gente mencionó que en Java System.nanoTime () podría devolver el tiempo negativo. Me disculpo por repetir lo que otras personas ya dijeron.
- nanoTime () no es un reloj sino un contador de ciclos de CPU.
- El valor de retorno se divide por frecuencia para que parezca tiempo.
- La frecuencia de la CPU puede fluctuar.
- Cuando el hilo está programado en otra CPU, existe la posibilidad de obtener nanoTime () que da como resultado una diferencia negativa. Eso es lógico. Los contadores en las CPU no están sincronizados.
- En muchos casos, podría obtener resultados bastante engañosos, pero no podría decirlo porque delta no es negativo. Piénsalo.
- (sin confirmar) Creo que puede obtener un resultado negativo incluso en la misma CPU si se reordenan las instrucciones. Para evitar eso, tendría que invocar una barrera de memoria serializando sus instrucciones.
Sería genial si System.nanoTime () devolviera coreID donde se ejecutó.
No es necesario debatir, solo usa la fuente. Aquí, SE 6 para Linux, saque sus propias conclusiones:
jlong os::javaTimeMillis() {
timeval time;
int status = gettimeofday(&time, NULL);
assert(status != -1, "linux error");
return jlong(time.tv_sec) * 1000 + jlong(time.tv_usec / 1000);
}
jlong os::javaTimeNanos() {
if (Linux::supports_monotonic_clock()) {
struct timespec tp;
int status = Linux::clock_gettime(CLOCK_MONOTONIC, &tp);
assert(status == 0, "gettime error");
jlong result = jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp.tv_nsec);
return result;
} else {
timeval time;
int status = gettimeofday(&time, NULL);
assert(status != -1, "linux error");
jlong usecs = jlong(time.tv_sec) * (1000 * 1000) + jlong(time.tv_usec);
return 1000 * usecs;
}
}
No, no lo es ... Depende de su CPU, compruebe el Temporizador de eventos de alta precisión para ver cómo y por qué las cosas se tratan de manera diferente según la CPU.
Básicamente, lea la fuente de su Java y verifique qué hace su versión con la función, y si funciona en contra de la CPU, la ejecutará.
IBM incluso sugiere que lo use para la evaluación comparativa del rendimiento (una publicación de 2008, pero actualizada).
nanoTime
es extremadamente inseguro para el tiempo. Lo probé en mis algoritmos básicos de prueba de primalidad y me dio respuestas que estaban literalmente separadas por un segundo para la misma entrada. No uses ese método ridículo. Necesito algo que sea más preciso y preciso que obtener el tiempo millis, pero no tan malo como nanoTime
.
Descargo de responsabilidad: soy el desarrollador de esta biblioteca
Puede que te guste esto mejor:
http://juliusdavies.ca/nanotime/
Pero copia un archivo DLL o Unix .so (objeto compartido) en el directorio de inicio del usuario actual para que pueda llamar a JNI.
Algunos antecedentes están en mi sitio en:
http://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html