Scope of fortran modules - scope

I already asked this question however this im going to try to be clearer this time.
Im really new to fortran so forgive any sytax error this is more psuedo code.
module variables
implicit none
SAVE
integer x
integer y
end module
subroutine init()
use variables
x = x + 2
y = y + 1
endsubroutine
then my main program would be
program main
use variables
implicit none
call init()
call some_other_function()
endprogram
If i included my modules will they retain their values in some_other_function()
assume that some_other_function() is an abstraction of a huge simulation program.
Can i rely on my initialized variables staying keeping their values.
is that was the SAVE statement in the module does?
Background info: I have program1 that is being called by program2
for a a significant amount of time. Program1 has a huge intilization phase that only needs to happen once. If I ran that initial phase before program2 calls program1, could i rely on all the module declared variables being saved

With a SAVE statement in the module, the values of the module variables are retained for the duration of the run of the program. If you initialize them in one procedure, the main program and other procedures will see those value. Module variables are preserved as long as they are in scope, so since you use your example module from the main program, their values would be retained for the duration of the run even without the SAVE statement. In principle, if a module was only used in some procedures and a SAVE statement were not used, the compiler could "forget" the values when none of the procedures were in the call chain. Probably many or perhaps all compilers don't actually reset the values ... it would be extra work to figure out whether a module had gone out of scope.
P.S. Your example has an error since you never initialize x and y. You only change their values.

Related

Warning: 'matchIter' is not GC-safe as it accesses 'x' which is a global using GC'ed memory [GcUnsafe2]

When building this code in nim:
import jester, asyncdispatch
let stuff = "thing"
routes:
get "/":
resp stuff
runForever()
it results in:
mytest.nim(3, 1) template/generic instantiation from here
lib/core/macros.nim(369, 70) template/generic instantiation from here
lib/pure/asyncmacro.nim(355, 31) Warning: 'matchIter' is not GC-safe
as it accesses 'stuff' which is a global using GC'ed memory
[GcUnsafe2]
I suppose it refers to the variable stuff and I suppose it's hard to diagnose because the jester routes are somekind of DSL.
If the message means what it means to mean, then why is it only a warning ? Or is it a false positive ? Or even more, is that concept of using variables in routes just plain impossible ?
The procedures which are generated by Jester have been marked with {.gcsafe.}, this makes the compiler check whether the procedure accesses any global variables.
Accessing global variables shouldn't be a problem for your application, as long as Jester (and your app) is single threaded, but once your program is using multiple threads (to serve requests in parallel for example) you will need to fix this problem.
One way to fix it is to use a {.threadvar.}: https://nim-lang.org/docs/manual.html#threads-threadvar-pragma
Hope this helps!

Is reading/writing to different elements of a module array thread-safe?

As long as a program does not allow simultaneous writes to the same elements of a shared data structure that is stored in a module, is it thread-safe? I know this is a noob question, but couldn't find it explicitly addressed anywhere. Here's the situation:
At the beginning of a program, data is initialized and stored in a module-level allocatable array (FIELDVARS) which then becomes accessible to any subroutine where the module is referenced by a USE statement.
Suppose now that the program enters a multi-threaded and/or multi-core computational phase, and FIELDVARS is accessed for "read/write" operations during repeated multiple simultaneous calls to subroutine (COMPUTE).
Once the computational phase is complete, the program returns to a single-threaded phase and FIELDVARS must be used in a subsequent subroutine (POST). However, FIELDVARS cannot be added to the input args of COMPUTE or POST because these are called from a closed-source main program. Therefore the module-level array is used to pass the addt'l data between subroutines.
Assume that FIELDVARS and COMPUTE have been designed so that each call to COMPUTE will always give access to a set of unique elements of FIELDVARS, which are guaranteed to be different than for any other call, so that simultaneous "write" operations on the same elements will never occur. For example:
[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ... ] <-- FIELDVARS
^---call 1---^ ^---call 2---^ ... <-- Each call to COMPUTE is guaranteed to access a specific set of elements of FIELDVARS.
Question: Is this scenario considered "thread-safe", "conditionally safe", or "not thread-safe"? If it is not safe, what is the specific danger and what would you suggest to handle it?
Other relevant details:
The main program controls threading.
The source code of the main program is not available and cannot be changed.
The main program controls how/when COMPUTE, POST, and other subroutines are called, as well as what args can be passed in. This is why the module-level array is used to pass data between different subroutines rather than as an arg.
! DEMO MODULE W/ ALLOCATABLE INTEGER ARRAY
module DATA_MODULE
integer, dimension(:), allocatable :: FIELDVARS !<-- allocated/populated elsewhere, prior to calling COMPUTE
end module DATA_MODULE
! DEMO COMPUTE SUBROUTINE (THREADED PHASE W/ MULTIPLE SIMULTANEOUS CALLS)
subroutine COMPUTE(x, y, x_idx, y_idx, flag)
use DATA_MODULE
logical :: flag
integer :: x,y,x_idx,y_idx !<-- different for every call to COMPUTE
if (flag == .false.) then !<-- read data only
...
x = FIELDVARS(x_idx)
y = FIELDVARS(y_idx)
...
else if (flag == .true.) then !<-- write data
...
FIELDVARS(x_idx) = 0
FIELDVARS(y_idx) = 0
...
endif
end subroutine COMPUTE
It is fine and many programs depend on that fact. In OpenMP you often loop over arrays and different threads may easily work with elements which are close to each other in memory, especially on the boundaries of the blocks assigned to each thread.
At modern CPUs this is a non-issue. See also https://en.wikipedia.org/wiki/Cache_coherence
What is a real problem is False sharing. Two or more threads working with elements of memory belonging to the same chache line will be compiting for a shared resource and it may be very slow.

Variable inside for loop not re-initialized on each iteration?

I have a C++/CLI project that declares a String^ variable inside a for loop but does not initialize it. On the first iteration, the variable is set to some value. On each subsequent
iteration, it appears to be retaining the previous value. Shouldn't a variable in local scope be initialized to null (or equivalent) each time thru the loop? This happens with an int as well. Also, the compiler
does not warn of a potentially uninitialized value unless I set the warning level to W4, and even then it only warns for the int and not the String^.
This is sample code that shows the behavior.
#include "stdafx.h"
using namespace System;
int main(array<System::String ^> ^args)
{
for(int n = 0; n < 10; n++)
{
String^ variable;
int x;
switch(n)
{
case 1:
variable = "One";
x = 1;
break;
case 5:
variable = "Five";
x = 5;
break;
}
Console::WriteLine("{0}{1}", variable, x);
}
}
The output of this will be
One, 1
One, 1
One, 1
One, 1
Five, 5
Five, 5
Five, 5
Five, 5
Five, 5
Am I completely misunderstanding how locally scoped variables are supposed to be initialized? Is this a "feature" unique to managed C++? If I convert
this to C# the compiler will warn about both variables, even at the base warning level.
Disclaimer: I know C and C++ pretty well; C++/CLI, not so much. But the behavior you're seeing is essentially the same that I'd expect for a similar program in C or C++.
String^ is a handle to a String, similar to a pointer in C or C++.
Unless C++/CLI adds new rules for initialization of handles, a block-scope variable of type String^ with no explicit initialization will initially have a garbage value, consisting of whatever happened to be in that chunk of memory.
Each iteration of the loop conceptually creates and destroys any variables defined between the { and }. And each iteration probably allocates its local variables in the same memory location (this isn't required, but there's no real reason for it not to do so). The compiler could even generate code that allocates the memory on entry to the function.
So on the first iteration of your loop, variable is set to "One" (or rather, to a handle that refers to "One"), that's the value printed by Console::WriteLine. No problem there.
On the second iteration, variable is allocated in the same memory location that was used for it on the first iteration. No new value is assigned to it, so it retains the value that was stored in that memory location on the first iteration. The same thing happens with x.
You cannot count on the previous value being retained, and your program's behavior is undefined. If your goal were to write a correctly working program, rather than to understand how this incorrect program behaves, the solution would be to ensure that all your variables are properly initialized before they're used.
If you did the initial assignment on the second iteration rather than the first, the program would likely crash on the first iteration -- though even that's not guaranteed.
As for why the compiler doesn't warn about this, I don't know. I hesitate to suggest a compiler bug, but this could be one.
Also, even with high warning levels enabled, warning about uninitialized variables requires control flow analysis that may not be done by default. Enabling both warnings and a high level of optimization might give the compiler enough information to warn about both variable and x.
It still seems odd that it warns about x and not about variable with W4.
C++/CLI is only an extension/superset of standard C++ so it complies with most of its specifications, extending it only to fit with the CLI (~.Net) requirements.
Shouldn't a variable in local scope be initialized to null (or
equivalent) each time thru the loop?
AFAIK the C++ standard does not define the way local loop variables should be initialized.
So, to avoid any overhead, compilers usually don't use specific local memory management for loops : see this SO question :
Is there any overhead to declaring a variable within a loop? (C++)
Am I completely misunderstanding how locally scoped variables are supposed to be initialized?
Is this a "feature" unique to managed C++
So no, this is not a feature or special behavior : your C++/CLI compiler is only using standard C++ practices.
If I convert this to C# the compiler will warn about both variables,
even at the base warning level.
C# and AFAIK Java try hard to avoid any undefined behaviors, so they force you to initialize local variables before they are used.
Here is the CIL resulting from the compilation (I've done some formatting and commenting to make this bunch of text understandable :)) :
.locals init (int32 V_0, int32 V_1, string V_2, int32 V_3)
// ^ ^ ^ ^
// n x variable tmp
// initialization of "n"
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0008
// loop starts here
// post iteration processing
IL_0004: ldloc.0
IL_0005: ldc.i4.1
IL_0006: add
IL_0007: stloc.0
// stop condition check
IL_0008: ldloc.0
IL_0009: ldc.i4.s 10
IL_000b: bge.s IL_003e
// initialization of temporary "tmp" variable for switch
IL_000d: ldloc.0
IL_000e: stloc.3
// check if "tmp" is 3
IL_000f: ldloc.3
IL_0010: ldc.i4.1
// if so go to "variable" intialization
IL_0011: beq.s IL_0019
// check if "tmp" is 5
IL_0013: ldloc.3
IL_0014: ldc.i4.5
IL_0015: beq.s IL_0023
// go to display
IL_0017: br.s IL_002b
// initialization of "variable"
IL_0019: ldstr "One"
IL_001e: stloc.2
...
So the variable is indeed never implicitly manipulated by the code generated by the compiler.

how can i keep variables private in subroutines which are called in a parallel section of openmp?

i am calling a nested for loop as follows:
do ir = 1,Nr
do iom = iom1, iom2
xyz(1) = xo(1) + xom(iom)*r
xyz(2) = xo(2) + yom(iom)*r
xyz(3) = xo(3) + zom(iom)*r
call FUNSUB(xyz,Nprop,PropXYZ)
enddo
enddo
where FUNSUB evaluates a property in the following manner:
id = 1
do l=0,lmax
do m=-l,l
id = id + 1
Prop(id) = RHO * Ylm(l,m,xl(1),xl(2),xl(3))
enddo
enddo
now i am trying to parallelize this with something of the form
!$OMP parallel do reduction(+:Prop) private(ir, l, m, j, iom, r, wrad, xyz, PropOm, PropOm1, PropXYZ)
where some of the other private variables seen here are left out of my example code for brevity. i am intentionally trying to make l and m private so that inside the FUNSUB loops, the properties are evaluated independently. i find, however, that they are shared between threads. i have put in some debugging options and found that id continually goes above the bounds of Prop and have found that l also goes about lmax as well as m being outside the bounds of (-l,l).
my question is: how do i go about making sure that l and m are kept private and NOT shared from the main routine? it seems that the problem is that it is an entirely different subroutine which holds these values and that, somehow these private declarations of variables do not carry over
I think your problem is that in Fortran, local subroutine variables can be static and that the !$OMP does not propagate to called functions.
Your code should work as expected if you copy-paste FUNSUB into the calling loops, i.e. if you manually inline it.
Update
After reading-up a bit on the looniness of how local variables may or may not be implemented by the compiler, I guess your best option is to declare FUNSUB as RECURSIVE. This forces all local variables onto the stack, meaning that each OpenMP thread which calls FUNSUB will have its own, private, set of local variables.
The full code of the FUNSUB would have to be investigated. Correct usage of an external function in an OpenMP region should not be a problem. There should be no reason and it is not possible to declare variables in scope of an external function as private.
Modern Fortran compilers will not create local variables of a function static, if you don't tell it to do so. This may be done using a compiler switch (big NO NO in a parallel code) or by declaring the variables as SAVE as has been save. Note that all initialized variables are SAVE implicitly. That means that:
integer :: local = 0
is SAVE even without the SAVE keyword and will be shared among threads.
It is a good practice to have all functions called in parallel declared as PURE. I am even for having all non-recursive functions at least effectively PURE.

Verilog automatic task

What does it mean if a task is declared with the automatic keyword in Verilog?
task automatic do_things;
input [31:0] number_of_things;
reg [31:0] tmp_thing;
begin
// ...
end
endtask;
Note: This question is mostly because I'm curious if there are any hardware programmers on the site. :)
"automatic" does in fact mean "re-entrant". The term itself is stolen from software languages -- for example, C has the "auto" keyword for declaring variables as being allocated on the stack when the scope it's in is executed, and deallocated afterwards, so that multiple invocations of the same scope do not see persistent values of that variable. The reason you may not have heard of this keyword in C is that it is the default storage class for all types :-) The alternatives are "static", which means "allocate this variable statically (to a single global location in memory), and refer to this same memory location throughout the execution of the program, regardless of how many times the function is invoked", and "volatile", which means "this is a register elsewhere on my SoC or something on another device which I have no control over; compiler, please don't optimize reads to me away, even when you think you know my value from previous reads with no intermediate writes in the code".
"automatic" is intended for recursive functions, but also for running the same function in different threads of execution concurrently. For instance, if you "fork" off N different blocks (using Verilog's fork->join statement), and have them all call the same function at the same time, the same problems arise as a function calling itself recursively.
In many cases, your code will be just fine without declaring the task or function as "automatic", but it's good practice to put it in there unless you specifically need it to be otherwise.
It means that the task is re-entrant - items declared within the task are dynamically allocated rather than shared between different invocations of the task.
You see - some of us do Verilog... (ugh)
The "automatic" keyword also allows you to write recursive functions (since verilog 2001). I believe they should be synthesisable if they bottom out, but I'm not sure if they have tool support.
I too, do verilog!
As Will and Marty say, the automatic was intended for recursive functions.
If a normal (i.e. not automatic) function is called with different values and processed by the simulator in the same time slice, the returned value is indeterminate. That can be quite a tricky bug to spot! This is only a simulation issue, when synthesised the logic will be correct.
Making the function automatic fixes this.
In computing, a computer program or subroutine is called re-entrant if multiple invocations can safely run concurrently (Wikipedia).
In simple words, the keyword automatic makes it safe, when multiple instances of a task run at a same time.
:D
Automatic is just opposite to static in usual programming. So is the case with Verilog. Think of static variables, they cannot be re-initialized. See the Verilog description below:
for (int i = 0; i < 3; i++) begin
static int f = 0;
f = f + 1;
end
Result of the above program will be f = 3. Also, see the program below:
for (int i = 0; i < 3; i++) begin
int f = 0;
f = f + 1;
end
The result of above program is f = 1. What makes a difference is static keyword.
Conclusion is tasks in Verilog should be automatic because they are invoked (called) so many times. If they were static (if not declared explicitly, they are static), they could have used the result from the previous call which often we do not want.

Resources