99久久全国免费观看_国产一区二区三区四区五区VM_久久www人成免费看片中文_国产高清在线a视频大全_深夜福利www_日韩一级成人av

徐土豆
認證:優質創作者
所在專題目錄 查看專題
C語言中去除不必要的內存引用可以有效地提高性能
C語言中內循環和外循環的位置可能產生性能上的區別
[C語言朝花夕拾] C語言中的命令行輸入參數判斷
用“位操作”取代“取模操作”判斷奇數偶數
c語言運行時出現segment fault的原因
一文理解C語言中的volatile修飾符
作者動態 更多
給定計算預算下的最佳LLM模型尺寸與預訓練數據量分配
05-19 09:33
大模型推理時的尺度擴展定律
05-18 10:32
世界多胞體與世界模型
05-13 09:42
獎勵模型中的尺度擴展定律和獎勵劫持
05-12 08:41
MeCo——給預訓練數據增加源信息,就能減少33%的訓練量并且提升效果
05-08 09:13

C語言中內循環和外循環的位置可能產生性能上的區別

本文轉載自徐飛翔的“C語言中內循環和外循環的位置可能產生性能上的區別

版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。

在圖像處理相關的代碼中,我們經常有類似于以下的代碼,去遍歷多維數組(張量)的每一個元素:

#define LENGTH 10000
void proc(){
	uint8 datas[LENGTH][LENGTH];
	int i, j;
	long long sum = 0;
	for (i = 0; i < LENGTH; i++){
		for (j = 0; j < LENGTH; j++){
			sum += datas[i][j];
		}
	}
}

其中的sum += datas[i][j];從語義上是和sum += datas[j][i];效果一致的,然而從性能上來說是否是一致的呢?答案是不是的,要看程序的編譯優化程度。我們會發現,當循環變量處于內循環和外循環時,其性能是不一樣的,即便是運算結果一致。


我們知道不管是一維數組還是多維數組,在內存中都是線性排列的,以二維數組為例子,為了能將二維的數組拉成一維的,一般需要考慮編譯器在編譯代碼時,其在內存中是行優先(row-major)排列還是列優先(colum-major)排列的。如下圖所示,如果一個數組是行優先排列的,那么其在連續內存上的排列順序如紅色線的順序。舉個例子,比如現在有個數組int vars[3][3],如果是行優先排列的,那么有:(===的意思是等價, (vars+i)表示對以vars作為數組指針的前提下,偏移i個元素的地址,而*(vars+i)是對其進行取內容。)

vars[0, 0] === *(vars+0);
vars[0, 1] === *(vars+1);
vars[1, 0] === *(vars+3);
==>
vars[i, j] === *(vars+3*i+j)

如果是列優先排列呢,則是

vars[0, 0] === *(vars+0);
vars[0, 1] === *(vars+1*3+1);
vars[1, 0] === *(vars+0*3+1);
==>
vars[i, j] === *(vars+3*j+i)

到這里為止都好理解,不過后續我們需要理解的一點是,我們現在跑得程序很多都不是在裸機上跑的。這里指的裸機就是沒有操作系統的計算機,比如單片機等,或者是沒有任何操作系統的其他CPU。在操作系統上跑程序,那么我們的程序的內存空間其實都是虛擬內存空間,是一種邏輯地址,其和物理的內存位置是沒有必然關聯的,需要受到操作系統的控制。采用虛擬內存有很多好處,其中最明顯的就是:

  1. 不需要考慮不同程序之間的相對地址偏移,每個程序都有其獨自的內存空間,其地址范圍都是從0到系統定義的最大值max_mem。
  2. 虛擬內存可以看成是一個巨大的線性內存空間,不需要考慮內存不足的情況,因為當內存不足的情況或者需要訪問的數據不在內存上時,就發生了缺頁錯誤(page fault),操作系統會自動進行“換頁”(paging),將物理內存暫時不用了的內存頁保存到存儲空間巨大的硬盤上,然后把需要讀取的內存加載到內存上。在這種情況下,可以把整個硬盤都看成是一個可以換入和切出的內存(雖然速度很慢,沒法和真正的內存比)

虛擬內存的細節太多,是操作系統設計的一個主要概念,其他細節需要參考其他書籍,比如[1,2]。我們在這里需要知道的是,我們程序中隨時可能遇到數據在內存中找不到的事情發生,這個時候就會發生換頁的操作,從硬盤中加載數據到內存(IO操作)是非?;〞r間的,因此很多程序的瓶頸都會在此。我們這里的關鍵點也正是在此。

在一個以行優先排序的編譯器上,每一行的數據在內存地址上都是比較接近的,而列數據的地址總是相差著sizeof(data_type) * N,其中N NN是每一行的元素數量。這就導致每一行的數據可能是處于同一個內存頁幀(page frame)上的,而每一個列的數據處于不同的頁幀上。在以行優先排序的編譯器上,如果外循環是列索引,內循環是行索引,有可能會發生頻繁地進行缺頁,換頁的操作(準確地說是n*m次),嚴重影響程序的性能。當然,這里只是可能,具體情況和你的數組大小,系統的頁大小設置等有關。(這里的缺頁特別在物理內存比較小的時候更為嚴重)

這里舉個代碼例子,說明性能上的差別。


考慮代碼:

# code 1
#define LENGTH 20000
int main(){
	float vector[LENGTH][LENGTH];
	int i, j;
	float sum = 0.0f;
	for (i = 0; i < LENGTH; i++){
		for (j = 0; j < LENGTH; j++){
			sum += datas[i][j];
		}
	}
	return 0;
}
# code 2
#define LENGTH 20000
int main(){
	float vector[LENGTH][LENGTH];
	int i, j;
	float sum = 0.0f;
	for (i = 0; i < LENGTH; i++){
		for (j = 0; j < LENGTH; j++){
			sum += datas[j][i];
		}
	}
	return 0;
}

這兩個代碼除了索引的順序不同(相當于內外循環調換)之外,其他別無差別。我們為了防止編譯器對代碼進行優化,影響分析,我們采用-O0編譯參數以去掉任何gcc的優化。(其實用其他優化等級效果也是類似的,讀者可以自行嘗試,并且用指令gcc -O0 -S code1.c觀察分析其匯編代碼。)

gcc -O0 code1.c
/usr/bin/time -v ./a.out

我們用/usr/bin/time分析程序的運行時間,我們有這兩者的運行時間分別為:

code 1的運行時間為2.05s

而code 2的時間則變成了5.68s,性能明顯差code 1很多。

但是如果我們把數組的大小從20000改成200會怎么樣呢?我們發現其性能將不會有明顯區別了,就是因為尺寸大小的不同影響了頁幀的換頁過程。

Reference

[1]. Bryant R E, David Richard O H, David Richard O H. Computer systems: a programmer’s perspective[M]. Upper Saddle River: Prentice Hall, 2003.

[2]. Tanenbaum A S. Structured computer organization[M]. Pearson Education India, 2016.

聲明:本內容為作者獨立觀點,不代表電子星球立場。未經允許不得轉載。授權事宜與稿件投訴,請聯系:editor@netbroad.com
覺得內容不錯的朋友,別忘了一鍵三連哦!
贊 2
收藏 2
關注 52
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧
主站蜘蛛池模板: 国产野精品久久久久久久不卡 | 伊人精品成人久久综合软件 | 最新理伦片eeuss影院2012 | 狠狠色成人综合网 | 斗罗大陆4终极斗罗免费观看 | 18禁无遮挡免费视频网站 | 色婷婷国产精品一区二区 | 男男av纯肉无码免费播放无码 | 丰满人妻熟女色情A片 | 中日精品一色哟哟 | 婷婷丁香亚洲色综合91 | 婷婷国产一区综合久久精品 | 国产剧情一区二区三区 | 亚洲精品av久久久久久久影院 | 成人免费毛片病毒 | 夜夜操天天射 | 97在线观看免费版高清 | 成人影院亚洲 | 免费吃奶摸下激烈视频青青网 | 亚洲最色视频 | 日本黄色xxxxx | 777片理伦片在线观看 | 亚洲无码专区三区在线观看 | 英语老师解开裙子坐我腿中间 | 国产高潮久久 | 二区三区偷拍浴室洗澡视频 | 国产91一区二区在线观看 | 国产精品高潮呻吟av久久4虎 | 国产视频久久网 | 国产成人亚洲第一 | 成人麻豆日韩在无码视频 | 欧洲在线一区二区 | 久久精品久久精品久久精品 | 最新国产精品视频 | 亚洲日韩av片在线观看 | 极品少妇粉嫩小泬v片可看 99热婷婷 | xxxx交换夫妇com1 | 69免费网站 | 亚洲AV永久无码精品三区在线4 | 亚洲日韩在线中文字幕第一页 | 中文字幕亚洲码在线观看 |