文献阅读笔记 # 面向大规模多版本软件系统的代码克隆检测加速技术

  • 面向大规模多版本软件系统的代码克隆检测加速技术,方维康 吴毅坚 赵文耘,《计算机应用与软件》复旦大学软件学院、复旦大学上海市数据科学重点实验室
  • 2022 April

面向大规模多版本软件系统的代码克隆检测加速技术

摘要

很多代码克隆检测方法主要针对软件系统的单个版本进行检测,在多版本情况下效率较低。本文提出一种针对多版本软件系统的克隆检测加速技术,可以快速得到每个版本的克隆情况。

通过版本间方法映射技术为不同版本代码内容高度相似的同一方法构建方法版本组,选取每个方法版本组中最早的版本作为样本方法,样本方法的集合构成历史映像,对历史映像进行克隆检测,同时建立样本方法和方法版本组间的方法索引。根据历史映像克隆检测结果及方法索引恢复原始的全量克隆关系。

结论:与文本对比方法提速4倍。
这里的多版本不是组件的多版本…是指被测软件具有多个版本…!!
ps:本文加速的重点不是克隆检测本身,而是如何处理多版本之间的重复代码,标记重复代码、减少查询量,去重后的集合叫历史映像

0 引言

  • 代码克隆普遍存在,代码克隆与程序的缺陷率、软件稳定性、软件质量、软件维护成本存在关联;
  • 传统的代码克隆检测在多版本时对每个版本挨个比较,计算量较大,没有充分利用同项目多版本之间的信息(版本更新变化的代码量只占总代码量中的小部分);

本文方法:方法版本组 => 样本方法 => 历史映像 => 克隆检测 => 版本恢复
关键技术:

  • 1.如何快速分析出系统所有版本中的每个方法;
  • 2.基于局部相似性比较在前后版本快速建立演化关系;
  • 3.基于索引快速恢复所有克隆关系;

1 代码克隆

Ⅰ型克隆: 除去空白符和注释之外完全一样的代码片段;
Ⅱ型克隆: 除了空白符、注释、标识符、类型和字面值有可能不同之外,语法结构上完全一致的代码片段;
Ⅲ型克隆:除了空白符、注释、标识符、类型和字面值有可能不同之外,还有可能添加、修改或删除了一些代码行的代码片段;
Ⅳ型克隆: 功能上一致但代码本身相似度较低的代码片段(语义级克隆);

  • 从Ⅰ型克隆到 Ⅲ 型克隆,克隆片段之间的语法相似度逐渐降低。Ⅳ 型在语法级别相似度已经很低。

  • 克隆对:存在克隆关系的两个代码片段被称为一组克隆对;
  • 克隆组(类):一组存在克隆关系的代码片段被称为克隆组;
  • 克隆实例:克隆对或克隆组中的每一个代码片段都称为一个克隆实例;
  • 方法级克隆:如果两个或多个方法是彼此克隆的,则将这种克隆称为方法级克隆。方法级克隆的克隆实例是完整的方法(即函数级克隆);

代码克隆检测基本思路:基于文本、基于 token、基于程序依赖图、基于抽象语法树、基于代码底层表示等;

  • 但上面的方法里,在大规模克隆检测(亿行级),只有 SourcererCC 和 SAGA 表现相对还行。
  • 考虑多版本的克隆检测:
    • 比如分析一个多版本项目的克隆演化图谱时,只分析目标项目最初版本的克隆检测结果,然后再用版本管理工具的修改信息追踪克隆;缺点:丢失最初版本后续版本的所有克隆(检测不出);【?为啥会检测不出,这个和增量克隆检测有啥区别
    • 增量克隆检测:缺点:不适用于跨项目克隆检测。【和上面有啥区别?跨项目是指最开始检测出的克隆组件结果里面根据增量在这个组件结果集合里去定位克隆部分,而不去查引入的新组件么?那如果放到所有组件库里去查不行吗?

本文相比增量检测,相当于是对增量也做了压缩,没有扫全部的增量,而是扫低于阈值的增量,对于轻微修改某函数是不会额外去检测的,但对于新创建的函数或者大幅修改逻辑会重新扫

2 基于版本间代码压缩的多版本克隆检测加速技术

2.1 项目信息预处理

目标项目集:所有待检测的项目的集合

  • 对目标项目进行预处理,括项目版本信息提取和项目方法信息提取
    • 版本信息提取:该项目所有发布版本的相关信息,包括每个版本的名称、发布时间、各个版本的代码,同时将该项目的各个版本按照发布时间先后进行组织排序;
    • 方法信息提取:对目标项目每个版本,方法提取器提取代码中所有方法的相关信息,其中根据该项目所使用的编程语言采用了相关的语法解析工具(例如 JavaParser、TXL 等)包括方法签名、方法完全限定名、方法所在文件的路径、方法起止行,最后将这些信息以方法为单位保存到一个集合中,将其称为该版本的方法信息集合

2.2 构建历史映像

历史映像:为不同版本中方法名及所属文件路径一致且代码内容相同或高度相似的同一方法( 下文简称为相同方法) 构建方法版本组。再选取每个方法版本组中最早的版本作为样本方法,样本方法的集合则称为历史映像

  • 方法版本组:方法映射器将含有多个版本的项目基于方法名及文件路径构建将不同版本、代码内容相同或高度相似的相同方法构建方法版本组。(不一定是完全一致,相似的方法/函数也作为一个方法版本组);
    • 规则: 版本按发布时间排序,对于每个方法,判断其是否已经属于某个方法版本组,否则新建一个组,对于该方法,提取其方法名与所在文件的相对路径,查找所有后续版本中与该相对路径、方法名都相同且文本高度相似的方法,将这些方法添加到该新的方法版本组。
    • 规则:相同方法判断依据:方法完全限定名相同/相似、方法所在的文件的路径一致且方法源代码间有非常高的文本相似度,本文采用最长公共子序列长度识别相似度。
      • 这种方式会导致方法移动、文件重命名的需要重新参与计算,但这个效率的损失相比不加路径限定考虑的代码带来的性能损失少很多。
  • 选择样本方法:本文统一选取所有方法版本组中最早的版本作为样本方法;

2.3 克隆检测

本文采用了 Saga;支持Ⅰ型到 Ⅲ 型克隆的检测;
Li G,Wu Y,Roy C K,et al. Saga: Efficient and largescale detection of near-miss clones with GPU acceleration [C]/ /2020 IEEE 27th International Conference on Software Analysis,Evolution and Reengineering ( SANER) . IEEE,2020: 272 - 283

2.4 恢复全量克隆关系

2.5 优化方案

方法版本组构建时用多线程对构建算法并行化改造,不同方法的版本组之间构建互不影响因此满足并行的前提。并行粒度(即线程池的核心数量)是 CPU 可用核数的两倍。

function FUNCVEGROUPCONSTRUCT(FuncInfoSetList)
	coreSize←availableProcessors( ) * 2
	exec←Executors.newFixedThreadPool(coreSzie)
	for currentVer∈AllVers do
		for currentFunc∈currentVers.getFuncInfoSet() do
			if currentFunc.isUnmarked() then
				currentFunc.mark()
				exec.submit(DetectSameFunc())
			end if
		end for
	end for
	exec.shutdown()
	return funcVerGroupMap
end function

function DETECTSAMEFUNC()
	for i from currentVer to lastVer do
		targetVer←FuncInfoSetList.get(i)
		if targetVer.getFuncInfoSet().contains(currentFunc) then
			targetFunc←targetVer.getFuncInfoSet().get(currentFunc)
			if getSimilarity(currentFunc, targetFunc) > threshold then
				funcVerGroupMap.get(currentFunc).add(targetFunc)
				targetFunction.mark()
			end if
		end if
	end for
end function

3 实验

设备:英特尔 i7-7820X 型 CPU(8 核心 16 线程), 32 GB 主存, 1 TB 固态存储硬盘, CentOS7 操作系统。
数据:github stars > 50, total 251 Java projects, date 2004~2019, 约 3 亿行。
结论:预处理后的查询量减少了87%,速度提升4倍。

4 结语

略。

猜你喜欢

转载自blog.csdn.net/qq_33583069/article/details/129238757