Skip to content

Commit

Permalink
deploy: b19b928
Browse files Browse the repository at this point in the history
  • Loading branch information
Chronostasys committed Jun 14, 2024
1 parent 7ecb2df commit d8614b8
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 97 deletions.
64 changes: 16 additions & 48 deletions print.html
Original file line number Diff line number Diff line change
Expand Up @@ -1560,29 +1560,16 @@ <h2 id="使用is_runtime导出rust函数"><a class="header" href="#使用is_runt
<p>标记impl块时,导出的函数名称会变为<code>{structname}__{fnname}</code>的形式,函数允许使用receiver。更多高级用法参见<code>is_runtime</code>的rust doc</p>
</blockquote>
<div style="break-before: page; page-break-before: always;"></div><h1 id="gc"><a class="header" href="#gc">GC</a></h1>
<blockquote>
<p>!WIP:此页面描述的功能仍然在实验性阶段,可能有些细节没有实现完毕。</p>
</blockquote>
<p>pivot-lang 是一门使用gc进行内存管理的语言。</p>
<p>pivot-lang 的gc目前是使用rust写的,采用一种叫做<code>immix</code>[[1]](https://www.cs.utexas.edu/users/speedway/DaCapo/papers/immix-pldi-2008.pdf)的mark region算法。</p>
<p>在以前的版本中,我们使用的是我们现在叫做<code>simple gc</code>的垃圾回收算法,他是一个简单的mark-sweep算法。
它由于性能问题和不支持多线程等原因最终被<code>immix</code>取代。不过我们仍然保留了它的代码,并且设置了一个编译开关(<em>feature:simple_gc</em>),可以在编译时手动选择使用该gc算法。</p>
<h2 id="simple-gc"><a class="header" href="#simple-gc">Simple GC</a></h2>
<p>simple gc就和他的名字一样,<a href="https://github.com/Pivot-Studio/pivot-lang/blob/master/vm/src/gc/_simple_gc.rs">代码</a>十分简单(算法实现大概100行)。它没有自己的allocator,直接
使用C中的<code>malloc</code><code>free</code>进行内存分配和释放。</p>
<p>simple gc是一个<a href="https://www.cs.cornell.edu/courses/cs6120/2020fa/blog/modern-gc/">保守gc算法(Conservative Garbage Collection)</a>,它没有能力精确的分辨出哪些内存是指针,哪些不是。因此它会试图将所有的内存都当做指针来处理。</p>
<p>目前simple gc不建议在生产环境中使用,其代码保留下来是为了方便我们在未来的版本中进行性能对比,以及为未来用于教育目的做准备。</p>
它由于性能问题和不支持多线程等原因最终被<code>immix</code>取代。</p>
<h2 id="immix-gc"><a class="header" href="#immix-gc">Immix GC</a></h2>
<p>immix gc是一种mark region算法,它是一个精确的gc算法。但是请注意,它的精确建立在使用它
的项目提供的特殊支持之上。可以认为目前我们的immix gc实现 <strong>是为pivot-lang量身定制</strong> 的。pl编译器为了和我们的immix gc配合,会在编译时专门生成一些额外的代码,如果缺少这些代码,immix gc将无法正常工作。
所以虽然理论上我们可以将我们的immix gc用到其他项目中,这么做的效益很可能并不是很高--
缺少编译器的支持,使用者将需要手动添加那些额外的代码。</p>
<p>immix gc的实现代码在<a href="https://github.com/Pivot-Studio/pivot-lang/blob/master/immix">这里</a>。它是天生支持多线程使用的,但是我们的pivot-lang目前还不支持多线程。</p>
<h2 id="benchmark"><a class="header" href="#benchmark">Benchmark</a></h2>
<p>我们对两种gc算法进行了一些基准测试,事实证明immix gc的回收性能要比simple gc <strong>快近20倍</strong>。如果你对这些测试感兴趣,可以在项目根目录运行<code>make bench</code>查看immix的benchmark,或者运行<code>make bench-simple-gc</code>查看simple gc的benchmark。</p>
<p>下方分别是simple gc和immix gc的benchmark结果,测试于2023年1月,commit 62b5c52c01e8133f5300e33a0131a50ba0c8d0de</p>
<p><img src="systemlib/2023-01-24-23-23-55.png" alt="" /></p>
<p><img src="systemlib/2023-01-24-23-25-06.png" alt="" /></p>
<p>immix gc的实现代码在<a href="https://github.com/Chronostasys/immix">这里</a></p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="pivot-lang-immix-gc"><a class="header" href="#pivot-lang-immix-gc">pivot-lang immix gc</a></h1>
<p>本文档将会描述pl使用的immix gc的一些实现细节与对外接口</p>
<div id="admonition-note" class="admonition note">
Expand Down Expand Up @@ -1617,9 +1604,9 @@ <h2 id="table-of-contents-1"><a class="header" href="#table-of-contents-1">Table
<li><a href="systemlib/immix.html#%E5%9C%A8%E7%BA%BF%E7%A8%8B%E5%8D%A1%E9%A1%BF%E7%9A%84%E6%97%B6%E5%80%99">在线程卡顿的时候</a></li>
</ul>
<h2 id="overview"><a class="header" href="#overview">Overview</a></h2>
<p>此gc是我们基于<a href="https://www.cs.utexas.edu/users/speedway/DaCapo/papers/immix-pldi-2008.pdf">immix gc论文</a>实现的,
大部分的实现细节都与论文一致,对于一些论文没提到的细节我们自行进行了实现,参考了很多别的gc项目。该gc是一个支持多线程使用的
基于shadow stack的,精确mark-region 非并发(Concurrency) 并行(Parallelism) gc。</p>
<p>此gc是我们基于<a href="https://www.cs.utexas.edu/users/speedway/DaCapo/papers/immix-pldi-2008.pdf">immix GC论文</a>实现的,
大部分的实现细节都与论文一致,对于一些论文没提到的细节我们自行进行了实现,参考了很多别的GC项目。该GC是一个支持多线程使用的
基于StackMap的,半精确mark-region 非并发(Concurrency) 并行(Parallelism) gc。</p>
<div id="admonition-gc的并发concurrency与并行parallelism" class="admonition tip">
<div class="admonition-title">
<p>gc的并发(Concurrency)与并行(Parallelism)</p>
Expand All @@ -1631,15 +1618,15 @@ <h2 id="overview"><a class="header" href="#overview">Overview</a></h2>
我们的immix gc目前只具备并行能力</p>
</div>
</div>
这里有一些创建该gc过程中我们主要参考的资料,列表如下:
<p>这里有一些创建该gc过程中我们主要参考的资料,列表如下:</p>
<ul>
<li><a href="https://www.cs.utexas.edu/users/speedway/DaCapo/papers/immix-pldi-2008.pdf">immix gc论文</a></li>
<li><a href="https://github.com/playXE/libimmixcons">playxe 的 immixcons(immix gc的一个rust实现,回收存在bug)-- 很多底层内存相关代码是参考该gc完成的,还有在函数头中加入自定义遍历函数的做法</a></li>
<li><a href="https://github.com/scala-native/immix">给scala-native使用的一个immix gc的C实现</a></li>
<li><a href="https://www.cs.cornell.edu/courses/cs6120/2019fa/blog/immix/">康奈尔大学CS6120课程关于immix gc的博客,可以帮助快速理解论文的基本思路</a></li>
</ul>
<h2 id="general-description"><a class="header" href="#general-description">General Description</a></h2>
<p>本gc是为pl <strong>定制的</strong>,虽然理论上能被其他项目使用,但是对外部项目的支持<strong>并不是主要目标</strong></p>
<p>本gc是为pl <strong>定制的</strong>,虽然理论上能被其他项目使用,但是对外部项目的支持 <strong>并不是主要目标</strong></p>
<p>pl的组件包含一个全局的<code>GlobalAllocator</code>,然后每个<code>mutator</code>线程会包含一个独属于该线程的<code>Collector</code>,每个<code>Collector</code>中包含一个
<code>ThreadLocalAllocator</code>。在线程使用gc相关功能的时候,该线程对应的<code>Collector</code>会自动被创建,直到线程结束或者
用户手动调用销毁api。</p>
Expand Down Expand Up @@ -1783,14 +1770,14 @@ <h3 id="thread-local-allocator"><a class="header" href="#thread-local-allocator"
</div>
</div>
<h2 id="mark"><a class="header" href="#mark">Mark</a></h2>
<p>Mark阶段的主要工作是标记所有被使用的line和block,以便在后续的sweep阶段进行回收。我们的mark算法是<strong>精确</strong>
<p>Mark阶段的主要工作是标记所有被使用的line和block,以便在后续的sweep阶段进行回收。我们的mark算法是__精确__的
这点对evacuation算法的实现至关重要。</p>
<p>精确GC有两个要求:</p>
<ul>
<li>root的精确定位</li>
<li>对象的精确遍历</li>
</ul>
<p>我们的精确root定位是基于<strong>Stack Map</strong>,这部分细节过于复杂,将在<a href="systemlib/stackmap.html">单独的文档</a>中介绍。</p>
<p>我们的精确root定位是基于__Stack Map__的,这部分细节过于复杂,将在<a href="systemlib/stackmap.html">单独的文档</a>中介绍。</p>
<p>对象的精确遍历是通过编译器支持实现的,plimmix将所有heap对象分类为以下4种:</p>
<ul>
<li>Atomic Object:原子对象,不包含指针的对象,如整数、浮点数、字符串等</li>
Expand Down Expand Up @@ -2014,8 +2001,8 @@ <h2 id="性能"><a class="header" href="#性能">性能</a></h2>
<p>使用github action进行的基准测试结果可以在<a href="https://chronostasys.github.io/bdwgcvsimmix-bench/report/">这里</a>查看,由于github action使用的机器
只有两个核心,所以测试线程数量为2,在此结果中,可以看到immix整体性能略差于bdwgc,但是差距小于单线程情况。</p>
<p>你可以从<a href="https://github.com/Chronostasys/bdwgcvsimmix-bench">这里</a>下载测试代码,在你的机器上运行并进行比较。这里我提供一组笔者机器上的测试数据截图</p>
<p><img src="systemlib/immix.png" alt="" /></p>
<p><img src="systemlib/bdw.png" alt="" /></p>
<p><img src="systemlib/immix.png" alt="immix" /></p>
<p><img src="systemlib/bdw.png" alt="bdw" /></p>
<p>测试环境为MacBook Pro (16-inch, 2021) Apple M1 Pro 16 GB,可以看出immix在此环境中已经具有近4倍的性能优势。</p>
<p>immix作为天生并发的gc,并发情况下几乎能完全避免锁竞争的出现,因此在多线程情况下的性能优势是非常明显的。并且其分配算法很好的维护了空间局部性,理论上
能带来更好的mutator性能。</p>
Expand Down Expand Up @@ -2054,7 +2041,7 @@ <h3 id="stackmap格式和读取方式"><a class="header" href="#stackmap格式
<p>为了性能和方便考虑,我们的gc实现了自己的gc策略(plimmix),此策略通过一个自定义llvm插件实现。其代码在 <strong>immix/llvm</strong> 目录下
两个C文件一个定义了我们的GC策略,一个定义了我们的stackmap格式和生成方式。</p>
<p>我们的stackmap格式如下:</p>
<pre><code>Header {
<pre><code class="language-Rust">Header {
i64 : Stack Map Version (current version is 1)
i32 : function 数量
}
Expand Down Expand Up @@ -2131,28 +2118,9 @@ <h3 id="stackmap格式和读取方式"><a class="header" href="#stackmap格式
<p><code>gc_init</code>函数主要会读取stackmap中的数据并且进行遍历,之后生成一个哈希表,用于快速的查找对应的safepoint地址。这个哈希表的key是safepoint地址,value是safepoint所在
函数的所有gcroot信息。</p>
<h3 id="基于stackmap的精确root定位实现"><a class="header" href="#基于stackmap的精确root定位实现">基于stackmap的精确root定位实现</a></h3>
<p>为了遍历函数调用栈,我们使用<code>backtrace.rs</code>包,该包封装了一些平台相关的函数调用栈遍历的实现。</p>
<div id="admonition-warning" class="admonition warning">
<div class="admonition-title">
<p>Warning</p>
<p><a class="admonition-anchor-link" href="systemlib/stackmap.html#admonition-warning"></a></p>
</div>
<div>
<p>栈爬取的实现不同平台差异巨大,很容易出现bug。目前我们发现在mac aarch64上如果使用lld进行链接会导致该backtrace包出现
segment fault,这个问题目前使用ld替代lld进行规避。</p>
</div>
</div>
<p>遍历的时候通过<code>backtrace.rs</code>拿到当前ip寄存器的值,然后去我们构建的stackmap中查找到当前函数栈的root进行遍历,遍历完成后继续向上层函数栈遍历。
注意这里遍历的起点不在mutator代码中,而在gc代码中,所以遍历的开头和结尾查不到对应记录是完全正常的。</p>
<div id="admonition-note" class="admonition note">
<div class="admonition-title">
<p>Note</p>
<p><a class="admonition-anchor-link" href="systemlib/stackmap.html#admonition-note"></a></p>
</div>
<div>
<p>潜在优化点:其实从gc的函数到目标语言最底层函数的调用栈层数在运行时是固定的,所以这里其实可以优化,跳过前几个栈帧,直接从目标语言最底层函数开始遍历。</p>
</div>
</div>
<p>为了遍历函数调用栈,在老版本中我们使用<code>backtrace.rs</code>包,该包封装了一些平台相关的函数调用栈遍历的实现。</p>
<p>在新版本中,由于<code>libbacktrace</code>中使用了全居锁,性能不好,我们决定手动进行栈遍历。为了完成这一点,我们需要
在mutator调用可能触发GC的runtime函数时,传入当前的<code>sp</code>寄存器值,之后利用StackMap中记录的各个函数栈的大小来一步一步往上爬取。</p>
<h2 id="参考资料"><a class="header" href="#参考资料">参考资料</a></h2>
<ol>
<li><a href="https://llvm.org/docs/StackMaps.html">llvm stackmap 文档</a></li>
Expand Down Expand Up @@ -2425,7 +2393,7 @@ <h3 id="code"><a class="header" href="#code">Code</a></h3>
<h3 id="tests"><a class="header" href="#tests">Tests</a></h3>
<p>强烈建议在提交修改的时候同时添加对应的测试,帮助我们将测试覆盖率保持在 <strong>85%</strong>, 帮助我们进一步完善测试也是相当欢迎的。</p>
<p>请在提交pr前确认自己的修改能通过所有的测试(通过运行 <code>cargo test --all</code>)</p>
<h3 id="benchmark-1"><a class="header" href="#benchmark-1">Benchmark</a></h3>
<h3 id="benchmark"><a class="header" href="#benchmark">Benchmark</a></h3>
<p>目前我们还没有基准测试,欢迎帮助我们添加基准测试。</p>
<h3 id="文档"><a class="header" href="#文档">文档</a></h3>
<p>参见 <a href="./dev-prepare.html">文档</a> 网站。对应源码在 <a href="https://github.com/Pivot-Studio/pivot-lang/tree/master/book">book</a> 目录中,欢迎帮助我们完善文档。</p>
Expand Down
2 changes: 1 addition & 1 deletion searchindex.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion searchindex.json

Large diffs are not rendered by default.

17 changes: 2 additions & 15 deletions systemlib/gc.html
Original file line number Diff line number Diff line change
Expand Up @@ -149,29 +149,16 @@ <h1 class="menu-title">Pivot Lang</h1>
<div id="content" class="content">
<main>
<h1 id="gc"><a class="header" href="#gc">GC</a></h1>
<blockquote>
<p>!WIP:此页面描述的功能仍然在实验性阶段,可能有些细节没有实现完毕。</p>
</blockquote>
<p>pivot-lang 是一门使用gc进行内存管理的语言。</p>
<p>pivot-lang 的gc目前是使用rust写的,采用一种叫做<code>immix</code>[[1]](https://www.cs.utexas.edu/users/speedway/DaCapo/papers/immix-pldi-2008.pdf)的mark region算法。</p>
<p>在以前的版本中,我们使用的是我们现在叫做<code>simple gc</code>的垃圾回收算法,他是一个简单的mark-sweep算法。
它由于性能问题和不支持多线程等原因最终被<code>immix</code>取代。不过我们仍然保留了它的代码,并且设置了一个编译开关(<em>feature:simple_gc</em>),可以在编译时手动选择使用该gc算法。</p>
<h2 id="simple-gc"><a class="header" href="#simple-gc">Simple GC</a></h2>
<p>simple gc就和他的名字一样,<a href="https://github.com/Pivot-Studio/pivot-lang/blob/master/vm/src/gc/_simple_gc.rs">代码</a>十分简单(算法实现大概100行)。它没有自己的allocator,直接
使用C中的<code>malloc</code><code>free</code>进行内存分配和释放。</p>
<p>simple gc是一个<a href="https://www.cs.cornell.edu/courses/cs6120/2020fa/blog/modern-gc/">保守gc算法(Conservative Garbage Collection)</a>,它没有能力精确的分辨出哪些内存是指针,哪些不是。因此它会试图将所有的内存都当做指针来处理。</p>
<p>目前simple gc不建议在生产环境中使用,其代码保留下来是为了方便我们在未来的版本中进行性能对比,以及为未来用于教育目的做准备。</p>
它由于性能问题和不支持多线程等原因最终被<code>immix</code>取代。</p>
<h2 id="immix-gc"><a class="header" href="#immix-gc">Immix GC</a></h2>
<p>immix gc是一种mark region算法,它是一个精确的gc算法。但是请注意,它的精确建立在使用它
的项目提供的特殊支持之上。可以认为目前我们的immix gc实现 <strong>是为pivot-lang量身定制</strong> 的。pl编译器为了和我们的immix gc配合,会在编译时专门生成一些额外的代码,如果缺少这些代码,immix gc将无法正常工作。
所以虽然理论上我们可以将我们的immix gc用到其他项目中,这么做的效益很可能并不是很高--
缺少编译器的支持,使用者将需要手动添加那些额外的代码。</p>
<p>immix gc的实现代码在<a href="https://github.com/Pivot-Studio/pivot-lang/blob/master/immix">这里</a>。它是天生支持多线程使用的,但是我们的pivot-lang目前还不支持多线程。</p>
<h2 id="benchmark"><a class="header" href="#benchmark">Benchmark</a></h2>
<p>我们对两种gc算法进行了一些基准测试,事实证明immix gc的回收性能要比simple gc <strong>快近20倍</strong>。如果你对这些测试感兴趣,可以在项目根目录运行<code>make bench</code>查看immix的benchmark,或者运行<code>make bench-simple-gc</code>查看simple gc的benchmark。</p>
<p>下方分别是simple gc和immix gc的benchmark结果,测试于2023年1月,commit 62b5c52c01e8133f5300e33a0131a50ba0c8d0de</p>
<p><img src="2023-01-24-23-23-55.png" alt="" /></p>
<p><img src="2023-01-24-23-25-06.png" alt="" /></p>
<p>immix gc的实现代码在<a href="https://github.com/Chronostasys/immix">这里</a></p>

</main>

Expand Down
Loading

0 comments on commit d8614b8

Please sign in to comment.