cocotb: Consider fork-like interface that doesn't schedule new coroutine immediately

Currently when calling fork, the new forked coroutine gets to run immediately, and the originating coroutine waits until fork returns before continuing. It might be useful to provide a way to queue the forked coroutine to run after the current one yields back to the scheduler.

_Originally posted by @garmin-mjames in https://github.com/cocotb/cocotb/pull/1526#issuecomment-605092873_

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 17 (17 by maintainers)

Most upvoted comments

@eric-wieser I forgot that was fixed… The second suggestion is equivalent to what we have now but uses an Event, instead of simply calling fork later. But the first should be sufficient for our needs.

But if await NullTrigger() does what we need it to, maybe we could codify that pattern and add documentation; that way we can consider this issue closed? I’m thinking something simple like:

def run_task_soon(coro: Union[RunningTask, coroutine]) -> RunningTask:
    """Runs a coroutine concurrently, starting after the current coroutine yields control"""
    async def later():
        await NullTrigger()
        await coro
    return cocotb.fork(later())

I took this issue as a general complaint about the scheduler being recursive and causing a number of bugs, but that should probably be in a separate issue.

@garmin-mjames I think we should change that behavior. If we are going to break the scheduler interface, we should just break it and do what we need to make it better. We need to queue up issues and detail what the end product of a scheduler rewrite should look like.

This is the test I used to check the behavior of NullTrigger():




@cocotb.test()
async def test_nulltrigger_reschedule(dut):

    @cocotb.coroutine
    async def reschedule(n):
        for i in range(4):
            cocotb.log.info("Fork {}, iteration {}".format(n, i))
            await NullTrigger()

    await Combine(*(reschedule(i) for i in range(4)))

The output shows NullTrigger not rescheduling.

make results.xml
make[1]: Entering directory '/home/kaleb/dev/cocotb/tests/test_cases/test_cocotb'
MODULE=test_scheduler \
        TESTCASE=test_nulltrigger_reschedule TOPLEVEL=sample_module TOPLEVEL_LANG=verilog COCOTB_SIM=1 \
        /usr/bin/vvp -M /home/kaleb/dev/cocotb/cocotb/libs -m libcocotbvpi_icarus   sim_build/sim.vvp 
     -.--ns INFO     cocotb.gpi                         ..mbed/gpi_embed.cpp:71   in set_program_name_in_venv        Did not detect Python virtual environment. Using system-wide Python interpreter
     -.--ns INFO     cocotb.gpi                         ../gpi/GpiCommon.cpp:106  in gpi_print_registered_impl       VPI registered
     0.00ns INFO     cocotb.gpi                                gpi_embed.cpp:332  in embed_sim_init                  Running on Icarus Verilog version 10.3 (stable)
     0.00ns INFO     cocotb.gpi                                gpi_embed.cpp:333  in embed_sim_init                  Python interpreter initialized and cocotb loaded!
     0.00ns INFO     cocotb                                      __init__.py:145  in _initialise_testbench           Running tests with cocotb v1.4.0.dev0 from /home/kaleb/dev/cocotb/cocotb
     0.00ns INFO     cocotb                                      __init__.py:162  in _initialise_testbench           Seeding Python random module with 1587743335
     0.00ns WARNING  cocotb.regression                         regression.py:187  in initialise                      No tests were discovered
     0.00ns INFO     cocotb.regression                         regression.py:194  in initialise                      Found test test_scheduler.test_nulltrigger_reschedule
     0.00ns INFO     cocotb.regression                         regression.py:422  in execute                         Running test 1/1: test_nulltrigger_reschedule
     0.00ns INFO     ..trigger_reschedule.0x7fdfde86aac8       decorators.py:253  in _advance                        Starting test: "test_nulltrigger_reschedule"
                                                                                                                     Description: None
     0.00ns INFO     cocotb                                test_scheduler.py:217  in reschedule                      Fork 0, iteration 0
     0.00ns INFO     cocotb                                test_scheduler.py:217  in reschedule                      Fork 0, iteration 1
     0.00ns INFO     cocotb                                test_scheduler.py:217  in reschedule                      Fork 0, iteration 2
     0.00ns INFO     cocotb                                test_scheduler.py:217  in reschedule                      Fork 0, iteration 3
     0.00ns INFO     cocotb                                test_scheduler.py:217  in reschedule                      Fork 2, iteration 0
     0.00ns INFO     cocotb                                test_scheduler.py:217  in reschedule                      Fork 2, iteration 1
     0.00ns INFO     cocotb                                test_scheduler.py:217  in reschedule                      Fork 2, iteration 2
     0.00ns INFO     cocotb                                test_scheduler.py:217  in reschedule                      Fork 2, iteration 3
     0.00ns ERROR    cocotb.scheduler                            __init__.py:204  in _sim_event                      Failing test at simulator request before test run completion: Simulator shutdown prematurely
     0.00ns ERROR    cocotb.regression                         regression.py:388  in _score_test                     Test error has lead to simulator shutting us down
                                                                                                                     cocotb.result.SimFailure: Failing test at simulator request before test run completion: Simulator shutdown prematurely
     0.00ns ERROR    cocotb.regression                         regression.py:232  in tear_down                       Failed 1 out of 1 tests (0 skipped)
     0.00ns INFO     cocotb.regression                         regression.py:477  in _log_test_summary               ****************************************************************************************************
                                                                                                                     ** TEST                                        PASS/FAIL  SIM TIME(NS)  REAL TIME(S)  RATIO(NS/S) **
                                                                                                                     ****************************************************************************************************
                                                                                                                     ** test_scheduler.test_nulltrigger_reschedule    FAIL            0.00          0.00         0.00  **
                                                                                                                     ****************************************************************************************************
                                                                                                                     
     0.00ns INFO     cocotb.regression                         regression.py:494  in _log_sim_summary                *************************************************************************************
                                                                                                                     **                                 ERRORS : 1                                      **
                                                                                                                     *************************************************************************************
                                                                                                                     **                               SIM TIME : 0.00 NS                                **
                                                                                                                     **                              REAL TIME : 0.00 S                                 **
                                                                                                                     **                        SIM / REAL TIME : 0.00 NS/S                              **
                                                                                                                     *************************************************************************************
                                                                                                                     
     0.00ns INFO     cocotb.regression                         regression.py:239  in tear_down                       Shutting down...
make[1]: Leaving directory '/home/kaleb/dev/cocotb/tests/test_cases/test_cocotb'

Funnily enough, that test fails too! Yay scheduler!

With COCOTB_SCHEDULER_DEBUG: sim.log.

EDIT: forking the coroutines before passing them to Combine shows it runs all the coroutines, but still in order and it still fails.

@ktbarrett I agree. But, NullTrigger won’t work, as you noted up-thread:

We don’t really have a way to force a reschedule. NullTrigger fires immediately, not allowing any other coroutines to run.