forums.silverfrost.com Forum Index forums.silverfrost.com
Welcome to the Silverfrost forums
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

About derived TYPEs and initializations

 
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> General
View previous topic :: View next topic  
Author Message
wahorger



Joined: 13 Oct 2014
Posts: 1214
Location: Morrison, CO, USA

PostPosted: Mon Oct 16, 2017 4:53 pm    Post subject: About derived TYPEs and initializations Reply with quote

This is not a complaint, just an FYI for others who may be doing similar things. The compiler is V8.10.0, and all the examples below were done using the default compiler options for RELEASE WIN32.

I was concerned about my executables becoming quite large. Looking at the executable file itself, I noticed large blocks (multi-megabytes) of what appeared to be initialized data.z'20', z'80', etc.

Looking through my data declarations, DATA statements, etc. I could not find any that would cause this. So, I dug deeper into the derived types I use.

It would appear that if you have labeled COMMON and initialize a single variable in that common, then the entire COMMON area will become initialized. For me, I have the count of the number of active elements as the first item in labeled COMMON, followed by the data item. In some cases, it is a derived type. All of my derived types are defined with initial values for each element. Now, derived types themselves will not be initialized with the specified initial values if they are in COMMON, but they will be initialized to a value if some other item in the COMMON is initialized. Stated another way, if one item in a COMMON block is initialized, then the entire COMMON block is initialized and placed in the executable file. Normally, if the COMMON block is not initialized in any way, the program loader will allocate the area without any initialization data. This makes the executable smaller.

What made my executables bigger; many COMMON blocks have one or more variables that had an initial value in BLOCK DATA.

So, I experimented with initialization of a single element of the derived type to see the results. It was illuminating!

That said, one should never use a variable unless it has been first initialized, explicitly. Never use without setting it first!

I had defined a simple derived type of two character variables and one integer. If I initialized one of the character variables explicitly in a DATA statement for the derived type in COMMON, then the entire derived type (character and integer) was initialized. The element itself was initialized to the proper value, the other character variable was initialized to spaces (z'20') AND the integer variable was also initialized to spaces (in this case, z'20202020').

As and FYI: If I initialized just the integer variable, the character variables were initialized to Z'80'.

[code:1:8a43a05ec6]
type:: cust_omer
sequence
character*5:: abcd=' '
character*9:: defg='to pay '
integer:: dummy_integer=12345
end type
integer i
type (cust_omer) customer(10)
type (cust_omer) dummy
type (cust_omer) dummy1(2)
common/abcd/customer,dummy,i
print *,"I= **************************"
print *,i
print *,'Dummy1:**********************'
print *,'(1)=',dummy1(1)%abcd,':',dummy1(1)%defg
print *,'(2)=',dummy1(2)%abcd,':',dummy1(2)%defg
print *,'Dummy: **********************'
print *,'%abcd=',dummy%abcd
print *,'%defg=',dummy%defg
print *,'%dummy_integer=',dummy%dummy_integer
print *,'Customer (1):**********************'
print *,'%abcd=',customer(1)%abcd
print *,'%dummy_integer=',customer(1)%dummy_integer
print *,'Customer (2):**********************'
print *,'%abcd=',customer(2)%abcd
print *,'%dummy_integer=',customer(2)%dummy_integer
stop
end
block data
type:: cust_omer ! re-define the initial data for the type
sequence
character*5:: abcd='qrst'
character*9:: defg='there '
integer:: dummy_integer = 34567
end type
type (cust_omer) customer(10)
type (cust_omer) dummy
common/abcd/customer,dummy
Back to top
View user's profile Send private message Visit poster's website
wahorger



Joined: 13 Oct 2014
Posts: 1214
Location: Morrison, CO, USA

PostPosted: Tue Oct 17, 2017 12:11 am    Post subject: Reply with quote

Just an FYI on this: Moving data from one block to another to prevent initializing the entire COMMON block reduced the executable size from 383MB to 123 MB.
Back to top
View user's profile Send private message Visit poster's website
JohnCampbell



Joined: 16 Feb 2006
Posts: 2551
Location: Sydney

PostPosted: Tue Oct 17, 2017 7:16 am    Post subject: Reply with quote

Bill,

You are clearly doing something that I am not; 383 mb .exe is a big file from my experience.

I have expected that using block data (which is required as standard conforming for common) would increase the size of the .exe.
I try to avoid initialising arrays at compile stage, so have an "initialise_run" routine to set all significant variables and arrays at run time. Documenting this approach can be as effective as a block data sub program. This has been my approach to reduce the size of the .exe. I think this is also required for ftn95 /64.

I have not placed derived types in common blocks, but you appear to be able to do that. Again I do not initialise arrays in modules at compile time, although I see many examples posted of this approach.
My approach is to define a derived type parameter, which can be defined as xxx_type_zero or xxx_type_unit, then apply this at "initialise_run" or when first used or when the derived type array is allocated.

My main use of " logical :: first call = .true." or "integer*8 :: last_tick = -1" is to make some key variables static, rather than dynamic. I would rarely have total initialised memory > 1 kb.
You can always isolate the initialisation in libraries, by having a first_call variable, then coding:
if (first_call) then
derived_type_array = derived_type_zero ! array = parameter
first_call = .false.
end if

My recommendations would be:
1) to look at MODULE, as they are not contiguous in memory for large size components, so would not have the problem of allocating the full common image in the .exe.
2) Also don't initialise arrays at compile time.
3) I also try to allocate all large arrays and place them in modules. Surely they do not contribute to the .exe in this case.

Again, my .exe files are usually 2mb to 10 mb in size so I do not have your experience. I'd be interested to know if this approach has any merit.

John
Code:
!  example of derived type definition
!
      TYPE widgit_RECORD
         integer*4 status                 ! not used
         integer*4 type                   ! type of equipment
         integer*4 tick                   ! time next available
         integer*4 ticks_to_breakdown
         integer*4 task(2)                ! allocated task
         real*8    breakdown              ! breakdown probability each time operated
         integer*4 yard                   ! yard for this stacker or reclaimer
         integer*4 berth                  ! berth for this loader
         integer*4 load_stream            ! load stream for this stacker or reclaimer
         integer*4 pile_index             ! pile where equipment is located
         integer*4 origin                 ! be not used
         integer*4 destination            ! be not used
         integer*4 flow_limit             ! flow limit for combined stacking flows
         integer*4 flow_sum               ! flow sum to test combined stacking flows
         integer*4 year_qu                ! tonnage units of transfer
         integer*4 year_tq                ! ticks of transfer
         integer*4 year_td                ! ticks of delay
         real*4    posn
         real*4    xs
         real*4    ys
      END TYPE widgit_RECORD
!
      type (widgit_Record), parameter ::                          &
      widgit_zero = widgit_record ( 0, 0, 0, -1, (/0,-99/), 0., 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0., 0., 0. )
Back to top
View user's profile Send private message
PaulLaidler
Site Admin


Joined: 21 Feb 2005
Posts: 7912
Location: Salford, UK

PostPosted: Tue Oct 17, 2017 7:46 am    Post subject: Reply with quote

Bill

I don't have a quick and definitive reply to your post but I am guessing that given the way that the compiler is designed, it has to initialise the data from the executable and the data must be initialised to something. Presumably it becomes too complicated to initialise only some of the data. That said, the compiler must preset the data to something and it may be that the strings are filled with spaces whilst the integers are set to "undefined". Given time I could look at the details but I presume that you are not asking for that and that the information would not be of any assistance.
Back to top
View user's profile Send private message AIM Address
JohnCampbell



Joined: 16 Feb 2006
Posts: 2551
Location: Sydney

PostPosted: Tue Oct 17, 2017 7:52 am    Post subject: Reply with quote

Bill,

Some variations for the part example you posted
Code:
module abcd

  type cust_omer
   sequence
   character*5 :: abcd
   character*9 :: defg
   integer     :: dummy_integer
  end type cust_omer

  type (cust_omer), parameter :: cust_omer_zero = cust_omer ( ' ', 'to pay ', 12345 )

  integer*4 i
  integer*4 mc
  type (cust_omer), allocatable :: customer(:)
  type (cust_omer) dummy
  type (cust_omer) dummy1(2)

end module abcd

use abcd

 call initialise_module_abcd (2002)
 
 print *,"I= **************************"
 print *,i, mc
 print *,'Dummy1:**********************'
 print *,'(1)=',dummy1(1)%abcd,':',dummy1(1)%defg
 print *,'(2)=',dummy1(2)%abcd,':',dummy1(2)%defg
 print *,'Dummy: **********************'
 print *,'%abcd=',dummy%abcd
 print *,'%defg=',dummy%defg
 print *,'%dummy_integer=',dummy%dummy_integer
 print *,'Customer (1):**********************'
 print *,'%abcd=',customer(1)%abcd
 print *,'%dummy_integer=',customer(1)%dummy_integer
 print *,'Customer (2):**********************'
 print *,'%abcd=',customer(2)%abcd
 print *,'%dummy_integer=',customer(2)%dummy_integer
 stop
 end
 
 subroutine initialise_module_abcd (n)
use abcd
!
  integer*4 :: n, stat

  allocate ( customer (n), stat=stat )

  i        = stat
  mc       = n
  customer = cust_omer_zero
!
  dummy    = cust_omer_zero
  dummy1   = cust_omer_zero
!
 end subroutine initialise_module_abcd


I use allocatable arrays in modules for most of my coding. I have not identified performance problems with this approach, as alignment is typically optimised.
I am not familiar with the need for "sequence" in derived types, as I have phased out equivalence. I prefer to transfer the record id as a routine argument and address the derived type array via use module.

John
Back to top
View user's profile Send private message
wahorger



Joined: 13 Oct 2014
Posts: 1214
Location: Morrison, CO, USA

PostPosted: Tue Oct 17, 2017 10:12 pm    Post subject: Reply with quote

Paul, I don't expect any action on your part. I'm not pointing out any error, just the "way things work". Once I had thought about it, I can see why the entire block would need to be output in the executable to ensure that all the actually initialized elements are in the proper place. Perhaps this is an answer to the person who was wondering why the size of the executable suddenly increased when compiler versions changed? Maybe it was an initialization?

When I keep the executables to their smallest value, my build and deploy processes run much faster. Basically, the deploy process compresses the file. With lots of the same data (COMMON blocks), it actually takes longer than one might expect.

Really, not an issue.

John,

If you have a derived type in COMMON, then you need to preserve the SEQUENCE of those variables. I ran into this early. Unlike "C", FORTRAN derived types are not guaranteed to have the same structure from compiled module to compiled module. And, that's exactly what I found. Perhaps if you compiled everything as one big compile, it would be, but I have the MAKE process re-compiling only what I need. Thus, the need for SEQUENCE. Also, since the derived type can be used for binary I/O, insuring the precise sequence of the variables is enforced.
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    forums.silverfrost.com Forum Index -> General All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group