Fork within loop with join ALL

In reply to jhardy:
Yes. If this code is inside a class, then it is already automatic by default.

In reply to theketi:
i < 8 has to fail in order to end the loop. So i will be 8 after exiting the loop.

In reply to dave_59:

Hello Dave,
I am trying to run below code :


        my_seq = new[2];
        fork 
            begin : isolating_thread
              for(int index=0;index<2;index++) begin : for_loop
                  automatic int idx=index;
                  automatic int local_qd=$urandom_range(1,4);
                  fork
                      `uvm_do_with(my_seq[idx],
                                    {
                                     qd           == local_qd;
                                    })
                  join_none;
              end : for_loop
            wait fork;
            end : isolating_thread
        join

I am getting below Error :

=======================================================
Solver failed when solving following set of constraints
integer qd = 0;
integer local_qd = 4;
constraint WITH_CONSTRAINT // (from this) (constraint_mode = ON) (<File_path>:233)
{
(qd == local_qd);
}
=======================================================

Can you please help me with this ?? Thanks a lot in advance.

  • Biren

In reply to birenkumar:

This likely has nothing to do with a fork statement. Maybe you did not declare qd as rand.

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


In reply to zz8318:

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.

In reply to dave_59:

With respect to the fork and join ALL inside for loop, I have a very basic question regarding the same.


for (i = 0; i<3;i++) begin
    automatic int j = i;
    fork 
       $display(j);
    join
end

Will the output for the above code will be :
0
1
2
???

In reply to SanjanaDhiran:

A fork/join with one statement behaves just like a begin/end block as far as your example is concerned.

In reply to dave_59:

Hie Dave,
Thank you for responding. However, I am still a little confused. Will my output be :
0
1
2
??

In reply to SanjanaDhiran:

Are you able to try it your self? There is always www.edaplayground.com

In reply to dave_59:

Hi Dave,

I have a question here.

Is there any different between below two snippet of code ? (The different code is pointed out with comment)
I have thread_A() which is an isolated thread, and thread_B(i) which is parameterized with forloop variable, and another thread_C() in my code. I want all thread_B(i) are spawned in parallel and start the thread_C() when all of them finished. and above process is regarded as a whole thread, and run with thread_A in parallel. One of them finished then disable all others.


        fork
            thread_A();
            begin
                fork   // here is difference
                    for (int i = 0; i < 8; i++) begin
                        fork
                            automatic int j = i;
                            thread_B(j);
                        join_none
                    end
                    wait fork;
                join    // here is difference
                thread_C();
            end
        join_any
        disable fork;


        fork
            thread_A();
            begin
                for (int i = 0; i < 8; i++) begin
                    fork
                        automatic int j = i;
                        thread_B(j);
                    join_none
                end
                wait fork;
                thread_C();
            end
        join_any
        disable fork;

In reply to zz8318:

The wait fork waits for all child processes of the current thread to terminate. In your first example, any process created by thread_A are cousins, not children of the current thread. In your second example, any process created by thread_A are children of the current thread.

In reply to dave_59:

Hi Dave,

How to determine which thread is current thread ?

and which one is correct to meet the requirement I mentioned in my last post ?

In reply to zz8318:

By current thread I mean from the perspective of the thread executing the wait fork statement. You should have enough information to make the correct decision.

module abc;

    task thread_A();
        #100;
    endtask

    task thread_B(int j);
        #2;
    endtask

    task thread_C();
        #30;
    endtask

    initial begin

        fork
            thread_A();
            begin
                fork   // here is difference
                    for (int i = 0; i < 8; i++) begin
                        fork
                            automatic int j = i;
                            thread_B(j);
                        join_none
                    end
                    wait fork;
                join    // here is difference
                thread_C();
            end
        join_any
        $display($time);
        disable fork;
    end 
    
    initial begin
        fork
            thread_A();
            begin
                for (int i = 0; i < 8; i++) begin
                    fork
                        automatic int j = i;
                        thread_B(j);
                    join_none
                end
                wait fork;
                thread_C();
            end
        join_any
        $display($time);
        disable fork;
    end
    
endmodule

Dave, can you help me with understanding the above example.
the first initial block is printing #30, expecting it to be 32 (thread_B + thread_C).
the second initial block is printing #32, expecting it to be 102 (thread_A + thread_B + thread_C) bcz of the “wait fork” inside the begin-end.

In reply to yourcheers:

These are valid results. Let me try to explain.


    // 1st initial block
    initial begin
        fork : fork_1
            thread_A();   // Thread 1 of fork_1
            begin  // Thread 2 of fork_1
                fork : fork_2  
                    for (int i = 0; i < 8; i++) begin //Thread 1 of fork_2
                        fork : fork_3
                            automatic int j = i;
                            thread_B(j);
                        join_none : fork_3
                    end
                    wait fork;  //Thread 2 of fork_2
                join : fork_2   
                thread_C();
            end
        join_any : fork_1
        $display($time);
        disable fork;
    end 

 //"wait fork;" is Thread 2 of fork_2. Thread 1 and Thread 2 are executing in parallel.  
 //None of the fork process were active during the execution of wait_fork. so it won't wait. so, Thread 2 finish at 0. 
 // Thread 1 will also finish in 0 time. Due to fork join_none (fork_3) 

    // fork_1
         //thread_A();  -> #100
         //begin _end  -> #30
    // join_any
    so, $display prints #30.

---------------------------------------------------------------------------------------
    //if you add begin....end fork 2 then you will see different 
    initial begin
        fork : fork_1
            thread_A();   // Thread 1 of fork_1
            begin  // Thread 2 of fork_1
                fork : fork_2  
                    begin /// ***Change***  //only Thread of fork_2
                        for (int i = 0; i < 8; i++) begin 
                            fork : fork_3
                               automatic int j = i;
                               thread_B(j);
                            join_none : fork_3
                        end
                    wait fork; 
                    end/// ***Change***
                join : fork_2   
                thread_C();
            end
        join_any : fork_1
        $display($time);
        disable fork;
    end 


    //2nd initial block
    initial begin
        fork : fork_1
            thread_A();  //Thread 1 of fork_1
            begin  //Thread 2  of fork_1
                for (int i = 0; i < 8; i++) begin
                    fork : fork_3
                        automatic int j = i;
                        thread_B(j);
                    join_none : fork_3
                end
                wait fork;  // wait for fork_3 to finish 
                thread_C();
            end
        join_any : fork_1
        $display($time);
        disable fork;
    end

   // It have 2 Thread 
   // Thread 1 execution time is #100 which is thread_A() execution time
   // Thread 2 execution time is #32 which is thread_B()+thread_C() execution time
   //fork...join_any will wait for any one of the thread to finish. so, it display #32
 


https://www.linkedin.com/in/patel-rahulkumar/

In reply to dave_59:

In reply to zz8318:
The wait fork waits for all child processes of the current thread to terminate. In your first example, any process created by thread_A are cousins, not children of the current thread. In your second example, any process created by thread_A are children of the current thread.

in the second example, as per Dave’s explanation, thread_A is children of current thread, and shouldn’t “wait-fork” wait for thread_A ?

In reply to dave_59:

In reply to jhardy:

begin
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
end

I’m not sure if this was asked, but can there be multiple threads within the inner fork/join_none? If so, does this require multiple wait fork commands?

begin
fork 
  begin : isolating_thread
    for(int index=0;index<4;index++)begin : for_loop
      fork
      automatic int idx=index;
        begin
            ...
        end
        begin
            ...
        end
      join_none;
    end : for_loop
  wait fork;
  end : isolating_thread
join
end

In reply to Robert.Lanier:

wait fork waits for ALL immediate children of the current thread to terminate. It doesn’t matter how the child threads are spawned; multiple statements in a single fork or multiple forks.

In reply to dave_59:

In reply to Robert.Lanier:
wait fork waits for ALL immediate children of the current thread to terminate. It doesn’t matter how the child threads are spawned; multiple statements in a single fork or multiple forks.

If we want to use a for loop within a fork to run a sequence(s) multiple times consecutively, I wouldn’t want to use the wait fork command since I want to wait for first sequence to complete before starting the second. Is a disable fork needed in this case?