Logo ryp 的博客

博客

标签
暂无

WyOJ 添加了伟大无敌正确胜利的 UB 检测器!

经过我一晚的奋战,WyOJ 已经成功加入了一个 UB 检测器!

截图

具体使用,只需要把语言选为 C++17ubsan,然后重新提交!非常简单也非常好用!!!!!!

然后,点击 Runtime Error 的数据点,可以看到 output 区域包含了具体 UB 信息

具体的实现是,我把 C++17ubsan 语言的 stderr 输出到了输出文件,于是 output 就会包含原先 stderr 的内容。

如果你的 stderr 内容过多,可能导致 UB 信息被挤掉看不到。 这时可以 #define stderr stdout,然后重新提交。

原先 AC 的点会变成 WA

使用检测器后的代码常数会变大不少,所以可能导致 TLE。

比赛期间看不到 output,所以本功能也自然在赛时无用。

同时,Special Judge 和 Hack 功能也已经修好!

Splay 详解

整理了一些关于 Splay 的资料,一个简洁美丽而高效的数据结构。

Splay 是最简洁的平衡树之一,支持维护区间信息。相比线段树,其可以动态地删点、加点,更加灵活;相比分块,其复杂度是均摊对数,更加高效。

在形态变化时,Splay 并不通过维护一系列性质来保证树高,而是通过伸展保证均摊复杂度。这让它少了常见平衡树的繁杂分讨,但常数也要大不少。

形态及操作

Splay 首先是一棵二叉搜索树,由许多节点组成。我们在每个节点维护父亲的左右儿子指针,以及键值。如有需要,还可以维护它子树内的信息,如它的子树大小。维护子树大小,可以实现快速查询第 k 大或者某数排名。

Splay 的核心操作是伸展(splay)。伸展某个节点 $x$,意味着将 $x$ 节点提升到根,同时更新所维护的子树信息。原来的根在伸展后成为某个普通内部节点。伸展操作的均摊复杂度是对数。

如果能够实现伸展操作,就可以方便地进行许多操作:

  • 插入。插入与普通二叉树的插入相同,按照二叉树的遍历方法找到某个叶子节点,将新值插入到该叶子的儿子下。不同的是,在插入某个点后,为了保证复杂度正确,我们要将这个节点伸展到根。

  • 删除。首先将这个节点伸展到根,然后将其与其儿子断开。这时原树分裂成两个子树,考虑合并它们。找到左子树的最大值,由二叉树的性质,这个数一定小于右子树的最小值。因此,我们将 $y$ 伸展到根。这时 $y$ 的右儿子一定空,于是将右子树拼到其右儿子上即可。

  • 查找某个数。按照二叉树的查找方法,一直找到这个数,或者某个叶子。将最后找到的节点伸展到根。

  • 查询排名。首先查找这个数,伸展到根。然后小于其的数数量就是现在根左子树的大小。如果待查询的值不存在,还要考虑根是否小于这个数。

  • 查询第 $k$ 大。和二叉树相同。从根节点开始遍历。如果当前节点 $x$ 左子树的大小,也就是小于 $x$ 的数字数量,大于等于 $k$,要找的节点在左子树;如果等于 $k - 1$,那么就是当前节点 $x$;否则,在右子树,并且 $k$ 减去左子树加上当前点大小。

  • 查询前驱。伸展到根,然后找左子树的最大值,也就是一直向右走。如果查询的值不存在,特判根是否小于待查值。

  • 查询后继。与查询前驱同。

  • 查询区间。设待查询区间为 $[l, r]$,我们将 $l - 1$ 旋到根,$r + 1$ 旋到根的右儿子,那么根的右儿子的左儿子,其上的信息就是 $[l, r]$ 的信息。

伸展

旋转

现在,我们只需要有效地实现伸展操作,就可完成所需的一切操作。

考虑怎么将某个节点高度提升一。我们称这个操作为旋转。

考虑怎么将 $2$ 提升到 $4$ 的位置。

那样,$4$ 该放到哪里?可以接到 $2$ 的右儿子上。$2$ 的右儿子放到哪里?放到 $4$ 的左儿子上,因为 $4$ 原来的左儿子是 $2$,现在已经空。其他子树不变。因此,变的只有 $2$ 和 $4$。

单旋与双旋

伸展操作能不能直接一直向上旋转呢?可以,但复杂度错误。

为了改善复杂度,我们需要引入双旋。

双旋是指,在伸展过程中,如果出现 $x$ 与 $x$ 的父亲同向,不能简单地旋转两次 $x$,而是要先旋转其父亲,再旋转 $x$。

我们如果想要将 $6$ 伸展到根,是不是需要双旋?答案是肯定的,因为 $4$ 和 $6$ 都是其父亲的右儿子,属于同向。如果是伸展 $3$,就不需要了。按照双旋的过程,我们先旋转 $4$,再旋转 $6$。也就是,先变成:

后旋转 $6$

光看上图,可能感觉双旋和单旋没有什么区别,但实际上在复杂度分析时,使用双旋可以保证某个性质,进而保证复杂度正确。

总之,我们已经知道了怎样以正确的复杂度将 $x$ 伸展到根。有关 Splay 的基本操作,就介绍完毕了。

附一份常数和美观程度都不错的实现

复杂度

势能分析简介

我们发现,Splay 的复杂度来源于两部分,一部分是遍历,另一部分是伸展。让最终遍历到节点马上被伸展到根,就可以把复杂度都算在伸展里,进而只需证明伸展的复杂度。

我们采用势能分析。势能分析是指,引入某个势能函数 $\Phi(D)$,描述某时数据结构的状态。

设每次操作的代价是 $c_i$,每次操作后数据结构为 $D_i$。要证 $\sum c_i$ 有某上界。如果 $\Phi(D_n) - \Phi(D_0) = O(F(n))$,$\Phi(D_n) - \Phi (D_0) + \sum c_i = \sum (c_i + \phi(D_i) - \phi(D_{i - 1})) = O(G(n))$,显然 $\sum c_i = O(F(n) + G(n))$。

这样有什么好处?我们考虑,Splay 等数据结构复杂度分析的难处,在于我们只知道 $c_i$ 的一个很松的上界,而不好直接分析 $\sum c_i$。实际上,某个大的 $c_i$ 对数据结构的影响也是大的,会导致后续的操作 $c_i$ 更小;换句话说,不会出现所有 $c_i$ 都取到上界的情况。

引入势能函数后,每个很大的 $c_i$,可以用一个很小的 $\Phi(D_i) - \Phi(D_{i-1})$ 来平衡。因而可以更方便地放缩,并得到上界。

具体分析

我们设某个节点的势能函数为 $\phi(x) = \log \lvert x\rvert$($\log$ 均以二为底;$\lvert x\rvert$ 表示 $x$ 的子树大小),$\Phi(D) = \sum \phi(x)$。显然的,$0\le \Phi(D) \lt n\log n$,并且 $\Phi(D_n) - \Phi(D_0) = O(n\log n)$。我们要证明每次伸展操作的均摊复杂度是对数。

伸展的分解

根据上面对 Splay 的介绍,我们可以将伸展分为三种具体操作。设 $x$ 为待伸展的节点,$y$ 为 $x$ 的父亲,$z$ 为 $y$ 的父亲。

  • zig,即一次单旋,在 $y$ 为根时候发生。直接旋转 $x$,其深度减少一。发现这种旋转最多发生一次。

  • zig-zig,即一次双旋,在 $y$ 和 $x$ 同向时发生。先旋转 $y$,后旋转 $x$。$x$ 深度减少二。

  • zig-zag,即两次对 $x$ 的单选,在 $x$ 和 $y$ 不同向时发生。$x$ 深度减少二。

伸展的过程是数次 zig-zig 与 zig-zag 的组合,加上可能存在的一次 zig。

zig 的分析

旋转的复杂度为 $O(1)$,势能的变化量为

$\phi(x') + \phi(y') - \phi(x) - \phi(y) = \phi(y') - \phi(x) \le \phi(x') - \phi(x)$

因此摊还代价是 $O(1) + \phi (x') - \phi (x)$。

zig-zig 的分析

摊还代价是

$$ \begin{aligned} & c \\ =& 1 + \phi(x') + \phi(y') + \phi(z') - \phi(x) - \phi(y) - \phi(z) \\ =& 1 + \phi(y') + \phi(z') - \phi(x) - \phi(y) \\ \end{aligned} $$

考虑怎么把 $1$ 去掉,因为如果引入 $1$,就会导致最终复杂度与旋转次数有关。

有:

$$ \begin{aligned} 2\phi(x') - \phi(x) - \phi(z') = \log (\dfrac{\lvert x'\rvert^2}{\lvert x\rvert\lvert z'\rvert}) \ge 1 \end{aligned} $$

这是因为 $\lvert x'\rvert \ge \lvert x\rvert+\lvert z'\rvert$。注意到不双旋时,此不等式不满足。这也是为什么双旋才能保证复杂度。

用这个不等式代换常数 $1$,得到

$$ \begin{aligned} & c \\ \le& 2\phi(x') - \phi(x) - \phi(z') + \phi(y') + \phi(z') - \phi(x) - \phi(y) \\ \le& 2\phi(x') - 2\phi(x) + \phi(y') - \phi(y) \\ \le& 3\phi(x') - 3\phi(x) \\ =& O(\phi(x') - \phi(x)) \end{aligned} $$

成功将常数消去,同时和前面的 $\phi(x') - \phi(x)$ 保持了一致。

zig-zag 的分析

类似的,我们有不等式:$2\phi(x') - \phi(y') - \phi(z') = \log (\dfrac{\lvert x'\rvert^2}{\lvert y'\rvert\lvert z'\rvert})\ge 1$

$$ \begin{aligned} & c \\ &= 1 + \phi(x') + \phi(y') + \phi(z') - \phi(x) - \phi(y) - \phi(z) \\ &= 1 + \phi(y') + \phi(z') - \phi(x) - \phi(y) \\ &\le 2\phi(x') - \phi(y') - \phi(z') + \phi(y') + \phi(z') - \phi(x) - \phi(y) \\ &\le 2\phi(x') - 2\phi(x) - \phi(y) \\ &\le 2\phi(x') - 2\phi(x) \\ &= O(\phi(x') - \phi(x)) \end{aligned} $$

综合

分析得到,zig 的摊还代价为 $O(1 + \phi(x') - \phi(x))$,而这种旋转最多一次;其他的两种旋转,摊还代价都是 $O(\phi(x') - \phi(x))$。这样,伸展的总代价就是 $O(\log \lvert x'\rvert - \log \lvert x\rvert + 1) = O(\log n)$。我们成功证明了伸展的复杂度是摊还对数,由此知道 Splay 的复杂度是正确的。

跳表

跳表实际上是一个多层链表,每一层链表都有序。从下到上(层数从小到大),链表逐渐变小。一个元素位于第 $k$ 层的概率是 $p^k$,实践中一般会限制层数。

因此 $n$ 个元素的跳表的第 $k$ 层链表的大小期望是 $np^k$,呈指数级下降。这保证复杂度正确。

对于实践,我们对每一个节点,维护它的值以及它在每一层的链表指针 nxt[]

接下来考虑操作。

最基本的操作是在跳表中查找一个节点。由于每一层链表有序,并且越高层节点越少,我们可以从最高层开始遍历。由于在高层的节点一定也在低层,并且每一层链表都具有单调性,所以这个算法正确。

考虑复杂度。显然的,如果证明了搜索的复杂度正确,跳表的其他一系列操作复杂度都正确。

注意到,搜索某个节点,实际上就是从 rank $1$ 走到 rank $k$ 的过程。与朴素链表不同的是,跳表允许不连续地从 $1$ 走到 $k$,这就是它节省的复杂度。

有一个比较简单的感性证明。考虑在第 $k$ 层,rank $i$ 走到 $rank j$ 的期望代价是 $(j - i) p^k$(二项分布),这个代价随着层数增加而减小。

严格证明可以看 OI Wiki,但是我觉得我这个感性就比较够了。

然后考虑更多的操作。考虑插入一个节点。我们需要决定把这个节点到前多少层,这可以随出来。我们找到这些层上这个节点的前驱,就可以按照链表的方法,把它插入到跳表中。删除一个节点同样简单,前驱后继也很基本。

第 $k$ 大和查排名不出所料地需要维护信息。

维护啥?如果能维护出每个节点的 $rank$,那就跟玩一样了。虽然我们显然办不到,但是我们可以维护每一层上相邻两个节点之间的实际距离,也就是排名差。

这个玩意儿是很好维护的。插入的时候我们将后继的排名差加一,删除的时候减一即可。于是我们做完了。

好吧,这个东西好像不那么好维护,但是我现在不太感兴趣了。我打算用 Rust 写一个类似 Redis 的内存数据库,主要是为了练习 Rust。

一个简单的渲染到 PPM 的渲染器

之前写了个渲染到 PPM 的最基本的渲染器,画了条贝塞尔曲线,但是非常简陋:

  • 只有 2D
  • 明显的锯齿
  • 渲染架构太简陋

第一个问题我以后再解决。至于锯齿,我觉得可以写一个 MSAA。渲染架构,就加一个包围盒。

我最开始想的是,维护所有包围盒,然后渲染时候用类似二维差分的东西做,后来发现这个东西差分掉之后很不自然,精度大概也有点问题。所以我决定做在线渲染,也就是接收到每一个图元的同时即时渲染出片段颜色。

但是之后咋办?二维遍历图元和像素点太慢,但是前缀和精度要爆。

哦我脑瘫了,只能这么做。而且这个也不能前缀和,因为矩形内部颜色又不一样。

发现图形学有很多神秘参数需要调。

【比赛通知】0621 模拟赛 须知

  1. 赛时只测样例,因此只要没有编译错误,都是满分。

  2. 赛后由老师点击重测来进行实际测试

  3. 第五、第六题是实际的第三、第四题,原第三、第四题是实际的第五、第六题

WyOJ 图床 潍坊一中校园网用户须知

请下载:

此证书

单击打开后,点击 “安装证书”,点击下一步,并选择 “将所有的证书都放入下列存储”,在 “浏览”中选择“受信任的根证书颁发机构”,确定,下一步,完成。

之后重新访问。

如果你是 Linux 用户,你应该会怎么安装这个证书。

WyOJ 现有配套图床了

q.ryp.org.cn

图片

我们对潍坊一中校园网做了特殊优化,可以直接重定向到局域网,大大增大了带宽与访问速度。

-- upd

图床已经炸了,并且因为用处不大,暂没有修复意愿。

64 位 WyOJ 评测机性能测评

\begin{array}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|} \hline \text{OJ} & \text{language} & \text{T1} & \text{T2} & \text{T3} & \text{T4} & \text{T5} & \text{T6-1} & \text{T6-2} & \text{T6-3} & \text{T7-1} & \text{T7-2} & \text{T8} & \text{T9-1} & \text{T9-2} \\ \hline \textbf{WyOJ64} & \text{C++} & 335 & 350 & 1127 & 867 & 790 & 466 & 415 & 45 & 418 & 1450 & 1203 & 959 & 796 \\ \hline \textbf{WyOJ32} & \text{C++} & 338 & 388 & 1324 & 810 & 644 & 712 & 597 & 53 & 1442 & 1450 & 906 & 726 & 644 \\ \hline \textbf{WyOJ32} & \text{C++11} & 334 & 378 & 1370 & 792 & 622 & 706 & 357 & 53 & 392 & 1170 & 899 & 747 & 649 \\ \hline \textbf{洛谷} & \text{G++(-O2,C++14)} & 372 & 500 & 964 & 1040 & 786 & 684 & 551 & 100 & 378 & 1170 & 928 & 726 & 585 \\ \hline \text{Atcoder} & \text{GCC12.2(C++20)} & 309 & 336 & 769 & 697 & 612 & 356 & 398 & 67 & 359 & 603 & 682 & 137 & 159 \\ \hline \text{Codeforces} & \text{G++ 5.1.0(-O2)} & 288 & 295 & 967 & 701 & 857 & 467 & 358 & 77 & 1045 & 1045 & 5912 & 639 & 530 \\ \hline \text{UOJ} & \text{G++ 4.8.4 (-O2)} & 374 & 525 & 1100 & 1375 & 700 & 821 & 587 & 64 & 417 & 1323 & 889 & 758 & 498 \\ \hline \text{LibreOJ} & \text{G++ 8.2.0(-O2,C++14)} & 246 & 310 & 598 & 586 & 418 & 474 & 396 & 55 & 282 & 604 & 27 & 519 & 272 \\ \hline \text{BZOJ} & \text{G++ 4.4.5(-O2)} & 504 & 1280 & 2092 & 1368 & 1568 & 1752 & 1516 & 180 & 2792 & 2788 & 6288 & 1636 & 1388 \\ \hline \end{array}

\begin{array}{|c|c|} \hline \textbf{测试点} & \textbf{内容} \\ \hline \text{T1} & \textbf{循环} \\ \hline \text{T2} & \textbf{欧拉筛} \\ \hline \text{T3} & \text{Floyd} \\ \hline \text{T4} & \text{set} \\ \hline \text{T5} & \textbf{内存申请} \\ \hline \text{T6} & \textbf{内存访问和缓存} \\ \hline \text{T7} & \textbf{整数除法与取模} \\ \hline \text{T8} & \textbf{浮点数运算} \\ \hline \text{T9} & \textbf{CPU 流水线和循环展开} \\ \hline \end{array}

WyOJ 正式切换到全 64 位环境 + 千兆以太网

如题!

这意味着以后可以正常使用 __int128 了!

而且评测机的性能会有一定提升。

同时,评测的延迟(同步数据的延迟)会缩小十倍。

欢歌载舞!交换比特!共同庆祝!

RISC-V 手册第一章翻译(由于 CSDN 的强制 VIP 流氓策略,特将本文搬运至此)

今天的内容(包括今天以后的很多很多天),是 RISC-V 手册页的翻译。为啥要讲这个玩意儿呢?有几个原因:

  • 如果想要自制处理器,不对外开放的 x86 显然走不通。即使是 ARM 也需要ARM公司来授权,而自己开发的指令集又存在没有生态这一巨大问题。所以,最好的选择是开源RISC-V架构。
  • 对于开发人员来说,RISC-V 架构更简单上手。它的手册页(也就是现在我们翻译的这个)一共大约有400页,而ARM架构有足足2070页,更不要说有了将近40年的x86架构。所以,对于想要找一个容易理解的架构学习,RISC-V 是不二的选择。
  • 第一条的原因,国内的许多厂商(大概)正在研究 RISC-V 架构(当然也在研究ARM),甚至已经出现了可行的 RISC-V 架构手机(忘了在哪里看到的。即使没有以后也会有的)。而且鉴于它比较容易上手的特点,学习它(大概)不会反悔。
  • 我已经开始卷了 :-)

好吧,其实,我也不过比大家先开始看了两三天(上册看完大概一半了),有什么问题千万不要问我啊!如果真的有地方觉得奇怪,就看一下原文吧。也是第一次翻译这种长文档,有的极长句子使用了机翻指导…… 所以如果突然出来风格不符的地方,就心里默默骂我两句吧……

RISC-V 指令集架构 (ISA instruction set manual) 手册

第一册 无特权的指令集架构

第一章 引言

RISC-V (那个音标不会打)是一个被设计成给研究和教学用的崭新的指令集(ISA,Instruction Set Archiecture),但现在我们(反悔了)希望它能够变成一个可投入生产的免费开源(或译为自由开放)架构。RISC-V 的设计目标如下:

  • 一个完全开源的ISA(记住这个词),可以免费开源的投入生产以及学术研究(academia and industry)
  • 一个可以直接硬件实现的真可用的 ISA,而不仅仅是(无聊的)模拟或者机器码翻译。
  • 一个避免过度设计的 ISA。它有着独特的微架构风格(particular microarchitecture style)(比如,微编码、乱序执行、分离的(大概是指指令分为I、F、D等多个部分,不清)、其他打破常规的东西)以及独特的工程实现(比如,支持全定制、ASIC、FPGA)。但它同样可以做到高效率。
  • 一个分成一个小的单独整数 ISA 的 ISA,使得定制的加速器(后文会提到,accelerators)以及仅仅为了教学的ISA 变得可能。并且也有可选的标准(指这些扩展由官方定义)扩展(extensions),以支持多种用途的软件开发。
  • 支持 2008 IEEE-754 浮点数标准。
  • 支持扩展 ISA 以及专门的变体。
  • 一个包含可供应用程序、内核和硬件实现选择的32 位和64 位地址空间(address space)的ISA。
  • 一个支持多处理器并行的架构,其中可能包括由很多种类组成的多处理器。
  • 可选的变长指令,可以用来减少指令大小,还可以用来支持可选的密集指令编码,来提升性能,减小代码大小以及能耗。
  • 对操作系统编写来说的全虚拟化的架构(大概指虚拟内存)。
  • 带有一个简化的新特权架构设计的ISA。

这里是我们(当然不是我啦)对于RISC-V的设计的评论。如果你不愿意读(only interested in the specification itself),可跳过(爱读不读)。

(所以说,在这里可能会有一些好玩的 :-),所以翻译的也比较随便。如果仅仅对原文本身感兴趣的话请读原文)

之所以有RISC-V这个名字,是因为前四个名字都被同校的那些用了。我们也用这个名字来双关(恶搞)一些别的词(绝对是写标准的时候现想的),比如变种(variations),向量(vectors),来支持架构研究,包括各种各样的并行加速器。这对ISA设计来说是一个明确的目标。

RISC-V 架构标准尽量避免提到实现实现细节(尽管评论中已经包含了实现的一些决定),并且应该被写成从软件视角看一个多样化的实现,而不是以一个硬件实现者的视角来看。这个手册包含两册。这一册包含基础的无权限指令,包括可选的无特权ISA 扩展。这些指令在所有的模式、所有的特权架构下都可以使用,尽管运行状态结果在一些不同模式不同特权架构下可能不太一样。第二册包含了第一个(“Classic”,原文)的特权架构。这个手册使用IEC 80000-13:2008的风格,每字节为8 位宽。

在无权限的ISA设计中,我们尝试避免所有诸如缓存行大小(cache line size)的依赖特殊微架构功能的地方,或者诸如地址转换的特权架构细节。这是为了让这些可供替代的微架构拥有简单性和灵活性(原文为,This is both for simplicity and to allow maximum flexibility for alternative microarchitectures or alternative privileged architectures. )

1.1 RISC-V 硬件平台术语

一个RISC-V 硬件平台包含了组合在一起的单个或多个的兼容RISC-V(RISC-V-compatible)处理核心,以及其他非RISC-V兼容的处理核心、固定功能的加速器(fixed-function accelerator)、各种各样的物理内存结构、IO设备以及用来支持组件通讯的互联结构。

术语组件(component)用来描述一个包含不依赖其他指令获取单元(instruction fetch unit)的核心。一个RISC-V 兼容核心 可能通过多线程(multithreading)支持多个RISC-V 兼容硬件线程或者harts

一个RISC-V核心可能拥有附加特殊指令集扩展(addtional specialized instruction-set extensions)或者一个协处理器。术语协处理器 指一个附加在一个RISC-V 核心上的单元,它多半根据RISC-V指令流来顺序操作,但它也可能拥有附加的状态保存(state)或者指令集扩展,并且完全有可能有一些受限制的相对自制权利。

我们使用术语加速器(accelerator)来表示一个不可编程的固定功能单元或者一个有特殊任务的,可以自主操作的核心。在一个RISC-V系统,我们预料到会有许多可编程的加速器,将会是一个带有特殊指令集扩展或定制的协处理器,以RISC-V为基础的核心。其中重要的一个就是IO加速器(I/O accelerators),它可以使应用程序核心卸下IO处理任务的沉重包袱。

RISC-V 硬件平台的系统级组织,可以是单核心的微型控制器或一个成千节点集群、共享内存的服务器(can range from a single-core micro-controller to a many-thousand-node cluster of shared-memory manycore server nodes)。一个小型的SoC 甚至也同样可结构化成一个包含等级制度的多计算机或多处理器,来实现模块化的开发或提供安全的子系统间隔离。

1.2 RISC-V 软件执行环境以及Harts

一个RISC-V 程序的反应依赖于它所运行的执行环境(execution environment)。一个RISC-V 执行环境接口(EEI,Execution Environment Interface)定义了程序的初始化状态、包含harts支持的特权级模式的环境中的hart的数量和类型、不同内存以及IO区域的访问权(accessibility and attributes)、执行在每个hart上的一切合法所带来的反应以及执行时以及环境调用时(environment call)抛出的异常或者中断的处理。EEI 的样例包括,Linux 应用程序二进制接口(ABI)或者RISC-V 管理者二进制接口(SBI)。一个RISC-V 执行环境的实现可以是纯硬件、纯软件或者软硬件结合。举个栗子,陷阱和软件仿真可以被用来实现硬件中未实现的功能(比如虚拟内存,译者注)。执行环境实现包含:

  • 纯金属(Bare metal)。Hart 被物理处理器进程直接实现,并且(软件)对全部物理地址空间有访问权。硬件平台在启动时(power-on reset)就定义好了执行环境。
  • RISC-V 操作系统通过将用户级hart多路复用到可用的物理处理器线程上,以及用虚拟内存控制内存访问来提供多用户级执行环境。(原文: RISC-V operating systems that provide multiple user-level execution environments by multiplexing user-level harts onto available physical processor threads and by controlling access to memory via virtual memory)。
  • RISC-V 虚拟机监控程序为来宾操作系统提供多个管理者级执行环境。(原文: RISC-V hypervisors that provide multiple supervisor-level execution environments for guest operating systems. )
  • 例如Spike、QEMU、rv8的模拟在其他例如x86的系统上模拟RISC-V hart的RISC-V 模拟器。它提供了一个用户级或管理者级执行环境。

一个纯硬件平台可以考虑定义一个EEI。可控的(accessible)hart、内存以及其他硬件居住在这个环境中。初始状态在启动时设置。通常地,大多数软件被设计成用多层抽象接口到硬件。具有更多抽象的EEI提供了在不同硬件平台之间的更大可移植性。通常,EEI 被分为多个层,更高层的EEI 使用下层EEI(提供的功能抽象)。

在软件执行在给定执行环境中的角度来看,hart是一个通过执行环境来自取并且自执行RISC-V指令的资源(resource)。在这一角度,hart表现的像一个硬件资源,尽管执行环境将时间多路传输到真正硬件上去(even if time-multiplexed onto real hardware by the execution environment)。一些EEI支持创建或销毁附加(虚拟)hart。比如,凭借环境调用来创建(fork)新的hart。

共 203 篇博客