I’d like to fork threads in a loop. So I use the classical approach:
for(int index=0;index<14;index++)begin
automatic int idx=index;
fork
begin
`ovm_do_on(sequence_inst,p_sequencer.my_sqr[idx]);
end
join_none;
end
And it works fine, except that I’d like to use “join” (all) instead of “join_none” since I have to wait for all the sequences to be completed before continuing the test case.
When I use “join”, it looks like the sequences are not forked, but launched one after the other…
Any idea why it behaves like this?
I’ve fixed this by unfolding the loop into a big fork and it works fine, but I’m really curious why the use of “join” in this loop breaks the parallelization.
Because fork/join is a blocking statement, only the statements inside the fork/join are executed in parallel.
What you need to do add a wait fork statement after the for loop. This block the current thread until all child threads have completed. You have to be careful if there are any other earlier fork_join_none statements that you do not want to wait for them to finish. If there are, the you need to create an isolating thread.
fork
begin : isolating_thread
for(int index=0;index<14;index++)begin : for_loop
fork
automatic int idx=index;
begin
`ovm_do_on(sequence_inst,p_sequencer.my_sqr[idx]);
end
join_none;
end : for_loop
wait fork;
end : isolating_thread
join
Dave :
I would like to know the purpose of using “wait fork” here ?
do you think fork/join actually already take care of wait fork? or it has to do something about child seqs of sequence_inst in Andreas38’s example?
thanks in adv
The wait fork suspends the parent sequence (or test) until all the child sequences (processes) have completed. There reason you can’t just use fork/join is because of the outer for_loop used to spawn each sequence (process) with a fork statement. If you used a fork/join, then each iteration of the loop would be blocked until the sequence completed, and the fork/join is not really doing anything different than a begin/end.
Thanks Dave. I am afraid i still dont fully understand the usage of wait fork here. :(
I copied your code below, I understand that using fork/join_none inside of for-loop, and using fork/join(first line and last line of your code) to wait all threads created by for-loop to be completed, but i dont understand why there is still a wait fork statement befor join, does the fork/join ( first line and last line of your code ) already wait for all threads to be completed?
thank you
fork
begin : isolating_thread
for(int index=0;index<14;index++)begin : for_loop
fork
automatic int idx=index;
begin
`ovm_do_on(sequence_inst,p_sequencer.my_sqr[idx]);
end
join_none;
end : for_loop
wait fork;
end : isolating_thread
join
A fork/join blocks until all direct child threads to complete. A fork/join block does not wait for its grandchildren threads to complete unless a child thread is blocked waiting for a grandchild thread.
In the example above there is only one child thread of the outerfork/join, the isolating_thread begin/end block. Without the wait fork statement, the isolating_thread would not block waiting for the grandchildren threads spawned by the fork/join_none inside the for loop.
Now the reason for the outer fork/join block is a bit trickier to explain, since we are only showing a fragment of code.
The wait fork statement blocks until all child threads of the current parent thread complete. We do not know if there were any other fork/join_none statements that came before this code snippet that we do not want to wait for, The isolating thread creates thread layer that guarantees that we only block waiting for the child threads of the isolating_thread.
In these examples, the automatic variable is declared before the fork. In most other examples I have seen it inside the Fork. Are both equivalent? Before forking feels as if the variable isn’t really belonging to the forked thread?
You are correct. There needs to be a separate idx variable for each invocation of the fork/join_none. I overlooked this since it was not the main point of the original question. I have edited the example.
Is it possible to do something similar, but accomplish join_any behavior instead of join_all? All examples that I have seen on this topic always use the “wait fork” statement.
I am interested in starting multiple threads in parallel and joining them when just one completes. In particular, I want to wait for just one of any events to occur. I have tried a few variations of the following example, but without success.
Any help would be greatly appreciated. Thanks!
JH
fork
begin
foreach(my_cbs[i]) begin // loop through an array of callbacks
fork
automatic int var_i = i;
begin
@(my_cbs[var_i].change_event); // wait for an event triggered within the callback
end
join_none
end
end
join_any
begin
event just_one_of any;
foreach(my_cbs[i]) // loop through an array of callbacks
fork
int var_i = i;
begin
@(my_cbs[var_i].change_event); // wait for an event triggered within the callback
-> just_one_of_any;
end
join_none
@just_one_of_any;
end
If I have two for-loop, how to handle it ? Is below code correct ?
fork
begin : isolating_thread
for(int index=0;index<14;index++)begin : for_loop
fork
automatic int idx=index;
for(int j=0;j<14;j++)begin
automatic int jdx=j;
begin
`ovm_do_on(sequence_inst,p_sequencer.my_sqr[idx][jdx]);
end
join_none;
end : for_loop
wait fork;
end
end : isolating_thread
join
In reply to dave_59:
Hi Dave,
If I have two for-loop, how to handle it ? Is below code correct ?
fork
begin : isolating_thread
for(int index=0;index<14;index++)begin : for_loop
fork
automatic int idx=index;
for(int j=0;j<14;j++)begin
automatic int jdx=j;
begin
`ovm_do_on(sequence_inst,p_sequencer.my_sqr[idx][jdx]);
end
join_none;
end : for_loop
wait fork;
end
end : isolating_thread
join
That should work, not sure you need that second automatic variable assignment for j, but it shouldn’t hurt.
I just ran into this problem yesterday… great thread… I totally missed the part about the automatic variable for the fork.