30 uvm_comparer comparer;
41 `uvm_component_utils_begin(cl_scb_test_queue_find_vs_search)
43 `uvm_component_utils_end
48 constraint co_indices {
50 indices[i] inside{[0:N-1]};
58 function new(
string name =
"cl_scb_test_queue_find_vs_search", uvm_component parent = null);
59 super.new(name, parent);
68 extern virtual function void pre_build();
69 extern task run_phase(uvm_phase phase);
71 extern function void compare_iterator_and_find_first();
72 extern function void compare_msw();
73 extern function void compare_msw_approaches(
int n,
int m,
int msw,
int num_iter, ref real results[$]);
74 extern function bit compare_items(uvm_object primary_item, uvm_object sec_item);
75 extern function void log_time(
string fname);
76 extern function real get_time_diff(
string file1,
string file2);
80 function void cl_scb_test_queue_find_vs_search::pre_build();
83 this.syoscb_cfgs.syoscb_cfg[0].set_enable_no_insert_check(1
'b0); 84 endfunction: pre_build 86 task cl_scb_test_queue_find_vs_search::run_phase(uvm_phase phase); 87 phase.raise_objection(this); 88 super.run_phase(phase); 90 this.compare_iterator_and_find_first(); 91 // Commented out on purpose: This test takes a long time to run, 92 // and does not contribute anything to regression testing. 93 // Uncomment and run manually where necessary 94 // this.compare_msw(); 96 phase.drop_objection(this); 99 //Gets current time, stores it in the file named "fname" 100 function void cl_scb_test_queue_find_vs_search::log_time(string fname); 101 $system($sformatf("date -Ins > %0s.time", fname)); 102 endfunction: log_time 104 // Wrapper around compare_msw_approaches for storing results between runs 105 function void cl_scb_test_queue_find_vs_search::compare_msw(); 107 //AA of all different N, M, MSW values 111 //For all tests: M=50, num_iter=50 112 real test_results[int][int][int]; 116 Nvals = '{100, 1000, 5000};
117 msw =
'{2, 4, 6, 8, 10}; 119 foreach(Nvals[i]) begin 120 foreach(msw[j]) begin 122 compare_msw_approaches(Nvals[i], 50, Nvals[i]/msw[j], 20, results); 123 test_results[Nvals[i]][msw[j]][0] = results[0]; 124 test_results[Nvals[i]][msw[j]][1] = results[1]; 125 test_results[Nvals[i]][msw[j]][2] = results[2]; 129 foreach(test_results[i,j,k]) begin 130 $display("test_results[%0d][%0d][%0d]=%f", i, j, k, test_results[i][j][k]); 132 endfunction: compare_msw 134 // Compares different approaches to finding items when max_search_window is non-zero 135 // Approach 1: Use an iterator to search over the queue instead of using find_first 136 // Approach 2: Use find_first, but if the found index is greater than msw, return null instead 137 // Approach 3: Copy the underlying queue, use SV queue-slicing to create a new queue with data from an old queue 138 function void cl_scb_test_queue_find_vs_search::compare_msw_approaches(int n, int m, int msw, int num_iter, ref real results[$]); 139 real sum_approach1, sum_approach2, sum_approach3; //sum of times for each approach 140 bit should_be_found[$]; //Indicates whether a given item should be found. Used for error checking 141 cl_syoscb_item items[$]; //All N items in the queue 142 cl_syoscb_item search_items[$]; //The M items we are searching for 148 //Reassigning to class variables to easily randomize indices 152 $display("Testing MSW approaches with N=%0d, msw=%0d", n, msw); 153 for(int iter=0; iter<num_iter; iter++) begin 154 search_items.delete(); 155 should_be_found.delete(); 156 //items is not deleted since it points to the SV queue used in scoreboard 158 //Generate the items to search for 159 for(int i=0; i<n; i++) begin 160 cl_tb_seq_item ctsi = cl_tb_seq_item::type_id::create($sformatf("ctsi_%0d", i)); 161 if(!ctsi.randomize()) begin 162 `uvm_fatal("RAND", $sformatf("Unable to randomize ctsi %0d on iteration %0d", i, iter)); 164 this.scb_env.syoscb[0].add_item("Q1", "P1", ctsi); 167 //Get handle to the underlying queue 169 cl_syoscb_queue_std queue_std; 170 cl_syoscb_queue_base queue_base; 172 queue_base = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q1"); 173 if(!$cast(queue_std, queue_base)) begin 174 `uvm_fatal("CAST", "Unable to cast Q1 to queue_std") 176 queue_std.get_native_queue(items); 179 //Generate the M indices that we wish to search for, store those M items in search_items 180 //If that items index is outside of range, set should_be_found to 0 181 void'(randomize(indices));
182 foreach(indices[i]) begin
183 search_items.push_back(items[indices[i]]);
184 if(indices[i] < msw) begin
185 should_be_found.push_back(1
'b1); 187 should_be_found.push_back(1'b0);
197 iter = this.syoscb_cfgs.syoscb_cfg[0].get_queue(
"Q1").create_iterator();
198 log_time(
"a1_start");
199 foreach(search_items[i]) begin
202 while(iter.has_next() && iter.next_index() < msw) begin 204 sec_item = proxy.get_item(); 205 if(this.compare_items(search_items[i], sec_item)) begin 206 //if match, verify that the code isn't sloppy. If not,
break out, look
for next item
207 if(!should_be_found[i]) begin
208 `uvm_fatal(
"APPROACH1", $sformatf(
"Iterator found item where it shouldn't. idx=%0d, msw=%0d", iter.previous_index(), msw))
216 void'(this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q1").delete_iterator(iter));
222 log_time("a2_start");
223 foreach(search_items[i]) begin
224 found = items.find_first_index(x) with (this.compare_items(x, search_items[i]));
225 if(found.size() != 1) begin
226 `uvm_fatal("APPROACH2", $sformatf("Unable to find match for search item %0d. found.size=%0d", i, found.size()))
238 log_time("a3_start");
239 foreach(search_items[i]) begin
240 subqueue = items[0:msw-1];
241 found = subqueue.find_first_index(x) with (this.compare_items(x, search_items[i]));
242 if(found.size() == 1 && !should_be_found[i]) begin
243 `uvm_fatal("APPROACH3", $sformatf("Found search_item[%0d] but was not supposed to find it. Iter=%0d, found.size()=%0d", i, iter, found.size()))
244 end else if (found.size() != 1 && should_be_found[i]) begin
245 `uvm_fatal("APPROACH3", $sformatf("Did not find search_item[%0d] but was supposed to find it. Iter=%0d, found.size=%0d", i, iter, found.size()))
251 sum_approach1 += get_time_diff("a1_start", "a1_end");
252 sum_approach2 += get_time_diff("a2_start", "a2_end");
253 sum_approach3 += get_time_diff("a3_start", "a3_end");
254 this.scb_env.syoscb[0].flush_queues_all();
255 $display("Iteration %0d/%0d finished", iter+1, num_iter);
259 results.push_back(sum_approach1);
260 results.push_back(sum_approach2);
261 results.push_back(sum_approach3);
262 endfunction: compare_msw_approaches
271 cl_tb_seq_item items[$];
272 cl_tb_seq_item search_items[$];
279 $display("Comparing iterator and find_first performance. N=%0d", this.N);
280 for(
int iter=0; iter<num_iter; iter++) begin
283 proxy_items.delete();
284 search_items.delete();
287 for(
int i=0; i<N; i++) begin
288 cl_tb_seq_item ctsi = cl_tb_seq_item::type_id::create($sformatf("ctsi_%0d", i));
289 if(!ctsi.randomize()) begin
290 `uvm_fatal("RAND", $sformatf("Unable to randomize ctsi %0d", i))
293 items.push_back(ctsi);
294 this.scb_env.syoscb[0].add_item("Q1", "P1", ctsi);
298 void'(randomize(indices));
299 foreach(indices[i]) begin
301 proxy.idx = indices[i];
302 proxy.set_queue(this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q1"));
304 proxy_items.push_back(proxy);
305 search_items.push_back(items[indices[i]]);
310 foreach(search_items[i]) begin
311 q = items.find_first with (this.compare_items(item, search_items[i]));
312 if(q.size() != 1) begin
313 `uvm_fatal("FIND_FIRST", $sformatf("find_first did not find the requested search item. q.size=%0d", q.size()))
321 foreach(proxy_items[i]) begin
327 queue = this.syoscb_cfgs.syoscb_cfg[0].get_queue("Q1");
328 iter = queue.get_iterator("default");
329 if(iter == null) begin
330 iter = queue.create_iterator("default");
335 while(iter.has_next()) begin
336 if(compare_items(proxy_items[i].get_item(), iter.next().get_item())) begin
343 `uvm_fatal("ITERATOR", $sformatf("Unable to find match for proxy_items[%0d]", i))
348 sum_findfirst += get_time_diff("time1", "time2");
349 sum_iterator += get_time_diff("time3", "time4");
352 this.scb_env.syoscb[0].flush_queues_all();
353 $display("Iteration %0d/%0d finished", iter+1, num_iter);
356 $display("num_iter: %0d, N=%0d, M=%0d", num_iter, this.N, this.M);
357 $display("Sum of FF times: %f. Avg of FF times: %f", sum_findfirst, sum_findfirst/real'(num_iter));
358 $display("Sum of iterator times: %f. Avg of iterator times: %f", sum_iterator, sum_iterator/real'(num_iter));
360 endfunction: compare_iterator_and_find_first
368 f1 = $fopen($sformatf("%0s.time", file1), "r");
369 f2 = $fopen($sformatf("%0s.time", file2), "r");
371 void'($fgets(s1, f1));
372 void'($fgets(s2, f2));
376 s1 = s1.substr(17, 28);
377 s2 = s2.substr(17, 28);
394 endfunction: get_time_diff
399 if (primary_item.compare(sec_item, this.comparer)) begin
400 `uvm_info("DEBUG", $sformatf(" Secondary item found"), UVM_FULL);
405 endfunction: compare_items
A test comparing the performance of using iterators vs using .find_first on a SV queue.
static void set_verbosity(uvm_comparer comparer, int unsigned cv=UVM_DEBUG)
Sets the verbosity level of a given comparer.
The UVM scoreboard item which wraps uvm_sequence_item .
Base class for all proxy items.
Queue iterator base class defining the iterator API used for iterating over queues.
Class which represents the base concept of a queue.
Proxy item implementation for standard queues.