循环赋值更快还是memcpy更快?

最近在优化白板书写提速的FrameBuffer库,发现有一个循环:

void drawPixelRect(int x, int y, int width, int height, int* pixels) {
	int loc = y * FIXED_WIDTH + x;
	int i, j, k = 0;
	//int endLoc = (y + height) * FIXED_WIDTH + x + width;
	for(i = 0; i < height; i++) {
		for(j = 0; j < width; j++) {
			fb0[loc + j] = fb1[loc + j] = fb2[loc + j] = pixels[k++];
		} 
		
		loc += FIXED_WIDTH; //add a row 
	}
}

这段代码的作用是分别给3个FrameBuffer端赋予同样的一个数据块,但我这个嵌套循环看着很不顺眼,因此优化成了:

void drawPixelRect(int x, int y, int width, int height, int* pixels) {
	int loc = y * FIXED_WIDTH + x;
	int i, j, k = 0;
	//int endLoc = (y + height) * FIXED_WIDTH + x + width;
	for(i = 0; i < height; i++) {
		memcpy(fb0 + loc, pixels + k, width * sizeof(int));
		memcpy(fb1 + loc, pixels + k, width * sizeof(int));
		memcpy(fb2 + loc, pixels + k, width * sizeof(int));
		k += width;
		
		loc += FIXED_WIDTH; //add a row 
	}
}

只要一个循环就可以了,而且循环展开之后对CPU流水线利用按我的认知应该会更充分,我认为应该是会更快的。那么究竟有多块呢?

 

因此我写了个Demo来进行测试:

#include "stdio.h"
#include "stdlib.h"
#include "sys/time.h"

#define TEST_SIZE 100005

int pixels[TEST_SIZE];

void test1(){
	int* frame = (int*)malloc(sizeof(int) * 300000);
	int* fb0 = frame;
	int* fb1 = frame + TEST_SIZE;
	int* fb2 = frame + TEST_SIZE * 2;
	int i;
	struct timeval tv;	
	int startTime, endTime;
	//纪录代码开始时间戳 
	gettimeofday(&tv, NULL);
	startTime = tv.tv_sec * 1000000 + tv.tv_usec;  //微秒
	for(i = 0; i < TEST_SIZE; i++){
		fb0[i] = fb1[i] = fb2[i] = pixels[i];
	}
	gettimeofday(&tv, NULL);
	//纪录代码结束时间戳
	endTime = tv.tv_sec * 1000000 + tv.tv_usec;  //微秒
	printf("used time :%d\n", endTime - startTime);
	
	/*for(i = 0; i < 300000; i++){
		printf("%d\t", frame[i]);
	}*/
	free(frame);
}

void test2(){
	int* frame = (int*)malloc(sizeof(int) * 300000);
	int* fb0 = frame;
	int* fb1 = frame + TEST_SIZE;
	int* fb2 = frame + TEST_SIZE * 2;
	int i;
	struct timeval tv;	
	int startTime, endTime;
	//纪录代码开始时间戳 
	gettimeofday(&tv, NULL);
	startTime = tv.tv_sec * 1000000 + tv.tv_usec;  //微秒
	//使用memcpy复制数据 
	memcpy(fb0, pixels, TEST_SIZE * sizeof(int));
	memcpy(fb1, pixels, TEST_SIZE * sizeof(int));
	memcpy(fb2, pixels, TEST_SIZE * sizeof(int));
	//纪录代码结束时间戳
	gettimeofday(&tv, NULL);
	endTime = tv.tv_sec * 1000000 + tv.tv_usec;  //微秒
	printf("used time :%d\n", endTime - startTime);
	/*for(i = 0; i < 300000; i++){
		printf("%d\t", frame[i]);
	}*/
	free(frame);
}

void test3(){
	int* frame = (int*)malloc(sizeof(int) * 300000);
	int* fb0 = frame;
	int* fb1 = frame + TEST_SIZE;
	int* fb2 = frame + TEST_SIZE * 2;
	int i;
	struct timeval tv;	
	int startTime, endTime;
	//纪录代码开始时间戳 
	gettimeofday(&tv, NULL);
	startTime = tv.tv_sec * 1000000 + tv.tv_usec;  //微秒
	//使用memcpy和循环混合复制数据 
	for(i = 0; i < 3; i++){
		memcpy(fb0 + TEST_SIZE * i, pixels, TEST_SIZE * sizeof(int));
	} 
	//纪录代码结束时间戳
	gettimeofday(&tv, NULL);
	endTime = tv.tv_sec * 1000000 + tv.tv_usec;  //微秒
	printf("used time :%d\n", endTime - startTime);
	/*for(i = 0; i < 300000; i++){
		printf("%d\t", frame[i]);
	}*/
	free(frame);
}


int main(){
	int i;
	for(i = 0; i < TEST_SIZE; i++){
		pixels[i] = i;
	}
	test1();
	test2();
	test3();
	return 0;
}

其中,函数test1使用了循环赋值的方法进行分段给数据,test2没有任何循环,直接用三段memcpy给数据;test3使用了3次循环和memcpy + 偏移地址进行给数据,结果可以发现,循环给数据速度是最慢的,使用memcpy,并且尽可能减少循环的层级,速度则快得多。所以在需要执行效率的模块上,尽可能少用循环,尤其是嵌套循环,并尽可能把循环多展开一些,可以提高程序的执行效率。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值