javascript、ruby和C性能一瞥(3) :上汇编
在博文(1)和(2)里分别用了4中方式写一个素数筛选的算法,分别是javascript in browser、node.js、ruby和c;最终的结果是c最快,node.js其次,js in b虽然也不慢,但极不稳定,所以排在第三,ruby最慢。
现在我们在linux64中用汇编语言重写sieve算法,看看动用最终的武器:汇编语言,我们能不能进一步优化素数筛选算法。
如果忘了算法逻辑,不要紧,下面分别再次贴出node.js、ruby以及c的sieve代码:
首先是node.js:
function sieve(n){
var a = new Int8Array(n+1);
var max = Math.floor(Math.sqrt(n));
var p = 2;
while(p <= max){
for(var i=2*p;i<=n;i+=p)
a[i] = 1;
while(a[++p]); /* empty */
}
while(a[n]) n--;
return n;
}
然后是ruby:
def sieve(n)
a = Array.new(n+1);
max = Math.sqrt(n).to_i;
p = 2;
while p<=max do
i = 2*p
while i<=n do
a[i] = 1
i+=p
end
while a[p+=1] == 1 do end
end
while a[n] do n-=1 end
n
end
最后是c的代码:
ULL sieve(ULL n)
{
char *a = malloc(n+1);
if(!a) return 0;
memset(a,0,n+1);
ULL max = sqrtl(n);
ULL p = 2;
while(p <= max){
for(ULL i=2*p;i<=n;i+=p)
a[i] = 1;
while(a[++p]); /* empty */
}
while(a[n]) n--;
return n;
}
下面尝试用汇编重写sieve函数,需要注意的几点是:
- 可以不调用C库中的sqrtx标准函数,直接使用浮点fsqrt指令;
- 可以将绝大部分内存变量放到寄存器中以加速存取;
- 只关心sieve函数的算法,而用c代码调用汇编的sieve,这样可以发挥各自的长处;否则我还得写个读取输入参数的前导代码,不值当的;
- 注意汇编和c的调用接口:在linux64中,参数并不压栈传递;因为sieve只有一个参数,所以放在rdi中传递,返回值还是放在rax中。
- 需要调用mmap申请足够的内存以便做筛表。注意这里没有写足够详细的错误处理,更详细的操作请参考本猫的【linux下64位汇编的系统调用】系列博文。
- 最后要注意的是,代码优化和代码编写一定不要同时进行!这在所有编程语言中都适用,汇编中尤为重要!否则必成一锅粥鸟!因为谁都不可能上来就写优化后的代码,一定是先功能逻辑正常后在着手考虑优化的问题。本猫第一遍写的是最保守代码,全部变量放在内存中,随用随取,用完保存。在代码逻辑正确后(这时计算sieve 100000000所花时间为4xxx ms),在逐步将内存变量转放到寄存器中。
要说明的是该段代码肯定还可以进一步优化,但本猫就到这里为止了,希望能够抛砖引玉。先把结果说一下吧:用汇编写的sieve版本是最快的,超过了c代码,在本猫 Intel(R) Core(TM)2 Duo CPU T7100 @ 1.80GHz上跑出了最快的37xx毫秒,比c版的平均要快100-200毫秒,而且非常稳定。
最后贴出C的main.c和汇编的sieve.s代码:
main.c:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
typedef unsigned long long ULL;
ULL sieve(ULL n);
int main(int argc,char **argv){
ULL n = 0;
if(argc < 2){
printf("usage %s n\n",argv[0]);
return 1;
}
sscanf(argv[1],"%llu",&n);
if(n == 0){
puts("wrong number format");
return 2;
}
else if(n < 0){
puts("must + number");
return 3;
}
int start = clock();
ULL result = sieve(n);
if(result == -1){
puts("sieve calc failed!");
return 4;
}
double end = ((1.0 * (clock() - start)) / CLOCKS_PER_SEC) * 1000.0;
printf("max p is %llu (take %f ms)\n",result,end);
return 0;
}
汇编的sieve.s:
section .data
n:dq 0
len:dq 0
addr: dq 0
p:dq 2
max:dq 0
i:dq 2
section .text
global sieve
sieve:
push rbp
push rbx
push rcx
mov rbp,rsp
mov [n],rdi ;save 1st arg to n
inc rdi
mov [len],rdi ;mmap len = n + 1
mov eax,9 ;call syscall mmap
mov rdi,0
mov rsi,[len]
mov rdx,3
mov r10,33
mov r8,-1
mov r9,0
syscall
cmp rax,0xfffffffffffff001 ;mmap error
jb next
mov rax,-1 ;return -1
jmp quit
next: ;save mmap return addr
;FIXME:mmap space always 0 ???
fild qword [n] ;calc sqrt(n) and save result to max
fsqrt
fistp qword [max]
mov r15,[p] ;r15 = p
mov r14,[max] ;r14 = max
mov r13,[n] ;r13 = n
mov r12,[i] ;r12 = i
enter_while:
cmp r15,r14 ;if p<=max
ja quit_while
mov rbx,r15
shl rbx,1
mov r12,rbx
enter_for:
cmp r12,r13
ja quit_for
mov byte [rax + r12],1
add r12,r15
jmp enter_for
quit_for:
inc r15
mov cl,byte [rax + r15]
test cl,cl
jnz quit_for
jmp enter_while
quit_while:
mov cl,byte [rax + r13]
test cl,cl
jz pre_quit
dec r13
jmp quit_while
pre_quit:
mov rax,r13
quit:
mov rsp,rbp
pop rcx
pop rbx
pop rbp
ret
javascript、ruby和C性能一瞥(3) :上汇编的更多相关文章
- javascript、ruby和C性能一瞥(1)
测试一下本地js.浏览器中的js以及ruby对于类似算法的性能.结果有些意外:浏览器js最快,本地其次当相差很小:ruby最慢而且不是一个数量级的: 因为写的匆忙,可能有重大问题没能看出来,请各位高人 ...
- javascript、ruby和C性能一瞥(2)
好吧,最后让我们用C来实现,看看再能榨取多少性能.注意我没有改变算法,C的算法和之前的3种都是基本相同的: #include <stdio.h> #include <stdlib.h ...
- javascript复制内容到剪切板/网页上的复制按钮的实现
javascript复制内容到剪切板/网页上的复制按钮的实现:DEMO如下 <!doctype html> <html> <head> <meta chars ...
- NVIDIA深度学习Tensor Core性能解析(上)
NVIDIA深度学习Tensor Core性能解析(上) 本篇将通过多项测试来考验Volta架构,利用各种深度学习框架来了解Tensor Core的性能. 很多时候,深度学习这样的新领域会让人难以理解 ...
- Yolov4性能分析(上)
Yolov4性能分析(上) 一.目录 实验测试 1) 测试介绍 2) Test 3) Train 二. 分析 1.实验测试 1. 1 实验测试方法 Yolov4训练train实验方法(Darkn ...
- JavaScript数据存取的性能问题
JavaScript中四种基本的数据存取位置: 字面量:只代表自身 字符串.数字.布尔值.对象.函数.数组.正则,以及null和undefined 快 本地变量:var定义的 快 数组元素 ...
- JavaScript 踩坑心得— 为了高速(上)
一.前言 很多情况下,产品的设计与开发人员一直想打造一套高品质的解决方案,从而快速.平稳地适应产品迭代.速度是衡量产品适应性的真正且唯一的标准,而且,这并不是笔者的一家之言. 「速度是衡量适应能力的真 ...
- JavaScript代码规范和性能整理
性能 Js在性能方面有多要注意的地方: 避免全局查找 Js性能优化最重要的就是注意全局查找,因为作用域的查找是先找局部作用域在没有找到之后在去上一级作用域查找直到全局作用域,所以全局作用域查找的性能消 ...
- (转)Javascript的DOM操作 - 性能优化
转载:https://my.oschina.net/blogshi/blog/198910 摘要: 想稍微系统的说说对于DOM的操作,把Javascript和jQuery常用操作DOM的内容归纳成思维 ...
随机推荐
- FFmpeg源代码简单分析:avformat_open_input()
===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...
- [struts2学习笔记] 第二节 使用Maven搞定管理和构造Struts 2 Web应用程序的七个步骤
本文地址:http://blog.csdn.net/sushengmiyan/article/details/40303897 官方文档:http://struts.apache.org/releas ...
- 开源项目——小Q聊天机器人V1.3
小Q聊天机器人V1.0 http://blog.csdn.net/baiyuliang2013/article/details/51386281 小Q聊天机器人V1.1 http://blog.csd ...
- 【java集合框架源码剖析系列】java源码剖析之HashMap
前言:之所以打算写java集合框架源码剖析系列博客是因为自己反思了一下阿里内推一面的失败(估计没过,因为写此博客已距阿里巴巴一面一个星期),当时面试完之后感觉自己回答的挺好的,而且据面试官最后说的这几 ...
- Android面试题目总结
1.java 基础题,输入结果是什么? public static void main(String[] args) { String str = new String("abc" ...
- 使用JavaScript动态的添加组件
使用JavaScript进行动态的网页窗体组件的添加是一件很方便也很容易实现的事情.话不多说,边看代码边做解释吧. 准备工作 由于html页面中不可以添加java代码,所以我在jsp页面中进行了测试. ...
- Android4.4.2KK竖屏强制更改为横屏的初步简略方案
点击打开链接 解决方案: 当前是根据当前问题场景即竖屏强制更改为横屏的需求而做的改动,基本是hardcode定义的状态,总共修改有效代码行数5行,如果后续有其他需求或者需要更灵活的配置横屏和竖屏,可以 ...
- Beanstalkd 一个高性能分布式内存队列系统
需要一个分布式内存队列,能支持这些特性:任务不重不漏的分发给消费者(最基础的).分布式多点部署.任务持久化.批量处理.错误重试..... 转载:http://rdc.taobao.com/blog/c ...
- UNIX网络编程——心跳包
所谓的心跳包就是在客户端和服务器端间定时通知对方自己状态的一个自己定义的命令字,按照一定的时间间隔发送,类似于心跳,所以叫做心跳包. 一般是用来判断对方(设备,进程或其它网元)是否正常动行,一般采用定 ...
- 【Unity Tips】备忘录(扫盲篇)
写在前面 Unity3D虽然是个非常方便的游戏引擎,但还是有一些地方会产生一些让人莫名其妙的问题,而且debug半天也不知道到底哪里错了.往往在经过了大量的log之后,也许我们才顿悟,原来Unity内 ...