UVM End of test Objection Mechanism and Phase Ready to End Implementation - system-verilog

I am exploring different ways to end a UVM test. One method that has come often from studying different blogs from Verification Academy and other sites is to use the Phase Ready to End. I have some questions regarding the implementation of this method.
I am using this method in scoreboard class, where my understanding is after my usual run phase is finished, it will call the phase ready to end method and implement it. The reason I am using it my scoreboard's run_phase finishes early, and there are some data into queues that need to be processed. So I am trying to prolong this scoreboard run_phase using this method. Here are is some pseudo-code that I have used.
function void phase_ready_to_end(uvm_phase phase);
if (phase.get_name() != "run") return;
if (queue.size() != 0) begin
phase.raise_objection(.obj(this));
fork
begin
delay_phase(phase);
end
join_none
end
endfunction
task delay_phase(uvm_phase phase);
wait(queue.size() == 0);
phase.drop_objection(.obj(this));
endtask
I have taken inspiration for this implementation from this link UVM-End of Test Mechanism for your reference. Here are some of the ungated thoughts in my mind on which I need guidance and help.
to the best of my understanding the phase_ready_to_end is called at the end of run_phase and when it runs it raises the objection for that scoreboard run_phase and runs delay_phase task.
That Delay Phase task is just waiting for the queue to end, but I am not seeing any method or task which will pop the items from the queue. Does I have to call some method to pop from the queue or as according to the 1st point above the raised objection will start the run phase so there is no need for that and we have to wait for a considerable amount of time?
Let me give you some pre-context to this question. I have a scoreboard where there are two queues whose write methods are implemented and they are being fed correctly by their source.
task run_phase (uvm_phase phase);
forever begin
compare_queues(); // this method takes data from two queues and compares them, both queues implementation are fine and they take data from their respective sources. Let me give you a scenario, let's suppose there are a total of 10 transactions being generated but the scoreboard was able to process only 6 of them and there are 4 transactions left when all objections are dropped. So to tackle that I implement this phase_to_ready_end method in my scoreboard.
end
endtask
The problem with this method that I am having is that, when I raise the objection in this phase_ready_to_end and call delay_phase method, nothing happens. And I am curious is there more to this implementation or not?
Sorry for the delay. I have shared more context to the existing question. Please see to that, let me know if it is confusing.
We have a pair of monitors that calls write method implemented inside the scoreboard. The monitors typically capture the transaction from BUS and call these WR methods to push the transactions. Thus two source and destination monitors WR into two - source and destination - queues as and when they find the transactions.
We have a checker task with RD-n-check running in forever loop in the run-phase of scoreboard. It's in a while loop and watches if the destination queue has non-zero entry. Once it finds so, it pops the head entry from destination queue and then pops the head entry from source queue as well and compares the two entries to declare if the check was a PASS or FAIL.
There are more than 2 queues and more than a pair of source/destination of course, but broadly this is the architecture around here.
Now in the current scenario, it seems that the checker tasks stop prints after certain point of time in some of the test cases. Upon adding debug prints thoroughly, it seems that checker tasks that does the job #2/#3 above and gets called inside the forever loop of the run-phase, exits gracefully one last time. However they are entered again - which is to say that the forever loop that should be calling them didn't call. As if the forever loop of run-phase stopped completely.
We also added another forever loop in run-phase that observes whether the queues are empty. From prints inside that parallel loop and from the monitor prints, we know that the queues aren't empty and monitors did push WRs into the queues for a long time.
It seems that the forever loop stopped working suddenly ( going by prints spewed out) all of a sudden but another set of threads that we added in runphase in another forever loop just to monitor those queues - keep printing that the queues have contents. So run-phase shouldn't be over but the checker tasks running in forever has stopped.
We are using Vivado 2020.2 for the simulation. This is a baffling/weird problem for us and we did go through prints multiple times to make sure nothing has been missed out. It seems we are missing very very basic or has hit a bug/broken some basics of UVM coding to land into here.
If you have any help, thoughts here, will appreciate that greatly.

The function phase_ready_to_end() gets called at the end of every task-based phase when all objections have been dropped (or never raised at all).
Typically a scoreboard has a queue or some kind of array of transactions waiting to be checked sent from a monitor via an analysis_port write() method. If your scoreboard is an in-order comparison checker, the queue size is zero when there are no more transactions waiting to be received.
If you look at the code in the link you shared, there is the following in the write_south method doing exactly that:
if (!item.compare(item_stream.pop_front()))

Related

How mutex guarantee ownership in freeRTOS?

I'm playing with Mutex in freeRTOS using esp32. in some documents i have read that mutex guarantee ownership, which mean if a thread (let's name it task_A) locks up a critical resource (take token) other threads (task_B and task_C) will stay in hold mode waiting for that resource to be unlocked by the same thread that locked it up(which is task_A). i tried to prove that by setting up the other tasks (task_B and task_C) to give a token before start doing anything and just after that it will try to take a token from the mutex holder, which is surprisingly worked without showing any kid of error.
Well, the method i used to verify or display how things works i created a display function that read events published (set and cleared) by each task (when it's in waiting mode it set the waiting bit up if it's working it will set the working bit up etc..., you get the idea). and a simple printf() in case of error in take or give function ( xSemaphoreTake != true and xSemaphoreGive != true).
I can't use the debug mode because i don't have any kind of micro controller debugger.
This is an example of what i'm trying to do:
i created many tasks and each one will call this function but in different time with different setup.
void vVirtualResource(int taskId, int runTime_ms){
int delay_tick = 10;
int currentTime_tick = 0;
int stopTime_tick = runTime_ms/portTICK_PERIOD_MS;
if(xSemaphoreGive(xMutex)!=true){
printf("Something wrong in giving first mutex's token in task id: %d\n", taskId);
}
while(xSemaphoreTake(xMutex, 10000/portTICK_PERIOD_MS) != true){
vTaskDelay(1000/portTICK_PERIOD_MS);
}
// notify that the task with <<task id>> is currently running and using this resource
switch (taskId)
{
case 1:
xEventGroupClearBits(xMutexEvent, EVENTMASK_MUTEXTSK1);
xEventGroupSetBits(xMutexEvent, EVENTRUN_MUTEXTSK1);
break;
case 2:
xEventGroupClearBits(xMutexEvent, EVENTMASK_MUTEXTSK2);
xEventGroupSetBits(xMutexEvent, EVENTRUN_MUTEXTSK2);
break;
case 3:
xEventGroupClearBits(xMutexEvent, EVENTMASK_MUTEXTSK3);
xEventGroupSetBits(xMutexEvent, EVENTRUN_MUTEXTSK3);
break;
default:
break;
}
// start running the resource
while(currentTime_tick<stopTime_tick){
vTaskDelay(delay_tick);
currentTime_tick += delay_tick;
}
// gives back the token
if(xSemaphoreGive(xMutex)!=true){
printf("Something wrong in giving mutex's token in task id: %d\n", taskId);
}
}
You will notice that for the very first time, the first task that will start running in the processor will print out the first error message because it can't give a token while there still a token in the mutex holder, it's normal, so i just ignore it.
Hope someone can explain to me how mutex guarantee ownership using code in freeRTOS. In the first place i didn't use the first xSemaphoreGive function and it worked fine. but that doesn't mean it guarantee anything. or i'm not coding right.
Thank you.
Your example is quite convoluted, I also don't see clear code of task_A, task_B or task_C so I'll try to explain on a simplier example which hopefully explains how mutex guarantees resource ownership.
The general approach to working with mutexes is the following:
void doWork()
{
// attempt to take mutex
if(xSemaphoreTake(mutex, WAIT_TIME) == pdTRUE)
{
// mutex taken - do work
...
// release mutex
xSemaphoreGive(mutex);
}
else
{
// failed to take mutex for 'WAIT_TIME' amount of time
}
}
The doWork function above is the function that may be called by multiple threads at the same time and needs to be protected. This pattern repeats for every function on given resource that needs protection. If resource is more complex, a good approach is to guard the top-most functions that are callable by threads, then if mutex is successfully taken call internal functions that do the actual work.
The ownership guarantee you speak about is the fact that there may not be more than one context (threads, but also interrupts) that are under the if(xSemaphoreTake(mutex, WAIT_TIME) == pdTRUE) statement. In other words, if one context successfully takes the mutex, it is guaranteed that no other context will be able to also take it, unless the original context releases it with xSemaphoreGive first.
Now as for your scenario - while it is not entirely clear to me how it's supposed to work, I can see two issues with your code:
xSemaphoreGive at the beginning of the function - don't do that. Mutexes are by default "given" and you're not supposed to be "giving" it if you aren't the one "taking" it first. Always put a xSemaphoreGive under a successful xSemaphoreTake and nowhere else.
This code block:
while(xSemaphoreTake(xMutex, 10000/portTICK_PERIOD_MS) != true){
vTaskDelay(1000/portTICK_PERIOD_MS);
}
If you need to wait for mutex for longer - specify a longer time. If you want infinite wait, simply specify longest possible time (0xFFFFFFFF). In your scenario, you're polling for mutex every 10s, then delay for 1s during which mutex isn't actually checked, meaning there will be cases where you'll have to wait almost a full second after mutex is released by other thread to start doing work in the current thread that requested it. Waiting for mutex is already done by RTOS in an optimal way - it'll wake the highest priority task currently waiting for the mutex as soon as it's released, there's no need to do more than necessary.
If I was to give an advice of how to fix your example - simplify it and don't do more than needed such as additional calls to xSemaphoreGive or implementing your own waiting for mutex. Isolate the portion of code that performs some work to a separate function that does a single call to xSemaphoreTake at the very top and a single call to xSemaphoreGive only if xSemaphoreTake succeeds. Then call this function from different threads to test whether it works.

How I can match bags an passenger in the reclaim area?

I'm simulating a security control process, and i can't do that each passenger pickup their baggage. I have tried with Match, Combine, Pickup, but I still can't execute the commands correctly.
I've created the follow flowchart, and the problem is in the wReclaimPax, pickup and wReclaimBags blocks (you can see them in the picture).
https://ibb.co/v3V57Tm
I saw this link Anylogic - Combined multiple items back to original owner to understand something, but I still need help.
I've created 3 functions:
isMatch:
if(equipaje.pasajeroLink.equals(pasajero.equipajeLink)){
return true;
}
return false;
paxBags:
for(int i=0;i<wait.size();i++){
Pasajero p=(Pasajero)wait.get(i);
if(isMatch(p,bag))
return p;
}
return null;
bagsPax:
for(int i=0;i<wait.size();i++){
Equipaje e=(Equipaje)wait.get(i);
if(isMatch(pasajero,e))
return e;
}
return null;
Assumed context
You haven't really explained how your code is related to your process but I'm assuming the following:
Because this is luggage-retrieval, you want to ensure that a passenger
agent (Pasajero) only enters the Pickup block (representing taking bag from
carousel) when his bag (Equipaje agent by the look of it) has
arrived into the wReclaimBag Wait, and been released from it to
queue4 Queue.
For this you need triggers (to remove agents from Wait blocks) when
either a passenger (Pasajero) arrives in wReclaimPax Wait, or a bag (Equipaje) arrives
in the wReclaimBag Wait (because you don't know whether the passenger or their bag will get to their respective Wait blocks first).
So your paxBags function is called in on-entry action of the wReclaimBag Wait, and your bagsPax function in the on-entry action of the wReclaimPax Wait.
Possible problems with current approach
Without knowing more of your model it's hard to say but problems I can think of based on what you've supplied are:
Your functions return the Pasajero or Equipaje if there is one that matches. Your match check relies seemingly on bidirectional connections (links) between Pasajero and Equipaje. Obviously if they're not setup properly the model won't work and, if you're using bidirectional connections you shouldn't need to check both ends.
Your functions need calling so that, if they return non null, they then free the matching agent from the other Wait block, and free themselves. Are you doing that? Without checking, there may be issues with calling free for yourself as you enter a Wait block (since this kind of depends on AnyLogic internals as to whether you count as being 'in' the block at this stage and can be freed). If this seems to be the problem you could create a timeout 0 dynamic event instance to do the free so that you're not doing it within the scope of the on-enter action.
Your pickup block (since it's been setup so that the entering agent will always want to pickup the first agent (Equipaje) in queue4) just needs to be set as waiting for quantity 1 (though see below).
If you've done all this the most likely problem is that the underlying events ordering of AnyLogic is affecting things. When you free agents I'm fairly sure the freeing actually happens in a timeout 0 event scheduled under-the-covers. So it may be that the passenger arrives at the Pickup before their Equipment arrives in queue4 though, if you set the Pickup to be "Exact quantity (wait for)", with quantity of 1, it should handle that.
The animation of the process (numbers in/out/within each block and details when clicking on blocks) should also help you debug what is going wrong; e.g., are bags being left in the Wait when they should have been released, etc.
P.S. With this kind of thing you should always create a minimal example model to make testing the issue/solution easier (and for sharing in help forums such as this where the rest of the complexity of your model is irrelevant). Often you find the problem 'naturally' in the process of trying to construct such a model that reproduces your problem in a minimal way.

swift stop loop and continue it with a button

is it possible to stop an for in loop and continue it and the stopped position with a button.
i mean something like this:
for x in 0..<5 {
if x == 3 {
// show a button
// this button have to be pressed
// which do some tasks
// when all tasks are finished >
// continue this loop at the stopped point
}
}
is this possible? if yes, how?
Short answer: use a semaphore
Longer answer:
Your situation is an example of the more general case of how to pause some computation, saving its current state (local variables, call stack, etc.), and later to resume it from the same point, with all state restored.
Some languages/systems provide coroutines to support this, others the more esoteric call with current continuation, neither are available to you (currently) Swift...
What you do have is Grand Central Dispatch (GCD), provided in Swift through Dispatch, which provides support for executing concurrent asynchronous tasks and synchronisation between them. Other concurrency mechanisms such as pthread are also available, but GCD tends to be recommended.
Using GCD an outline of a solution is:
Execute you loop as an asynchronous concurrent task. It must not be executing on the main thread or you will deadlock...
When you wish to pause:
Create a semaphore
Start another async task to display the button, run the other jobs etc. This new task must signal the semaphore when it is finished. The new task may call the main thread to perform UI operations.
Your loop task waits on the semaphore, this will block the loop task until the button task signals it.
This may sound complicated but with Swift block syntax and Dispatch it is quite simple. However you do need to read up on GCD first!
Alternatively you can ask whether you can restructure your solution into multiple parts so saving/restoring the current state is not required. You might find designs such as continuation passing style useful, which again is quite easy using Swift's blocks.
HTH

How a runloop actually works

Earlier this month I asked this question 'What is a runloop?' After reading the answers and did some tries I got it to work, but still I do not understand it completely. If a runloop is just an loop that is associated with an thread and it don't spawn another thread behind the scenes how can any of the other code in my thread(mainthread to keep it simple) execute without getting "blocked"/not run because it somewhere make an infinite loop?
That was question number one. Then over to my second.
If I got something right about this after having worked with this, but not completely understood it a runloop is a loop where you attach 'flags' that notify the runloop that when it comes to the point where the flag is, it "stops" and execute whatever handler that is attached at that point? Then afterwards it keep running to the next in que.
So in this case no events is placed in que in connections, but when it comes to events it take whatever action associated with tap 1 and execute it before it runs to connections again and so on. Or am I as far as I can be from understanding the concept?
"Sort of."
Have you read this particular documentation?
It goes into considerable depth -- quite thorough depth -- into the architecture and operation of run loops.
A run loop will get blocked if it dispatches a method that takes too long or that loops forever.
That's the reason why an iPhone app will want to do everything which won't fit into 1 "tick" of the UI run loop (say at some animation frame rate or UI response rate), and with room to spare for any other event handlers that need to be done in that same "tick", either broken up asynchronously, on dispatched to another thread for execution.
Otherwise stuff will get blocked until control is returned to the run loop.

Tutorial OpenCl event handling

In my last question, OpenCl cleanup causes segfault. , somebody hinted that missing event handling, i.e. not waiting for code to finish, could cause the seg faults. Since then I looked again into the tutorials I used, but they don't pay attention to events (Matrix Multiplication 1 (OpenCL) and NVIDIA_OpenCL_GettingStartedLinux.pdf) or talk about it in detail and (for me) understandable.
Do you know a tutorial on where and how to wait in OpenCL?
Merci!
I don't have a tutorial on events in OpenCL, and I'm by no means an expert, but since no one else is responding...
As a rule of thumb, you'll need to wait for any function named clEnqueue*. Those functions return immediately before the job is done. The easiest way to make sure your queue is finished is to call clFinish(). It won't return until the entire queue has completed.
If you want to get a little fancier, most of the clEnqueue* functions have an optional cl_event parameter that you can pass in. You can check on a particular event with clGetEventInfo(), and you can wait for a particular set of events to finish with clWaitForEvents().