首先依旧是参考
SIR的tcas项目:https://sir.csc.ncsu.edu/php/common/download.php?ac=pub&key=sir/cobjects/sun&id=20&file=tcas_2.0.tar.gz
介绍tcas:https://blog.csdn.net/mangoer_ys/article/details/25974067
介绍gcov工具:https://blog.csdn.net/yanxiangyfg/article/details/80989680
前文:https://blog.csdn.net/CAceAs/article/details/88834485
按照昨天的反思,我尝试移除了lcov语句,这样就没有简洁的info文档可供读取,仅能读取tcas.c.gcov。
提升有三:
1.运行速度大大提升,在虚拟机的linux系统运行一个版本的时间由约240秒到18秒。
2.除了需要的matrix和result外不生成过多的多余文档(之前每个版本下有1608个t1,t2…记录分支覆盖和r1,r2…记录lcov结果)
3.因为效率提高,所以一次运行了41个版本。之前需手动改变version40次
以下是具体代码:
import os
import numpy as np
version = 1
test = 1
statement = 1
f = open("./runall.sh")
oldscript = f.readlines()
for version in range(1,42):
#version
#this module is used for running test language----shell
matrix = np.zeros((1609,65))
os.system("gcc -fprofile-arcs -ftest-coverage -o ../versions.alt/versions.orig/v"+str(version)+"/tcas.exe ../versions.alt/versions.orig/v"+str(version)+"/tcas.c -w\n")
os.system("cp ../versions.alt/versions.orig/v"+str(version)+"/tcas.exe ../source\n")
os.system("mv ../scripts/tcas.gcno ../versions.alt/versions.orig/v"+str(version)+"\n")
os.system("mkdir ../outputs/v"+str(version)+"\n")
oldscript = [line for line in oldscript if(not line.startswith("echo"))]
for line in oldscript:
#test case
os.system(line.replace('../outputs', '../outputs/v'+str(version)))
os.system("mv ../scripts/tcas.gcda ../versions.alt/versions.orig/v"+str(version)+"\n")
os.system("gcov -b ../versions.alt/versions.orig/v"+str(version)+"/tcas.c > /dev/null")
g = open("tcas.c.gcov")
#this module is used for generate test case matrix
for line in g.readlines():
#statement
if(line.strip()[0] in ('1','2','3','4','5','6','7','8')):
matrix[test-1][statement-1] = int(line.strip()[0])
matrix[-1][statement-1] += 1
statement += 1
elif(line.strip()[0] == '#'):
matrix[test-1][statement-1] = 0
statement += 1
statement = 1
test += 1
g.close()
test = 1
np.savetxt("../versions.alt/versions.orig/v"+str(version)+"/matrix",matrix,fmt='%d')
#this module is used for print out results
false_num = 0
true_num = 0
LF = 65
LH = 0
max_num = 0
min_num = 1608
sum_num = 0
mean_num = 0
for i in range(1, 1609):
tmp = os.system("diff ../outputs/v0/t"+str(i)+" ../outputs/v"+str(version)+"/t" + str(i) + ">/dev/null")
if tmp != 0:
false_num += 1
else:
true_num += 1
for i in range(0,LF):
if(matrix[-1][i-1] != 0):
LH += 1
if(matrix[-1][i-1] > max_num):
max_num = matrix[-1][i-1]
if(matrix[-1][i-1] < min_num):
min_num = matrix[-1][i-1]
sum_num += matrix[-1][i-1]
linecov = round(LH/LF,4)
mean_num = round(sum_num/LF,2)
r = open("../versions.alt/versions.orig/v"+str(version)+"/result","w+")
r.write("True test number: "+str(true_num)+"\nFalse test number: "+str(false_num))
r.write("\nThe total statements: "+str(LF)+"\nThe statements executed: "+str(LH))
r.write("\nThe line coverage: "+("%.2f%%" % (linecov * 100)))
r.write("\nMax number of executed times: "+str(max_num))
r.write("\nMin number of executed times: "+str(min_num))
r.write("\nMean number of execute times: "+str(mean_num))
r.close()
f.close()
其中,
oldscript = [line for line in oldscript if(not line.startswith("echo"))]
是一个对line的判断,仅读取测试用例进入oldscript,取代了添加一个额外的if判断,减少一层代码上的嵌套。
for line in g.readlines():
#statement
if(line.strip()[0] in ('1','2','3','4','5','6','7','8')):
matrix[test-1][statement-1] = int(line.strip()[0])
matrix[-1][statement-1] += 1
statement += 1
elif(line.strip()[0] == '#'):
matrix[test-1][statement-1] = 0
statement += 1
改进的核心,读取gcov文件部分,将数字开头的文件读入matrix,由于未被执行的可执行语句并不是用‘0’而是‘#####’表示,所以分两个判断读取,将之前版本的matrix最后一行的生成循环即:
for cursor in range(0,65):
for test_num in range(0,1608):
if(matrix[test_num][cursor] != 0):
matrix[-1][cursor] = matrix[-1][cursor] + 1
合并到这一循环中。
在优化之后尝试运行了41个版本,发现了一处问题,编译报错大概是:Index 65 is out of matrix,出错代码是
matrix[test-1][statement-1] = int(line.strip()[0])
原因:在程序中定义matrix时采用np.zeros((1609,65)),其中65意味着我们默认可执行语句是65个,这也是下面没计算LF的原因,但是具体定位发现,第31个版本是67个可执行语句,导致矩阵索引超过边界。
因此,给出最后的修改好的测试脚本:
如果觉得有用请Star一下哦!
有很多细微改动,主要解决办法是
1.在进行第一层循环(版本级别)时加上LF=0
2.定义matrix有100列
3.在结束第三层循环(语句级别)后,清空statement之前将值赋给LF
4.savetxt时保存内容由matrix改成matrix[:,0:LF]
在进行第一处纠错后发现第二个问题,LH(被执行语句)总是少一个,平均值也总是偏小,那么原因在哪儿呢?对比发现在对写好的矩阵进行统计时好像总是少收集一行数据,出错代码在:
for i in range(0,LF):
if(matrix[-1][i-1] != 0):
LH += 1
if(matrix[-1][i-1] > max_num):
max_num = matrix[-1][i-1]
if(matrix[-1][i-1] < min_num):
min_num = matrix[-1][i-1]
sum_num += matrix[-1][i-1]
i的取值范围在0,LF就是执行到LF-1这没有错,但是下文就不应该再按照[i-1]进行取值,因为0,LF已经考虑了索引值从0开始的事实。只要把i-1改为i就行。
但是更深入的考虑一下,为什么之前就没有错误呢?改变LF不能改变i-1写错了的事实啊,为什么之前数据都正确呢?
原因是!当时矩阵定义了65列,没有一行是多余数据,以i-1为索引时读取按照-1,0,1,2…63进行统计,而矩阵的-1索引代表倒数第一列,正好统计了64,巧合般的完全覆盖了,而改正后统计矩阵为zeros((1609,100))倒数第一列显然不会存放有效数据,问题就暴露了。
这次改进仍给我带来新理解,这次的版本显然更简洁高效,但是与之前版本按步骤给出代码相比,这次的代码可读性可能变差了。尽管我认为还是更优雅了一些
编译报错:TypeError: ‘builtin_function_or_method’ object has no attribute ‘getitem’
以及
编译报错:TypeError: ‘builtin_function_or_method’ object is not iterable
原因:使用readlines未添加括号。
编译报错:inconsistent use of tabs and spaces in indentation
原因:在缩进中不一致地使用Tab和空格,所以python需要很严格的格式,对齐很重要.
解决:重新敲缩进
使用gc编译器命令时弹出编译警告,不影响运行但是打乱命令行的观察
解决:gcc命令最后加上参数-w(-Wall)
使用mkdir命令弹出文件夹已存在的警告,不影响运行但是打乱命令行的观察
解决:加上-p参数