优化Swtich case结构为双层表查询+Lamda表达式

优化Swtich case结构为双层表查询+Lamda表达式

目录

1. 优化背景

  
最近在工作中遇到了这样一段代码,是三层switch嵌套的结构,第一次swtich有4个case,第二层switch有上百个case,第二层switch下有的case下会有第三层swtich结构。  

  1. 整段代码是可以正常工作的。
  2. 多次调用这段代码时,如果第二个switch结构中多次访问的是靠后的几个case,由于处理器设计的原因,会逐case去刷新缓存,这会让代码执行效率变得很差。那有什么办法可以去优化这个结构呢?
  3. 导师一眼看过来,就对着这坨说到改成表查询。那现在就开始修改这坨代码吧。(虽然什么表查询都学过,但是早就随风远去,这几年更是一直再写C,对C++也不熟练,趁此机会正好恶补一下吧)。

2.修改思路

  
首先让我们看一下要优化的结构伪代码:

#define OPMVV 0
#define OPIVV 1
#define OPSVV 2
#define OPDVV 3

int main(int argc, char** argv) {
   
   
    int opcode_H = 0;
    switch(opcode_H) {
   
   
        switch(opcode_M) {
   
   
            case 1:
            break;
            case 2:
                switch(opcode_L) {
   
   
                    case 1:
                    break;
                    case 2
                    break;
                    //假设还有其他很多case
                }
            break;
            //假设还有其他很多case
        }
    case OPMVV:
        break;
    case OPIVV:
        break;
    case OPSVV:
        break;
    case OPDVV:
        break;
    }
    return 0;
}

  
在这段代码中,任一层的switch结构下的case都会调同一个函数,只是在调这个函数时,传的参数不一样。接下来让我记录一下我整个优化的过程。
这里留下一个还没解决的问题,那就是如果不同的case下调用的函数不同该怎么处理

3. 解决过程

3.1 Q1:这个switch我想给他改成表查询的结构以提升在case特别多的情况下的性能,但是这个case下还有嵌套if的情况,那么要怎么改成表查询呢?

switch(ncc_inst.ncc_ct_opcode.range(31,26)){
   
   
    case OPMVV_VMANDNOT:
        fifo_inst.SetArithInst(ncc_inst,id,VMANDNOT,0);
        break;
    case OPMVV_VMAND:
        fifo_inst.SetArithInst(ncc_inst,id,VMAND,0);
        break;
    case OPMVV_VMOR:
        fifo_inst.SetArithInst(ncc_inst,id,VMOR,0);
        break;
    case OPMVV_VCPOP:
        if (ncc_inst.ncc_ct_opcode.range(19,15)==0b10000)
            fifo_inst.SetArithInst(ncc_inst,id,VCPOP,0);
        else if(ncc_inst.ncc_ct_opcode.range(19,15)==0b10001)
            fifo_inst.SetArithInst(ncc_inst,id,VFIRST,0);
        else
            this->vcsr.SetVill(1);
        break;
    default:
        break;
}

3.2 Answer1:

  
switch-case 结构改为表查询是一种常见的优化方法,尤其是当 case 条件很多时。要实现这种优化,我们可以通过使用函数指针或 lambda 表达式的方式,将 case 中的处理逻辑放到一个查找表中。对于存在嵌套 if 逻辑的情况,也可以通过合并不同的条件到表中的不同函数来处理。

方案 1:使用函数指针查找表

你可以将每个 case 的处理逻辑封装成独立的函数或 lambda 表达式,并创建一个映射表。对于嵌套的 if 条件,可以在处理函数内处理这些逻辑。

实现步骤:
  1. 定义一个类型为函数指针或 lambda 表达式的数组或映射表。
  2. 使用 opcode 值查找对应的函数。
  3. 嵌套 if 可以在处理函数内完成。
示例代码:
#include <functional>
#include <unordered_map>

// 定义处理函数类型
using ArithInstFunc = std::function<void(uint32_t)>;

// 假设定义的这些常量
constexpr uint32_t OPMVV_VMANDNOT = 0x01;
constexpr uint32_t OPMVV_VMAND = 0x02;
constexpr uint32_t OPMVV_VMOR = 0x03;
constexpr uint32_t OPMVV_VCPOP = 0x04;

// 创建查找表
std::unordered_map<uint32_t, ArithInstFunc> opcodeTable;

// 初始化查找表
void initOpcodeTable() {
   
   
    opcodeTable[OPMVV_VMANDNOT] = [&](uint32_t ncc_inst) {
   
   
        fifo_inst.SetArithInst(ncc_inst, id, VMANDNOT, 0);
    };
    
    opcodeTable[OPMVV_VMAND] = [&](uint32_t ncc_inst) {
   
   
        fifo_inst.SetArithInst(ncc_inst, id, VMAND, 0);
    };

    opcodeTable[OPMVV_VMOR] = [&](uint32_t ncc_inst) {
   
   
        fifo_inst.SetArithInst(ncc_inst, id, VMOR, 0);
    };

    opcodeTable[OPMVV_VCPOP] = [&](uint32_t ncc_inst) {
   
   
        // 嵌套的 if 在这里处理
        if (ncc_inst.ncc_ct_opcode.range(19,15) == 0b10000) {
   
   
            fifo_inst.SetArithInst(ncc_inst, id, VCPOP, 0);
        } else if (ncc_inst.ncc_ct_opcode.range(19,15) == 0b10001) {
   
   
            fifo_inst.SetArithInst(ncc_inst, id, VFIRST, 0);
        } else {
   
   
            this->vcsr.SetVill(1);
        }
    };
}

// 查找并执行对应的指令处理函数
void executeOpcode(uint32_t opcode, uint32_t ncc_inst) {
   
   
    if (opcodeTable.find(opcode) != opcodeTable.end()) {
   
   
        opcodeTable[opcode](ncc_inst);
    } else {
   
   
        // 默认情况处理
    }
}
解释:
  1. 函数类型定义ArithInstFunc 是一个 std::function 类型,代表处理某个 opcode 的函数。
  2. 查找表初始化opcodeTable 是一个映射表,将每个 opcode 与其对应的处理函数关联。
  3. 处理函数:每个 case 语句中的逻辑都封装在 lambda 表达式中,并且嵌套的 if 逻辑也在对应的 lambda 内处理。
  4. 查找并执行executeOpcode 函数根据 opcode 查找并执行对应的处理函数。
方案 2:使用数组作为查找表

如果 opcode 值是连续的,可以使用数组而不是 unordered_map 来提高查找效率。

using ArithInstFunc = std::function<void(uint32_t)>;

// 假设 opcode 的范围是 0 到 255
ArithInstFunc opcodeTable[256];

// 初始化查找表
void initOpcodeTable() {
   
   
    opcodeTable[OPMVV_VMANDNOT] = [&](uint32_t ncc_inst) {
   
   
        fifo_inst.SetArithInst(ncc_inst, id, VMANDNOT, 0);
    };
    // 其他初始化同前
}

// 查找并执行
void executeOpcode(uint32_t opcode, uint32_t ncc_inst) {
   
   
    if (opcode < 256 && opcodeTable[opcode]) {
   
   
        opcodeTable[opcode](ncc_inst
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值