下面所涉及的实验平台
ubuntu host电脑
android设备
首先,我们回顾一下在ubuntu中如何实现覆盖率统计
rgb2yuv.cpp是本次试验用的代码
编译
1、命令行编译
gcc rgb2yuv.cpp -fprofile-arcs -ftest-coverage
2、或者用makefile编译
edit : rgb2yuv.o
gcc rgb2yuv.o -o edit -fprofile-arcs
rgb2yuv.o : rgb2yuv.cpp
gcc -c -fprofile-arcs -ftest-coverage rgb2yuv.cpp
以上编译会产生下面几个文件
xxx@xxx:~/ca07/frameworks/av/cmds/camerad$ ./edit
-rwxrwxr-x 1 qyang qyang 28777 2月 15 15:10 edit*
-rw-rw-r-- 1 qyang qyang 126 2月 14 16:42 Makefile
-rw-rw-r-- 1 qyang qyang 2897 2月 14 16:49 rgb2yuv.cpp
-rw-rw-r-- 1 qyang qyang 2964 2月 15 15:10 rgb2yuv.gcno
-rw-rw-r-- 1 qyang qyang 6760 2月 15 15:10 rgb2yuv.o
其中edit为产生的可执行文件,rgb2yuv.gcno是由-ftest-coverage产生的,它包含了重建基本块图和相应的块的源码的行号的信息。
运行程序并收集覆盖数据
xxx@xxx:~/ca07/frameworks/av/cmds/camerad$ ./edit
程序结束后会产生下面的文件
rgb2yuv.gcda
此文件由 -fprofile-arcs 编译参数的编译后的文件运行所产生的,它记录了每行代码执行的次数和其他的概要信息。
生成报告
lcov -c -d ./ -o res.info --rc lcov_branch_coverage=1
genhtml -o report res.info --rc lcov_branch_coverage=1
上面完成后会在目录产生res.info和report目录,使用浏览器打开report目录中的index.html,即可看到覆盖率信息。
在Android平台中统计C/C++覆盖率
Android.mk 按下面的样式
include $(CLEAR_VARS)
LOCAL_SRC_FILES := rgb2yuv.cpp
LOCAL_SHARED_LIBRARIES := libutils libgui libbinder libui libcutils liblog
LOCAL_CFLAGS += -fprofile-arcs -ftest-coverage
LOCAL_LDFLAGS := -fprofile-arcs
LOCAL_MODULE:= rgb2yuv
include $(BUILD_EXECUTABLE)
编译
编译完后rgb2yuv.gcno文件在out目录中
out/target/product/top6735_35gu_l1/obj/EXECUTABLES/rgb2yuv_intermediates/rgb2yuv.gcno
将此文件copy到代码目录中
部署
将编译完的rgb2yuv push到设备中
adb push ~/ca07/out/target/product/top6735_35gu_l1/system/bin/rgb2yuv /mnt/hd/
运行
shell@android:/mnt/hd $ export GCOV_PREFIX=/mnt/hd/
shell@android:/mnt/hd $ ./rgb2yuv
hello world
产生的文件在下面路径中
/mnt/hd/home/qyang/ca07/out/target/product/top6735_35gu_l1/obj/EXECUTABLES/rgb2yuv_intermediates/rgb2yuv.gcda
PS:
1、一定要设置GCOV_PREFIX环境,否则会在根目录下产生gcda文件,但根目录只读,会导致产生失败。
2、设置的目录一定要有写权限,如果目录指向sdcard卡,还必须在AndroidManifast.xml中申明权限。
shell@android:/mnt/hd $ ./rgb2yuv
hello world
profiling:/home:Cannot create directory
profiling:/home/qyang/ca07/out/target/product/top6735_35gu_l1/obj/EXECUTABLES/rgb2yuv_intermediates/rgb2yuv.gcda:Skip
产生报告
adb pull /mnt/hd/home/qyang/ca07/out/target/product/top6735_35gu_l1/obj/EXECUTABLES/rgb2yuv_intermediates/rgb2yuv.gcda
有了gcda文件,和gcno文件,再产生html报告就和上面一样了。
lcov -c -d ./ -o res.info --rc lcov_branch_coverage=1
genhtml -o report res.info --rc lcov_branch_coverage=1
容易被忽略的地方
一定要等到程序正常停止退出才会产生gcda文件,如果Ctl+C中断,或crash,都不会有这个文件。
附件
// rgb2yuv.cpp
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
static int RGB2YUV_YR[256], RGB2YUV_YG[256], RGB2YUV_YB[256];
static int RGB2YUV_UR[256], RGB2YUV_UG[256], RGB2YUV_UBVR[256];
static int RGB2YUV_VG[256], RGB2YUV_VB[256];
//
// Table used for RGB to YUV420 conversion
//
void InitLookupTable()
{
int i=0;
for (i = 0; i < 256; i++) RGB2YUV_YR[i] = (float)65.481 * (i << 8);
for (i = 0; i < 256; i++) RGB2YUV_YG[i] = (float)128.553 * (i << 8);
for (i = 0; i < 256; i++) RGB2YUV_YB[i] = (float)24.966 * (i << 8);
for (i = 0; i < 256; i++) RGB2YUV_UR[i] = (float)37.797 * (i << 8);
for (i = 0; i < 256; i++) RGB2YUV_UG[i] = (float)74.203 * (i << 8);
for (i = 0; i < 256; i++) RGB2YUV_VG[i] = (float)93.786 * (i << 8);
for (i = 0; i < 256; i++) RGB2YUV_VB[i] = (float)18.214 * (i << 8);
for (i = 0; i < 256; i++) RGB2YUV_UBVR[i] = (float)112 * (i << 8);
}
//
// Convert from RGB24 to YUV420
//
int ConvertRGB2YUV(const int w, const int h, const uint8_t *bmp, uint8_t *yuv)
{
uint8_t *u,*v;
const uint8_t *r = bmp;
if (!yuv || !bmp)
return -1;
uint8_t *vv = yuv + w * h;
uint8_t *uu = vv + w*h/4;
u = uu;
v = vv;
//Get YUV values for rgb values...
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x += 2) {
register uint8_t rd = *r++;
register uint8_t gd = *r++;
register uint8_t bd = *r++;
r++;
*yuv++ = (RGB2YUV_YR[rd] + RGB2YUV_YG[gd] + RGB2YUV_YB[bd] + 1048576) >> 16;
rd = *r++;
gd = *r++;
bd = *r++;
r++;
*yuv++ = (RGB2YUV_YR[rd] + RGB2YUV_YG[gd] + RGB2YUV_YB[bd] + 1048576) >> 16;
if (y & 1) {
*u++ = (-RGB2YUV_UR[rd] - RGB2YUV_UG[gd] + RGB2YUV_UBVR[bd] + 8388608) >> 16;
*v++ = ( RGB2YUV_UBVR[rd]- RGB2YUV_VG[gd] - RGB2YUV_VB[bd] + 8388608) >> 16;
}
}
}
// Now sample the U & V to obtain YUV 4:2:0 format
// Sampling mechanism...
/*
@ -> Y
# -> U or V
@ @ @ @
# #
@ @ @ @
@ @ @ @
# #
@ @ @ @
*/
/*
uint8_t *pu1,*pu2,*pu3,*pu4;
uint8_t *pv1,*pv2,*pv3,*pv4;
// Get the right pointers...
u = yuv + w*h;
v = u + (w*h)/4;
// For U
pu1 = uu;
pu2 = pu1 + 1;
pu3 = pu1 + w;
pu4 = pu3 + 1;
// For V
pv1 = vv;
pv2 = pv1 + 1;
pv3 = pv1 + w;
pv4 = pv3 + 1;
// Do sampling....
for (int i = 0; i < h; i +=2) {
for (int j = 0; j < w; j+=2) {
*u++ = (*pu1+*pu2+*pu3+*pu4) >> 2;
*v++ = (*pv1+*pv2+*pv3+*pv4) >> 2;
pu1 += 2;
pu2 += 2;
pu3 += 2;
pu4 += 2;
pv1 += 2;
pv2 += 2;
pv3 += 2;
pv4 += 2;
}
pu1 += w;
pu2 += w;
pu3 += w;
pu4 += w;
pv1 += w;
pv2 += w;
pv3 += w;
pv4 += w;
}
*/
return 0;
}
int main(int argc, char* const argv[])
{
InitLookupTable();
InitLookupTable();
printf("hello world\n");
sleep(10);
ConvertRGB2YUV(0, 0, NULL, NULL);
ConvertRGB2YUV(0, 0, NULL, NULL);
return 0;
}