Page 24 - 《软件学报》2024年第6期
P. 24

2600                                                       软件学报  2024  年第  35  卷第  6  期


                 者修复了重构后的逃逸算法上的           Bug.

                 代码  5. DBI-Go  发现的新逃逸算法出错的例子        1.
                 1. package nomain
                 2. type prefixError struct{s string}
                 3. func New(f string, x ...interface{}) error {
                 4.  // 误将字面量  prefixError{}分配到栈上
                 5.  return & prefixError{}
                 6. }
                 7. func (e *prefixError) Error() string {
                 8.   return “1” + e.s
                 9. }

                 代码  6. DBI-Go  发现的新逃逸算法出错的例子        2.

                 1. var gm map[string]interface{}
                 2.
                 3. func Test() {
                 4.  // 误将  b 分配到栈上
                 5.  var b int
                 6.  gm[“1”] = & b
                 7. }

                 4.2   额外开销

                 4.2.1    额外运行时开销             4 (2.8%). 产生额外的
                    相比于只需在运行前执行一次的静态分析和初始化, 插桩的回调函数带来的额外运行时开销在反复执行时会
                 占据主要比例, 这些额外的运行时开销主要包括以下几部分: (1) 调用回调函数的开销; (2) 获取                        Go  的运行时信息
                 的开销; (3) 利用规则    1  和规则  2  进行运行时验证的开销. 为了了解这些额外运行时开销的影响, 我们使用第                      4.1
                 节中所述的    Go 标准库和编译工具链中的          277  个包中的测例进行了测试. 最终, 记录了插桩的回调函数带来的额
                 外运行时开销相比于直接执行时所花费的开销的比值. 为了表述方便, 在下文使用                          R c/o  表示额外的运行时开销相
                 比于直接执行时所花费的开销的比值.
                    为了了解    R c/ 的分布, 对得到的额外开销数据使用了          KDE (kernel density estimation, 核密度估计, 一种用于估
                              o
                 计随机变量的概率密度函数的非参数方法)              [40, 41] 估计了  R c/ 在这  277  个包中的分布密度, 如后文图  10  所示. 该曲
                                                              o
                 线的波峰在    R c/ 约为  0.25  处达到, 且绝大多数的额外开销相比于原生开销的比值均小于                 2 (93.3%) 只有在极少数
                            o
                 store 密集型的程序中该比值才会大于                          2  倍运行时开销是可以承受的.

                 4.2.2    额外初始化开销
                    在前文中提到, 由于初始化部分只需在运行前执行一次, 因此其相比于可以反复执行的运行时开销可以忽略.
                 但用于初始化的该部分开销在使用时也会对总时间造成影响, 因此对该部分开销的测试也是必要的. 额外的初始
                 化开销包括以下几部分时间: (1) Pin 加载用户二进制的开销; (2) 反汇编的开销; (3) 使用静态分析, 利用                   Go  的写屏
                 障机制恢复    Go store 语义的开销. 使用和第     4.2.1  节相同的测试集和测试方式, 通过记录额外的初始化开销与原生
                 开销的比值, 并使用      KDE  估计分布密度, 可以得到图        11. 为了表述方便, 在下文使用       R i/ 来表示额外的初始化开
                                                                                     o
                 销相比于原生开销的比值.
                    图  11  有两波波峰, 第  1  波大约在  R i/ 为 o  4  处, 另一波对应的 R i/o  则超过了 100. 相比于原生开销 100 倍的额外
   19   20   21   22   23   24   25   26   27   28   29