System.nanoTime ()이 완전히 쓸모 없습니까?
x86 시스템 에서 블로그 게시물 Java의 System.nanoTime ()주의 x86 시스템 에서 설명하는 것처럼 Java의 System.nanoTime ()은 CPU 특정 카운터를 사용하여 시간 값을 반환합니다 . 이제 통화 시간을 측정하는 데 사용하는 다음 사례를 고려하십시오.
long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;
이제 멀티 코어 시스템에서 time1을 측정 한 후 스레드가 이전 CPU의 카운터보다 적은 다른 프로세서로 스레드가 예약 될 수 있습니다. 따라서 time1보다 작은 time2의 값을 얻을 수 있습니다. 따라서 timeSpent에서 음수 값을 얻습니다.
이 경우를 고려할 때 System.nanotime이 지금은 거의 쓸모가 없습니까?
시스템 시간을 변경해도 나노 시간에는 영향을 미치지 않습니다. 그것은 위에서 설명한 문제가 아닙니다. 문제는 각 CPU가 켜진 이후 다른 카운터를 유지한다는 것입니다. 이 카운터는 첫 번째 CPU에 비해 두 번째 CPU에서 더 낮을 수 있습니다. 스레드는 time1을 얻은 후 OS에서 두 번째 CPU로 스케줄 할 수 있으므로 timeSpent 값이 올바르지 않고 음수 일 수도 있습니다.
이 답변은 2011 년 당시 운영 체제에서 실행 된 시간의 Sun JDK가 실제로 한 일의 관점에서 2011 년에 작성되었습니다. 그것은 오래 전이었습니다! leventov의 답변 은보다 최신의 관점을 제공합니다.
그 게시물은 잘못되어 nanoTime
안전합니다. Sun의 실시간 및 동시성 사용자 인 David Holmes의 블로그 게시물에 링크되는 게시물에 대한 의견이 있습니다 . 그것은 말한다 :
System.nanoTime ()은 QueryPerformanceCounter / QueryPerformanceFrequency API를 사용하여 구현됩니다. [...] QPC에서 사용하는 기본 메커니즘은 하드웨어 추상화 계층 (HAL)에 의해 결정됩니다. [...]이 기본값은 하드웨어뿐만 아니라 OS에서도 변경됩니다. 버전. 예를 들어, Windows XP 서비스 팩 2는 SMP 시스템의 다른 프로세서에서 TSC가 동기화되지 않는 문제와 주파수로 인해 TSC (프로세서 타임 스탬프 카운터)가 아닌 전원 관리 타이머 (PMTimer)를 사용하도록 변경했습니다. 전원 관리 설정에 따라 달라질 수 있습니다 (따라서 경과 시간과의 관계).
그래서, Windows에서,이 이었다 WINXP SP2까지 문제가 있지만 지금은 아니다.
다른 플랫폼에 대해 이야기하는 II 부 (또는 그 이상)를 찾을 수 없지만이 기사에는 Linux가 같은 방식으로 동일한 문제를 발견하고 해결했다는 언급이 포함되어 있습니다. clock_gettime (CLOCK_REALTIME)에 대한 FAQ 링크 라고 말합니다.
- clock_gettime (CLOCK_REALTIME)이 모든 프로세서 / 코어에서 일관성이 있습니까? (아키 문제가 있습니까? 예 : ppc, arm, x86, amd64, sparc).
그것은 해야 되거나 버그 간주.
그러나 x86 / x86_64에서는 동기화되지 않거나 가변 주파수 TSC로 인해 시간 불일치가 발생할 수 있습니다. 2.4 커널은 실제로 이것에 대한 보호 기능이 없었으며 초기 2.6 커널은 여기서도 잘하지 못했습니다. 2.6.18부터는 이것을 감지하는 논리가 더 좋으며 일반적으로 안전한 클럭 소스로 돌아갑니다.
ppc에는 항상 동기화 된 타임베이스가 있으므로 문제가되지 않습니다.
따라서 Holmes의 링크가 해당 nanoTime
호출 을 암시하는 것으로 읽을 수 있다면 clock_gettime(CLOCK_REALTIME)
x86의 커널 2.6.18과 항상 PowerPC에서 안전합니다 (Intel과 달리 IBM과 Motorola는 실제로 마이크로 프로세서를 설계하는 방법을 알고 있기 때문에).
슬프게도 SPARC 또는 Solaris에 대한 언급은 없습니다. 물론 IBM JVM이 무엇을하는지 전혀 모릅니다. 그러나 최신 Windows 및 Linux의 Sun JVM이이 권리를 얻습니다.
편집 :이 답변은 인용 소스를 기반으로합니다. 그러나 나는 그것이 실제로 완전히 잘못되었을 수도 있다고 여전히 걱정합니다. 좀 더 최신 정보는 정말 귀중 할 것입니다. 방금 유용한 Linux 시계에 관한 4 년 간의 최신 기사 링크를 보았습니다 .
나는 약간의 검색을했는데 하나가 현혹 적이라면 예, 쓸모없는 것으로 간주 될 수 있습니다 ... 특정 상황에서 ... 필요한 시간이 얼마나 민감한 지에 달려 있습니다 ...
Java Sun 사이트 에서이 인용문 을 확인하십시오 .
실시간 클록과 System.nanoTime ()은 모두 동일한 시스템 호출을 기반으로하므로 동일한 클록을 기반으로합니다.
Java RTS를 사용하면 모든 시간 기반 API (예 : 타이머, 정기 스레드, 데드 라인 모니터링 등)가 고해상도 타이머를 기반으로합니다. 또한 실시간 우선 순위와 함께 실시간 제약 조건에 적합한 코드가 적시에 실행되도록 할 수 있습니다. 대조적으로, 일반 Java SE API는 특정 시간에 실행을 보장하지 않고 고해상도 시간을 처리 할 수있는 몇 가지 메소드 만 제공합니다. 경과 시간 측정을 수행하기 위해 코드의 여러 지점간에 System.nanoTime ()을 사용하면 항상 정확해야합니다.
Java는 또한 nanoTime () 메소드에 대한주의 사항이 있습니다 .
이 방법은 경과 시간을 측정하는 데만 사용할 수 있으며 다른 시스템 또는 벽시계 시간 개념과 관련이 없습니다. 반환 된 값은 고정되었지만 임의의 시간 (나중에 값이 음수 일 수 있음) 이후 나노초를 나타냅니다. 이 방법은 나노초 정밀도를 제공하지만 반드시 나노초 정확도는 아닙니다. 값이 얼마나 자주 변경되는지는 보증하지 않습니다. 약 292.3 년 (2 63 나노초)을 초과하는 연속 호출의 차이는 숫자 오버플로로 인해 경과 시간을 정확하게 계산하지 않습니다.
그릴 수있는 유일한 결론은 nanoTime ()을 정확한 값으로 신뢰할 수 없다는 것입니다. 따라서, 단지 나노초 간격의 시간을 측정 할 필요가 없으면 결과 리턴 값이 음수 인 경우에도이 방법으로 충분합니다. 그러나 더 높은 정밀도가 필요한 경우 JAVA RTS를 사용하는 것이 좋습니다.
따라서 귀하의 질문에 대답하기 위해 ... no nanoTime ()은 쓸모가 없습니다 .... 모든 상황에서 사용하는 가장 신중한 방법은 아닙니다.
토론 할 필요없이 소스 만 사용하십시오. 다음은 Linux 용 SE 6입니다. 자신 만의 결론을 내립니다.
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;
}
}
Java 7부터는 System.nanoTime()
JDK 사양에 의해 안전합니다. System.nanoTime()
Javadoc 은 JVM 내에서 (즉, 모든 스레드에서) 관찰 된 모든 호출이 단조롭다는 것을 분명히합니다.
The value returned represents nanoseconds since some fixed but arbitrary origin time (perhaps in the future, so values may be negative). The same origin is used by all invocations of this method in an instance of a Java virtual machine; other virtual machine instances are likely to use a different origin.
JVM/JDK implementation is responsible for ironing out the inconsistencies that could be observed when underlying OS utilities are called (e. g. those mentioned in Tom Anderson's answer).
The majority of other old answers to this question (written in 2009–2012) express FUD that was probably relevant for Java 5 or Java 6 but is no longer relevant for modern versions of Java.
It's worth mentioning, however, that despite JDK guarantees nanoTime()
's safety, there have been several bugs in OpenJDK making it to not uphold this guarantee on certain platforms or under certain circumstances (e. g. JDK-8040140, JDK-8184271). There are no open (known) bugs in OpenJDK wrt nanoTime()
at the moment, but a discovery of a new such bug or a regression in a newer release of OpenJDK shouldn't shock anybody.
With that in mind, code that uses nanoTime()
for timed blocking, interval waiting, timeouts, etc. should preferably treat negative time differences (timeouts) as zeros rather than throw exceptions. This practice is also preferable because it is consistent with the behaviour of all timed wait methods in all classes in java.util.concurrent.*
, for example Semaphore.tryAcquire()
, Lock.tryLock()
, BlockingQueue.poll()
, etc.
Nonetheless, nanoTime()
should still be preferred for implementing timed blocking, interval waiting, timeouts, etc. to currentTimeMillis()
because the latter is a subject to the "time going backward" phenomenon (e. g. due to server time correction), i. e. currentTimeMillis()
is not suitable for measuring time intervals at all. See this answer for more information.
Instead of using nanoTime()
for code execution time measurements directly, specialized benchmarking frameworks and profilers should preferably be used, for example JMH and async-profiler in wall-clock profiling mode.
Disclaimer: I am the developer of this library
You might like this better:
http://juliusdavies.ca/nanotime/
But it copies a DLL or Unix .so (shared object) file into the current user's home directory so that it can call JNI.
Some background information is on my site at:
http://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html
Linux corrects for discrepancies between CPUs, but Windows does not. I suggest you assume System.nanoTime() is only accurate to around 1 micro-second. A simple way to get a longer timing is to call foo() 1000 or more times and divide the time by 1000.
Absolutely not useless. Timing aficionados correctly point out the multi-core problem, but in real-word applications it is often radically better than currentTimeMillis().
When calculating graphics positions in frame refreshes nanoTime() leads to MUCH smoother motion in my program.
And I only test on multi-core machines.
I have seen a negative elapsed time reported from using System.nanoTime(). To be clear, the code in question is:
long startNanos = System.nanoTime();
Object returnValue = joinPoint.proceed();
long elapsedNanos = System.nanoTime() - startNanos;
and variable 'elapsedNanos' had a negative value. (I'm positive that the intermediate call took less than 293 years as well, which is the overflow point for nanos stored in longs :)
This occurred using an IBM v1.5 JRE 64bit on IBM P690 (multi-core) hardware running AIX. I've only seen this error occur once, so it seems extremely rare. I do not know the cause - is it a hardware-specific issue, a JVM defect - I don't know. I also don't know the implications for the accuracy of nanoTime() in general.
To answer the original question, I don't think nanoTime is useless - it provides sub-millisecond timing, but there is an actual (not just theoretical) risk of it being inaccurate which you need to take into account.
This doesn't seem to be a problem on a Core 2 Duo running Windows XP and JRE 1.5.0_06.
In a test with three threads I don't see System.nanoTime() going backwards. The processors are both busy, and threads go to sleep occasionally to provoke moving threads around.
[EDIT] I would guess that it only happens on physically separate processors, i.e. that the counters are synchronized for multiple cores on the same die.
No, it's not... It just depends on your CPU, check High Precision Event Timer for how/why things are differently treated according to CPU.
Basically, read the source of your Java and check what your version does with the function, and if it works against the CPU you will be running it on.
IBM even suggests you use it for performance benchmarking (a 2008 post, but updated).
I am linking to what essentially is the same discussion where Peter Lawrey is providing a good answer. Why I get a negative elapsed time using System.nanoTime()?
Many people mentioned that in Java System.nanoTime() could return negative time. I for apologize for repeating what other people already said.
- nanoTime() is not a clock but CPU cycle counter.
- Return value is divided by frequency to look like time.
- CPU frequency may fluctuate.
- When your thread is scheduled on another CPU, there is a chance of getting nanoTime() which results in a negative difference. That's logical. Counters across CPUs are not synchronized.
- In many cases, you could get quite misleading results but you wouldn't be able to tell because delta is not negative. Think about it.
- (unconfirmed) I think you may get a negative result even on the same CPU if instructions are reordered. To prevent that, you'd have to invoke a memory barrier serializing your instructions.
It'd be cool if System.nanoTime() returned coreID where it executed.
Java is crossplatform, and nanoTime is platform-dependent. If you use Java - when don't use nanoTime. I found real bugs across different jvm implementations with this function.
The Java 5 documentation also recommends using this method for the same purpose.
This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time.
Also, System.currentTimeMillies()
changes when you change your systems clock, while System.nanoTime()
doesn't, so the latter is safer to measure durations.
nanoTime
is extremely insecure for timing. I tried it out on my basic primality testing algorithms and it gave answers which were literally one second apart for the same input. Don't use that ridiculous method. I need something that is more accurate and precise than get time millis, but not as bad as nanoTime
.
참고URL : https://stackoverflow.com/questions/510462/is-system-nanotime-completely-useless
'IT' 카테고리의 다른 글
PHP 클래스 메소드에서 밑줄로 처리하는 것은 무엇입니까? (0) | 2020.06.11 |
---|---|
루트와 관련된 링크가 있습니까? (0) | 2020.06.11 |
파이썬 jinja2 속기 조건부 (0) | 2020.06.11 |
WPF 모호한 글꼴 문제-솔루션 (0) | 2020.06.11 |
쉼표 연산자는 무엇을합니까? (0) | 2020.06.11 |