how to stop resetting the system clock

how to stop resetting the system clock

I have used absoft's f90 and intel's ifc compiler to run fortran prorgrams on the Mandrake linux fortran. I use the system_clock subroutine to estimate CPU time taken.

However,both compilers reset the system time after 2600 odd seconds. I would like to know if there is an option where I can disable the resetting of the system clock.

Any help will be appreciated.


12 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

I'm guessing that what you mean is that the difference of 2 values returned by system_clock, taken as default (32-bit) integers, rolls over from HUGE positive to larger negative after an interval < 1 hr. If you want CPU time, rather than system_clock time, over intervals of minutes or hours, call cpu_time() may be the simplest solution.

You could double the interval which you can time with system_clock by adjusting negative differences, using appropriate data types. All this is ugly.

You could write a lower level function, e.g. in C, which goes either to the rdtsc time counter, or to the QueryPerformance Windows API, which you might do in Fortran, where you use 64-bit integers.

Hmm - I had hoped to find out that Intel Fortran had adopted the Compaq Fortran extension of allowing INTEGER(8) arguments to SYSTEM_CLOCK, but it seems not. That will come in a future version. (In Compaq Fortran, when I8 arguments are used, the COUNT_MAX is much higher and the COUNT_RATE is somewhat higher.)


Steve - Intel Developer Support


I want to use SYSTEM_CLOCK for a Fortran application, but I have arequirement that its use must be "standard" Fortran (i.e., no extensions). What issues will I encounter (i.e., system clock reset times)? What are my options?



The value returned by SYSTEM_CLOCK does eventually wrap, and how close it gets to doing so depends on when you call it. I just tried it and I get 13 hours before it wraps.

Basically, you want to include some defensive code that looks to see if the interval from A to B is negative, and if it is, add COUNT_MAX to B. For example:

real(kind(0.0D0)) :: start_d, end_d
integer :: start, end, count_rate, count_max
call system_clock (start)
... code to be timed
call system_clock (end, count_rate, count_max)
end_d = dble(end)
start_d = dble(start)
if (end_d < start_d) end_d = end_d + dble(count_max)
write (*,*) "Time = ", (end-start)/dble(count_rate)

Note that I convert the values to double precision so that we don't lose bits and can add count_max without a problem.

Now I suppose it's possble for it to wrap twice, but that would take about four days of elapsed time.

Steve - Intel Developer Support

I note that system_clock with integer(8) arguments on linux resolves short time intervals, as documented, while on Windows it still measures in 60 Hz ticks with the 11.1/065 release.

Do not confuse precision with resolution. My testing shows that Windows updates the system clock at a 1000Hz (1ms) rate. Greater resolutions are available with the multimedia timer APIs.

Steve - Intel Developer Support


I found your explanation and example very helpful. However, I do not quite understand the example. Why doesn't it say in the last two lines:

if (end_d < start_d) end_d = abs(end_d) + dble(count_max)
write (*,*) "Time = ", (end_d-start_d)/dble(count_rate)

Note that I added an abs(end_d) in the first line, because supposedly end_d is negative, and in the second line I changed the numerator to have the double precision variables. Which version is correct?


If your question is how to measure time intervals across 32-bit signed integer wrap, the primary answer is to use the facility required by f2003 to use larger than default integers (integer*8 works).  Steve's example was on how to deal with a compiler which doesn't have this support, so it is outdated by 6 years.  I think Steve is on holiday.

All current linux compilers I know of are working well with the 64-bit system_clock, with ability to measure microsecond intervals up to huge(1_16) microseconds (if the platform can run that long).

Your point may be valid that the posted suggestion might not work.  I would expect that the count would wrap from huge(1) to -huge(1)-1, so it would be necessary to add 2*dble(huge(1))+2 when the value is negative, assuming that count_max == huge(1).  If working, at best this would extend the usefulness of 32-bit system_clock beyond 1 hour as well as fixing the problem with wraps, but I don't see that Fortran standard guarantees it to work.

Taking absolute value looks like a bad idea here.  When system_clock is returning negative values, it doesn't reverse the sign of time intervals, as taking absolute value would do.  If using 64-bit integers in accordance with current standard, converting those values to double before taking differences will reduce accuracy.  That's one more reason for calling this legacy suggestion obsolete.





When using the 32-bit clock counter, 2^31-1 is the largest positive signed integer. The clock counter is unsigned, Fortran does not directly handle unsigned integers. One tick after 2^31-1, the unsigned number is 2^31 == 0x80000000. Taking the abs of this, depending on how abs is done {if( x=-x} produces 0x80000000. The next tick the unsigned number is  0x80000001, abs of this is 0x7FFFFFFF, which is 2^31-1, next tick abs returns 2^31-2, etc... IOW it would appear ticks are moving backwards.

What you want instead is unsigned modulus. An easy way to do this



	  INTEGER(4) :: X

	   X=HUGE(X) ! largest 32-bit signed number

	  WRITE(*,*) X, KIAND(INT8(X), Z'00000000FFFFFFFF')

	  X=X+1 ! first overflow

	  WRITE(*,*) X, KIAND(INT8(X), Z'00000000FFFFFFFF')

	  X=X+1 ! second overflow

	  WRITE(*,*) X, KIAND(INT8(X), Z'00000000FFFFFFFF')


	  2147483647            2147483647

	 -2147483648            2147483648

	 -2147483647            2147483649


Note the first column, if abs were taking, would be counting down, not up.

As TimP and others have mentioned, the above is a partial fix, because at some point the 32-bit unsigned number will overflow. The results will, if run long enogh, wrap back to 0. Therefore your code, if run long enough, will need to periodically poll the counter

	real(kind(0.0D0)) :: start_d, end_d

	integer :: start, end, count_rate, count_max

	integer(8) :: elapse


	elapse = 0

	call system_clock (start)

	vvv code to be timed begins vvv

	... code under test ...

	! start of periodic code inside code under test

	call system_clock (end)

	elapse = elapse + (end-start)

	start = end

	! end of periodic code inside code under test

	... code under test

	! ^^^ end code to be timed

	call system_clock (end, count_rate, count_max)

	elapse = elapse + (end-start)

	write (*,*) "Time = ", elapse/dble(count_rate)


Jim Dempsey

Forum gripe.

It is bad enough that I cannot drag and drop sample code from VS into the forum, and have to result to pasting into Notepad. Then copy and paste. This used to work. Now, copy from NOTEPAD and paste into forum results in double spaced lines. Please permit the former, and if not, at least permit the latter. This site is user unfriendly enough (sluggish), don't make it worse.

Also note while I can drag from selected portion of other poster's message and drop into comment box, and this works. Using Ctrl-C to copy from other posters message, and Ctrl-V to past, crashes the web page. This is particularly annoying when the portion of text I want is several comments prior to where the edit box is for new comment.

Sign me grumpy old man.


I can't reproduce copy/paste issues, either from Visual Studio or from Notepad. I have seen the double-space issue before, but can't get it to happen today.  Rather than griping here, send me a message with instructions for how to reproduce the problem.

As for SYSTEM_CLOCK, if you use INTEGER(8), the max count is VERY large nowadays.

Steve - Intel Developer Support

Leave a Comment

Please sign in to add a comment. Not a member? Join today