⚡ optimize gc
This commit is contained in:
parent
de524938cf
commit
cb547499ac
4
makefile
4
makefile
|
@ -58,8 +58,8 @@ test:nasal
|
|||
@ ./nasal -d test/life.nas
|
||||
@ ./nasal -t test/loop.nas
|
||||
@ ./nasal -t -d test/mandel.nas
|
||||
@ ./nasal -t -d test/mandelbrot.nas
|
||||
@ ./nasal -t -d test/md5.nas
|
||||
@ ./nasal -t test/mandelbrot.nas
|
||||
@ ./nasal -t test/md5.nas
|
||||
@ ./nasal -t -d test/md5compare.nas
|
||||
-@ ./nasal -d test/module_test.nas
|
||||
@ ./nasal -e test/nasal_test.nas
|
||||
|
|
81
nasal_gc.h
81
nasal_gc.h
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <unordered_map>
|
||||
#include <chrono>
|
||||
|
||||
|
@ -219,24 +218,15 @@ struct nas_co {
|
|||
|
||||
u32 pc;
|
||||
var* top;
|
||||
var* canary;
|
||||
var* canary=stack+STACK_DEPTH-1;
|
||||
var* localr;
|
||||
var* memr;
|
||||
var funcr;
|
||||
var upvalr;
|
||||
|
||||
u32 status;
|
||||
nas_co():
|
||||
pc(0),top(stack),
|
||||
canary(stack+STACK_DEPTH-1),
|
||||
localr(nullptr),
|
||||
memr(nullptr),
|
||||
funcr({vm_nil,(f64)0}),
|
||||
upvalr({vm_nil,(f64)0}),
|
||||
status(nas_co::suspended) {
|
||||
for(u32 i=0;i<STACK_DEPTH;++i) {
|
||||
stack[i]={vm_nil,(f64)0};
|
||||
}
|
||||
nas_co() {
|
||||
clear();
|
||||
}
|
||||
void clear() {
|
||||
for(u32 i=0;i<STACK_DEPTH;++i) {
|
||||
|
@ -248,6 +238,7 @@ struct nas_co {
|
|||
top=stack;
|
||||
status=nas_co::suspended;
|
||||
funcr={vm_nil,(f64)0};
|
||||
upvalr={vm_nil,(f64)0};
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -488,7 +479,7 @@ struct gc {
|
|||
std::vector<var> strs; // reserved address for const vm_str
|
||||
std::vector<var> env_argv; // command line arguments
|
||||
std::vector<nas_val*> memory; // gc memory
|
||||
std::queue<nas_val*> unused[gc_tsize]; // gc free list
|
||||
std::vector<nas_val*> unused[gc_tsize]; // gc free list
|
||||
|
||||
/* values for analysis */
|
||||
u64 size[gc_tsize];
|
||||
|
@ -517,28 +508,28 @@ struct gc {
|
|||
|
||||
/* gc functions */
|
||||
void gc::mark() {
|
||||
std::queue<var> bfs;
|
||||
std::vector<var> bfs;
|
||||
// scan coroutine process stack when coroutine ptr is not null
|
||||
// scan main process stack when coroutine ptr is null
|
||||
// this scan process must execute because when running coroutine,
|
||||
// the nas_co related to it will not update it's context(like `top`) until the coroutine suspends or exits.
|
||||
for(var* i=stack;i<=top;++i) {
|
||||
bfs.push(*i);
|
||||
bfs.push_back(*i);
|
||||
}
|
||||
bfs.push(funcr);
|
||||
bfs.push(upvalr);
|
||||
bfs.push(temp);
|
||||
bfs.push_back(funcr);
|
||||
bfs.push_back(upvalr);
|
||||
bfs.push_back(temp);
|
||||
if (cort) { // scan main process stack
|
||||
for(var* i=mctx.stack;i<=mctx.top;++i) {
|
||||
bfs.push(*i);
|
||||
bfs.push_back(*i);
|
||||
}
|
||||
bfs.push(mctx.funcr);
|
||||
bfs.push(mctx.upvalr);
|
||||
bfs.push_back(mctx.funcr);
|
||||
bfs.push_back(mctx.upvalr);
|
||||
}
|
||||
|
||||
while(!bfs.empty()) {
|
||||
var tmp=bfs.front();
|
||||
bfs.pop();
|
||||
var tmp=bfs.back();
|
||||
bfs.pop_back();
|
||||
if (tmp.type<=vm_num || tmp.val.gcobj->mark) {
|
||||
continue;
|
||||
}
|
||||
|
@ -546,32 +537,32 @@ void gc::mark() {
|
|||
switch(tmp.type) {
|
||||
case vm_vec:
|
||||
for(auto& i:tmp.vec().elems) {
|
||||
bfs.push(i);
|
||||
bfs.push_back(i);
|
||||
}
|
||||
break;
|
||||
case vm_hash:
|
||||
for(auto& i:tmp.hash().elems) {
|
||||
bfs.push(i.second);
|
||||
bfs.push_back(i.second);
|
||||
}
|
||||
break;
|
||||
case vm_func:
|
||||
for(auto& i:tmp.func().local) {
|
||||
bfs.push(i);
|
||||
bfs.push_back(i);
|
||||
}
|
||||
for(auto& i:tmp.func().upval) {
|
||||
bfs.push(i);
|
||||
bfs.push_back(i);
|
||||
}
|
||||
break;
|
||||
case vm_upval:
|
||||
for(auto& i:tmp.upval().elems) {
|
||||
bfs.push(i);
|
||||
bfs.push_back(i);
|
||||
}
|
||||
break;
|
||||
case vm_co:
|
||||
bfs.push(tmp.co().funcr);
|
||||
bfs.push(tmp.co().upvalr);
|
||||
bfs.push_back(tmp.co().funcr);
|
||||
bfs.push_back(tmp.co().upvalr);
|
||||
for(var* i=tmp.co().stack;i<=tmp.co().top;++i) {
|
||||
bfs.push(*i);
|
||||
bfs.push_back(*i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -582,7 +573,7 @@ void gc::sweep() {
|
|||
for(auto i:memory) {
|
||||
if (i->mark==GC_UNCOLLECTED) {
|
||||
i->clear();
|
||||
unused[i->type-vm_str].push(i);
|
||||
unused[i->type-vm_str].push_back(i);
|
||||
i->mark=GC_COLLECTED;
|
||||
} else if (i->mark==GC_FOUND) {
|
||||
i->mark=GC_UNCOLLECTED;
|
||||
|
@ -596,7 +587,7 @@ void gc::extend(u8 type) {
|
|||
for(u32 i=0;i<incr[index];++i) {
|
||||
nas_val* tmp=new nas_val(type);
|
||||
memory.push_back(tmp);
|
||||
unused[index].push(tmp);
|
||||
unused[index].push_back(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -612,7 +603,7 @@ void gc::init(const std::vector<string>& s,const std::vector<string>& argv) {
|
|||
for(u32 j=0;j<ini[i];++j) {
|
||||
nas_val* tmp=new nas_val(i+vm_str);
|
||||
memory.push_back(tmp);
|
||||
unused[i].push(tmp);
|
||||
unused[i].push_back(tmp);
|
||||
}
|
||||
}
|
||||
cort=nullptr;
|
||||
|
@ -638,9 +629,7 @@ void gc::clear() {
|
|||
}
|
||||
memory.clear();
|
||||
for(u8 i=0;i<gc_tsize;++i) {
|
||||
while(!unused[i].empty()) {
|
||||
unused[i].pop();
|
||||
}
|
||||
unused[i].clear();
|
||||
}
|
||||
for(auto& i:strs) {
|
||||
delete i.val.gcobj;
|
||||
|
@ -651,7 +640,7 @@ void gc::clear() {
|
|||
|
||||
void gc::info() {
|
||||
const char* name[]={"str ","vec ","hash ","func ","upval","obj ","co "};
|
||||
std::cout<<"\ngarbage collector info (gc count|alloc count|memory size)\n";
|
||||
std::clog<<"\ngarbage collector info (gc count|alloc count|memory size)\n";
|
||||
u32 maxlen=0;
|
||||
for(u8 i=0;i<gc_tsize;++i) {
|
||||
u32 len=std::to_string(gcnt[i]).length();
|
||||
|
@ -665,15 +654,15 @@ void gc::info() {
|
|||
for(u8 i=0;i<gc_tsize;++i) {
|
||||
if (gcnt[i] || acnt[i] || ini[i] || size[i]) {
|
||||
total+=gcnt[i];
|
||||
std::cout<<" "<<name[i]<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<gcnt[i];
|
||||
std::cout<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<acnt[i];
|
||||
std::cout<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<ini[i]+size[i]*incr[i]<<" (+"<<size[i]<<")\n";
|
||||
std::clog<<" "<<name[i]<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<gcnt[i];
|
||||
std::clog<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<acnt[i];
|
||||
std::clog<<" | "<<std::left<<std::setw(maxlen)<<std::setfill(' ')<<ini[i]+size[i]*incr[i]<<" (+"<<size[i]<<")\n";
|
||||
}
|
||||
}
|
||||
double t=worktime*1.0/1000000000; // seconds
|
||||
std::cout<<" time | "<<(t<0.1? t*1000:t)<<(t<0.1? " ms\n":" s\n");
|
||||
std::clog<<" time | "<<(t<0.1? t*1000:t)<<(t<0.1? " ms\n":" s\n");
|
||||
if (total) {
|
||||
std::cout<<" avg | "<<t/total*1000<<" ms\n";
|
||||
std::clog<<" avg | "<<t/total*1000<<" ms\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -690,9 +679,9 @@ var gc::alloc(u8 type) {
|
|||
if (unused[index].empty()) {
|
||||
extend(type);
|
||||
}
|
||||
var ret={type,unused[index].front()};
|
||||
var ret={type,unused[index].back()};
|
||||
ret.val.gcobj->mark=GC_UNCOLLECTED;
|
||||
unused[index].pop();
|
||||
unused[index].pop_back();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -73,10 +73,11 @@ println("coroutine state:\e[91m ",coroutine.status(co),"\e[0m");
|
|||
println("ok");
|
||||
|
||||
# pressure test
|
||||
for(var t=0;t<5;t+=1){
|
||||
for(var t=0;t<10;t+=1){
|
||||
var productor=func(){
|
||||
for(var i=0;;i+=1)
|
||||
while(1){
|
||||
coroutine.yield(i);
|
||||
}
|
||||
}
|
||||
var total=1000; # ms
|
||||
var co=coroutine.create(productor);
|
||||
|
@ -86,14 +87,16 @@ for(var t=0;t<5;t+=1){
|
|||
var bar=process_bar.high_resolution_bar(40);
|
||||
var consumer=func(){
|
||||
counter+=1;
|
||||
for(var i=0;i<5;i+=1)
|
||||
for(var i=0;i<t+1;i+=1)
|
||||
coroutine.resume(co);
|
||||
var rate=(tm.elapsedMSec()+1)/total;
|
||||
print(" ",bar.bar(rate)," ",int(rate*100),"% | ",counter," tasks \r");
|
||||
if(counter-int(counter/1000)*1000==0){
|
||||
var rate=(tm.elapsedMSec()+1)/total;
|
||||
print(" ",bar.bar(rate)," ",int(rate*100),"% | ",str(counter)," tasks in ",t+1," \r");
|
||||
}
|
||||
}
|
||||
|
||||
tm.stamp();
|
||||
while(tm.elapsedMSec()<total)
|
||||
consumer();
|
||||
println();
|
||||
println(" ",bar.bar(1)," 100% | ",str(counter)," tasks in ",t+1," ");
|
||||
}
|
|
@ -1,14 +1,16 @@
|
|||
import.stl.sort;
|
||||
import.stl.process_bar;
|
||||
|
||||
for(var i=0;i<3910;i+=1){
|
||||
for(var i=0;i<1954;i+=1){
|
||||
runtime.gc.extend("str");
|
||||
}
|
||||
for(var i=0;i<3907;i+=1){
|
||||
runtime.gc.extend("vec");
|
||||
}
|
||||
|
||||
var test=func(n){
|
||||
var ts=maketimestamp();
|
||||
var bar=process_bar.high_resolution_bar(50);
|
||||
var bar=process_bar.high_resolution_bar(40);
|
||||
|
||||
var color=[];
|
||||
var message=[];
|
||||
|
@ -21,10 +23,10 @@ var test=func(n){
|
|||
message[i]=[i+n*10,"message "~i];
|
||||
if((i-last_step)/n>1/100){
|
||||
last_step=i;
|
||||
print(bar.bar((i+1)/n)~" "~str(int((i+1)/n*100))~"% \r");
|
||||
print(" ",bar.bar((i+1)/n)~" "~str(int((i+1)/n*100))~"% \r");
|
||||
}
|
||||
}
|
||||
print(bar.bar((i+1)/n)~" 100% | ",ts.elapsedMSec()/1000," s | ");
|
||||
print(" ",bar.bar((i+1)/n)~" 100% | ",ts.elapsedMSec()/1000," s | ");
|
||||
|
||||
var mess=func(vec){
|
||||
var s=size(vec);
|
||||
|
|
Loading…
Reference in New Issue