默认情况下,我们直接使用源码中提供的CMake编译参数编译.so文件,那么我们在跑一个SystemC程序的时候,即使代码中有很多SC_THREAD / SC_METHOD的注册函数,也会发现程序只占用一个物理CPU core。
如果我们在编译时 enable了SC_USE_PTHREADS这个宏,则会出现不同的现象:每一个SC_THREAD / SC_METHOD都会创建一个CPU线程;但这种情况对我们的仿真速度其实影响很大,当我们代码中的SC_THREAD / SC_METHOD特别多时,会严重拖慢我们的仿真速度,因为SystemC kernel对这些线程的调度 所花费的CPU时间 已经远远超出了 多线程带来的并行效果。故一般情况下,我们都会disable SC_USE_PTHREADS这个宏。以下对于SystemC 调度机制的解释也都默认此宏不打开。
Synopsys 公司的VDK (Virtualizer Development Kit,Virtualizer 开发套件 (VDK) )软件中集成了一种可以实现真正并行多CPU物理线程执行的解决方案,此方案对于DSP 、AI芯片等数据处理功能比较多、核心比较多的SystemC module比较友善,可以大幅提升 module的仿真速度。
Elaboration和Simulation阶段都是串行执行。
Simulation阶段,在某一个SystemC仿真时刻点,SystemC kernel都会依次调用每一个SC_THREAD关联函数,都会查看每一个SC_METHOD的敏感事件是否被触发。
在调用一个SC_THREAD关联函数时,相当于程序控制权暂时由SystemC kernel移交给这个函数,函数会一直执行,直到遇到显式或隐式的wait调用,此函数被挂起,然后程序控制权转回到SystemC kernel;SystemC kernel接着再开始调用下一个SC_THREAD关联函数。SC_THREAD关联函数的挂起点是需要被记录的,下个SystemC仿真时刻,SystemC kernel再来调用这个函数时,从上次的挂起点开始执行。如果wait的事件被触发了,或wait的( SystemC仿真)时间达到了,就可以跳出wait,继续往下执行,直到遇到wait被再次挂起。
SC_METHOD被SystemC kernel调度的过程比较简单:查看这个SC_METHOD对应的敏感事件是否被触发,触发了,完整执行一次关联函数,否则不做处理。由于SC_METHOD的关联函数中不能有wait,所以SystemC仿真时间不会往前推进。
SystemC kernel调度SC_THREAD关联函数的具体过程比较复杂,具体可参考spec中的 4.2 Simulation章节,具体为evaluation 、update、delta notification 、timed notification phase。以下是spec中的一些关键语句。
From the set of runnable processes, select a process instance, remove it from the set, and only then trigger or resume its execution. Run the process instance immediately and without interruption up to the point where it either returns or, in the case of a thread or clocked thread process, calls the function wait or calls the member function suspend of a process handle associated with the process instance itself.
Since process instances execute without interruption, only a single process instance can be running at any one time, and no other process instance can execute until the currently executing process instance has yielded control to the kernel. A process shall not pre-empt or interrupt the execution of another process. This is known as co-routine semantics or co-operative multitasking.
Repeat this step(evaluation phase) until the set of runnable processes is empty; then go on to the update phase.
If, at the end of the delta notification phase, the set of runnable processes is non-empty, go back to the evaluation phase.
从可运行processes集合中选择一个流程实例,将其从集合中删除,然后才触发或恢复其执行。立即运行流程实例,并且不中断,直到该实例返回或(在线程或有时钟的线程进程的情况下)调用与流程实例本身关联的流程句柄的函数wait或成员函数suspend为止。
由于流程实例在不中断的情况下执行,因此在任何时候只能运行一个流程实例,并且在当前执行的流程实例将控制权交给内核之前,其他流程实例都不能执行。一个进程不能抢占或中断另一个进程的执行。这被称为协同例行语义或合作多任务处理。
SystemC执行过程,需要防止 由于 调度顺序导致的问题。
Because the order in which processes are run within the evaluation phase is not under the control of the application, access to shared storage should be explicitly synchronized to avoid non-deterministic behavior.