Stdout buffer in gfortran

 time x1 >x
   
real    1m51.059s
user    1m50.279s
sys     0m0.577s
urbanjs@venus:~$ time x1 >/dev/null

real    3m3.942s
user    2m10.459s
sys     0m53.480s
urbanjs@venus:~$ cat x1.f90
program test
implicit none
integer :: i, j
do j=1,10000000
   do i=49,90
      WRITE(*,"(A)")achar(i)
   enddo
print*,""
enddo
end program test

This is largely due to the buffering issues, but you can see writing to /dev/null is considerably slower using gfortran.

preprocessing can be a good solution. In fixed-format a very common extension in the past was that lines starting with a “D” in column 1 were treated as comments unless a compiler flag was supplied, in which case the “D” was ignored. Some modern compilers no longer supply that or a free-format equivalent, but some do. A shame there is no standard equivalent.

Even having I/O or conditionals in a routine can affect optimization, and so some form of preprocessing or conditional compilation can be the only solution, but in general it should not be overused. A conditional branch around the I/O and debug-related statements is sufficient for many routines.

Part of the reason you see code where error codes are returned but no I/O is produced in the routine is not only to do things like allow for multi-lingual message catalogs to be used but to reduce or prevent some of the problems with optimizing routines containing I/O.

I would encourage messages and parameter validation checking wherever it does not cause critical performance issues just using standard Fortran conditionals perhaps optionally triggered by an environment variable or input option passed to the code.

This really applies to very large programs where I have seen hundreds of gigabytes of I/O generated and then thrown to a unit assigned to /dev/null assuming that there is no penalty;
it is a “trick” that has been passed around several large institutions that I have a pet peeve about as it keeps rearing its head as it is so much easer to have some main program do

open(file=’/dev/null’,newunit=debug)

and have the DEBUG value in a module

and then have debug statements throughout the code that say

write(debug,…

with no conditionals. Then all you have to do is set the DEBUG value to something like 6 and you see all your debug statements, and/or you can change the LUN just is some stretches of code to see the debug statements from just routines. The concept is so much more appealing that most methods it gets passed around a lot; but is NOT a free or efficient solution.

Most users will not see this crushing their systems; but if you are running many thousands of processes doing this and see an entire cluster overloaded with I/O being generated in the inner loop of a massive program so it can be thrown away and fix that to see it start happening again with a new code shortly thereafter you get peeved. Take a look at a node running 96 of your infinite loops concurrently (mileage varies depending on a lot of system configurations) and you can see it is not going to do much else productively while it is throwing away write statements to /dev/null for “free”.

So all I really want to say is if you are writing large-scale or using something that is going to be used in a time-critical fashion ANY system calls should be avoided when possible, including I/O of any kind, but especially ASCII representations of data; and writing those to /dev/null does not make them overhead-free.

To me, there is something very pleasing about a Fortran program crushing a CPU and when you run an strace(1) on it you see nothing at all till it is ready to pop out some answers. As a co-worker has a habit of saying “Oog say system call bad”, while doing a bad impression of a cave-man. But putting that aside, he is nearly always right.

1 Like