本次更新修复了一些致命漏洞,解决了一些内存泄漏问题,重新设计了移植接口架构,并添加了stdc++的实现。
本次更新发行2.4.58版本。
在运算过程中,出现了如下致命漏洞:
这些漏洞来自TypeCalculator.cpp,目前已被修复。
为了增强项目的可移植性,我将移植接口做了模块化设计。接下来,我会逐步将项目主体代码也进行模块化,从而实现每个项目主体模块依赖必要的移植接口模块。开发者在移植时可以根据功能需求,删减掉不需要的项目主体模块,从而了解需要移植哪些移植接口模块,最后自选或动手开发移植接口模块。
具体的移植接口模块设计方案和原理,被记录到了移植接口开发指导.md中。
除部分函数外,大部分移植接口的接口约束代码被迁移到了stamon::interface命名空间中。
我使用move和左右值引用减少了无用复制,从而减少了内存分配次数。具体修改的项目主体文件为:
Main.cppStamon.cppAstIr.cppSFN.cppAstIrReader.cpp接下来我可能会重构代码以进行更完全的优化。
我使用move和左右值引用减少了无用复制,从而减少了内存分配次数。
对于HashMap,我还额外添加了getValList()方法。
以往的EasySmartPtr只能对单个对象进行内存管理,若管理数组则会发生内存泄漏。
因此,我参考了stdc++的智能指针设置。现在,我们可以使用EasySmartPtr<T[]>来表示一个数组指针。智能指针会智能识别类型并作出相应的内存释放方式,从而解决内存泄漏问题。
在特定情况下,智能指针不能删除其所托管的内存。因此各个代码都编写了“什么都不销毁”的内存销毁函数。为了减少冗余代码,我在StamonLib.hpp中统一定义了DestoyNothing()函数,他的实现如下:
// 一个什么也不做的销毁函数,用于智能指针
template<typename T> void DestroyNothing(T *p) {
return;
}由于EasySmartPtr的定义被调整,而跟着被调整的项目主体文件如下:
BufferStream.cppAstRunner.cpp以往的Stack必须以指针为元素类型,这使得内存管理尤为困难。
因此,我重新调整了Stack的实现。现在Stack的元素类型可以是指针以外的其他类型了。
以往,Stack<T>托管的元素类型是T*;现在,Stack<T>托管的元素类型是T。
由于Stack的模板类型定义被调整,而跟着被调整的项目主体文件如下:
AstFileReader.cppAstFileWriter.cppAstIr.cpp我使用stdc++实现了移植接口,支持stdc++的平台可以选用该实现,通常情况下,stdc++实现的性能更优。
为了更直观、客观的看到基于stdc的实现和基于stdc++的实现的差距,以及本次更新的优化效果,我选取了2.4.53内部版本与2.4.58发行版进行对比,两个版本都使用Makefile编译。测试在WSL(版本:
2.6.3.0,内核版本:
6.6.87.2-1)中的Alpine Linux v3.23 x86_64运行,我采用perf 6.18.6作为性能测试工具。
我们测试了三个样例:十万次空循环、朴素递归计算斐波那契数列第三十项、从2到50000的埃氏素数筛。
测试代码如下:
import std;
def i=1;
while i<=100000: i+=1;
println("done!");
生成的原始结果分别如下:
# 优化前
Performance counter stats for './stamon_2.4.53 run loop_2.4.53.stvc':
198894300 task-clock # 0.960 CPUs utilized
21 context-switches # 105.584 /sec
0 cpu-migrations # 0.000 /sec
3651 page-faults # 18.356 K/sec
1768127633 instructions # 2.35 insn per cycle
752404789 cycles # 3.783 GHz
371318980 branches # 1.867 G/sec
2888284 branch-misses # 0.78% of all branches
0.207134601 seconds time elapsed
0.187452000 seconds user
0.012225000 seconds sys
# 优化后
Performance counter stats for './stamon_2.4.58 run loop_2.4.58.stvc':
140413600 task-clock # 0.916 CPUs utilized
38 context-switches # 270.629 /sec
0 cpu-migrations # 0.000 /sec
3850 page-faults # 27.419 K/sec
1053122765 instructions # 2.00 insn per cycle
525891656 cycles # 3.745 GHz
221371017 branches # 1.577 G/sec
1007838 branch-misses # 0.46% of all branches
0.153222000 seconds time elapsed
0.125370000 seconds user
0.016176000 seconds sys
测试代码如下:
import std;
func fib(x) {
if x<=2: return 1;
return fib(x-1)+fib(x-2);
}
println(fib(30));
生成的原始结果分别如下:
# 优化前
832040
Performance counter stats for './stamon_2.4.53 run fib_2.4.53.stvc':
5865342000 task-clock # 0.998 CPUs utilized
28 context-switches # 4.774 /sec
1 cpu-migrations # 0.170 /sec
27891 page-faults # 4.755 K/sec
47337946707 instructions # 2.16 insn per cycle
21879201815 cycles # 3.730 GHz
9934221064 branches # 1.694 G/sec
106778379 branch-misses # 1.07% of all branches
5.876182195 seconds time elapsed
5.794224000 seconds user
0.071878000 seconds sys
# 优化后
Performance counter stats for './stamon_2.4.58 run fib_2.4.58.stvc':
4374857300 task-clock # 0.996 CPUs utilized
90 context-switches # 20.572 /sec
15 cpu-migrations # 3.429 /sec
27493 page-faults # 6.284 K/sec
33893694856 instructions # 2.07 insn per cycle
16382153037 cycles # 3.745 GHz
7015854946 branches # 1.604 G/sec
58933691 branch-misses # 0.84% of all branches
4.392140304 seconds time elapsed
4.248055000 seconds user
0.127881000 seconds sys
测试代码如下:
import std;
func nsieve(n) {
def count = 0;
def arr = [n], i=0;
while i < n {
arr[i]=true;
i += 1;
}
for i in range_ab(2, n - 1) {
if arr[i] {
count += 1;
def j = i << 1;
while j < n {
arr[j] = false;
j += i;
}
}
}
print("Primes up to ");
print(n);
print(" ");
println(count);
}
def main = func {
nsieve(50000);
}();
生成的原始结果分别如下:
# 优化前
Performance counter stats for './stamon_2.4.53 run nsieve_2.4.53.stvc':
698734500 task-clock # 0.983 CPUs utilized
23 context-switches # 32.917 /sec
0 cpu-migrations # 0.000 /sec
9682 page-faults # 13.856 K/sec
5903937153 instructions # 2.23 insn per cycle
2642267435 cycles # 3.782 GHz
1239155201 branches # 1.773 G/sec
12474872 branch-misses # 1.01% of all branches
0.711171600 seconds time elapsed
0.675939000 seconds user
0.023856000 seconds sys
# 优化后
Performance counter stats for './stamon_2.4.53 run nsieve_2.4.58.stvc':
699443400 task-clock # 0.987 CPUs utilized
23 context-switches # 32.883 /sec
0 cpu-migrations # 0.000 /sec
9684 page-faults # 13.845 K/sec
5903652717 instructions # 2.23 insn per cycle
2647239011 cycles # 3.785 GHz
1239098383 branches # 1.772 G/sec
12481248 branch-misses # 1.01% of all branches
0.708518398 seconds time elapsed
0.660241000 seconds user
0.040014000 seconds sys
上述原始测试结果被数据提取并整理成了以下表格:
| 测试项 | 优化前耗时(按秒计) | 优化后耗时(按秒计) |
|---|---|---|
| 十万次空循环 | 0.207134601 | 0.153222000 |
| 朴素递归计算斐波那契数列第三十项 | 5.876182195 | 4.392140304 |
| 从2到50000的埃氏素数筛 | 0.711171600 | 0.708518398 |
在使用stdc++作为移植接口实现并对细节处进行优化后,stamon的性能在部分测试中得到了显著提升。