【DVCon-US-2020】基于多线程UVM测试平台的仿真加速方法

简介: 【DVCon-US-2020】基于多线程UVM测试平台的仿真加速方法

论文概述


 本文题目 Multithreading a UVM Testbench for Faster Simulation,作者是 Intel 的加拿大验证工程师。


 本文提出了一种C/C++ model和simulation并行的方法,来提升 UVM 测试平台的仿真速度。




研究目的


 为了验证仿真结果的正确性,simulation 中常用UVM来创建predictor和scoreboard组件。predictor可以用SV直接写,但对于偏算法的、较为复杂的DUT,尤其是Vender提供的IP,常采用DPI调用C/C++ model等软件模型作为参考模型(如图1)。


 正常情况下,SV DPI调用C/C++ model时,simulation会停在原地等待C model执行完毕,从而影响simulation效率。即便目前先进的simulator支持多线程的DUT仿真,但对于整个UVM测试平台而言,CPU内仍然时按照单线程运行的。本文目的便是为了提升这种DPI 调用软件模型的simulation效率,为了突破单线程桎梏,来进一步提升 UVM 测试平台的仿真速度。


a5111908e17a42ecbc70794d9b298775.png

图1 UVM testbench using a C++ Predictor Model




新方法


方法提出


本文提出一种方法(图2),开辟一个甚至多个新线程单独跑C/C++ model(其他任何软件模型),与原有的UVM TB并行,能够缩短仿真耗时。运行中的simulation和C/C++ model采用进程间通信机制来交换数据。


 为了对多进程启动顺序、数据交换等进行管理,本文构建了一个线程池 管理器(thread pool manager)。线程池是一个可配置线程数目的软件对象,其中的每个线程都可以单独执行所分配的任务(Job)。Job通过输入队列丢到线程池,由线程池中的空闲线程执行该Job。执行完毕后线程池采用异步方式返回Job执行结果。


641cd6b6b9b3471dacd746b953acf9e1.png


图2 Modified UVM testbench with an asynchronous predictor model




方法实现


线程池的初始化及访问


通过单独开辟新线程的方式来初始化及访问thread_pool class。这种设计隐藏了初始化行为及全局状态,为人所诟病。但该方法使得thread pool class能够响应多个不同组件的调度请求,多个传输单元的code只做微调即可轻松获取 thread pool instance,总体而言是利大于弊的。C++惰性计算的特性也保证了thread pool object只在初次执行thread_pool::get_instance进行调用的时候进行一次初始化。


 线程池类的实现需要 :


  1. 一个私有默认构建函数(private default constructor)


  1. get_instance 函数,以返回thread_pool静态实例的引用
class thread_pool {
public:
    static thread_pool& get_instance()
    {
        static thread_pool inst; //Class will be initialized a single time
        return inst;
    }
private:
    thread_pool() = default; //Prevent creation of other instances
}



线程调度


 线程池初始化时即生成了制定数量的线程 std::thread,初始化完毕后进入idle状态。线程由std::condition_variable唤醒,从输入任务队列中pop出job然后执行job,Input Job Queue的保证了线程的执行顺序。若线程池所有线程处于忙碌状态,则暂时停止从任务队列中pop job,待有job执行完毕、线程ilde之后再行pop。


多个job虽然是按照既定顺序开始执行的,但不同job的执行时间不同,并不能保证按顺序完成job。对于scoreboard等对job反馈结果有严格顺序要求的情况,需按照顺序同步返回job执行结果。本文采用std::packaged_task返回值std::future来解决该问题。


 std::future具有按序立即返回的特性,因此可以在调用线程池时把std::future压入一个特殊队列,在scoreboard需获取新数据时检查std::future队列相关job是否完成并将其弹出,便于scoreboard区分其所需的data,也避免了早前丢出的多个任务抢同一个返回结果。




线程池集成到UVM TB


 为了实现model和UVM并排走,需要把线程池集成到原有的UVM环境中,需要对C model和UVM TB做响应调整。


C/C++的改动


 需要对原有的C/C++ 代码做点微调才能把线程池集成到UVM环境中,主要改动如下:


   添加std::future及其队列std::queue<std::future> futures


   添加predictor中调用的function predict_call()


   添加scoreboard中调用的scoreboard_call()


 示意代码如下:

//C++ Code
//Store futures in the order they are created for a particular task type
std::queue<std::future<int>> futures;
//Function that would have previously been called by the predictor
//Returns the expected result from a single integer input
int calc_result(int num)
{
    int result = 0;
    //Do complex math work or any other modelling here
    return result;
}
//New function called from the UVM Predictor
extern "C" void predict_call(const int num)
{
    thread_pool& tp = thread_pool::get_instance();
    //Queue the job on the thread_pool and store the std::future
    futures.emplace(tp.add_job(calc_result, num));
}
//New function called from the UVM Scoreboard
extern "C" int scoreboard_call()
{
    int num = futures.front().get();
    futures.pop();
    return num;
}



SV/UVM的改动


 之前的方式是在UVM中 predictor中DPI调用C/C++ model,等model执行完毕后通过 analysis fifo 把结果传递给scoreboard。为了实现C/C++ model与UVM TB的并行,UVM环境中原有model调用方式改为在predictor中调用model(丢job)然后立即退出,在scoreboard中调用model(丢job)收集job计算结果,不再通过analysis fifo收结果。


//Predictor
//DPI call to submit work to the thread pool
import "DPI-C" function void predict_call(input int num);
class my_predictor extends uvm_subscriber #(my_item);
    //Predictor code
    function void write(my_item item);
        predict_call(item.data);
    endfunction
endclass : my_predictor
//Scoreboard
//DPI call to retrieve the next predicted value
import "DPI-C" function int scoreboard_call();
class my_scoreboard #(type T = my_item) extends uvm_scoreboard;
    uvm_analysis_imp_received #(T, my_scoreboard) received_export;
    //Scoreboard code
    virtual function void write_received(T txn);
        int rx_data;
        int pred = scoreboard_call(); //Get predicted data
        rx_data = txn.data;
        if (rx_data != pred) begin
            `uvm_error("Scoreboard", "Failure")
        end
    endfunction
endclass : my_scoreboard




实验结果


  本文以不同predictor time和有无thread pool为变量做了几组对比试验,证明了本文所提出的方法的确能够加速仿真。predictor time越大,提升效果越明显。


17523377b7954846b19bb5f64759f732.png



讨论


  根据本文实验结果,该方法对于predictor time 2~20ms的仿真,提速效果为3~4x。对于1ms以内的仿真,提速效果并不明显。鉴于复杂度并不高,无论如何大家都可以试一下,学点新知识嘛。 😀

目录
相关文章
|
6天前
|
芯片
LDO的原理及测试方法
一、基本结构 这是LM317芯片的核心,这个电路单元称为Bandgap Reference带隙基准源。属于模拟集成电路中的经典电路结构。 LDO拓扑结构图 常见的基本结构 利用VBE的负温度系数,而VT是正温度系数,正负温度系数抵消就的得到稳定的基准参考电压了(三极管的方程VBE=VT*In(lC/IS))。 二、测试意义 了解集成电路的内部结构对测试有意义么? 1、了解内部结构,才能更好的理解测试原理或者设计测试方案2、可以学习提升对电路结构的理解能力。 针对LM317,了解了内部简单原理,可以知道1、内部结构设计针对的是温度系数,因此可能受温度的影响,实际也是会受到温度的影
152 88
|
5天前
|
机器学习/深度学习 敏捷开发 大数据
软件测试的演变之旅:从传统方法到自动化革命
在数字时代的浪潮下,软件测试作为保障产品质量的关键一环,经历了从手工测试到自动化测试的重大转变。本文将探讨这一演变背后的驱动力、所面临的挑战以及未来的发展趋势,为读者揭示软件测试领域的深层次变革。
|
8天前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
|
15天前
|
算法 安全 Java
三种方法教你实现多线程交替打印ABC,干货满满!
本文介绍了多线程编程中的经典问题——多线程交替打印ABC。通过三种方法实现:使用`wait()`和`notify()`、`ReentrantLock`与`Condition`、以及`Semaphore`。每种方法详细讲解了实现步骤和代码示例,帮助读者理解和掌握线程间的同步与互斥,有效解决并发问题。适合不同层次的开发者学习参考。
35 11
|
9天前
|
Java Spring
运行@Async注解的方法的线程池
自定义@Async注解线程池
34 3
|
18天前
|
SQL Java 测试技术
SpringBoot单元测试快速写法问题之PorkService 接口中的 getPork 方法的作用如何解决
SpringBoot单元测试快速写法问题之PorkService 接口中的 getPork 方法的作用如何解决
|
19天前
|
安全 Java API
|
22天前
|
测试技术 Android开发 iOS开发
Appium 是一个开源的自动化测试框架,它支持多种平台和多种编程语言
Appium是一款开源自动化测试框架,支持iOS和Android多平台及多种编程语言。通过WebDriver协议,开发者可编写自动化测试脚本。在iPhone上实现屏幕点击等操作需安装Appium及其依赖,启动服务器,并设置所需的测试环境参数。利用Python等语言编写测试脚本,模拟用户交互行为,最后运行测试脚本来验证应用功能。对于iPhone测试,需准备真实设备或Xcode模拟器。
55 1
|
24天前
|
Java
java开启线程的四种方法
这篇文章介绍了Java中开启线程的四种方法,包括继承Thread类、实现Runnable接口、实现Callable接口和创建线程池,每种方法都提供了代码实现和测试结果。
java开启线程的四种方法
|
11天前
|
安全 数据安全/隐私保护 架构师
用Vaadin打造坚不可摧的企业级应用:安全性考虑全解析
【8月更文挑战第31天】韩林是某金融科技公司的架构师,负责构建安全的企业级应用。在众多Web框架中,他选择了简化UI设计并内置多项安全特性的Vaadin。韩林在其技术博客中分享了使用Vaadin时的安全考虑与实现方法,包括数据加密、SSL/TLS保护、结合Spring Security的用户认证、XSS防护、CSRF防御及事务性UI更新机制。他强调,虽然Vaadin提供了丰富的安全功能,但还需根据具体需求进行调整和增强。通过合理设计,可以构建高效且安全的企业级Web应用。
22 0