Aiur – ZelluX 的技术博客

Security, Kernel, Virtualization, Programming Languages

Archive for March, 2008

ICS Lab4 常用优化方法

without comments

几个基本的优化:

1. 用iaddl代替irmovl, opl,效果显著
2. 删去不必要的andl,效果显著
3. 改变判断分支(大多数是正数),效果显著
4. 实现Load Forwarding,效果显著
5. 函数结束时使用自己的epilogue,效果一般

Unrolling相关:

1. 通过合并相邻两个循环,把mrmovl和rmmovl拆开,效果显著
2. 32, 16, 8, 4, 1分段处理,效果显著,我用这个方法做到过7.2左右

Jump Table

由Duff’s Device引申出来的想法,代替了我原来那个32-16-8-4-1程序。
很好用的一个技巧,配合unrolling就不需要不断比较i和len的大小了。
比如len=15的时候,只要跳转到倒数第15个复制段落,就可以挨个做下来,而不需要多余的判断。
具体的实现可以想想x86里的情况,假设几个复制段落的标签为Loop1, Loop2, …

jump: .long Loop1
.long Loop2

之后就只要取出jump + (len – 1) * 4处的值,然后跳到这个位置就行了。
跳的时候还有个技巧,最简单的是把这个值push到栈,然后再ret。这样的话bubble很多。

考虑到这个模拟器里代码段是不受保护的,也就是说运行的时候可以动态修改内存中的代码,于是在跳转的地方写个jmp 0,然后运行的时候动态把这个0改掉就行。

另外要注意用这个方法的时候得手动写几个nop,或者在改内存的语句和jmp语句之间加几个其他命令,因为y86模拟器是默认程序不会修改自己的代码的(p328 灰色背景部分)。

用这个方法的时候还有一些细节可以优化,就不列举了。另外不知道利用自我修改这个特点能不能做出更神奇的效果呢?

比如我还想到另一种类似的方法,让程序从头到尾运行,不跳转,而是在程序运行时动态的插入ret语句直接把程序运行流掐断。我还没试过,有兴趣的同学可以试一试。

不知道还有没有其他的优化方法,欢迎讨论~

Written by zellux

March 23rd, 2008 at 5:06 pm

Posted in Computer System

Tagged with ,

Java直接读取内存的一个例子

without comments

水木上讨论如何修改一个immutable类(Long)的帖子,zms大牛给出了一种直接访问内存的方案

关键类:sun.misc.Unsafe

Class klass=Class.forName("java.nio.DirectByteBuffer");
Field field = klass.getDeclaredField("unsafe");
field.setAccessible(true);
Object o = field.get(null);
Unsafe unsafe= (Unsafe) o;
field=Long.class.getDeclaredField("value");
long offset=unsafe.objectFieldOffset(field);  //这是偏移量
//unsafe 和 offset可以一直用

final Long n=100L;
unsafe.putLong(n,offset,200);
System.out.println(n);

拜一下

Written by zellux

March 18th, 2008 at 4:59 pm

Posted in Programming

Tagged with

ICS Lab4 经验

without comments

1. 编译

不安装图形界面:
修改sim/Makefile,把前三行非注释部分用#注释掉,变成
# GUIMODE …
# TKLIB …
# TKINC …
保存后运行make

图形界面:
需要安装Tcl/Tk库
+ Redhat 9:
可以在Redhat菜单->System Settings->Add/Remove Applications中添加X Software Development,根据提示载入相关镜像文件。
然后在sim目录下运行make
+ Arch Linux:
有包管理机制的发行版直接用相关软件安装(比如Arch中pacman -S tcl tk),注意安装好以后生成的动态链接库可能带有版本号(比如libtcl8.5.so libtk8.5.so)
具体版本号通过pacman -Ql tcl tk | grep ‘.so’查得
接着只要修改Makefile中的TKLIBS参数,或者用ln建个链接即可
+ Ubuntu
由于ubuntu默认没有lex词法分析工具,在编译时需要先安装flex
sudo apt-get install flex

图形界面和Arch类似
sudo apt-get install tcl8.5-dev tk8.5-dev tcl8.5 tk8.5
然后修改Makefile
ltcl->ltcl8.5
ltk->ltk8.5
/usr/local/lib/.. -> /usr/lib/..
/usr/local/include/ -> /usr/lib/tcl8.5/include/

2. Part A
用y86写三个小程序,基本上仿照seq/asum.ys写就行了。装了图形界面的模拟器的话调试起来也很方便。
相关命令(假设在seq目录下):
编译 make asum.yo
运行 ../misc/yis asum.yo
调试 ./ssim -g asum.yo

3. Part B
同样不需要花多少力气,把Homework 16的答案写成HCL语言就行,可以参照opl, irmovl, popl这三个指令的写法。
通过ICS主页上的Lab4.pdf中的几个测试命令即可。

4. Part C
通过修改HCL和y86代码优化程序,最麻烦的一块。
在pipe目录下运行./benchmark.pl -f ncopy.ys,这个脚本就会自动运行一系列测试程序并计时,最后一行显示了平均所需的时间。
优化方法很多,系版的精华区的讨论帖里就有不少。
另外可以看看pipe/README这个文件,里面也说了几种方法。
最简单的就是实现iaddl指令,用它替换部分语句缩短时间;还有一个比较重要的就是loop unrolling,所谓loop unrolling就是把一个循环中的语句合并,减少循环次数。
用C语言简单的举一个例子

for (int i = 0; i < 10; i++)
    dst[i] = src[i];

把相邻两个循环合并起来,变成

for (int i = 0; i < 10; i += 2) {
    dst[i] = src[i];
    dst[i + 1] = src[i + 1];
}

这样增加i的值的语句就从原来的10个减少到了现在的5个。
另外这里还有一个潜在的好处,dst[i] = src[i]在执行的时候有个Load/Use Data Hazards,会产生一个bubble,如果先读出src[i],再读出src[i+1],然后依次写入dst[i],dst[i+1],这样就可以消去这个bubble,从而为每个元素节约一个左右的时钟数。

测试方法:
先保证pipe-full.hcl中的iaddl语句的正确,make以后在ptest目录下运行
make SIM=../pipe/psim TFLAGS=-i TFLAGS=-i
之后在pipe目录下运行./correctness.pl -f ncopy.ys测试样例程序,通过以后再运行./benchmark.pl -f ncopy.ys就能看到这个程序的性能了。

5. 其他一些补充
1) correctness.pl这个脚本测试时报的错误可能会和实际不一致,比如Bad count和Incorrect copying貌似会混淆。
2) unrolling的时候建议写个专门生成相关代码片段的脚本,否则改起来太麻烦了。

Written by zellux

March 16th, 2008 at 7:46 pm

Posted in Computer System

Tagged with ,

FireStats icon Powered by FireStatsBetter Tag Cloud