- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
Thanks,
DEEPAK
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
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?
Thanks,
Arney
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.lt.0) 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
[fortran]
PROGRAM TEST
USE IFPORT
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')
END PROGRAM TEST
2147483647 2147483647
-2147483648 2147483648
-2147483647 2147483649
[/fortran]
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
[fortran]
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)
[/fortran]
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Jim,
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.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page