How can I use foreach and fork together to do something in parallel?

Kaushal Modi picture Kaushal Modi · Nov 5, 2013 · Viewed 10.6k times · Source

This question is not UVM specific but the example that I am working on is UVM related. I have an array of agents in my UVM environment and I would like to launch a sequence on all of them in parallel.

If I do the below:

foreach (env.agt[i])
  begin
    seq.start(env.agt[i].sqr);
  end

, the sequence seq first executes on env.agt[0].sqr. Once that gets over, it then executes on env.agt[1].sqr and so on.

I want to implement a foreach-fork statement so that seq is executed in parallel on all agt[i] sequencers.

No matter how I order the fork-join and foreach, I am not able to achieve that. Can you please help me get that parallel sequence launching behavior?

Thanks.

Update to clarify the problem I am trying to solve: The outcome of the below code constructs is the exact same as above without the fork-join.


foreach (env.agt[i])
  fork
    seq.start(env.agt[i].sqr);
  join


fork
  foreach (env.agt[i])
    seq.start(env.agt[i].sqr);
  join


// As per example in § 9.3.2 of IEEE SystemVerilog 2012 standard
for (int i=0; i<`CONST; ++i)
  begin
    fork
      automatic int var_i = i;
      seq.start(env.agt[var_i].sqr);
    join
  end

Answer

Greg picture Greg · Nov 5, 2013

The issue is each thread of the fork is pointing to the same static variable i. Each thread needs its own unique copy and this can be achieved with the automatic keyword.

foreach (env.agt[i])
  begin
    automatic int var_i = i;
    fork
      seq.start(env.agt[var_i].sqr);
    join_none // non_blocking, allow next operation to start
  end
wait fork;// wait for all forked threads in current scope to end

IEEE std 1800-2012 § 6.21 "Scope and lifetime" gives examples of the uses static and automatic. Also check out § 9.3.2 "Parallel blocks", the last example shows demonstrates parallel threads in a for-loop.

Use join_none to create new threads; § 9.3.2 "Parallel blocks", Table 9-1—"fork-join control options".

Use fork wait statement to wait for all threads in the current scope to complete; § 9.6.1 "Wait fork statement"


Example:

byte a[4];
initial begin
    foreach(a[i]) begin
        automatic int j =i;
        fork
            begin
                a[j] = j;
                #($urandom_range(3,1));
                $display("%t :: a[i:%0d]:%h a[j:%0d]:%h",
                        $time, i,a[i], j,a[j]);
            end
        join_none // non-blocking thread
    end
    wait fork; // wait for all forked threads in current scope to end
    $finish;
end

Outputs:

2 :: a[i:4]:00 a[j:3]:03
2 :: a[i:4]:00 a[j:0]:00
3 :: a[i:4]:00 a[j:2]:02
3 :: a[i:4]:00 a[j:1]:01