专栏名称: 唤之
目录
相关文章推荐
待字闺中  ·  DeepSeek 爆火带来的大变化 ·  1 周前  
OSC开源社区  ·  李彦宏:DeepSeek让我们明白要将最优秀 ... ·  3 天前  
OSC开源社区  ·  大模型训练中的开源数据和算法:机遇及挑战 ·  3 天前  
程序猿  ·  TCP 才不傻! ·  4 天前  
51好读  ›  专栏  ›  唤之

shen-go接下来的一些优化方向

唤之  · 掘金  · 程序员  · 2017-12-25 07:53

正文

shen-go接下来的一些优化方向

2017-12-24

想不到居然已经时隔一个多月了, 接上篇 ,编译到字节码的工作算是基本完成。 shen-go 是shen语言在Go的实现。前几天给shen-go打上了v0.1的tag。不知道多少天熬夜,连续好多周末宅着调试代码,看到所有的测试都跑通那一刻,真是感觉所有的努力都没有白费。

好的代码是艺术品,功能确定好,反复打磨,当一行代码也不能再增加,并且一行代码也不能减少的时候,就比较接近于完美了。其中 有50行我是比较满意的 ,称得上可以拿出手的作品。

50行代码的编译器!就像王垠的40行一样,大多数的人不会看得懂它干了什么,嗯,所以编译器对他们永远是魔法。

其实还可以更短,真正也就40行,这么短的代码里,实现尾递归优化,支持了异常机制,还做了自动curry化!

编译出来字节码是 长这样子的 ,很奇怪是不是?偷懒直接用sexp表示的。

事情总算可以告一段落,接下来是写一些可能的优化方向。

JIT 是肯定不做的,坑太深了。一个很重要的点就是克制自己什么东西都想弄一弄,明确哪些feature是重要的,不然技术的研究就没完没了了。其实做的过程中,好几次差点没克制自己去写一个C语言的版本,光想想涉及GC就没完没了。(如果哪一天真用 C 重写了,那它应该放到 cora 那个项目里面了,神圣的代码仓库里面只能有 C 和 lisp。嗯,“每个lisper都应该拥有属于自己的lisp”)

纯的 evaluator 执行效率太低了,bytecode 是一个比较好的折中的平衡点,投入的精力和达到的效果。在这个大的取舍之下,考虑的就是三部分:

  • 编译器优化
  • 虚拟机优化
  • 运行时优化

虚拟机优化方面, zinc 的PPT 里面讲到的大部分,差不多都优化到头了。最新的master正在拆环境,静态部分和动态部分。环境和调用栈合并没做,编译期决定变量位置没做。都是在考虑了代码引入的复杂程度,和带来的性能提升上面,做的取舍。

peephole optimizations

加速特定的函数来实现优化效果。由于 shen 到 klambda 的编译是用 shen 实现的,也就是会跑 bytecode。里面的 hash 等等常用函数,如果用原生实现而不是跑 bytecode,这块应该是可以有不少收益的。

涉及到的主要包括 hash,dict。然后还有文件IO相关的,都可以改用原生实现去替换掉 shen 编译器里面的 bytecode 实现。还有一些基本的函数。它里面有些函数的实现效率实在让人看不下去,比如 symbol?

fixnum tagging

目前在 shen-go 里面,所有东西都是用一个 Obj 表示的,是一个boxed value。它实际上是一个指针,指向一块内存。那里面将类型和值打包到一块了。 数字类型,现在直接用的 float64。也是开始做的时候深思熟虑后的取舍:float64 其实表示定点数其实可以是"准确"的,根据IEEE 754标准,只要算出阶码部分,再看后面多少位尾数为0,可以确定它是否真的有小数部分。

那么 fixnum tagging 又是要优化什么呢?是这样的,假设内存是对齐的,由于 Obj 都是指针,最低3位必然全是0。如果用最低一位为1当作区分,我们可以剩下63位用来存储 fixnum。这样子,最后1位为0它就是一个数字,否则它是一个指针。数字类型就可以不用在堆上分配空间了。

在 C 里面是司空见惯的技巧,尚不确定 Go 里面能不能做,Go是托管内存的,乱玩也许会 panic。

threaded code

Threaded code 又是一项在 C 里面非常常用的技巧。准确来说是 gcc,编译器提供了一个扩展,可以直接拿到标签对应的机器指令的地址,于是可以直接jmp过去,让指令预测更友好,相对于 switch-case 的写法要更加高效。

switch instruction {
  case Push:
  case Pop:
}

很不幸,这个 Go 语言里面似乎搞不了。

thread:
  &pushA
  &pushB
  &add
  ...
pushA:
  *sp++ = A
  jump *ip++
pushB:
  *sp++ = B
  jump *ip++
add:
  addend = *--sp
  *sp++ = *--sp + addend
  jump *ip++

优化symbol表示

对于 lisp 语言,优化 symbol 还是很有必要的。目前我还是用 string 来实现的,而实际上 symbol 应该就类似于指针,symbol 做 eq 比较应该是没任何开销的。







请到「今天看啥」查看全文