博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

关于汇编和C++链表的高级应用及性能分析

Posted on 2011-04-06 17:54  Code_HXH  阅读(1504)  评论(3编辑  收藏  举报
使用的编译器:MASM8.0和Visual Studio 2008
我们主要通过C++和汇编各自构建一个功能完全相同的链表结构,其中这个链表的功能有:
1. 声明结构
2. 构建链表
3. 对链表进行冒泡排序
4. 对链表进行复制操作
5. 计算从1-5所花费的毫秒数这里就是我们链表所要做的事情,同样的,我们链表采用的是指针链表,单向,非双向,考虑到汇编实现起来会有很多障碍,所以我们尽量让代码简洁些,这样子能够更好的从C++翻译到Assembly里面.好的,那我么现在就开始吧.首先,我们要先构造一个数组,这个数组我决定用汇编编译器来生成,反正代码之前都已经写好过了:
The Code:
.code
main PROC
call randomize
mov ecx,20
L1:
mov eax,1000
call RandomRange
call Writedec
call crlf
loop L1
exit
main ENDP
END main

所生成的随机数组:773 270 206 705 532 160 689 18 291 876 405 935 989 950 102 564 30 235 288 613

通过刚才的代码我们直接生成了一组没有重复过的二十个的数字,接下来我们就要用这些数字来进行一下所有的操作. 首先,我们先构建C++大约的框架,和汇编大约的框架.这里可能会有所不通,但是这只是一开始的设想,接下来还是会改的的
The code of C++

// 链表测试项目.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"


int _tmain(int argc, _TCHAR* argv[])
{
	return 0;
}

struct LinkofData 
{
	int temp;
	LinkofData *next;
};

void main()
{

}

void CreateTheLink()
{

}

void SortTheLink()
{

}

void CopyTheLink()
{

}

int TheTimeToPass()
{

}



接下来完善代码
FULL Code of C++
// 链表测试项目.cpp : 定义控制台应用程序的入口点。
//

//-------------------------------------------------------------------------预编译区
#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
	return 0;
}
#include "time.h"
#include <iostream>
using namespace std;

//-------------------------------------------------------------------------声明结构
struct LinkofData 
{
	int temp;
	LinkofData *next;
};

//-------------------------------------------------------------------------链表构造函数
void CreateTheLink(int a[],LinkofData *linklist)
{
	linklist->temp = NULL;
	linklist->next = NULL;
	for (int i=0;i<20;i++)
	{
		LinkofData *linklist1=new LinkofData;
		linklist1->temp=a[i];
		linklist1->next=NULL;
		linklist->next=linklist1;
		linklist=linklist1;
	}

}

//-------------------------------------------------------------------------冒泡排序函数
void SortTheLink(LinkofData *linklist)
{
	LinkofData *o,*p,*q;
	for (int i=0;i<19;i++)
	{	
		o=linklist;
		for (int j=0;j<19;j++)
		{
			if ((o->next->temp) > (o->next->next->temp))
			{
				p=o->next;
				q=o->next->next;
				p->next=q->next;
				q->next=p;
				o->next=q;
				o=o->next;
			}
			else
			{
				o=o->next;
			}
		}
	}
}

//-------------------------------------------------------------------------复制函数
void CopyTheLink(const LinkofData *link1,LinkofData *link2)
{
	LinkofData *p;
	p=link1->next;
	LinkofData *Topoflink2;
	Topoflink2=link2;
	link2->temp=NULL;
	link2->next=NULL; 
	while(p->next != NULL)
	{	
		LinkofData *templink2=new LinkofData;
		templink2->temp=p->temp;
		link2->next=templink2;
		link2=link2->next;
		p=p->next;
	}
	link2->next=NULL;
	link2=Topoflink2;
}

//-------------------------------------------------------------------------显示链表
void DisplayTheLinklist(const LinkofData *Linklist)
{
	LinkofData *temp;
	temp=Linklist->next;
	for(int i=0;i<20;i++)
	{
		cout<<temp->temp;
		temp=temp->next;
		cout<<"->";
	}
}

//-------------------------------------------------------------------------主函数区
void main()
{
	long start,finish;
	double dtime;
	start=clock();
	int a[20]={773,270,206,705,532,160,689,18,291,876,405,935,989,950,102,564,30,235,288,613};
	LinkofData *Linklist1;
	Linklist1 = new LinkofData;
	LinkofData *Linklist2;
	Linklist2 = new LinkofData;
	for (int i=0;i<200000;i++)
	{	
		CreateTheLink(a,Linklist1);
		SortTheLink(Linklist1);
		CopyTheLink(Linklist1,Linklist2);
	}
	finish=clock();
	dtime=(double)(finish-start);
	cout<<dtime;
	system("pause");
}
程序大概的流程图
FUll Code of Assembly:
TITLE Creating a Linked List (List.asm)

;// This program shows how the STRUC directive
;
// and the REPT directive can be combined to
;
// create a linked list at assembly time.
;
// Last update: 11/8/02

;//仿真要求:要根据指针域来寻址

INCLUDE Irvine32.
inc

CreateLinkList proto
SortLinkList proto
CopyLinkList proto

ListNode STRUCT
NodeData DWORD ?
NextPtr DWORD ?
ListNode ENDS

TotalNodeCount =
22
NULL =
0
Counter =
0

.data

TheNum DWORD
0,773,270,206,705,532,160,689,18,291,876,405,935,989,950,102,564,30,235,288,613
LinkedList ListNode TotalNodeCount dup(<
0,0>)
LinkedList1 ListNode TotalNodeCount dup(<
0,0>)
temp dword ?
tempq dword ?
tempp dword ?
StartTimer dword ?
.code
main PROC
call getmseconds
mov StartTimer,eax
repeat
200000
call CreateLinkList
call SortLinkList
call CopyLinkList
endm
call getmseconds
sub eax,StartTimer
call WriteDec
call crlf




;//--------------------------------------------开始遍历链表
mov esi,OFFSET LinkedList
NextNode:
; Check for the tail node.
mov eax,(ListNode PTR [esi]).NextPtr
cmp eax,NULL
je quit1

; Display the node data.
mov eax,(ListNode PTR [esi]).NodeData
call WriteDec
call Crlf

; Get pointer to next node.
mov esi,(ListNode PTR [esi]).NextPtr
jmp NextNode
quit1:
;//-------------------------------------------链表遍历完毕
call waitmsg
exit
main ENDP
CreateLinkList PROC
push ebp
mov ebp,esp
;//--------------------------------------------构建链表
push ecx
push edi
push eax
push esi
mov ecx,21
mov edi,offset LinkedList
mov esi,0
LW:
mov eax,dword ptr TheNum[esi]
mov (ListNode ptr [edi]).NodeData,eax
mov eax,edi
add eax,type ListNode
mov (ListNode ptr [edi]).NextPtr,eax
add edi,type ListNode
add esi,type TheNum
LOOP LW
push esi
push eax
push edi
push ecx
;//--------------------------------------------链表构建完毕
mov esp,ebp
pop ebp
ret
CreateLinkList ENDP

SortLinkList PROC
push ebp
mov ebp,esp
;//--------------------------------------------冒泡排序开始
;// 这里用到了 edi 头寻址 ecx 循环控制 ebx,edx,
push edi
push ecx
push eax
push ebx
push edx
push esi
mov edi,offset LinkedList
mov ecx,19
;//根据定理,这里的offset Linkedlist永远是指向一个固定位置的
maopao1:
push ecx
mov ecx,19
mov eax,edi
maopao2:
mov ebx,(ListNode PTR [eax]).NextPtr
mov edx,(ListNode PTR [ebx]).NextPtr
mov esi,(ListNode PTR [ebx]).NodeData
cmp esi,(ListNode PTR [edx]).NodeData
jb allhavetodo
bigger:;//-----------------------------------进行对换
mov (ListNode PTR [eax]).NextPtr,edx
push eax
mov eax,(ListNode PTR [edx]).NextPtr
mov (ListNode PTR [ebx]).NextPtr,eax
pop eax
mov (ListNode PTR [edx]).NextPtr,ebx
;//-----------------------------------对换结束
allhavetodo:
mov eax,(ListNode PTR [eax]).NextPtr
;//-----------------------------------上面的eax指向eax的下一个地址
loop maopao2
pop ecx
loop maopao1
push esi
push edx
push ebx
push eax
push ecx
push edi
mov esp,ebp
pop ebp
ret
;//--------------------------------------------冒泡排序结束
SortLinkList ENDP

CopyLinkList PROC
push ebp
mov ebp,esp
;//--------------------------------------------链表复制开始
;// edi为LinkedList首地址 ebx为LinkedList1首地址 eax为临时变量
push edi
push ebx
push eax
mov edi,offset LinkedList
mov ebx,offset LinkedList1
Copytwo:
mov eax,(ListNode PTR [edi]).NextPtr
cmp eax,NULL
je quit

mov eax,(ListNode ptr [edi]).NodeData
mov (ListNode ptr [ebx]).NodeData,eax
mov eax,ebx
add eax,type ListNode
mov (ListNode ptr [ebx]).NextPtr,eax
add edi,type ListNode
add ebx,type ListNode
jmp Copytwo
quit:
pop eax
pop ebx
pop edi
mov esp,ebp
pop ebp
ret
;//--------------------------------------------链表复制结束
CopyLinkList ENDP


END main
FUll Code2 of Assembly:
TITLE Creating a Linked List (List.asm)

;// This program shows how the STRUC directive
;
// and the REPT directive can be combined to
;
// create a linked list at assembly time.
;
// Last update: 11/8/02

;//仿真要求:要根据指针域来寻址

INCLUDE Irvine32.
inc

CreateLinkList proto
SortLinkList proto
CopyLinkList proto

ListNode STRUCT
NodeData DWORD ?
NextPtr DWORD ?
ListNode ENDS

TotalNodeCount =
22
NULL =
0
Counter =
0

.data

TheNum DWORD
0,773,270,206,705,532,160,689,18,291,876,405,935,989,950,102,564,30,235,288,613
LinkedList ListNode TotalNodeCount dup(<
0,0>)
LinkedList1 ListNode TotalNodeCount dup(<
0,0>)
temp dword ?
tempq dword ?
tempp dword ?
StartTimer dword ?
.code
main PROC
call getmseconds
mov StartTimer,eax
repeat
200000
call CreateLinkList
call SortLinkList
call CopyLinkList
endm
call getmseconds
sub eax,StartTimer
call WriteDec
call crlf




;//--------------------------------------------开始遍历链表
mov esi,OFFSET LinkedList
NextNode:
; Check for the tail node.
mov eax,(ListNode PTR [esi]).NextPtr
cmp eax,NULL
je quit1

; Display the node data.
mov eax,(ListNode PTR [esi]).NodeData
call WriteDec
call Crlf

; Get pointer to next node.
mov esi,(ListNode PTR [esi]).NextPtr
jmp NextNode
quit1:
;//-------------------------------------------链表遍历完毕
call waitmsg
exit
main ENDP
CreateLinkList PROC
push ebp
mov ebp,esp
;//--------------------------------------------构建链表
push ecx
push edi
push eax
push esi
mov ecx,21
mov edi,offset LinkedList
mov esi,0
LW:
mov eax,dword ptr TheNum[esi]
mov (ListNode ptr [edi]).NodeData,eax
mov eax,edi
add eax,type ListNode
mov (ListNode ptr [edi]).NextPtr,eax
add edi,type ListNode
add esi,type TheNum
LOOP LW
push esi
push eax
push edi
push ecx
;//--------------------------------------------链表构建完毕
mov esp,ebp
pop ebp
ret
CreateLinkList ENDP

SortLinkList PROC
push ebp
mov ebp,esp
;//--------------------------------------------冒泡排序开始
;// 这里用到了 edi 头寻址 ecx 循环控制 ebx,edx,
push edi
push ecx
push eax
push ebx
push edx
push esi
mov edi,offset LinkedList
mov ecx,19
;//根据定理,这里的offset Linkedlist永远是指向一个固定位置的
maopao1:
push ecx
mov ecx,19
mov eax,edi
maopao2:
mov ebx,eax
add ebx,type ListNode
mov edx,ebx
add edx,type ListNode
mov esi,(ListNode PTR [ebx]).NodeData
cmp esi,(ListNode PTR [edx]).NodeData
jb allhavetodo
bigger:;//-----------------------------------进行对换
push eax
push esi
mov eax,(ListNode PTR [ebx]).NodeData
mov esi,(ListNode PTR [edx]).NodeData
mov (ListNode PTR [ebx]).NodeData,esi
mov (ListNode PTR [edx]).NodeData,eax
pop esi
pop eax
;//-----------------------------------对换结束
allhavetodo:
add eax,type ListNode
;//-----------------------------------上面的eax指向eax的下一个地址
loop maopao2
pop ecx
loop maopao1
pop esi
pop edx
pop ebx
pop eax
pop ecx
pop edi
mov esp,ebp
pop ebp
ret
;//--------------------------------------------冒泡排序结束
SortLinkList ENDP


CopyLinkList PROC
push ebp
mov ebp,esp
;//--------------------------------------------链表复制开始
;// edi为LinkedList首地址 ebx为LinkedList1首地址 eax为临时变量
push edi
push ebx
push eax
mov edi,offset LinkedList
mov ebx,offset LinkedList1
Copytwo:
mov eax,(ListNode PTR [edi]).NextPtr
cmp eax,NULL
je quit

mov eax,(ListNode ptr [edi]).NodeData
mov (ListNode ptr [ebx]).NodeData,eax
mov eax,ebx
add eax,type ListNode
mov (ListNode ptr [ebx]).NextPtr,eax
add edi,type ListNode
add ebx,type ListNode
jmp Copytwo
quit:
pop eax
pop ebx
pop edi
mov esp,ebp
pop ebp
ret
;//--------------------------------------------链表复制结束
CopyLinkList ENDP


END main
汇编也跟我们这里用到的是相同的函数
1.    构造函数
2.    排序函数
3.    复制函数
 
同样的,这里给出构造函数所使用的
CreateLinkList:
         这里用到的有ecx,edi,eax,esi
         Ecx用来做循环变量控制
       Edi 用来进行传递链表首地址
       Esi用来进行递增控制
 
SortLinkList:
         这里用到的有ecx,eax,edi,ebx,edx,esi
         其中:
         Ecx用来进行循环变量控制
              由于ecx 要用在两层变量循环控制里面,所以当进入另外一层的时候,我们必须把ecx压栈
              然后在里层循环结束的时候ecx再出栈,这样子就能保证正常的二层循环了
       Edi用来传递链表首地址
       Eax用来临时传递链表首地址
       Edx,ebx,esi都用来进行临时交换数据的空间
 
CopyLinkList:
         这里用到的有edi,ebx,eax.
不用ecx的原因是因为我们的循环控制换成的比较来控制是否跳出循环
Edi 用来传递链表1的临时地址
Ebx用来传递链表2 的临时地址
Eax用来传递链表1的当前地址的下一个指针
   
关于汇编版本1的代码和版本2的代码的差别:
在说差别之前,我们先来说下汇编的链表跟C++的链表的具体差别
首先,汇编的链表在一开始我们就已经申请了N个地址的空间,这个空间是连续的,固定的,所以我们就能够知道链表的下一个地址是什么,并且通过数字可以直接寻址得到,不用花费太多心血.
但是C++的链表空间是动态分配的,动态分配有个好处,那么就是链表的长度可以无限长,所以汇编的链表可以说是静态链表,伪链表,真数组,而C++的链表就是名副其实的链表了
下面我们通过图示来证明这一点
 
 
 
 

这是我们汇编一开始申请的链表并且已经初始化完毕
 
  
  
  
  
  
  
  
  
  
  
  
 
 
 
 
 

 
这是我们C++一开始申请的链表并且已经初始化完毕
  
  
  
  
  
  
  
  
  
  
  
  
 
 
 
  
  
这是我们汇编代码1所进行的其中一个排序找错

  
  
  
  
  
  
  
  
  
  
  
  
 
 
 
  
 
 
这是汇编代码2的所进行的其中一种排序
  
  
  
  
  
  
  
  
  
  
  
  
 
 
 
 
 
 
 
  
大家仔细斟酌下就能发现其中的差别了.
下面,我们通过汇编形成了三个文件
通过比较可得,C++编译器生成的文件很小,我也不知道为什么突然一下子汇编的要达到3.6兆,这个留给高手解决吧.
那么接下来的还有的准备就是调整下电脑的功率模式:
 
在处理器最省电模式下:

 

 

 

 
文件名称
 
 
C++LINK.exe
 
 
Assembly_LINK1.exe
 
 
Assembly_LINK2.exe
 
 
所用时间
 
 
 

 

 
 
百分比
 
 
100
 
 
15.75%
 
 
15.44%
 
在最高性能下:
       
 
文件名称
 
 
C++LINK.exe
 
 
Assembly_LINK1.exe
 
 
Assembly_LINK2.exe
 
 
所用时间
 

 
 
 
百分比
 
 
100%
 
 
15.34%
 
 
14.65%
 
通过对比可得,程序确实是在完全计算之后才得出结论的,因为这里的CPU功率在高和低的状态下得出的时间是完全不一样的,高性能状态下,时间缩短了几近一倍,通过对比也可发现,汇编的速度已经快接近C++编译出来的十倍左右了,那么到了这里,也差不多已经接近尾声了,探讨结果已经出来,汇编显示出了让人折服的速度,这正是汇编所具有的优势,虽然我不知道为什么编译出来的文件体积如此之大,但是尝试后还是发现了,当我循环20000遍的体积跟循环10000是差了一倍左右的,这可能跟汇编编译器的工作原理有关,由于查不出答案,所以我的猜测应该是汇编里面的循环的每一遍都拷贝了一边,所以……答案是怎样的呢?可以下期探讨,如果我的出来的话.