Silverfrost Forums

Welcome to our forums

FTN95 64-bit beta test

27 Sep 2015 6:02 #16847

Quoted from DanRRight Over the years the existence of stack caused nothing but the troubles and crashes. Probably it is just poorly implemented or buggy. Plus there is no facilities that tell what is going on with the allocation and how stack is full. OK, how about making at least the option /stack:-1 which will disable all the traces of involvement of stack facilities completely

Stack is originally designed to store temporary and local variables (automatic storage). Unfortunately, it's not so easy to keep track of stack usage as program may have recursive procedures or Fortran compiler may even create array temporaries. Anyway using stack is fast and convenient way to reserve space for local variables and access them. I personally would use heap allocation to store huge amounts of data and prefer to keep stack size small. Also you should remember that every thread uses it's own stack, so you are probably not going to see stack disappear any time soon.

28 Sep 2015 10:28 #16851

Here is some code for GlobalMemoryStatusEx.

program gmem
integer, parameter:: knd = 4

type MEMORYSTATUSEX
sequence
  integer dwLength;
  integer dwMemoryLoad;
  integer(knd) ullTotalPhys;
  integer(knd) ullAvailPhys;
  integer(knd) ullTotalPageFile;
  integer(knd) ullAvailPageFile;
  integer(knd) ullTotalVirtual;
  integer(knd) ullAvailVirtual;
  integer(knd) ullAvailExtendedVirtual;
end type  

stdcall GlobalMemoryStatusEx 'GlobalMemoryStatusEx'(REF):logical
type(MEMORYSTATUSEX)::mdata

mdata%dwLength = 64
if(GlobalMemoryStatusEx(mdata))then
  print *,  'Percentage of physical memory in use        ', mdata%dwMemoryLoad           
  print 10, 'Amount of actual physical memory            ', mdata%ullTotalPhys            
  print 10, 'Amount of physical memory available         ', mdata%ullAvailPhys         
  print 10, 'Committed memory limit                      ', mdata%ullTotalPageFile        
  print 10, 'Amount of memory current process can commit ', mdata%ullAvailPageFile        
  print 10, 'Size of virtual address space               ', mdata%ullTotalVirtual         
  print 10, 'Amount of unreserved/uncommitted memory     ', mdata%ullAvailVirtual         
else
  print*,'Failed'  
endif

10 format(1x,a,i12)
end program

What would an FTN95 library routine look like (preferably without optional arguments)?

28 Sep 2015 12:56 #16852

Could it look something like this: module Global_Memory_Status_a integer, parameter:: knd = 4

 type MEMORYSTATUSEX 
 sequence 
   integer dwLength; 
   integer dwMemoryLoad; 
   integer(knd) ullTotalPhys; 
   integer(knd) ullAvailPhys; 
   integer(knd) ullTotalPageFile; 
   integer(knd) ullAvailPageFile; 
   integer(knd) ullTotalVirtual; 
   integer(knd) ullAvailVirtual; 
   integer(knd) ullAvailExtendedVirtual; 
 end type  

 stdcall GlobalMemoryStatusEx 'GlobalMemoryStatusEx'(REF):logical 
 type(MEMORYSTATUSEX)::mdata 
!
end module Global_Memory_Status_a

program gmem
 call paul_example
 call lib_example
end program gmem

subroutine paul_example
 use Global_Memory_Status_a

 real*4    gb
 external  gb

 write (*,*) ' '
 mdata%dwLength = 64 
 if (GlobalMemoryStatusEx(mdata)) then 
   print *,  'Percentage of physical memory in use        ', mdata%dwMemoryLoad            
   print 10, 'Amount of actual physical memory            ', gb(mdata%ullTotalPhys)
   print 10, 'Amount of physical memory available         ', gb(mdata%ullAvailPhys)
   print 10, 'Committed memory limit                      ', gb(mdata%ullTotalPageFile)
   print 10, 'Amount of memory current process can commit ', gb(mdata%ullAvailPageFile)
   print 10, 'Size of virtual address space               ', gb(mdata%ullTotalVirtual)
   print 10, 'Amount of unreserved/uncommitted memory     ', gb(mdata%ullAvailVirtual)
 else 
   print*,'Failed'  
 end if 

 10 format(1x,a,f0.3) 
 
end subroutine paul_example

subroutine lib_example

 real*4    gb
 integer*8 get_physical_memory_a, get_available_memory_a, get_memory_limit_a, get_virtual_memory_limit_a, jj
 external  get_physical_memory_a, get_available_memory_a, get_memory_limit_a, get_virtual_memory_limit_a, gb

 write (*,*) ' '
 jj = get_physical_memory_a ()
 write (*,11) 'Amount of actual physical memory            ', gb(jj), jj
 jj = get_available_memory_a ()
 write (*,11) 'Amount of physical memory available         ', gb(jj), jj
 jj = get_memory_limit_a ()
 write (*,11) 'Committed memory limit                      ', gb(jj), jj
 jj = get_virtual_memory_limit_a ()
 write (*,11) 'Size of virtual address space               ', gb(jj), jj

 11 format(1x,a,f10.3, i14) 
 
 end subroutine lib_example

 integer*8 function get_physical_memory_a ()
 use Global_Memory_Status_a
 
   mdata%dwLength = 64 
   if (GlobalMemoryStatusEx(mdata)) then 
     get_physical_memory_a = mdata%ullTotalPhys
   else           
     get_physical_memory_a = -1
   end if
 end function get_physical_memory_a

 integer*8 function get_available_memory_a ()
 use Global_Memory_Status_a
 
   mdata%dwLength = 64 
   if (GlobalMemoryStatusEx(mdata)) then 
     get_available_memory_a = mdata%ullAvailPhys
   else           
     get_available_memory_a = -1
   end if
 end function get_available_memory_a

 integer*8 function get_memory_limit_a ()
 use Global_Memory_Status_a
 
   mdata%dwLength = 64 
   if (GlobalMemoryStatusEx(mdata)) then 
     get_memory_limit_a = mdata%ullTotalPageFile
   else           
     get_memory_limit_a = -1
   end if
 end function get_memory_limit_a

 integer*8 function get_virtual_memory_limit_a ()
 use Global_Memory_Status_a
 
   mdata%dwLength = 64 
   if (GlobalMemoryStatusEx(mdata)) then 
     get_virtual_memory_limit_a = mdata%ullTotalVirtual
   else           
     get_virtual_memory_limit_a = -1
   end if
 end function get_virtual_memory_limit_a
28 Sep 2015 1:02 #16853
 real*4 function gb (leng)
   integer*8 leng
   gb = real(leng)/(1024.**3)
 end function gb

Paul,

Thanks very much for the examples. _a could be replaced by @ and functions placed into salflibc.dll I've also recommended some other additions which would be useful as documented extension utility functions.

John

28 Sep 2015 10:24 #16855

Several things occur to me about this. Going to 64-bit is going to create a mix of INTEGER4 and INTEGER8 that will irritate Dan (sorry Dan) just as the last few INTEGER*2 variables do now. If you hit the limits of available memory frequently, the problem is in the forefront of the programmer’s mind. The less frequently you hit it, then the more shocking it will be when it happens, hence my suggestion that we need a Fortran routine for checking available space. I think it is more likely that one hits this limit with ALLOCATE than with statically allocated memory, and it seems to me essential to check that there is space before trying to allocate it (especially if you don’t want users to see a system message). I wasn't expecting to see it so soon! With statically allocated memory we are likely to know what the minimum computer configuration is needed to run the program in the first place, and if it won’t run that other applications need to be closed. With dynamically allocated memory this simple test/solution isn’t available. Ask yourself where is the memory allocated for local, unSAVEd variables. The answer is probably on the stack. The stack used to be tiny (tinier even than tiny total memory), and its use had to be restricted to such things as passing the addresses of subprogram parameters and return addresses, so there were severe limitations on the call tree depth (or whatever computer scientists call it now). When you contaminate it by filling it up with large volumes of local array storage then you are asking for the trouble you most certainly get, no matter how big the stack is. Eddie

29 Sep 2015 6:25 #16858

John

Thanks. I get the idea about creating simple Fortran functions.

It made me realise two things...

  1. clearwin_info@ ought to return integer(7) in the new header files and
  2. we can use clearwin_info@ in this context.
29 Sep 2015 8:22 #16859

Paul,

I'd prefer to have the simple functions, like listed, as they are useful for programs not using clearwin.

I've sent a list of some useful routines, which I think would be better in salflibc.dll. I expect they are all easy to implement and would help with program testing, such as processor name, compiler version, dll version and compiler options. Note compiler_option is part of F08 ISO_FORTRAN_ENV, returning a string of variable length. I am not sure if that is easily supported, but adopting some of this would certainly provide some upward conformity and standardised KIND names. It would help with the KIND portability problem.

Also the two SSE functions, as they give easy access to vector instructions for the most common array calculations, if vector instructions are not going to be provided generally in the short term.

John

29 Sep 2015 9:55 #16860

John

'ClearWin+' functions are always available with 'FTN95' functions. They reside in the same library(s). To save a lot of work at this end I will implement them via clearwin_info@, at least for the time being. In fact I have already done this. Just need to test that they work.

30 Sep 2015 9:06 #16863

As we discuss 64bit compiler here and in the other places i suspect i was not clear what i wanted to see in the next beta. I asked for simpler thing (though i might be wrong that it is simple) then to implement the debugger at this stage. If compiler just reported the error line where error occurs (and all other standard diagnostics) then it would be great milestone. For example in this text

a=1
b=0
c=a/b
print*, c
end

compiler has to tell not just 'floating point divide by zero in #MAIN at address x000001001000101011000101010101000010101100000' but the

'floating point divide by zero in #MAIN at the line 3'.

Is this doable without any major rebuilds?

30 Sep 2015 11:52 #16864

If the line address is not available, what would it require to provide a trace back of the routines called? This is the main reason I use /debug with /32. A combination of both /OPT and /Trace_Back would be good for both /32 and /64. With my present program builds with many .f90 files, I am choosing different compile options for each file, when the line number is all I am requiring from the /DEBUG option. If /Trace_Back could provide some optimisation, that would be a good change. I tend to mix: /CHECK for data reading routines /DEBUG for program management routines /OPT for compute intensive routines All in the one program. There are many cases where /Trace_Back would be preferred to what I assume /DEBUG provides.

John

1 Oct 2015 1:18 #16865

I am surprised that you do not use SDBG. Does PLATO use its own debugger?

And what is the /Trace_back and how it is used?

1 Oct 2015 2:13 #16866

Dan,

/Trace_Back does not exist. I think it would be a good subset of /DEBUG. I was suggesting an alternative to /DEBUG that might be used in conjunction with /OPT, as areas of code that impact on run time performance can benefit from /OPT, especially real*8 calculations.

Regarding SDBG, I typically use other strategies. Some coding approaches performs differently with /CHECK, such as ALLOCATE. Should I again mention /IMPLICIT_NONE !!

John

1 Oct 2015 6:44 #16867

Plato does not have its own debugger. It spawns SDBG.

Both the 32 bit and 64 bit versions provide a trace back when an exception is raised but you do need to use /explist in order to identify the line in the source where the error occurred.

The trace provides an offset for the offending assembler instruction whilst the 'explist' shows the lines of the code with their corresponding offsets.

1 Oct 2015 8:05 #16868

Paul,

Yes you are correct. The trace back is being provided with offset addresses. This will identify the call sequence. You just have to identify the line of code from the /explist. So Dan, you are not totally in the dark, but you could be appealing for bad light. (cricket reference). This is better than I remembered, but it is easier to use /debug than /explist.

John

1 Oct 2015 8:39 #16873

OK, let's check /explist as i suspect i will be first to really used it with all underlying consequences 😃. Taking my program above,compiling it with /explist and running. We get floating point divide error. Here is saved from screen the file error.txt

Floating point divide by zero
Floating point co-processor fault at address 00401034

 00401000 main [+0034]

eax=00000000   ebx=0000401e   ecx=00000001
edx=000000fe   esi=00402000   edi=0360fce8
ebp=0360fce0   esp=0360fca8   IOPL=0
ds=002b   es=002b   fs=0053
gs=002b   cs=0023   ss=002b
flgs=00010212 [NC OP NZ SN DN NV]

 00401034  fstp     [ebp-0x10] 
 00401037  wait      
 00401038  lea      eax,[00404000] 

First how to understand confusing numbers 00401034 and 00401000 main [+0034]

And here is the listing file generated by /explist

Compiler Options in Effect:
    COLOUR DELETE_OBJ_ON_ERROR EXPLIST LINK MINIMISE_REBUILD  NO_QUIT NON_STANDARD SINGLE_THREADED 
    

   0001   a=1                                                                                    AT 0
 ; Start of SUBROUTINE MAIN@

      00000000(3/1/1)            push      ebp
      00000001(4/1/1)            mov       ebp,esp
      00000003(5/1/1)            push      ebx
      00000004(6/1/1)            push      esi
      00000005(7/1/1)            push      edi
      00000006(8/1/1)            push      eax
      00000007(9/1/1)            lea       ecx,2
      0000000d(10/1/1)           push      ecx
      0000000e(11/1/1)           lea       edi,[ebp+8]       ; Get command line arguments
      00000011(12/1/1)           push      edi
      00000012(13/1/1)           call      __FTN95INIT1_
      00000017(14/1/1)           add       esp,=8
      0000001a(15/1/1)           sub       esp,=24           ; Adjusted later if temporaries allocated
      00000020(16/3/2)           mov       A,Z'3f800000'
   0002   b=0                                                                                    AT 27
      00000027(17/3/5)           mov       B,=0
   0003   c=a/b                                                                                  AT 2e
      0000002e(18/4/9)           fld       A
      00000031(19/4/9)           fdiv      B
      00000034(20/3/10)          fstp      C
      00000037(21/3/10)          wait      
   0004   print*, c                                                                              AT 38
      00000038(22/4/17)          lea       eax,2
      0000003e(23/3/14)          push      eax
      0000003f(24/4/15)          lea       ecx,-32234_2
      00000045(25/3/14)          push      ecx
      00000046(26/3/14)          push      eax
      00000047(27/3/14)          mov       Temp@3,eax
      0000004a(28/3/14)          mov       Temp@4,ecx
      0000004d(29/3/14)          call      WSF1@@
      00000052(30/3/14)          add       esp,=12
      00000055(31/4/22)          lea       edi,1
      0000005b(32/3/19)          push      edi
      0000005c(33/4/20)          lea       eax,C
      0000005f(34/3/19)          push      eax
..........
..........
   0005   end                                                                                    AT 80

Now we have one more difference. Why both addresses in first file do not coincide with this one? The closest related line is

0003   c=a/b                                                                                  AT 2e
00000034(20/3/10)          fstp      C

which is not

00401034  and
00401000 main [+0034]
2 Oct 2015 1:10 #16874

No need for confusion here! Let's use your example and work things out. The first piece of information is in the error report:

Floating point co-processor fault at address 00401034 

  00401000 main [+0034] 

Remember, a fault occurs [u:1ea39aaef3]after [/u:1ea39aaef3] the instruction is executed. The processor does not know whether the next instruction in the pipeline will or will not cause a fault. Therefore, the address given is the value of EIP after the fault occurred. It is easy to back up one instruction using an EXPlist, but the fault handler may not be able or care to disassemble the code and figure out how many bytes to go back. We look up main+0034 in the EXPlist, and go back one instruction, which gives us the FDIV. In fact, the first line in the error message said '...divide by zero', so the instruction had better be a floating point division. If your code is 80X87 code, the instruction is FDIV.

Many instructions use EIP- (or RIP-) relative addresses for jump and call instructions, and use the same convention to express offsets. Here is an example:

  00401070: E8 2B 0A 00 00     call        00401AA0
  00401075: 83 C4 24           add         esp,24h

Again, take the address of the instruction after the CALL, and subtract that from the address of the CALL target: 401AA0 - 401075, which is 000A2B, which is why the four bytes of the address in the instruction, in little-endian order, are 2B, 0A, 00, 00. See those bytes in the instruction bytes field?

The error handler has already computed the offset from the beginning of the routine (main) by taking the EIP value, 401034H and subtracting the load address of that routine, which is 401000H; that is the _0034 that it reported.

All these numbers are hexadecimal. On old machines, these might have been displayed in octal, but octal is no longer suitable when word sizes are not multiples of 3-bits.

2 Oct 2015 4:04 (Edited: 8 Oct 2015 5:59) #16875

Thanks mecej4, now things are more clear. I mean, now i see more clearly that this is a total darkness 😃 and with my uncountable errors i make this way of debugging will not be a fun to do. I think Silverfrost has to accelerate implementing at least offending line reporting if not the full debugger.

2 Oct 2015 7:17 #16876

Mecej4,

I understand that you may find this hexadecimal arithmetic straight-forward, but I'll also wait for reporting of line numbers in the code. Since we changed to ISO base 10 units, I will now only accept decimal line numbers ! I prefer to think about what the bug may be in the Fortran, rather than finding it listed in assembler code.

7 Oct 2015 7:20 #16888

John

I don't know if I should try to explain Dan's misunderstanding about the aims and objectives of the 64 bit beta release. I have stated these earlier (probably in this thread), but you provoke me to make the main point again.

The 64 bit beta release does not include 64 bit debugging facilities but the 32 bit debugging facilities are still in place. So, for at little while, users should do their development in '32 bit' mode, and only use the 64 bit feature for the final release version.

Putting it a different way, we have extended the existing compiler FTN95 by adding a new command line option /64 which has the effect of producing 64 bit object code. When not using /64, FTN95 works exactly as before.

You will find that Dan manages to combine being one of our strongest supporters with being our most vocal critic. If we conversed in Spanish things might be different.

8 Oct 2015 12:28 (Edited: 8 Oct 2015 6:05) #16891

Hah, Spanish. For internal use i apply Russian.

I think and hope my support and critics are reasonable. They reflect actual contrasts of this compiler over the quarter century of its development. It is the best one with many things but trails the worst ones in others. Good though is that things are moving forward where it was missing.

It always deserved to have much larger adoption rates. To me it was always way the best one, years ahead of all others. But systematic funding of other compilers in major markets like the US over decades shifted it into the shadows. Plus possibly UK developers feel kind of inferiority complex with respect to US and do not push their products. But hope with the new features added and massive debugging campaign over the past decade after making compiler affordable the company will finally take more aggressive stance in the market.

Please login to reply.