领域特定语言
Feb 12th, 2019
0
下面的内容主要基于Kunle Olukotun在Stanford开设的课程CS 442: High Productivity and Performance with Domain Specific Languages in Scala, 2011, Online。
但这门课是研究性质的,即主要以Stanford Pervasive Parallelism Lab (PPL)组开发的Delite作为基石讲解。
因而在这里我只会将部分通用的重要的章节抽取出来。
简介
常见的DSL如
- 图像处理OpenGL
- 科学计算Matlab
- 排版软件TeX
- 数据库MySQL
DSL的好处
- 提高生产力
- 将程序员从复杂的并行编程中隔离开来
- 注重于算法应用实现而不是底层细节
- 提高性能
- 更加符合一般化的并行执行领域高层抽象
- 限制表达力(expressiveness)进而更易提取可用并行
- 用领域知识做静态/动态优化
- 可移植性(portability)与前向可扩展性(forward scalability)
- DSL和Runtime能够进化到利用最新硬件特性的优势
- 应用无需改变
- 允许革新硬件而不用担心应用的可移植性
两种DSL
- 一种依赖于宿主语言(embeded DSL, “Just a library”)
- 方便开发,可以重用整个宿主语言
- 方便学习,只需有宿主语言的基础
- 能够结合多种DSL在一个程序中
- 能够共用DSL基础设施
- 但难以通过领域知识优化
- 与宿主语言一样面向同一硬件
- 例子
- Halide依赖于C++编译到汇编/cuda
- Chisel依赖于Scala编译到Verilog
- 一种做更高层的抽象(stand-alone)
- 能够做大量优化
- 但需要大量人力来实现一门充分成熟的语言
- 多种DSL之间的交互比较麻烦(这倒不是太大问题)
- 例子
- GraphIt直接编译为C++
- Spatial直接编译为Chisel
需要做得更好,目标是设计一门嵌入式的DSL,但是性能和单一的DSL一样
典型的编译器
- DSL采用高度可表达的嵌入式语言的前端(Scala)
- 但可以定制化IR和后端Pass(Delite)
graph LR
c --> d
subgraph frontend
a["Lexer"] --> b["Parser"]
b --> c["Type checker"]
end
subgraph backend
d["Analysis"] --> e["Optimization"]
e --> f["Code gen"]
end
设计DSL
最关键还是3P
- Portability
- 自动重定向不同硬件MPI/cuda/…
- 添加新的硬件需要修改语言吗
- Performance
- Productivity(通常最难达到)
最重要从例子开始,进行泛化(generalize)
- 尽可能多地寻找这个领域的例子(广度)
- 从中提取出常见模式
- 并行化执行
- 为什么是例子?
- 让这个领域对非领域专家来说更加具体
- 确定这种语言应该支持什么特性
- 并行实施展现如何生成高效的代码
- 例子间的重叠看看什么是需要被语言所handle的
- 有效的应用应该是(DSL应该能够自动执行下面这些)
- 找到并行性
- 暴露局部性
- 推出同步性(synchronization)
好的DSL
- 语言的特性能够将并行性、局部性、同步性暴露出来(platform-independent)
- 编译器能够自动提取这些知识并重定向到不同架构(platform-specific)
语言(language)与框架(framework)的区别
- 编程语言主要是一系列的语法语义规则
- 框架
则是用现成的编程语言写成的一些库(library)/工具(tool)的集合,提供API接口,重用性高(reusable),避免重复造轮子,可以直接调用