Has anyone a view on when it is better to use an OVM class verses a module (that would of course have an OVM driver) to implement verification IP?
I imagine there may be some speed improvements with a module based implementation because the compiler can better optimize something that is fixed at compile time. I am thinking here of low level items that run very often such as bit, frame or packet generators.
This used to be any easy question to answer, the testbench was a insignificant burden on the simulation - so people didn’t worry about testbench. Then testbenches started taking more than 50% of the simulation (I’ve seen up to 80%). A lot of that was due to the fact that the testbench language was being executed by a separate engine (Vera/Specman). But now SystemVerilog has removed that separation and put performance of the testbench back where it should be.
After saying all that, I will say that a dynamic reference to a bit may be more expensive then a fixed reference to a bit. Hopefully, using a higher level of abstaction will reduce the number of dynamic references to indiviual bits in your testbench.
Dave Rich
Hello everyone
This might be more of a SV question than OVM question but since this is the only SV forum I read and there are lots SV experts here, I hope someone can help me.
I’ve problems with dynamic memory allocation and seem to run out of memory when running simulations with 10-20 millions cycles (simulating with QuestaSim 6.4a). I understand that this might happen easily if you just keep allocating memory and never free it. But if I understood the SV LRM 3.1a correctly (11.6a memory management), you can free memory by assigning null value to an object handle (because allocated memory is no longer pointed by any handle and thus garbage collected). Or if the object handle goes out of scope, memory should also be garbage collected.
Is assigning null to object handle equivalent to calling free() / delete() in C/C++ or is garbage collection in SV something that might happen or not (determined by simulation tool perhaps)?
When running the following simulation, the task manager shows that memory footprint increases gradually about 1 MB/s until the simulation crashes. Is there something wrong with my code memory allocation-wise?
Thanks in advance for all the help.
Here’s a part of the code from my “testbench” along with some additional lines:
class PixelCluster extends ovm_object;
...
endclass
PixelDualTransaction extends ovm_transaction;
// only bit variables here
endclass
class PixelDualCluster extends PixelCluster;
/* For storing generated transactions. */
<font color=cyan>PixelDualTransaction share_trans[];</font>
...
endclass
module ClusterTest;
...
initial begin
for( int mean = 1; mean < 11; mean++) begin
PixelCluster pixel_cluster;
PixelDualCluster new_cluster;
new_cluster = new(, seed1, seed2);
new_cluster.set_mean_of_hits(mean);
dual_bits = 0;
packet_count_dual = 0;
for(int i = 0; i < CYCLES; i++) begin
new_cluster.clusterize_new(1);
packet_count_dual += new_cluster.share_trans.size();
foreach(new_cluster.<font color=cyan>share_trans</font>[k]) begin
dual_bits += new_cluster.share_trans[k].get_size_variable_map();
int_array = new_cluster.share_trans[k].get_coordinates();
pixel_cluster.update_check_map( result_map, int_array);
end
foreach(new_cluster.share_trans[k])
<font color=red><font color=black>new_cluster.</font><font color=cyan>share_trans</font><font color=cyan>[k]</font> = null;</font> // after this memory should be freed
<font color=red><font color=black>new_cluster.</font><font color=cyan>share_trans</font> = null;</font> // after this memory should be freed
end
pixel_cluster = new_cluster;
dual_real = dual_bits;
...
<font color=red><font color=black>pixel_cluster =</font> null; </font><font color=#000000>// after this memory should be freed</font>
<font color=red><font color=black>dual_cluster =</font> null; </font><font color=#000000>// after this memory should be freed</font>
end // for(int mean = 1 ...
endmodule: ClusterTest
tpoikela,just want to remind you that the SV 3.1a LRM is over 6 years out of date.
The precise method of garbage collection is not specified by the LRM.
Assigning a class variable to null is not equivalent to calling free(). As you quoted the LRM, all other references to an object must be gone before you can reclaim its memory. So any kind of assignment to a class variable, not just a null value, could cause all references to an object to disappear, as well as the disappearance of the class variable itself.
There are some garbage collection algorithms that do periodic sweeps of the memory allocation tables to free up memory. These sweeps need to be scheduled, and it’s possible in your simple test, you have not given the scheduler an opportunity to perform a sweep. You may have to add a #0 in you loop, or some other blocking statement.
It’s also possible that you have not removed all the references to your object, either in your own code, or within the OVM. You haven’t shown enough code for me to make that determination. Questa has a capacity analysis feature that can help you determine which class objects are not getting de-allocated.
Dave Rich
Thanks for the response Dave.
The only process I’m running is the one in my testbench, and I’m not forking any other processes inside the classes PixelCluster and PixelDualCluster which are the only instantiations I make in the testbench.
With each call to function “clusterize_new(1)”, I allocate certain amount of memory to dynamic array “share_trans”. But shouldn’t the old allocations be garbage-collected as soon as I allocate the memory again? I mean, the memory shouldn’t leak every time I allocate memory for new dynamic array which is referenced by the same object handle as the previous array was referenced. I also did the memory profiling and it seems that most of the memory is reserved by Verilog memories (~ 7GB) while QDAS reserved only 2.2 GB. I’m not sure what does this imply though.
Also I’m not using OVM’s run_test() in this testbench at all although classes I’m using are inherited from ovm_object. So I assume OVM shouldn’t create any “hidden” reference to the object?
I tried to find some information about garbage collecting from SV LRM 2007 but it seems that there’s only the same chapter as there was in 3.1a. Adding delays to code didn’t seem to have any impact on memory reservation. One thing I’ve yet to try is to include another process to code and see if the garbage collection happens at when you do context switch from a process to another one.