There might be a simple solution, but currently I cannot get my head around it. Maybe someone could help me out.
So I have the following problem:
I have in total N SAS jobs that I want to finish. As my resources on my machine are too limited to start all N jobs simultaneously, I only want to start say k = 5 at the same time. Every time one job finishes, I want to start the next one. The order in which the jobs are completed is not important.
Currently, I let all k=5 jobs finish before I start the next 5.
So here is the pseudo code, for what I am currently doing:
/*The following macro starts k threads*/
%macro parallel_processing(k);
options fullstimer autosignon=yes sascmd="sas -nonews -threads";
%global thread jj idlist;
/*These are the N ID numbers for the jobs*/
%let idlist = 1 2 3 4 5 ... N;
%let jj = 0;
%do %until(&jj.=N);
%do thread = 1 %to &k.;
%let jj = %eval(&thread.+&jj.);
%syslput thread = &thread;
%syslput jj = &jj.;
%syslput idlist = &idlist.;
rsubmit process=task&thread. wait=no sysrputsync=yes;
%let id =%scan(%trim(&idlist.),&jj.);
/*Do the job*/
%job(id);
endrsubmit;
%end;
/* HERE IS MY PROBLEM:
I want to wait for each job separately, and start a new one
with an increased id. So that constantly k threads are busy.
*/
/* Wait for all threads to finish */
waitfor _all_ %do thread = 1 %to &k.;
task&thread
%end;
/* GET RESULTS FROM THREADS */
%do thread = 1 %to (&k.);
rget task&thread;
%end;
/* SIGNOFF THREADS*/
%do thread = 1 %to (&k.);
signoff task&thread;
%end;
%end;
%mend parallel_processing;
%parallel_processing(k);
Maybe somebody has a nice idea, I would be grateful! Thank you in advance.
Use waitfor _any_ ... instead of waitfor _all_ ...:
Start the first 5 tasks, keeping a note of which 5 tasks are active.
Wait for any one of them to finish and remove it from the list of active tasks.
Start the next task from the queue and add it to the list of active tasks.
Repeat steps 2 and 3 until there are no tasks left in the queue.
You can use any method you like to keep track of which 5 tasks are currently active.
Following my previous question : Unable to implement MPI_Intercomm_create
The problem of MPI_INTERCOMM_CREATE has been solved. But when I try to implement a basic send receive operations between process 0 of color 0 (globally rank = 0) and process 0 of color 1 (ie globally rank = 2), the code just hangs up after printing received buffer.
the code:
program hello
include 'mpif.h'
implicit none
integer tag,ierr,rank,numtasks,color,new_comm,inter1,inter2
integer sendbuf,recvbuf,tag,stat(MPI_STATUS_SIZE)
tag = 22
sendbuf = 222
call MPI_Init(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD,numtasks,ierr)
if (rank < 2) then
color = 0
else
color = 1
end if
call MPI_COMM_SPLIT(MPI_COMM_WORLD,color,rank,new_comm,ierr)
if (color .eq. 0) then
if (rank == 0) print*,' 0 here'
call MPI_INTERCOMM_CREATE(new_comm,0,MPI_Comm_world,2,tag,inter1,ierr)
call mpi_send(sendbuf,1,MPI_INT,2,tag,inter1,ierr)
!local_comm,local leader,peer_comm,remote leader,tag,new,ierr
else if(color .eq. 1) then
if(rank ==2) print*,' 2 here'
call MPI_INTERCOMM_CREATE(new_comm,2,MPI_COMM_WORLD,0,tag,inter2,ierr)
call mpi_recv(recvbuf,1,MPI_INT,0,tag,inter2,stat,ierr)
print*,recvbuf
end if
end
The communication with intercommunication is not well understood by most users, and examples are not as many as examples for other MPI operations. You can find a good explanation by following this link.
Now, there are two things to remember:
1) Communication in an inter communicator always go from one group to the other group. When sending, the rank of the destination is its the local rank in the remote group communicator. When receiving, the rank of the sender is its local rank in the remote group communicator.
2) Point to point communication (MPI_send and MPI_recv family) is between one sender and one receiver. In your case, everyone in color 0 is sending and everyone in color 1 is receiving, however, if I understood your problem, you want the process 0 of color 0 to send something to the process 0 of color 1.
The sending code should be something like this:
call MPI_COMM_RANK(inter1,irank,ierr)
if(irank==0)then
call mpi_send(sendbuf,1,MPI_INT,0,tag,inter1,ierr)
end if
The receiving code should look like:
call MPI_COMM_RANK(inter2,irank,ierr)
if(irank==0)then
call mpi_recv(recvbuf,1,MPI_INT,0,tag,inter2,stat,ierr)
print*,'rec buff = ', recvbuf
end if
In the sample code, there is a new variable irank that I use to query the rank of each process in the inter-communicator; that is the rank of the process in his local communicator. So you will have two process of rank 0, one for each group, and so on.
It is important to emphasize what other commentators of your post are saying: when building a program in those modern days, use moderns constructs like use mpi instead of include 'mpif.h' see comment from Vladimir F. Another advise from your previous question was yo use rank 0 as remote leader in both case. If I combine those 2 ideas, your program can look like:
program hello
use mpi !instead of include 'mpif.h'
implicit none
integer :: tag,ierr,rank,numtasks,color,new_comm,inter1,inter2
integer :: sendbuf,recvbuf,stat(MPI_STATUS_SIZE)
integer :: irank
!
tag = 22
sendbuf = 222
!
call MPI_Init(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD,rank,ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD,numtasks,ierr)
!
if (rank < 2) then
color = 0
else
color = 1
end if
!
call MPI_COMM_SPLIT(MPI_COMM_WORLD,color,rank,new_comm,ierr)
!
if (color .eq. 0) then
call MPI_INTERCOMM_CREATE(new_comm,0,MPI_Comm_world,2,tag,inter1,ierr)
!
call MPI_COMM_RANK(inter1,irank,ierr)
if(irank==0)then
call mpi_send(sendbuf,1,MPI_INT,0,tag,inter1,ierr)
end if
!
else if(color .eq. 1) then
call MPI_INTERCOMM_CREATE(new_comm,0,MPI_COMM_WORLD,0,tag,inter2,ierr)
call MPI_COMM_RANK(inter2,irank,ierr)
if(irank==0)then
call mpi_recv(recvbuf,1,MPI_INT,0,tag,inter2,stat,ierr)
if(ierr/=MPI_SUCCESS)print*,'Error in rec '
print*,'rec buff = ', recvbuf
end if
end if
!
call MPI_finalize(ierr)
end program h
I am debugging an expect program with the traditional debugging way by passing the -D 1 flag for the following script.
#!/usr/bin/expect
proc p3 {} {
set m 0
}
proc p2 {} {
set c 4
p3
set d 5
}
proc p1 {} {
set a 2
p2
set a 5
}
p1
With the debugger command w, I am trying to see the stack frame and got the following error.
dinesh#mypc:~/pgms/expect$ expect -D 1 stack.exp
1: proc p3 {} {
set m 0
}
dbg1.0> n
1: proc p2 {} {
set c 4
p3
set d 5
}
dbg1.1>
1: proc p1 {} {
set a 2
p2
set a 5
}
dbg1.2>
1: p1
dbg1.3> s
2: set a 2
dbg2.4>
2: p2
dbg2.5>
3: set c 4
dbg3.6> w
0: expect {-D} {1} {stack.exp}
Segmentation fault (core dumped)
dinesh#mypc:~/pgms/expect$
I am having the expect version 5.45.
Is there anything wrong in my way of command execution ?
In order to achieve the debugging trace, Expect pokes its fingers inside the implementation of Tcl. In particular, it has copies of the definitions of some of the internal structures used inside Tcl (e.g., the definition of the implementation of procedures and of stack frames). However, these structures change from time to time; we don't announce such internal implementation changes, as they shouldn't have any bearing on any other code, but that's obviously not the case.
Overall, this is a bug in Expect (and it might be that the fix is for a new C API function to be added to Tcl). In order to see about fixing this, we need to know not just the exact version of Expect but also the exact version of Tcl (use info patchlevel to get this).
I want to see what functions are called in my user-space C99 program and in what order. Also, which parameters are given.
Can I do this with DTrace?
E.g. for program
int g(int a, int b) { puts("I'm g"); }
int f(int a, int b) { g(5+a,b);g(8+b,a);}
int main() {f(5,2);f(5,3);}
I wand see a text file with:
main(1,{"./a.out"})
f(5,2);
g(10,2);
puts("I'm g");
g(10,5);
puts("I'm g");
f(5,3);
g(10,3);
puts("I'm g");
g(11,5);
puts("I'm g");
I want not to modify my source and the program is really huge - 9 thousand of functions.
I have all sources; I have a program with debug info compiled into it, and gdb is able to print function parameters in backtrace.
Is the task solvable with DTrace?
My OS is one of BSD, Linux, MacOS, Solaris. I prefer Linux, but I can use any of listed OS.
Here's how you can do it with DTrace:
script='pid$target:a.out::entry,pid$target:a.out::return { trace(arg1); }'
dtrace -F -n "$script" -c ./a.out
The output of this command is like as follows on FreeBSD 14.0-CURRENT:
dtrace: description 'pid$target:a.out::entry,pid$target:a.out::return ' matched 17 probes
I'm g
I'm g
I'm g
I'm g
dtrace: pid 39275 has exited
CPU FUNCTION
3 -> _start 34361917680
3 -> handle_static_init 140737488341872
3 <- handle_static_init 2108000
3 -> main 140737488341872
3 -> f 2
3 -> g 2
3 <- g 32767
3 -> g 5
3 <- g 32767
3 <- f 0
3 -> f 3
3 -> g 3
3 <- g 32767
3 -> g 5
3 <- g 32767
3 <- f 0
3 <- main 0
3 -> __do_global_dtors_aux 140737488351184
3 <- __do_global_dtors_aux 0
The annoying thing is that I've not found a way to print all the function arguments (see How do you print an associative array in DTrace?). A hacky workaround is to add trace(arg2), trace(arg3), etc. The problem is that for nonexistent arguments there will be garbage printed out.
Yes, you can do this with dtrace. But you probably will never be able to do it on linux. I've tried multiple versions of the linux port of dtrace and it's never done what I wanted. In fact, it once caused a CPU panic. Download the dtrace toolkit from http://www.brendangregg.com/dtrace.html. Then set your PATH accordingly. Then execute this:
dtruss -a yourprogram args...
Your question is exceedingly likely to be misguided. For any non-trivial program, printing the sequense of all function calls executed with their parameters will result in multi-MB or even multi-GB output, that you will not be able to make any sense of (too much detail for a human to understand).
That said, I don't believe you can achieve what you want with dtrace.
You might begin by using GCC -finstrument-functions flag, which would easily allow you to print function addresses on entry/exit to every function. You can then trivialy convert addresses into function names with addr2line. This gives you what you asked for (except parameters).
If the result doesn't prove to be too much detail, you can set a breakpoint on every function in GDB (with rb . command), and attach continue command to every breakpoint. This will result in a steady stream of breakpoints being hit (with parameters), but the execution will likely be at least 100 to 1000 times slower.
Can anyone help me in understanding how this will created 19 process?
Main()
{
Fork();
Fork() && fork () || fork ();
Fork ();
}
Try to draw a tree of the process creation and study/remember the following points:
P1. fork() returns the pid (which is bigger tan 0) to the current process
and returns 0 in the child process.
P2. you will need to know how the
expression A() && B() || C() is evaluated; for example if A() returns
0 (false) function B will not get evaluated because 0 && whatever is
always 0.
Now, let's label the calls to for ease of reference:
Main()
{
Fork() /*[1]*/;
Fork() /*[2]*/ && fork ()/*[3]*/ || fork ()/*[4]*/;
Fork ()/*[5]*/;
}
I will draw the first level of process creation (and a bit of second level):
[0]
/ / \ \
[1] [2] [3] [5]
/ | \
[2] [3] [5]
The above tree means process [0] (the initial process) will execute the fork() function numbered 1, 2, 3, and 5. Why didn't process [0] run fork()[4]? Because fork()[2] && fork[3] evaluate to true already, so no point to evaluate fork()[4].
Apply similar concept to the process forked by fork[1] on the second level to see why process fork[4] was not called.
You can complete the process creation tree by applying P1 and P2 at each level of the process creation tree.
Remember that fork has a return value, either 0 or a PID (can't remember if the child gets the PID or the parent). So the && and || operators will evaluate to true when a PID is returned in which case some more processes will be forked. Hope that helps