virtual function的一些心得

本文探讨了虚拟函数在设计与性能之间的权衡,提出了通过宏包含、模板、typedef等方式进行性能优化的方法,同时强调了在不同设计场景下选择虚拟函数的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:http://blog.youkuaiyun.com/toughbro/article/details/2204345

        virtual function是design上一个非常好的东西,它可以在保持面向接口编程的前提下做到运行时刻动态决定使用某一种实现。而且使得代码的语义表达,设计美感都好很多。

      问题就是virtual function太费了。

      对于pc平台来说,它是乱序执行的cpu,cache miss还可以忍受,对于console平台,这种顺序执行的处理器,cache miss会带来非常大的性能损失。

virtual function table与object在内存上的分离,决定要在很大可能上付出一个额外的cache miss,这是很可惜的。

      个人认为,对于virtual的态度可以这样:

  1. 对于design意义上重要的或者调用率比较低的接口,可以直接virtual,virtual在design上的美感和带来的可读性是很值的,而且如果调用率比较低,那么代价也很小,就没有必要去做一些优化了。
  2. 对于design要求不高的或者调用频繁的,性能与design的衡量就必要了,这个时侯如果可以的话,可以考虑使用一些变换方式。

变换方式包括:

  1. 宏包含来做编译时刻可以决定的virtual function替换:可以在类表达和接口上保持和virtual function一样的效果,但是却不用付出virtual function的性能损失。表现方式可以是template,可以是typedef,也可以是#define,没有本质区别。这里是个typedef的代码。
    virtual function version:
    
    class CmdBufInterface
    {
        virtual void flip()=0;
    };
    
    class CmdBufDoubleBuffer
    {
        virtual void flip(){....}
    };
    
    class CmdBufRingBuffer
    {
        virtual void flip(){....}
    };
    
    class GcmManager
    {
        CmdBufInterface* mCmdBuf;
        void Init()
      {
    #if DEBUG
            mCmdBuf = new CmdBufDoubleBuffer;
    #else
            mCmdBuf = new CmdBufRingBuffer;
    #endif
      }
    };
    
    // e.g. MY favorate: I think this is good for a replacement of virtual function, and no disadvantage of design side.
    
    class CmdBufDoubleBuffer
    {
        void flip(){....}
    };
    
    class CmdBufRingBuffer
    {
        void flip(){....}
    };
     
    #if DEBUG
    typedef  CmdBufDoubleBuffer CmdBufInterface;
    #else
    typedef CmdBufRingBuffer CmdBufInterface;
    #endif
    
    class GcmManager
    {
        CmdBufInterface* mCmdBuf;
        void Init()
      {
            mCmdBuf = new CmdBufInterface;
      }
    };
  2.  运行时刻的变换可以是callback函数。这里我原先有个误解,以为callback函数指针地址也要有一个memory访问,所以也会有cache miss,不会有优势。但是我错了,virtual function的访问也需要去访问object的内存,然后跳到virtual table,然后是函数地址。call back只是访问object内存就可以了。而且object内存在load到cache里面之后,在函数中有很大几率又会被访问到,所以这个cache miss很大几率不是白费的,可以得到和正常函数一样的效率。
### UVM 中 Virtual Function 的定义与用法 在 SystemVerilog 和 UVM (Universal Verification Methodology) 中,`virtual function` 是一种重要的概念,用于实现多态行为和接口抽象化。以下是关于 `virtual function` 的详细说明: #### 定义 `virtual function` 是一种允许子类重写的函数类型。当一个基类中的方法被声明为虚拟时,派生类可以对该方法进行重新定义以适应特定需求[^2]。这种特性使得继承结构更加灵活,并支持运行时动态绑定。 #### 声明语法 在 SystemVerilog 中,`virtual function` 或 `virtual task` 可以通过如下方式声明: ```systemverilog class BaseClass; virtual function void display(); $display("Base Class Display"); endfunction endclass ``` 如果某个派生类希望覆盖该功能,则可以在其内部重新定义此方法: ```systemverilog class DerivedClass extends BaseClass; function void display(); // 覆盖父类的方法 $display("Derived Class Display"); endfunction endclass ``` #### 使用场景 1. **测试平台组件扩展** 测试平台通常由多个层次化的模块组成,而这些模块可能需要不同的行为逻辑。借助于虚函数机制,开发者能够轻松定制各层的行为而不破坏原有框架的一致性[^3]。 2. **回调机制设计** 在某些情况下,用户可能会希望通过注册自定义操作来增强默认的功能表现。此时可以通过创建带有虚函数的接口类并让其他部分实例化具体版本从而达到目的。 3. **提高代码可维护性和复用率** 将通用算法封装到基础类别里作为模板供后续修改调优提供了便利条件;同时也减少了重复编写相似片段的工作量。 #### 示例程序 下面给出一段简单的例子展示如何运用上述原理构建一个基于 UVM 验证环境下的随机序列发生器及其变体形式: ```systemverilog // 定义基本事务项 class transaction #(type T=int); rand T data; constraint c_data {data inside {[0:100]};} virtual function string convert2string(); return $sformatf("Data=%d", this.data); endfunction : convert2string endclass : transaction // 创建第一个派生物件 class my_transaction_int extends transaction #(.T(int)); localparam int MAX_LIMIT=80; function new (); super.new(); add_constraint(c_limit_max); endfunction constraint c_limit_max { data <MAX_LIMIT ; } // Override parent class method virtual function string convert2string(); return {"My Transaction Int:",super.convert2string()}; endfunction :convert2string endclass :my_transaction_int program automatic testbench ; initial begin transaction#(int) tr=new(); repeat(5)begin assert(tr.randomize()); $display("%t %s",$time,tr.convert2string()); end my_transaction_int mtr=new(); repeat(5)begin assert(mtr.randomize()); $display("%t %s",$time,mtr.convert2string()); end end endprogram:testbench ``` 在这个案例中可以看到我们先建立了一个泛型交易对象包含数据成员以及转换字符串表示的方法。接着衍生出了另一个限定数值范围更窄的新种类别,并且改写了原有的打印格式处理过程以便区分两者差异之处。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值