Changes in / [74ec742:29d8c02]
- Files:
-
- 4 added
- 36 deleted
- 137 edited
-
benchmark/Cargo.toml.in (modified) (1 diff)
-
benchmark/Makefile.am (modified) (1 diff)
-
benchmark/c.c (added)
-
benchmark/plot.py (modified) (7 diffs)
-
benchmark/process-mutilate.py (modified) (8 diffs)
-
benchmark/readyQ/bench.go (modified) (1 diff)
-
benchmark/readyQ/churn.cfa (modified) (8 diffs)
-
benchmark/readyQ/churn.cpp (deleted)
-
benchmark/readyQ/churn.go (deleted)
-
benchmark/readyQ/churn.rs (deleted)
-
benchmark/readyQ/cycle.cpp (modified) (1 diff)
-
benchmark/readyQ/rq_bench.hpp (modified) (1 diff)
-
benchmark/readyQ/transfer.cfa (modified) (6 diffs)
-
benchmark/readyQ/transfer.cpp (modified) (8 diffs)
-
benchmark/readyQ/transfer.go (modified) (11 diffs)
-
benchmark/readyQ/transfer.rs (modified) (10 diffs)
-
benchmark/readyQ/yield.cfa (modified) (1 diff)
-
benchmark/readyQ/yield.cpp (modified) (1 diff)
-
benchmark/readyQ/yield.rs (modified) (1 diff)
-
benchmark/rmit.py (modified) (6 diffs)
-
doc/theses/mubeen_zulfiqar_MMath/dofree.tex (added)
-
doc/theses/thierry_delisle_PhD/thesis/Makefile (modified) (3 diffs)
-
doc/theses/thierry_delisle_PhD/thesis/data/churn.jax (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/data/churn.low.jax (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/data/cycle.jax (modified) (1 diff)
-
doc/theses/thierry_delisle_PhD/thesis/data/cycle.low.jax (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/data/memcd.rate (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/data/memcd.updt (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/data/yield.jax (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/data/yield.low.jax (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/fig/SAVE.fig (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/fig/idle.fig (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/fig/idle1.fig (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/fig/idle2.fig (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/fig/idle_state.fig (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/local.bib (modified) (1 diff)
-
doc/theses/thierry_delisle_PhD/thesis/test.svg (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/text/eval_macro.tex (modified) (1 diff)
-
doc/theses/thierry_delisle_PhD/thesis/text/eval_micro.tex (modified) (8 diffs)
-
doc/theses/thierry_delisle_PhD/thesis/text/practice.tex (modified) (4 diffs)
-
doc/theses/thierry_delisle_PhD/thesis/thesis.tex (modified) (2 diffs)
-
libcfa/src/Makefile.am (modified) (2 diffs)
-
libcfa/src/algorithms/range_iterator.cfa (modified) (1 diff)
-
libcfa/src/assert.cfa (modified) (3 diffs)
-
libcfa/src/bits/align.hfa (modified) (2 diffs)
-
libcfa/src/bits/debug.cfa (modified) (2 diffs)
-
libcfa/src/bits/defs.hfa (modified) (1 diff)
-
libcfa/src/bits/weakso_locks.cfa (modified) (1 diff)
-
libcfa/src/common.cfa (modified) (1 diff)
-
libcfa/src/concurrency/alarm.cfa (modified) (1 diff)
-
libcfa/src/concurrency/clib/cfathread.cfa (modified) (1 diff)
-
libcfa/src/concurrency/coroutine.cfa (modified) (10 diffs)
-
libcfa/src/concurrency/coroutine.hfa (modified) (1 diff)
-
libcfa/src/concurrency/exception.cfa (modified) (1 diff)
-
libcfa/src/concurrency/invoke.c (modified) (4 diffs)
-
libcfa/src/concurrency/io.cfa (modified) (3 diffs)
-
libcfa/src/concurrency/io/call.cfa.in (modified) (1 diff)
-
libcfa/src/concurrency/io/setup.cfa (modified) (2 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (8 diffs)
-
libcfa/src/concurrency/kernel.hfa (modified) (1 diff)
-
libcfa/src/concurrency/kernel/cluster.cfa (modified) (1 diff)
-
libcfa/src/concurrency/kernel/private.hfa (modified) (1 diff)
-
libcfa/src/concurrency/kernel/startup.cfa (modified) (8 diffs)
-
libcfa/src/concurrency/locks.cfa (modified) (9 diffs)
-
libcfa/src/concurrency/locks.hfa (modified) (5 diffs)
-
libcfa/src/concurrency/monitor.cfa (modified) (18 diffs)
-
libcfa/src/concurrency/monitor.hfa (modified) (1 diff)
-
libcfa/src/concurrency/preemption.cfa (modified) (6 diffs)
-
libcfa/src/concurrency/ready_subqueue.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/thread.cfa (modified) (1 diff)
-
libcfa/src/containers/maybe.cfa (modified) (1 diff)
-
libcfa/src/containers/result.cfa (modified) (1 diff)
-
libcfa/src/containers/string.cfa (modified) (1 diff)
-
libcfa/src/containers/string_sharectx.hfa (modified) (1 diff)
-
libcfa/src/containers/vector.cfa (modified) (2 diffs)
-
libcfa/src/device/cpu.cfa (modified) (2 diffs)
-
libcfa/src/exception.c (modified) (2 diffs)
-
libcfa/src/fstream.cfa (modified) (4 diffs)
-
libcfa/src/fstream.hfa (modified) (1 diff)
-
libcfa/src/heap.cfa (modified) (42 diffs)
-
libcfa/src/interpose.cfa (modified) (5 diffs)
-
libcfa/src/iostream.cfa (modified) (1 diff)
-
libcfa/src/limits.cfa (modified) (1 diff)
-
libcfa/src/memory.cfa (modified) (1 diff)
-
libcfa/src/parseargs.cfa (modified) (2 diffs)
-
libcfa/src/parseconfig.cfa (modified) (4 diffs)
-
libcfa/src/rational.cfa (modified) (1 diff)
-
libcfa/src/startup.cfa (modified) (2 diffs)
-
libcfa/src/stdlib.cfa (modified) (2 diffs)
-
libcfa/src/strstream.cfa (modified) (3 diffs)
-
libcfa/src/time.cfa (modified) (1 diff)
-
libcfa/src/virtual.c (modified) (1 diff)
-
src/AST/Convert.cpp (modified) (5 diffs)
-
src/AST/Copy.cpp (modified) (2 diffs)
-
src/AST/Decl.cpp (modified) (3 diffs)
-
src/AST/Decl.hpp (modified) (2 diffs)
-
src/AST/Eval.hpp (added)
-
src/AST/Expr.cpp (modified) (5 diffs)
-
src/AST/Expr.hpp (modified) (2 diffs)
-
src/AST/Label.hpp (modified) (1 diff)
-
src/AST/Node.hpp (modified) (2 diffs)
-
src/AST/Pass.proto.hpp (modified) (3 diffs)
-
src/AST/Stmt.cpp (modified) (2 diffs)
-
src/AST/Stmt.hpp (modified) (2 diffs)
-
src/AST/Util.cpp (modified) (3 diffs)
-
src/AST/module.mk (modified) (1 diff)
-
src/CodeGen/CodeGenerator.cc (modified) (1 diff)
-
src/CodeGen/FixMain.cc (modified) (1 diff)
-
src/CodeGen/FixMain2.cc (deleted)
-
src/CodeGen/LinkOnce.cc (modified) (1 diff)
-
src/CodeGen/module.mk (modified) (1 diff)
-
src/Common/CodeLocationTools.cpp (modified) (4 diffs)
-
src/Common/Indenter.cc (deleted)
-
src/Common/Indenter.h (modified) (2 diffs)
-
src/Common/SemanticError.h (modified) (4 diffs)
-
src/Common/module.mk (modified) (1 diff)
-
src/Common/utility.h (modified) (2 diffs)
-
src/Concurrency/module.mk (modified) (1 diff)
-
src/ControlStruct/LabelGeneratorNew.hpp (modified) (1 diff)
-
src/ControlStruct/MultiLevelExit.cpp (modified) (6 diffs)
-
src/ControlStruct/module.mk (modified) (2 diffs)
-
src/GenPoly/Lvalue.cc (modified) (2 diffs)
-
src/GenPoly/Lvalue2.cc (deleted)
-
src/GenPoly/module.mk (modified) (1 diff)
-
src/InitTweak/FixInitNew.cpp (modified) (4 diffs)
-
src/InitTweak/module.mk (modified) (2 diffs)
-
src/Parser/DeclarationNode.cc (modified) (3 diffs)
-
src/Parser/ParseNode.h (modified) (1 diff)
-
src/Parser/TypeData.cc (modified) (2 diffs)
-
src/Parser/parser.yy (modified) (21 diffs)
-
src/ResolvExpr/AlternativeFinder.cc (modified) (1 diff)
-
src/ResolvExpr/Resolver.cc (modified) (2 diffs)
-
src/SymTab/Autogen.h (modified) (14 diffs)
-
src/SymTab/Demangle.cc (modified) (1 diff)
-
src/SymTab/Demangle.h (deleted)
-
src/SymTab/Mangler.h (modified) (1 diff)
-
src/SymTab/Validate.cc (modified) (12 diffs)
-
src/SymTab/Validate.h (modified) (3 diffs)
-
src/SymTab/ValidateType.cc (deleted)
-
src/SymTab/ValidateType.h (deleted)
-
src/SymTab/demangler.cc (modified) (1 diff)
-
src/SymTab/module.mk (modified) (1 diff)
-
src/SynTree/BaseSyntaxNode.cc (deleted)
-
src/SynTree/module.mk (modified) (1 diff)
-
src/Tuples/TupleExpansion.cc (modified) (2 diffs)
-
src/Tuples/Tuples.cc (modified) (5 diffs)
-
src/Tuples/module.mk (modified) (2 diffs)
-
src/Validate/Autogen.cpp (modified) (2 diffs)
-
src/Validate/EliminateTypedef.cpp (deleted)
-
src/Validate/EliminateTypedef.hpp (deleted)
-
src/Validate/FixQualifiedTypes.cpp (deleted)
-
src/Validate/FixQualifiedTypes.hpp (deleted)
-
src/Validate/ForallPointerDecay.cpp (modified) (2 diffs)
-
src/Validate/ForallPointerDecay.hpp (modified) (2 diffs)
-
src/Validate/GenericParameter.cpp (modified) (3 diffs)
-
src/Validate/HoistStruct.cpp (deleted)
-
src/Validate/HoistStruct.hpp (deleted)
-
src/Validate/NoIdSymbolTable.hpp (deleted)
-
src/Validate/module.mk (modified) (2 diffs)
-
src/Virtual/module.mk (modified) (1 diff)
-
src/main.cc (modified) (6 diffs)
-
tests/.expect/forall.txt (modified) (1 diff)
-
tests/.expect/loop_else.txt (deleted)
-
tests/.expect/nested-types-ERR2.nast.txt (deleted)
-
tests/.expect/nested-types-ERR2.oast.txt (deleted)
-
tests/.expect/nested-types-ERR2.txt (added)
-
tests/forall.cfa (modified) (4 diffs)
-
tests/include/.expect/includes.nast.txt (modified) (1 diff)
-
tests/include/includes.cfa (modified) (7 diffs)
-
tests/loop_else.cfa (deleted)
-
tests/pybin/settings.py (modified) (1 diff)
-
tests/pybin/test_run.py (modified) (1 diff)
-
tests/test.py (modified) (2 diffs)
-
tests/unified_locking/.expect/fast_block_lock.txt (deleted)
-
tests/unified_locking/.expect/locks.txt (modified) (1 diff)
-
tests/unified_locking/fast_block_lock.cfa (deleted)
-
tests/unified_locking/locks.cfa (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
benchmark/Cargo.toml.in
r74ec742 r29d8c02 4 4 authors = ["Cforall"] 5 5 edition = "2018" 6 7 [[bin]]8 name = "rdq-churn-tokio"9 path = "@abs_srcdir@/readyQ/churn.rs"10 6 11 7 [[bin]] -
benchmark/Makefile.am
r74ec742 r29d8c02 614 614 RDQBENCHES = \ 615 615 rdq-churn-cfa \ 616 rdq-churn-tokio \617 rdq-churn-go \618 rdq-churn-fibre \619 616 rdq-cycle-cfa \ 620 617 rdq-cycle-tokio \ -
benchmark/plot.py
r74ec742 r29d8c02 22 22 23 23 class Field: 24 def __init__(self, unit, _min, _log , _name=None):24 def __init__(self, unit, _min, _log): 25 25 self.unit = unit 26 26 self.min = _min 27 27 self.log = _log 28 self.name = _name29 28 30 29 field_names = { … … 33 32 "Ops per procs" : Field('Ops' , 0, False), 34 33 "Ops per threads" : Field('Ops' , 0, False), 35 "ns per ops/procs" : Field(' ' , 0, False, _name = "Latency (ns $/$ (Processor $\\times$ Operation))"),36 "Number of threads" : Field(' ', 1, False),34 "ns per ops/procs" : Field('ns' , 0, False), 35 "Number of threads" : Field('thrd' , 1, False), 37 36 "Total Operations(ops)" : Field('Ops' , 0, False), 38 37 "Ops/sec/procs" : Field('Ops' , 0, False), 39 38 "Total blocks" : Field('Blocks', 0, False), 40 "Ops per second" : Field(' ' , 0, False),39 "Ops per second" : Field('Ops' , 0, False), 41 40 "Cycle size (# thrds)" : Field('thrd' , 1, False), 42 41 "Duration (ms)" : Field('ms' , 0, False), 43 "Target QPS" : Field('' , 0, False), 44 "Actual QPS" : Field('' , 0, False), 45 "Average Read Latency" : Field('us' , 0, True), 42 "Target QPS" : Field('QPS' , 0, False), 43 "Actual QPS" : Field('QPS' , 0, False), 46 44 "Median Read Latency" : Field('us' , 0, True), 47 45 "Tail Read Latency" : Field('us' , 0, True), 48 "Average Update Latency": Field('us' , 0, True),49 46 "Median Update Latency" : Field('us' , 0, True), 50 47 "Tail Update Latency" : Field('us' , 0, True), 51 "Update Ratio" : Field('\%' , 0, False),52 48 } 53 49 54 def plot(in_data, x, y, o ptions):50 def plot(in_data, x, y, out): 55 51 fig, ax = plt.subplots() 56 52 colors = itertools.cycle(['#0095e3','#006cb4','#69df00','#0aa000','#fb0300','#e30002','#fd8f00','#ff7f00','#8f00d6','#4b009a','#ffff00','#b13f00']) … … 96 92 print("Making Plots") 97 93 98 for name, data in s orted(series.items()):94 for name, data in series.items(): 99 95 _col = next(colors) 100 96 plt.scatter(data['x'], data['y'], color=_col, label=name, marker='x') … … 110 106 print("Finishing Plots") 111 107 112 plt.ylabel( field_names[y].name if field_names[y].name elsey)108 plt.ylabel(y) 113 109 # plt.xticks(range(1, math.ceil(mx) + 1)) 114 plt.xlabel( field_names[x].name if field_names[x].name elsex)110 plt.xlabel(x) 115 111 plt.grid(b = True) 116 112 ax.xaxis.set_major_formatter( EngFormatter(unit=field_names[x].unit) ) 117 if options.logx: 118 ax.set_xscale('log') 119 elif field_names[x].log: 113 if field_names[x].log: 120 114 ax.set_xscale('log') 121 115 else: … … 123 117 124 118 ax.yaxis.set_major_formatter( EngFormatter(unit=field_names[y].unit) ) 125 if options.logy: 126 ax.set_yscale('log') 127 elif field_names[y].log: 119 if field_names[y].log: 128 120 ax.set_yscale('log') 129 121 else: 130 plt.ylim(field_names[y].min, options.MaxY if options.MaxY elsemy*1.2)122 plt.ylim(field_names[y].min, my*1.2) 131 123 132 124 plt.legend(loc='upper left') 133 125 134 126 print("Results Ready") 135 if o ptions.out:136 plt.savefig(o ptions.out, bbox_inches='tight')127 if out: 128 plt.savefig(out) 137 129 else: 138 130 plt.show() … … 147 139 parser.add_argument('-y', nargs='?', type=str, default="", help="Which field to use as the Y axis") 148 140 parser.add_argument('-x', nargs='?', type=str, default="", help="Which field to use as the X axis") 149 parser.add_argument('--logx', action='store_true', help="if set, makes the x-axis logscale")150 parser.add_argument('--logy', action='store_true', help="if set, makes the y-axis logscale")151 parser.add_argument('--MaxY', nargs='?', type=int, help="maximum value of the y-axis")152 141 153 142 options = parser.parse_args() … … 193 182 194 183 195 plot(data, wantx, wanty, options )184 plot(data, wantx, wanty, options.out) -
benchmark/process-mutilate.py
r74ec742 r29d8c02 14 14 parser = argparse.ArgumentParser(description='Python Script to convert output from mutilate to rmit like output') 15 15 parser.add_argument('--out', nargs='?', type=argparse.FileType('w'), default=sys.stdout) 16 parser.add_argument('--var', nargs='?', type=str, default='Target QPS')17 16 try: 18 17 options = parser.parse_args() … … 32 31 33 32 try: 34 latAvs = fields[1]35 33 lat50s = fields[6] 36 34 lat99s = fields[9] … … 39 37 40 38 try: 41 latAv = locale.atof(latAvs)42 39 lat50 = locale.atof(lat50s) 43 40 lat99 = locale.atof(lat99s) … … 45 42 raise Warning("Warning: \"{}\" \"{}\"! can't convert to float".format(lat50s, lat99s)) 46 43 47 return lat Av, lat50, lat9944 return lat50, lat99 48 45 49 46 def want0(line): … … 61 58 try: 62 59 if line.startswith("read"): 63 rlat Av, rlat50, rlat99 = precentile(line)60 rlat50, rlat99 = precentile(line) 64 61 65 62 elif line.startswith("update"): 66 ulat Av, ulat50, ulat99 = precentile(line)63 ulat50, ulat99 = precentile(line) 67 64 68 65 elif line.startswith("Total QPS"): … … 87 84 88 85 try: 89 out['Average Read Latency'] = rlatAv90 86 out['Median Read Latency'] = rlat50 91 87 out['Tail Read Latency'] = rlat99 … … 94 90 95 91 try: 96 out['Average Update Latency'] = ulatAv97 92 out['Median Update Latency'] = ulat50 98 93 out['Tail Update Latency'] = ulat99 … … 117 112 continue 118 113 119 d = { options.var: int(rate) }114 d = { 'Target QPS': int(rate) } 120 115 121 116 w = extract( f, d ) -
benchmark/readyQ/bench.go
r74ec742 r29d8c02 71 71 duration = 5 72 72 clock_mode = true 73 fmt.Printf("Running for %f seconds (default)\n", duration)73 fmt.Printf("Running for %f seconds\n", duration) 74 74 } 75 75 -
benchmark/readyQ/churn.cfa
r74ec742 r29d8c02 1 1 #include "rq_bench.hfa" 2 2 3 #include <locks.hfa>4 5 3 unsigned spot_cnt = 2; 6 semaphore * spots;4 bench_sem * volatile * spots; 7 5 8 6 thread BThrd { 9 7 unsigned long long count; 10 8 unsigned long long blocks; 11 b ool skip;9 bench_sem sem; 12 10 }; 13 11 … … 16 14 this.count = 0; 17 15 this.blocks = 0; 18 this.skip = false;19 16 } 20 17 … … 22 19 23 20 void main( BThrd & this ) with( this ) { 24 park();21 wait( sem ); 25 22 for() { 26 uint32_t r = prng(this); 27 semaphore & sem = spots[r % spot_cnt]; 28 if(!skip) V( sem ); 29 blocks += P( sem ); 30 skip = false; 31 23 uint32_t r = prng(); 24 bench_sem * next = __atomic_exchange_n(&spots[r % spot_cnt], &sem, __ATOMIC_SEQ_CST); 25 if(next) post( *next ); 26 blocks += wait( sem ); 32 27 count ++; 33 28 if( clock_mode && stop) break; … … 44 39 { 's', "spots", "Number of spots in the system", spot_cnt } 45 40 }; 46 BENCH_OPT_PARSE("cforall c hurnbenchmark");41 BENCH_OPT_PARSE("cforall cycle benchmark"); 47 42 48 43 { … … 54 49 spots = aalloc(spot_cnt); 55 50 for(i; spot_cnt) { 56 (spots[i]){ 0 };51 spots[i] = 0p; 57 52 } 58 53 … … 60 55 BThrd * threads[nthreads]; 61 56 for(i; nthreads ) { 62 BThrd & t = *(threads[i] = malloc()); 63 (t){}; 64 t.skip = i < spot_cnt; 57 threads[i] = malloc(); 58 (*threads[i]){}; 65 59 } 66 60 printf("Starting\n"); … … 70 64 71 65 for(i; nthreads) { 72 unpark( *threads[i]);66 post( threads[i]->sem ); 73 67 } 74 68 wait(start, is_tty); … … 78 72 printf("\nDone\n"); 79 73 80 for(i; spot_cnt) {81 for(10000) V( spots[i] );82 }83 84 74 for(i; nthreads) { 75 post( threads[i]->sem ); 85 76 BThrd & thrd = join( *threads[i] ); 86 77 global_counter += thrd.count; -
benchmark/readyQ/cycle.cpp
r74ec742 r29d8c02 46 46 } 47 47 for(unsigned i = 0; i < tthreads; i++) { 48 threads[i] = new Fibre(); 49 threads[i]->run( partner_main, &thddata[i] ); 48 threads[i] = new Fibre( reinterpret_cast<void (*)(void *)>(partner_main), &thddata[i] ); 50 49 } 51 50 printf("Starting\n"); -
benchmark/readyQ/rq_bench.hpp
r74ec742 r29d8c02 143 143 } 144 144 145 if(strcmp(arg, "Y") == 0) {146 value = true;147 return true;148 }149 150 if(strcmp(arg, "y") == 0) {151 value = true;152 return true;153 }154 155 145 if(strcmp(arg, "no") == 0) { 156 value = false;157 return true;158 }159 160 if(strcmp(arg, "N") == 0) {161 value = false;162 return true;163 }164 165 if(strcmp(arg, "n") == 0) {166 146 value = false; 167 147 return true; -
benchmark/readyQ/transfer.cfa
r74ec742 r29d8c02 14 14 15 15 bool exhaust = false; 16 volatile bool estop = false;17 18 16 19 17 thread$ * the_main; … … 37 35 static void waitgroup() { 38 36 Time start = timeHiRes(); 39 OUTER:for(i; nthreads) {37 for(i; nthreads) { 40 38 PRINT( sout | "Waiting for :" | i | "(" | threads[i]->idx | ")"; ) 41 39 while( threads[i]->idx != lead_idx ) { … … 44 42 print_stats_now( bench_cluster, CFA_STATS_READY_Q | CFA_STATS_IO ); 45 43 serr | "Programs has been blocked for more than 5 secs"; 46 estop = true; 47 unpark( the_main ); 48 break OUTER; 44 exit(1); 49 45 } 50 46 } … … 63 59 static void lead(MyThread & this) { 64 60 this.idx = ++lead_idx; 65 if(lead_idx > stop_count || estop) {61 if(lead_idx > stop_count) { 66 62 PRINT( sout | "Leader" | this.id | "done"; ) 67 63 unpark( the_main ); … … 104 100 wait( this ); 105 101 } 106 if(lead_idx > stop_count || estop) break;102 if(lead_idx > stop_count) break; 107 103 } 108 104 } … … 176 172 sout | "Number of processors : " | nprocs; 177 173 sout | "Number of threads : " | nthreads; 178 sout | "Total Operations(ops) : " | lead_idx - 1;174 sout | "Total Operations(ops) : " | stop_count; 179 175 sout | "Threads parking on wait : " | (exhaust ? "yes" : "no"); 180 176 sout | "Rechecking : " | rechecks; 181 sout | "ns per transfer : " | (end - start)`dms / lead_idx;182 177 183 178 -
benchmark/readyQ/transfer.cpp
r74ec742 r29d8c02 12 12 13 13 bool exhaust = false; 14 volatile bool estop = false;15 14 16 15 bench_sem the_main; … … 43 42 if( to_miliseconds(timeHiRes() - start) > 5'000 ) { 44 43 std::cerr << "Programs has been blocked for more than 5 secs" << std::endl; 45 estop = true; 46 the_main.post(); 47 goto END; 44 std::exit(1); 48 45 } 49 46 } 50 47 } 51 END:;52 48 PRINT( std::cout | "Waiting done"; ) 53 49 } … … 63 59 void lead() { 64 60 this->idx = ++lead_idx; 65 if(lead_idx > stop_count || estop) {61 if(lead_idx > stop_count) { 66 62 PRINT( std::cout << "Leader " << this->id << " done" << std::endl; ) 67 63 the_main.post(); … … 92 88 } 93 89 94 static void main( MyThread * arg) {95 MyThread & self = * arg;90 static void main(void * arg) { 91 MyThread & self = *reinterpret_cast<MyThread*>(arg); 96 92 self.park(); 97 93 … … 105 101 self.wait(); 106 102 } 107 if(lead_idx > stop_count || estop) break;103 if(lead_idx > stop_count) break; 108 104 } 109 105 } … … 148 144 for(size_t i = 0; i < nthreads; i++) { 149 145 threads[i] = new MyThread( i ); 150 handles[i] = new Fibre(); 151 handles[i]->run( MyThread::main, threads[i] ); 146 handles[i] = new Fibre( MyThread::main, threads[i] ); 152 147 } 153 148 … … 169 164 PRINT( std::cout << i << " joined" << std::endl; ) 170 165 rechecks += thrd.rechecks; 166 // delete( handles[i] ); 171 167 delete( threads[i] ); 172 168 } … … 180 176 std::cout << "Number of processors : " << nprocs << std::endl; 181 177 std::cout << "Number of threads : " << nthreads << std::endl; 182 std::cout << "Total Operations(ops) : " << (lead_idx - 1)<< std::endl;178 std::cout << "Total Operations(ops) : " << stop_count << std::endl; 183 179 std::cout << "Threads parking on wait : " << (exhaust ? "yes" : "no") << std::endl; 184 180 std::cout << "Rechecking : " << rechecks << std::endl; 185 std::cout << "ns per transfer : " << std::fixed << (((double)(end - start)) / (lead_idx)) << std::endl;186 181 187 182 -
benchmark/readyQ/transfer.go
r74ec742 r29d8c02 6 6 "math/rand" 7 7 "os" 8 "regexp"9 8 "runtime" 10 9 "sync/atomic" … … 17 16 id uint64 18 17 idx uint64 19 estop uint6420 18 seed uint64 21 19 } … … 36 34 37 35 func NewLeader(size uint64) (*LeaderInfo) { 38 this := &LeaderInfo{0, 0, 0,uint64(os.Getpid())}36 this := &LeaderInfo{0, 0, uint64(os.Getpid())} 39 37 40 38 r := rand.Intn(10) … … 53 51 } 54 52 55 func waitgroup( leader * LeaderInfo, idx uint64, threads [] MyThread, main_sem chan struct {}) {53 func waitgroup(idx uint64, threads [] MyThread) { 56 54 start := time.Now() 57 Outer:58 55 for i := 0; i < len(threads); i++ { 59 56 // fmt.Fprintf(os.Stderr, "Waiting for :%d (%d)\n", threads[i].id, atomic.LoadUint64(&threads[i].idx) ); … … 64 61 if delta.Seconds() > 5 { 65 62 fmt.Fprintf(os.Stderr, "Programs has been blocked for more than 5 secs") 66 atomic.StoreUint64(&leader.estop, 1); 67 main_sem <- (struct {}{}) 68 break Outer 63 os.Exit(1) 69 64 } 70 65 } … … 79 74 if i != me { 80 75 // debug!( "Leader waking {}", i); 81 defer func() {82 if err := recover(); err != nil {83 fmt.Fprintf(os.Stderr, "Panic occurred: %s\n", err)84 }85 }()86 76 threads[i].sem <- (struct {}{}) 87 77 } … … 94 84 atomic.StoreUint64(&leader.idx, nidx); 95 85 96 if nidx > stop_count || atomic.LoadUint64(&leader.estop) != 0{86 if nidx > stop_count { 97 87 // debug!( "Leader {} done", this.id); 98 88 main_sem <- (struct {}{}) … … 102 92 // debug!( "====================\nLeader no {} : {}", nidx, this.id); 103 93 104 waitgroup( leader, nidx, threads, main_sem);94 waitgroup(nidx, threads); 105 95 106 96 leader.next( uint64(len(threads)) ); … … 156 146 waitleader( exhaust, leader, &threads[me], &r ) 157 147 } 158 if atomic.LoadUint64(&leader.idx) > stop_count || atomic.LoadUint64(&leader.estop) != 0{ break; }148 if atomic.LoadUint64(&leader.idx) > stop_count { break; } 159 149 } 160 150 … … 165 155 func main() { 166 156 // Benchmark specific command line arguments 167 exhaustOpt := flag. String("e", "no", "Whether or not threads that have seen the new epoch should park instead of yielding.")157 exhaustOpt := flag.Bool("e", false, "Whether or not threads that have seen the new epoch should park instead of yielding.") 168 158 169 159 // General benchmark initialization and deinitialization 170 bench_init() 171 172 exhaustVal := *exhaustOpt; 173 174 var exhaust bool 175 re_yes := regexp.MustCompile("[Yy]|[Yy][Ee][Ss]") 176 re_no := regexp.MustCompile("[Nn]|[Nn][Oo]") 177 if re_yes.Match([]byte(exhaustVal)) { 178 exhaust = true 179 } else if re_no.Match([]byte(exhaustVal)) { 180 exhaust = false 181 } else { 182 fmt.Fprintf(os.Stderr, "Unrecognized exhaust(-e) option '%s'\n", exhaustVal) 183 os.Exit(1) 184 } 185 160 defer bench_init()() 161 162 exhaust := *exhaustOpt; 186 163 if clock_mode { 187 fmt.Fprintf(os.Stderr, "Programs does not support fixed duration mode \n")164 fmt.Fprintf(os.Stderr, "Programs does not support fixed duration mode") 188 165 os.Exit(1) 189 166 } … … 238 215 ws = "no" 239 216 } 240 p.Printf("Duration (ms) : % d\n", delta.Milliseconds() )217 p.Printf("Duration (ms) : %f\n", delta.Milliseconds() ) 241 218 p.Printf("Number of processors : %d\n", nprocs ) 242 219 p.Printf("Number of threads : %d\n", nthreads ) 243 p.Printf("Total Operations(ops) : %15d\n", (leader.idx - 1))220 p.Printf("Total Operations(ops) : %15d\n", stop_count ) 244 221 p.Printf("Threads parking on wait : %s\n", ws) 245 222 p.Printf("Rechecking : %d\n", rechecks ) 246 p.Printf("ns per transfer : %f\n", float64(delta.Nanoseconds()) / float64(leader.idx) ) 247 } 223 } -
benchmark/readyQ/transfer.rs
r74ec742 r29d8c02 6 6 use std::hint; 7 7 use std::sync::Arc; 8 use std::sync::atomic::{Atomic Bool, AtomicUsize, Ordering};8 use std::sync::atomic::{AtomicUsize, Ordering}; 9 9 use std::time::{Instant,Duration}; 10 10 … … 44 44 match val { 45 45 "yes" => true, 46 "Y" => true,47 "y" => true,48 46 "no" => false, 49 "N" => false,50 "n" => false,51 47 "maybe" | "I don't know" | "Can you repeat the question?" => { 52 48 eprintln!("Lines for 'Malcolm in the Middle' are not acceptable values of parameter 'exhaust'"); … … 68 64 id: AtomicUsize, 69 65 idx: AtomicUsize, 70 estop: AtomicBool,71 66 seed: u128, 72 67 } … … 77 72 id: AtomicUsize::new(nthreads), 78 73 idx: AtomicUsize::new(0), 79 estop: AtomicBool::new(false),80 74 seed: process::id() as u128 81 75 }; … … 106 100 } 107 101 108 fn waitgroup( leader: &LeaderInfo, idx: usize, threads: &Vec<Arc<MyThread>>, main_sem: &sync::Semaphore) {102 fn waitgroup(idx: usize, threads: &Vec<Arc<MyThread>>) { 109 103 let start = Instant::now(); 110 'outer:for t in threads {104 for t in threads { 111 105 debug!( "Waiting for :{} ({})", t.id, t.idx.load(Ordering::Relaxed) ); 112 106 while t.idx.load(Ordering::Relaxed) != idx { … … 114 108 if start.elapsed() > Duration::from_secs(5) { 115 109 eprintln!("Programs has been blocked for more than 5 secs"); 116 leader.estop.store(true, Ordering::Relaxed); 117 main_sem.add_permits(1); 118 break 'outer; 110 std::process::exit(1); 119 111 } 120 112 } … … 139 131 leader.idx.store(nidx, Ordering::Relaxed); 140 132 141 if nidx as u64 > exp.stop_count || leader.estop.load(Ordering::Relaxed){133 if nidx as u64 > exp.stop_count { 142 134 debug!( "Leader {} done", this.id); 143 135 main_sem.add_permits(1); … … 147 139 debug!( "====================\nLeader no {} : {}", nidx, this.id); 148 140 149 waitgroup( leader, nidx, threads, main_sem);141 waitgroup(nidx, threads); 150 142 151 143 leader.next( threads.len() ); … … 200 192 wait( exhaust, &leader, &threads[me], &mut rechecks ).await; 201 193 } 202 if leader.idx.load(Ordering::Relaxed) as u64 > exp.stop_count || leader.estop.load(Ordering::Relaxed){ break; }194 if leader.idx.load(Ordering::Relaxed) as u64 > exp.stop_count { break; } 203 195 } 204 196 … … 281 273 println!("Number of processors : {}", (nprocs).to_formatted_string(&Locale::en)); 282 274 println!("Number of threads : {}", (nthreads).to_formatted_string(&Locale::en)); 283 println!("Total Operations(ops) : {:>15}", ( leader.idx.load(Ordering::Relaxed) - 1).to_formatted_string(&Locale::en));275 println!("Total Operations(ops) : {:>15}", (exp.stop_count).to_formatted_string(&Locale::en)); 284 276 println!("Threads parking on wait : {}", if exhaust { "yes" } else { "no" }); 285 277 println!("Rechecking : {}", rechecks ); 286 println!("ns per transfer : {}", ((duration.as_nanos() as f64) / leader.idx.load(Ordering::Relaxed) as f64)); 287 288 } 278 } -
benchmark/readyQ/yield.cfa
r74ec742 r29d8c02 1 #include "rq_bench.hfa" 1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <limits.h> 5 6 extern "C" { 7 #include <locale.h> 8 #include <getopt.h> 9 } 10 11 #include <unistd.h> 12 13 #include <clock.hfa> 14 #include <time.hfa> 15 #include <stats.hfa> 16 17 #include "../benchcltr.hfa" 18 19 extern bool traceHeapOn(); 20 21 22 volatile bool run = false; 23 volatile unsigned long long global_counter; 2 24 3 25 thread __attribute__((aligned(128))) Yielder { 4 unsigned long long count ;26 unsigned long long counter; 5 27 }; 6 28 void ?{}( Yielder & this ) { 7 ((thread&)this){ "Yielder Thread", bench_cluster };8 this.count = 0;29 this.counter = 0; 30 ((thread&)this){ "Yielder Thread", *the_benchmark_cluster }; 9 31 } 10 32 11 33 void main( Yielder & this ) { 12 34 park(); 13 for() { 35 /* paranoid */ assert( true == __atomic_load_n(&run, __ATOMIC_RELAXED) ); 36 37 while(__atomic_load_n(&run, __ATOMIC_RELAXED)) { 14 38 yield(); 15 this.count++; 16 if( clock_mode && stop) break; 17 if(!clock_mode && this.count >= stop_count) break; 39 this.counter++; 18 40 } 19 20 __atomic_fetch_add(&threads_left, -1, __ATOMIC_SEQ_CST); 41 __atomic_fetch_add(&global_counter, this.counter, __ATOMIC_SEQ_CST); 21 42 } 22 43 23 44 int main(int argc, char * argv[]) { 45 unsigned num_io = 1; 46 io_context_params params; 47 24 48 cfa_option opt[] = { 25 BENCH_OPT 49 BENCH_OPT_CFA 26 50 }; 27 BENCH_OPT_PARSE("cforall yield benchmark"); 51 int opt_cnt = sizeof(opt) / sizeof(cfa_option); 52 53 char **left; 54 parse_args( argc, argv, opt, opt_cnt, "[OPTIONS]...\ncforall yield benchmark", left ); 28 55 29 56 { 30 unsigned long long global_counter = 0;57 printf("Running %d threads on %d processors for %f seconds\n", nthreads, nprocs, duration); 31 58 32 59 Time start, end; 33 BenchCluster bc = { nprocs};60 BenchCluster cl = { num_io, params, CFA_STATS_READY_Q }; 34 61 { 35 threads_left = nthreads; 36 Yielder threads[nthreads]; 37 printf("Starting\n"); 62 BenchProc procs[nprocs]; 63 { 64 Yielder threads[nthreads]; 65 printf("Starting\n"); 38 66 39 bool is_tty = isatty(STDOUT_FILENO); 40 start = timeHiRes(); 67 bool is_tty = isatty(STDOUT_FILENO); 68 start = timeHiRes(); 69 run = true; 41 70 42 for(i; nthreads) {43 unpark( threads[i] );44 }45 wait(start, is_tty);71 for(i; nthreads) { 72 unpark( threads[i] ); 73 } 74 wait(duration, start, end, is_tty); 46 75 47 stop = true; 48 end = timeHiRes(); 49 printf("\nDone\n"); 50 51 for(i; nthreads) { 52 Yielder & y = join( threads[i] ); 53 global_counter += y.count; 76 run = false; 77 end = timeHiRes(); 78 printf("\nDone\n"); 54 79 } 55 80 } 56 81 57 printf("Duration (ms) : %'ld\n", (end - start)`dms); 58 printf("Number of processors : %'d\n", nprocs); 59 printf("Number of threads : %'d\n", nthreads); 60 printf("Total Operations(ops): %'15llu\n", global_counter); 61 printf("Ops per second : %'18.2lf\n", ((double)global_counter) / (end - start)`s); 62 printf("ns per ops : %'18.2lf\n", (end - start)`dns / global_counter); 63 printf("Ops per threads : %'15llu\n", global_counter / nthreads); 64 printf("Ops per procs : %'15llu\n", global_counter / nprocs); 65 printf("Ops/sec/procs : %'18.2lf\n", (((double)global_counter) / nprocs) / (end - start)`s); 66 printf("ns per ops/procs : %'18.2lf\n", (end - start)`dns / (global_counter / nprocs)); 82 printf("Duration (ms) : %'ld\n", (end - start)`dms); 83 printf("Number of processors: %'d\n", nprocs); 84 printf("Number of threads : %'d\n", nthreads); 85 printf("Total yields : %'15llu\n", global_counter); 86 printf("Yields per second : %'18.2lf\n", ((double)global_counter) / (end - start)`s); 87 printf("ns per yields : %'18.2lf\n", ((double)(end - start)`ns) / global_counter); 88 printf("Yields per procs : %'15llu\n", global_counter / nprocs); 89 printf("Yields/sec/procs : %'18.2lf\n", (((double)global_counter) / nprocs) / (end - start)`s); 90 printf("ns per yields/procs : %'18.2lf\n", ((double)(end - start)`ns) / (global_counter / nprocs)); 67 91 fflush(stdout); 68 92 } -
benchmark/readyQ/yield.cpp
r74ec742 r29d8c02 1 #include "rq_bench.hpp" 2 #include <libfibre/fibre.h> 1 #include <cassert> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <climits> 6 7 extern "C" { 8 #include <locale.h> 9 #include <getopt.h> 10 } 11 12 #include <unistd.h> 13 14 #include <chrono> 15 16 using Clock = std::chrono::high_resolution_clock; 17 using duration_t = std::chrono::duration<double>; 18 using std::chrono::nanoseconds; 19 20 21 template<typename Ratio, typename T> 22 T duration_cast(T seconds) { 23 return std::chrono::duration_cast<std::chrono::duration<T, Ratio>>(std::chrono::duration<T>(seconds)).count(); 24 } 3 25 4 26 volatile bool run = false; 5 27 volatile unsigned long long global_counter; 6 28 29 #include "libfibre/fibre.h" 7 30 8 void fibre_main() { 9 fibre_park(); 10 unsigned long long count = 0; 11 for(;;) { 12 Fibre::yield(); 13 count++; 14 if( clock_mode && stop) break; 15 if(!clock_mode && count >= stop_count) break; 31 FredBarrier * barrier; 32 struct __attribute__((aligned(128))) counter_t { 33 int value = 0; 34 }; 35 36 void fibre_main( counter_t * counter ) { 37 barrier->wait(); 38 // /* paranoid */ assert( true == __atomic_load_n(&run, __ATOMIC_RELAXED) ); 39 40 while(__atomic_load_n(&run, __ATOMIC_RELAXED)) { 41 Fibre::forceYield(); 42 // fibre_yield(); 43 counter->value++; 16 44 } 17 18 __atomic_fetch_add(&global_counter, count, __ATOMIC_SEQ_CST); 19 __atomic_fetch_add(&threads_left, -1, __ATOMIC_SEQ_CST); 45 __atomic_fetch_add(&global_counter, counter->value, __ATOMIC_SEQ_CST); 20 46 } 21 47 22 48 int main(int argc, char * argv[]) { 23 option_t opt[] = { 24 BENCH_OPT 25 }; 26 BENCH_OPT_PARSE("libfibre yield benchmark"); 49 double duration = 5; 50 int nprocs = 1; 51 int nthreads = 1; 52 53 std::cout.imbue(std::locale("")); 54 setlocale(LC_ALL, ""); 55 56 for(;;) { 57 static struct option options[] = { 58 {"duration", required_argument, 0, 'd'}, 59 {"nprocs", required_argument, 0, 'p'}, 60 {"nthreads", required_argument, 0, 't'}, 61 {0, 0, 0, 0} 62 }; 63 64 int idx = 0; 65 int opt = getopt_long(argc, argv, "d:p:t:", options, &idx); 66 67 const char * arg = optarg ? optarg : ""; 68 char * end; 69 switch(opt) { 70 case -1: 71 goto run; 72 // Numeric Arguments 73 case 'd': 74 duration = strtod(arg, &end); 75 if(*end != '\0') { 76 fprintf(stderr, "Duration must be a valid double, was %s\n", arg); 77 goto usage; 78 } 79 break; 80 case 't': 81 nthreads = strtoul(arg, &end, 10); 82 if(*end != '\0' || nthreads < 1) { 83 fprintf(stderr, "Number of threads must be a positive integer, was %s\n", arg); 84 goto usage; 85 } 86 break; 87 case 'p': 88 nprocs = strtoul(arg, &end, 10); 89 if(*end != '\0' || nprocs < 1) { 90 fprintf(stderr, "Number of processors must be a positive integer, was %s\n", arg); 91 goto usage; 92 } 93 break; 94 // Other cases 95 default: /* ? */ 96 fprintf( stderr, "Unkown option '%c'\n", opt); 97 usage: 98 fprintf( stderr, "Usage: %s [options]\n", argv[0]); 99 fprintf( stderr, "\n" ); 100 fprintf( stderr, " -d, --duration=DURATION Duration of the experiment, in seconds\n" ); 101 fprintf( stderr, " -t, --nthreads=NTHREADS Number of kernel threads\n" ); 102 fprintf( stderr, " -q, --nqueues=NQUEUES Number of queues per threads\n" ); 103 exit(1); 104 } 105 } 106 run: 27 107 28 108 { 29 109 printf("Running %d threads on %d processors for %lf seconds\n", nthreads, nprocs, duration); 30 110 31 FibreInit( 1, nprocs);32 uint64_t start, end;111 FibreInit(); 112 barrier = new FredBarrier(nthreads + 1); 33 113 { 34 threads_left = nthreads; 35 Fibre * threads[nthreads]; 36 for(unsigned i = 0; i < nthreads; i++) { 37 threads[i] = new Fibre(); 38 threads[i]->run(fibre_main); 39 } 40 printf("Starting\n"); 41 bool is_tty = isatty(STDOUT_FILENO); 42 start = timeHiRes(); 114 Context::CurrCluster().addWorkers(nprocs); 115 { 116 counter_t counters[nthreads]; 117 Fibre threads[nthreads]; 118 for(int i = 0; i < nthreads; i++) { 119 threads[i].run(fibre_main, &counters[i]); 120 } 121 printf("Starting\n"); 122 bool is_tty = isatty(STDOUT_FILENO); 123 auto before = Clock::now(); 124 run = true; 43 125 44 for(unsigned i = 0; i < nthreads; i++ ) { 45 fibre_unpark( threads[i] ); 46 } 47 wait<Fibre>(start, is_tty); 126 barrier->wait(); 127 for(;;) { 128 usleep(500'000); 129 auto now = Clock::now(); 130 duration_t durr = now - before; 131 if( durr.count() > duration ) { 132 break; 133 } 134 if(is_tty) { 135 std::cout << "\r" << std::setprecision(4) << durr.count(); 136 std::cout.flush(); 137 } 138 } 48 139 49 stop = true; 50 end = timeHiRes(); 51 for(unsigned i = 0; i < nthreads; i++ ) { 52 fibre_join( threads[i], nullptr ); 140 auto after = Clock::now(); 141 duration_t durr = after - before; 142 duration = durr.count(); 143 run = false; 144 printf("\nDone\n"); 145 for(auto & thread : threads) { 146 thread.join(); 147 } 148 149 // for(const auto & counter : counters) { 150 // std::cout << counter.value << std::endl; 151 // } 53 152 } 54 153 } 55 154 56 printf("Duration (ms) : %'ld\n", to_miliseconds(end - start));57 printf("Number of processors : %'d\n", nprocs);58 printf("Number of threads : %'d\n", nthreads); 59 printf(" Total Operations(ops): %'15llu\n", global_counter);60 printf(" Ops per second : %'18.2lf\n", ((double)global_counter) / to_fseconds(end - start));61 printf(" ns per ops : %'18.2lf\n", ((double)(end - start)) / global_counter);62 printf(" Ops per threads : %'15llu\n", global_counter / nthreads);63 printf(" Ops per procs : %'15llu\n", global_counter / nprocs);64 printf(" Ops/sec/procs : %'18.2lf\n", (((double)global_counter) / nprocs) / to_fseconds(end - start));65 printf("ns per ops/procs : %'18.2lf\n", ((double)(end - start)) / (global_counter / nprocs));66 fflush(stdout); 155 auto dur_nano = duration_cast<std::nano>(duration); 156 auto dur_dms = duration_cast<std::milli>(duration); 157 158 printf("Duration (ms) : %'.2lf\n", dur_dms ); 159 printf("Total yields : %'15llu\n", global_counter ); 160 printf("Yields per procs : %'15llu\n", global_counter / nprocs ); 161 printf("Yields per second : %'18.2lf\n", ((double)global_counter) / duration ); 162 printf("Yields/sec/procs : %'18.2lf\n", (((double)global_counter) / nprocs) / duration ); 163 printf("ns per yields : %'18.2lf\n", dur_nano / global_counter ); 164 printf("ns per yields/procs : %'18.2lf\n", dur_nano / (global_counter / nprocs) ); 165 67 166 } 68 167 } -
benchmark/readyQ/yield.rs
r74ec742 r29d8c02 90 90 }); 91 91 92 println!("Duration (ms) : {}", (duration.as_millis()).to_formatted_string(&Locale::en));93 println!("Number of processors : {}", (nprocs).to_formatted_string(&Locale::en));94 println!("Number of threads : {}", (nthreads).to_formatted_string(&Locale::en));95 println!("Total Operations(ops): {:>15}", (global_counter).to_formatted_string(&Locale::en));96 println!(" Ops per second: {:>15}", (((global_counter as f64) / duration.as_secs() as f64) as u64).to_formatted_string(&Locale::en));97 println!("ns per ops: {:>15}", ((duration.as_nanos() as f64 / global_counter as f64) as u64).to_formatted_string(&Locale::en));98 println!(" Ops per threads: {:>15}", (global_counter / nthreads as u64).to_formatted_string(&Locale::en));99 println!(" Ops per procs: {:>15}", (global_counter / nprocs as u64).to_formatted_string(&Locale::en));100 println!(" Ops/sec/procs: {:>15}", ((((global_counter as f64) / nprocs as f64) / duration.as_secs() as f64) as u64).to_formatted_string(&Locale::en));101 println!("ns per ops/procs: {:>15}", ((duration.as_nanos() as f64 / (global_counter as f64 / nprocs as f64)) as u64).to_formatted_string(&Locale::en));92 println!("Duration (ms) : {}", (duration.as_millis()).to_formatted_string(&Locale::en)); 93 println!("Number of processors: {}", (nprocs).to_formatted_string(&Locale::en)); 94 println!("Number of threads : {}", (nthreads).to_formatted_string(&Locale::en)); 95 println!("Total yields : {:>15}", (global_counter).to_formatted_string(&Locale::en)); 96 println!("Yields per second : {:>15}", (((global_counter as f64) / duration.as_secs() as f64) as u64).to_formatted_string(&Locale::en)); 97 println!("ns per yields : {:>15}", ((duration.as_nanos() as f64 / global_counter as f64) as u64).to_formatted_string(&Locale::en)); 98 println!("Yields per threads : {:>15}", (global_counter / nthreads as u64).to_formatted_string(&Locale::en)); 99 println!("Yields per procs : {:>15}", (global_counter / nprocs as u64).to_formatted_string(&Locale::en)); 100 println!("Yields/sec/procs : {:>15}", ((((global_counter as f64) / nprocs as f64) / duration.as_secs() as f64) as u64).to_formatted_string(&Locale::en)); 101 println!("ns per yields/procs : {:>15}", ((duration.as_nanos() as f64 / (global_counter as f64 / nprocs as f64)) as u64).to_formatted_string(&Locale::en)); 102 102 } -
benchmark/rmit.py
r74ec742 r29d8c02 46 46 pass 47 47 48 if values.startswith('\\'): 49 return key, values[1:].split(',') 50 elif re.search("^[0-9-,]+$", values): 48 if re.search("^[0-9-,]+$", values): 51 49 values = parse_range(values) 52 50 return key, [v for v in values] … … 65 63 return eval(fmt) 66 64 67 # Evaluate all the options68 # options can be of the for key = val or key = some_math(other_key)69 # produce a list of all the options to replace some_math(other_key) with actual value70 65 def eval_options(opts): 71 # Find all the options with dependencies72 66 dependents = [d for d in opts.values() if type(d) is DependentOpt] 73 74 # we need to find all the straglers75 67 processed = [] 76 77 # extract all the necessary inputs 78 input_keys = {} 68 nopts = [] 79 69 for d in dependents: 80 # Mark the dependent as seen81 70 processed.append(d.key) 82 83 # process each of the dependencies 71 lists = [] 84 72 for dvar in d.vars: 85 # Check that it depends on something that exists86 73 if not dvar in opts.keys(): 87 74 print('ERROR: extra pattern option {}:{} uses unknown key {}'.format(d.key,d.value,dvar), file=sys.stderr) 88 75 sys.exit(1) 89 76 90 # Check that it's not nested 91 if type(dvar) is DependentOpt: 92 print('ERROR: dependent options cannot be nested {}:{} uses key {}'.format(d.key,d.value,dvar), file=sys.stderr) 93 sys.exit(1) 94 95 # Add the values to the input keys 96 if dvar not in input_keys: 97 input_keys[dvar] = opts[dvar] 98 else : 99 if input_keys[dvar] != opts[dvar]: 100 print('INTERNAL ERROR: repeat input do not match {}:{} vs {}'.format(dvar,opts[dvar],input_keys[dvar]), file=sys.stderr) 101 sys.exit(1) 102 103 # Mark the input as seen 77 lists.append([(dvar, o) for o in opts[dvar]]) 104 78 processed.append(dvar) 105 79 106 # add in all the straglers they should cause too many problems 107 for k, v in opts.items(): 108 if type(v) is DependentOpt: 109 continue 110 111 if k in processed: 112 # consistency check 113 if k not in input_keys: 114 print('INTERNAL ERROR: key \'{}\' marked as processed but not in input_keys'.format(k), file=sys.stderr) 115 sys.exit(1) 116 continue 117 118 # consistency check 119 if k in input_keys: 120 print('INTERNAL ERROR: key \'{}\' in input_keys but not marked as processed'.format(k), file=sys.stderr) 121 sys.exit(1) 122 123 # add the straggler 124 input_keys[k] = v 125 126 # flatten the dict into a list of pairs so it's easier to work with 127 input_list = [] 128 for k, v in input_keys.items(): 129 input_list.append([(k, o) for o in v]) 130 131 # evaluate all the dependents 132 # they are not allowed to produce new values so it's a one-to-one mapping from here 133 evaluated = [] 134 for inputs in list(itertools.product(*input_list)): 135 this_eval = list(inputs) 136 for d in dependents: 137 this_eval.append((d.key, eval_one(d.value, inputs))) 138 139 evaluated.append(this_eval) 140 141 # reformat everything to a list of arguments 142 formated = [] 143 for o in evaluated: 144 inner = [] 145 for k,v in o: 146 inner.append("-{}".format(k)) 147 inner.append("{}".format(v)) 148 149 # print(inner) 150 formated.append(inner) 151 152 return formated 80 kopt = [] 81 for vals in list(itertools.product(*lists)): 82 res = ['-{}'.format(d.key), "{}".format(eval_one(d.value, vals))] 83 for k, v in vals: 84 res.extend(['-{}'.format(k), "{}".format(v)]) 85 kopt.append(res) 86 nopts.append(kopt) 87 88 89 for k, vals in opts.items(): 90 if k not in processed: 91 kopt = [] 92 for v in vals: 93 kopt.append(['-{}'.format(k), "{}".format(v)]) 94 nopts.append(kopt) 95 96 return nopts 153 97 154 98 # returns the first option with key 'opt' … … 178 122 known_hosts = { 179 123 "jax": { 180 range( 1, 2 5) : "48-71",181 range( 25, 4 9) : "48-71,144-167",182 range( 49, 9 7) : "48-95,144-191",183 range( 97, 14 5) : "24-95,120-191",184 range(145, 19 3) : "0-95,96-191",124 range( 1, 24) : "48-71", 125 range( 25, 48) : "48-71,144-167", 126 range( 49, 96) : "48-95,144-191", 127 range( 97, 144) : "24-95,120-191", 128 range(145, 192) : "0-95,96-191", 185 129 }, 186 130 } … … 240 184 241 185 except: 186 print('ERROR: invalid arguments', file=sys.stderr) 187 parser.print_help(sys.stderr) 242 188 sys.exit(1) 243 189 … … 269 215 # Figure out all the combinations to run 270 216 actions = [] 271 for p in itertools.product(range(options.trials), commands, opts):217 for p in itertools.product(range(options.trials), commands, *opts): 272 218 act = [p[1]] 273 219 for o in p[2:]: … … 335 281 336 282 if options.file != sys.stdout: 337 print("Done ")283 print("Done"); ") -
doc/theses/thierry_delisle_PhD/thesis/Makefile
r74ec742 r29d8c02 37 37 emptytree \ 38 38 fairness \ 39 idle \40 idle1 \41 idle2 \42 idle_state \43 39 io_uring \ 44 40 pivot_ring \ … … 46 42 cycle \ 47 43 result.cycle.jax.ops \ 48 result.yield.jax.ops \49 result.churn.jax.ops \50 result.cycle.jax.ns \51 result.yield.jax.ns \52 result.churn.jax.ns \53 result.cycle.low.jax.ops \54 result.yield.low.jax.ops \55 result.churn.low.jax.ops \56 result.cycle.low.jax.ns \57 result.yield.low.jax.ns \58 result.churn.low.jax.ns \59 result.memcd.updt.qps \60 result.memcd.updt.lat \61 result.memcd.rate.qps \62 result.memcd.rate.99th \63 44 } 64 45 … … 135 116 python3 $< $@ 136 117 137 cycle_jax_ops_FLAGS = --MaxY=120000000 138 cycle_low_jax_ops_FLAGS = --MaxY=120000000 139 cycle_jax_ns_FLAGS = --MaxY=2000 140 cycle_low_jax_ns_FLAGS = --MaxY=2000 118 build/result.%.ns.svg : data/% | ${Build} 119 ../../../../benchmark/plot.py -f $< -o $@ -y "ns per ops" 141 120 142 yield_jax_ops_FLAGS = --MaxY=150000000 143 yield_low_jax_ops_FLAGS = --MaxY=150000000 144 yield_jax_ns_FLAGS = --MaxY=1500 145 yield_low_jax_ns_FLAGS = --MaxY=1500 146 147 build/result.%.ns.svg : data/% Makefile | ${Build} 148 ../../../../benchmark/plot.py -f $< -o $@ -y "ns per ops/procs" $($(subst .,_,$*)_ns_FLAGS) 149 150 build/result.%.ops.svg : data/% Makefile | ${Build} 151 ../../../../benchmark/plot.py -f $< -o $@ -y "Ops per second" $($(subst .,_,$*)_ops_FLAGS) 152 153 build/result.memcd.updt.qps.svg : data/memcd.updt Makefile | ${Build} 154 ../../../../benchmark/plot.py -f $< -o $@ -y "Actual QPS" -x "Update Ratio" 155 156 build/result.memcd.updt.lat.svg : data/memcd.updt Makefile | ${Build} 157 ../../../../benchmark/plot.py -f $< -o $@ -y "Average Read Latency" -x "Update Ratio" 158 159 build/result.memcd.rate.qps.svg : data/memcd.rate Makefile | ${Build} 160 ../../../../benchmark/plot.py -f $< -o $@ -y "Actual QPS" -x "Target QPS" 161 162 build/result.memcd.rate.99th.svg : data/memcd.rate Makefile | ${Build} 163 ../../../../benchmark/plot.py -f $< -o $@ -y "Tail Read Latency" -x "Target QPS" 121 build/result.%.ops.svg : data/% | ${Build} 122 ../../../../benchmark/plot.py -f $< -o $@ -y "Ops per second" 164 123 165 124 ## pstex with inverted colors -
doc/theses/thierry_delisle_PhD/thesis/data/cycle.jax
r74ec742 r29d8c02 1 [["rdq-cycle-go", "./rdq-cycle-go - p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10001.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 1138076440.0, "Ops per second": 113792094.48, "ns per ops": 8.79, "Ops per threads": 94839.0, "Ops per procs": 47419851.0, "Ops/sec/procs": 4741337.27, "ns per ops/procs": 210.91}],["rdq-cycle-go", "./rdq-cycle-go -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 200285.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 17638575791.0, "Ops per second": 88067238.72, "ns per ops": 11.35, "Ops per threads": 2204821.0, "Ops per procs": 1102410986.0, "Ops/sec/procs": 5504202.42, "ns per ops/procs": 181.68}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10100.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 54856916.0, "Ops per second": 5485691.0, "ns per ops": 184.0, "Ops per threads": 109713.0, "Ops per procs": 54856916.0, "Ops/sec/procs": 5485691.0, "ns per ops/procs": 184.0}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10025.449006, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 558836360.0, "Total blocks": 558836360.0, "Ops per second": 55741778.71, "ns per ops": 17.94, "Ops per threads": 69854.0, "Ops per procs": 34927272.0, "Ops/sec/procs": 3483861.17, "ns per ops/procs": 287.04}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10038.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 58647049.0, "Total blocks": 58647049.0, "Ops per second": 5842287.68, "ns per ops": 171.17, "Ops per threads": 7330.0, "Ops per procs": 3665440.0, "Ops/sec/procs": 365142.98, "ns per ops/procs": 2738.65}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10003.489711, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 728096996.0, "Total blocks": 728096996.0, "Ops per second": 72784299.98, "ns per ops": 13.74, "Ops per threads": 60674.0, "Ops per procs": 30337374.0, "Ops/sec/procs": 3032679.17, "ns per ops/procs": 329.74}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10021.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 63157049.0, "Total blocks": 63157049.0, "Ops per second": 6302255.13, "ns per ops": 158.67, "Ops per threads": 15789.0, "Ops per procs": 7894631.0, "Ops/sec/procs": 787781.89, "ns per ops/procs": 1269.39}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10009.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 62412200.0, "Total blocks": 62411700.0, "Ops per second": 6235572.31, "ns per ops": 160.37, "Ops per threads": 124824.0, "Ops per procs": 62412200.0, "Ops/sec/procs": 6235572.31, "ns per ops/procs": 160.37}],["rdq-cycle-go", "./rdq-cycle-go -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10000.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 464608617.0, "Ops per second": 46457191.42, "ns per ops": 21.53, "Ops per threads": 116152.0, "Ops per procs": 58076077.0, "Ops/sec/procs": 5807148.93, "ns per ops/procs": 172.2}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10099.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 391521066.0, "Ops per second": 39152106.0, "ns per ops": 25.0, "Ops per threads": 97880.0, "Ops per procs": 48940133.0, "Ops/sec/procs": 4894013.0, "ns per ops/procs": 206.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10099.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 963549550.0, "Ops per second": 96354955.0, "ns per ops": 10.0, "Ops per threads": 80295.0, "Ops per procs": 40147897.0, "Ops/sec/procs": 4014789.0, "ns per ops/procs": 251.0}],["rdq-cycle-go", "./rdq-cycle-go -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10001.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 867718190.0, "Ops per second": 86761170.55, "ns per ops": 11.53, "Ops per threads": 108464.0, "Ops per procs": 54232386.0, "Ops/sec/procs": 5422573.16, "ns per ops/procs": 184.41}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10100.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 962016289.0, "Ops per second": 96201628.0, "ns per ops": 10.0, "Ops per threads": 80168.0, "Ops per procs": 40084012.0, "Ops/sec/procs": 4008401.0, "ns per ops/procs": 251.0}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10016.837824, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 54738237.0, "Total blocks": 54737741.0, "Ops per second": 5464622.46, "ns per ops": 183.0, "Ops per threads": 109476.0, "Ops per procs": 54738237.0, "Ops/sec/procs": 5464622.46, "ns per ops/procs": 183.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10099.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 731309408.0, "Ops per second": 73130940.0, "ns per ops": 13.0, "Ops per threads": 91413.0, "Ops per procs": 45706838.0, "Ops/sec/procs": 4570683.0, "ns per ops/procs": 220.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10100.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 739772688.0, "Ops per second": 73977268.0, "ns per ops": 13.0, "Ops per threads": 92471.0, "Ops per procs": 46235793.0, "Ops/sec/procs": 4623579.0, "ns per ops/procs": 218.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10100.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 391449785.0, "Ops per second": 39144978.0, "ns per ops": 25.0, "Ops per threads": 97862.0, "Ops per procs": 48931223.0, "Ops/sec/procs": 4893122.0, "ns per ops/procs": 206.0}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10048.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 57239183.0, "Total blocks": 57239183.0, "Ops per second": 5696211.13, "ns per ops": 175.56, "Ops per threads": 4769.0, "Ops per procs": 2384965.0, "Ops/sec/procs": 237342.13, "ns per ops/procs": 4213.33}],["rdq-cycle-go", "./rdq-cycle-go -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10000.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55248375.0, "Ops per second": 5524562.87, "ns per ops": 181.01, "Ops per threads": 110496.0, "Ops per procs": 55248375.0, "Ops/sec/procs": 5524562.87, "ns per ops/procs": 181.01}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10021.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 61553053.0, "Total blocks": 61553053.0, "Ops per second": 6142186.88, "ns per ops": 162.81, "Ops per threads": 15388.0, "Ops per procs": 7694131.0, "Ops/sec/procs": 767773.36, "ns per ops/procs": 1302.47}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10008.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 62811642.0, "Total blocks": 62811142.0, "Ops per second": 6275517.47, "ns per ops": 159.35, "Ops per threads": 125623.0, "Ops per procs": 62811642.0, "Ops/sec/procs": 6275517.47, "ns per ops/procs": 159.35}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10018.820873, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 260866706.0, "Total blocks": 260862710.0, "Ops per second": 26037665.44, "ns per ops": 38.41, "Ops per threads": 65216.0, "Ops per procs": 32608338.0, "Ops/sec/procs": 3254708.18, "ns per ops/procs": 307.25}],["rdq-cycle-go", "./rdq-cycle-go -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10000.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 874581175.0, "Ops per second": 87449851.2, "ns per ops": 11.44, "Ops per threads": 109322.0, "Ops per procs": 54661323.0, "Ops/sec/procs": 5465615.7, "ns per ops/procs": 182.96}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10099.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55228782.0, "Ops per second": 5522878.0, "ns per ops": 182.0, "Ops per threads": 110457.0, "Ops per procs": 55228782.0, "Ops/sec/procs": 5522878.0, "ns per ops/procs": 182.0}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10009.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 62564955.0, "Total blocks": 62564455.0, "Ops per second": 6250797.96, "ns per ops": 159.98, "Ops per threads": 125129.0, "Ops per procs": 62564955.0, "Ops/sec/procs": 6250797.96, "ns per ops/procs": 159.98}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10100.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 738848909.0, "Ops per second": 73884890.0, "ns per ops": 13.0, "Ops per threads": 92356.0, "Ops per procs": 46178056.0, "Ops/sec/procs": 4617805.0, "ns per ops/procs": 218.0}],["rdq-cycle-go", "./rdq-cycle-go -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10001.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 1131221613.0, "Ops per second": 113108175.94, "ns per ops": 8.84, "Ops per threads": 94268.0, "Ops per procs": 47134233.0, "Ops/sec/procs": 4712840.66, "ns per ops/procs": 212.19}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10008.209159, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 729328104.0, "Total blocks": 729328099.0, "Ops per second": 72872987.81, "ns per ops": 13.72, "Ops per threads": 60777.0, "Ops per procs": 30388671.0, "Ops/sec/procs": 3036374.49, "ns per ops/procs": 329.34}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10099.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 961002611.0, "Ops per second": 96100261.0, "ns per ops": 10.0, "Ops per threads": 80083.0, "Ops per procs": 40041775.0, "Ops/sec/procs": 4004177.0, "ns per ops/procs": 252.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10099.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 390098231.0, "Ops per second": 39009823.0, "ns per ops": 25.0, "Ops per threads": 97524.0, "Ops per procs": 48762278.0, "Ops/sec/procs": 4876227.0, "ns per ops/procs": 207.0}],["rdq-cycle-tokio", "./rdq-cycle-tokio -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10100.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55237591.0, "Ops per second": 5523759.0, "ns per ops": 182.0, "Ops per threads": 110475.0, "Ops per procs": 55237591.0, "Ops/sec/procs": 5523759.0, "ns per ops/procs": 182.0}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10016.576699, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 54510321.0, "Total blocks": 54509820.0, "Ops per second": 5442011.04, "ns per ops": 183.76, "Ops per threads": 109020.0, "Ops per procs": 54510321.0, "Ops/sec/procs": 5442011.04, "ns per ops/procs": 183.76}],["rdq-cycle-go", "./rdq-cycle-go -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10001.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 1135730371.0, "Ops per second": 113558509.97, "ns per ops": 8.81, "Ops per threads": 94644.0, "Ops per procs": 47322098.0, "Ops/sec/procs": 4731604.58, "ns per ops/procs": 211.34}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10039.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 61004037.0, "Total blocks": 61004037.0, "Ops per second": 6076255.04, "ns per ops": 164.58, "Ops per threads": 7625.0, "Ops per procs": 3812752.0, "Ops/sec/procs": 379765.94, "ns per ops/procs": 2633.2}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10004.891999, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 747946345.0, "Total blocks": 747934349.0, "Ops per second": 74758062.86, "ns per ops": 13.38, "Ops per threads": 62328.0, "Ops per procs": 31164431.0, "Ops/sec/procs": 3114919.29, "ns per ops/procs": 321.04}],["rdq-cycle-go", "./rdq-cycle-go -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10000.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 466424792.0, "Ops per second": 46638931.23, "ns per ops": 21.44, "Ops per threads": 116606.0, "Ops per procs": 58303099.0, "Ops/sec/procs": 5829866.4, "ns per ops/procs": 171.53}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10086.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 57343570.0, "Total blocks": 57343570.0, "Ops per second": 5685308.81, "ns per ops": 175.89, "Ops per threads": 4778.0, "Ops per procs": 2389315.0, "Ops/sec/procs": 236887.87, "ns per ops/procs": 4221.41}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10020.39533, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 263517289.0, "Total blocks": 263513293.0, "Ops per second": 26298093.07, "ns per ops": 38.03, "Ops per threads": 65879.0, "Ops per procs": 32939661.0, "Ops/sec/procs": 3287261.63, "ns per ops/procs": 304.2}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10025.357431, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 551670395.0, "Total blocks": 551662399.0, "Ops per second": 55027503.89, "ns per ops": 18.17, "Ops per threads": 68958.0, "Ops per procs": 34479399.0, "Ops/sec/procs": 3439218.99, "ns per ops/procs": 290.76}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 24 -d 10 -r 5 -t 2400", {"Duration (ms)": 10050.0, "Number of processors": 24.0, "Number of threads": 12000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 56162695.0, "Total blocks": 56162695.0, "Ops per second": 5588033.65, "ns per ops": 178.95, "Ops per threads": 4680.0, "Ops per procs": 2340112.0, "Ops/sec/procs": 232834.74, "ns per ops/procs": 4294.89}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10019.690183, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 271866976.0, "Total blocks": 271862980.0, "Ops per second": 27133271.69, "ns per ops": 36.86, "Ops per threads": 67966.0, "Ops per procs": 33983372.0, "Ops/sec/procs": 3391658.96, "ns per ops/procs": 294.84}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10057.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 62105022.0, "Total blocks": 62105022.0, "Ops per second": 6175186.04, "ns per ops": 161.94, "Ops per threads": 15526.0, "Ops per procs": 7763127.0, "Ops/sec/procs": 771898.25, "ns per ops/procs": 1295.51}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10025.81217, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 537080117.0, "Total blocks": 537072121.0, "Ops per second": 53569736.59, "ns per ops": 18.67, "Ops per threads": 67135.0, "Ops per procs": 33567507.0, "Ops/sec/procs": 3348108.54, "ns per ops/procs": 298.68}],["rdq-cycle-go", "./rdq-cycle-go -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10000.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55967030.0, "Ops per second": 5596438.25, "ns per ops": 178.69, "Ops per threads": 111934.0, "Ops per procs": 55967030.0, "Ops/sec/procs": 5596438.25, "ns per ops/procs": 178.69}],["rdq-cycle-go", "./rdq-cycle-go -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10000.0, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 55703320.0, "Ops per second": 5570084.72, "ns per ops": 179.53, "Ops per threads": 111406.0, "Ops per procs": 55703320.0, "Ops/sec/procs": 5570084.72, "ns per ops/procs": 179.53}],["rdq-cycle-go", "./rdq-cycle-go -p 8 -d 10 -r 5 -t 800", {"Duration (ms)": 10000.0, "Number of processors": 8.0, "Number of threads": 4000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 469211793.0, "Ops per second": 46918327.16, "ns per ops": 21.31, "Ops per threads": 117302.0, "Ops per procs": 58651474.0, "Ops/sec/procs": 5864790.9, "ns per ops/procs": 170.51}],["rdq-cycle-cfa", "./rdq-cycle-cfa -p 1 -d 10 -r 5 -t 100", {"Duration (ms)": 10016.545208, "Number of processors": 1.0, "Number of threads": 500.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 54925472.0, "Total blocks": 54924976.0, "Ops per second": 5483474.68, "ns per ops": 182.37, "Ops per threads": 109850.0, "Ops per procs": 54925472.0, "Ops/sec/procs": 5483474.68, "ns per ops/procs": 182.37}],["rdq-cycle-fibre", "./rdq-cycle-fibre -p 16 -d 10 -r 5 -t 1600", {"Duration (ms)": 10037.0, "Number of processors": 16.0, "Number of threads": 8000.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 60770550.0, "Total blocks": 60770550.0, "Ops per second": 6054474.7, "ns per ops": 165.17, "Ops per threads": 7596.0, "Ops per procs": 3798159.0, "Ops/sec/procs": 378404.67, "ns per ops/procs": 2642.67}]]1 [["rdq-cycle-go", "./rdq-cycle-go -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 43606897.0, "Ops per second": 8720908.73, "ns per ops": 114.67, "Ops per threads": 2180344.0, "Ops per procs": 10901724.0, "Ops/sec/procs": 2180227.18, "ns per ops/procs": 458.67}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5010.922033, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 93993568.0, "Total blocks": 93993209.0, "Ops per second": 18757739.07, "ns per ops": 53.31, "Ops per threads": 1174919.0, "Ops per procs": 5874598.0, "Ops/sec/procs": 1172358.69, "ns per ops/procs": 852.98}],["rdq-cycle-go", "./rdq-cycle-go -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 136763517.0, "Ops per second": 27351079.35, "ns per ops": 36.56, "Ops per threads": 1709543.0, "Ops per procs": 8547719.0, "Ops/sec/procs": 1709442.46, "ns per ops/procs": 584.99}],["rdq-cycle-go", "./rdq-cycle-go -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 27778961.0, "Ops per second": 5555545.09, "ns per ops": 180.0, "Ops per threads": 5555792.0, "Ops per procs": 27778961.0, "Ops/sec/procs": 5555545.09, "ns per ops/procs": 180.0}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5009.290878, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 43976310.0, "Total blocks": 43976217.0, "Ops per second": 8778949.17, "ns per ops": 113.91, "Ops per threads": 2198815.0, "Ops per procs": 10994077.0, "Ops/sec/procs": 2194737.29, "ns per ops/procs": 455.64}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5009.151542, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 44132300.0, "Total blocks": 44132201.0, "Ops per second": 8810334.37, "ns per ops": 113.5, "Ops per threads": 2206615.0, "Ops per procs": 11033075.0, "Ops/sec/procs": 2202583.59, "ns per ops/procs": 454.01}],["rdq-cycle-go", "./rdq-cycle-go -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 46353896.0, "Ops per second": 9270294.11, "ns per ops": 107.87, "Ops per threads": 2317694.0, "Ops per procs": 11588474.0, "Ops/sec/procs": 2317573.53, "ns per ops/procs": 431.49}],["rdq-cycle-go", "./rdq-cycle-go -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 27894379.0, "Ops per second": 5578591.58, "ns per ops": 179.26, "Ops per threads": 5578875.0, "Ops per procs": 27894379.0, "Ops/sec/procs": 5578591.58, "ns per ops/procs": 179.26}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5008.743463, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 32825528.0, "Total blocks": 32825527.0, "Ops per second": 6553645.29, "ns per ops": 152.59, "Ops per threads": 6565105.0, "Ops per procs": 32825528.0, "Ops/sec/procs": 6553645.29, "ns per ops/procs": 152.59}],["rdq-cycle-go", "./rdq-cycle-go -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 138213098.0, "Ops per second": 27640977.5, "ns per ops": 36.18, "Ops per threads": 1727663.0, "Ops per procs": 8638318.0, "Ops/sec/procs": 1727561.09, "ns per ops/procs": 578.85}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5007.914168, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 44109513.0, "Total blocks": 44109419.0, "Ops per second": 8807961.06, "ns per ops": 113.53, "Ops per threads": 2205475.0, "Ops per procs": 11027378.0, "Ops/sec/procs": 2201990.27, "ns per ops/procs": 454.13}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5012.121876, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 94130673.0, "Total blocks": 94130291.0, "Ops per second": 18780603.37, "ns per ops": 53.25, "Ops per threads": 1176633.0, "Ops per procs": 5883167.0, "Ops/sec/procs": 1173787.71, "ns per ops/procs": 851.94}],["rdq-cycle-go", "./rdq-cycle-go -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 140936367.0, "Ops per second": 28185668.38, "ns per ops": 35.48, "Ops per threads": 1761704.0, "Ops per procs": 8808522.0, "Ops/sec/procs": 1761604.27, "ns per ops/procs": 567.66}],["rdq-cycle-go", "./rdq-cycle-go -t 4 -p 4 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 4.0, "Number of threads": 20.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 44279585.0, "Ops per second": 8855475.01, "ns per ops": 112.92, "Ops per threads": 2213979.0, "Ops per procs": 11069896.0, "Ops/sec/procs": 2213868.75, "ns per ops/procs": 451.7}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5008.37392, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 32227534.0, "Total blocks": 32227533.0, "Ops per second": 6434730.02, "ns per ops": 155.41, "Ops per threads": 6445506.0, "Ops per procs": 32227534.0, "Ops/sec/procs": 6434730.02, "ns per ops/procs": 155.41}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 16 -p 16 -d 5 -r 5", {"Duration (ms)": 5011.019789, "Number of processors": 16.0, "Number of threads": 80.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 90600569.0, "Total blocks": 90600173.0, "Ops per second": 18080265.66, "ns per ops": 55.31, "Ops per threads": 1132507.0, "Ops per procs": 5662535.0, "Ops/sec/procs": 1130016.6, "ns per ops/procs": 884.94}],["rdq-cycle-cfa", "./rdq-cycle-cfa -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5008.52474, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 32861776.0, "Total blocks": 32861775.0, "Ops per second": 6561168.75, "ns per ops": 152.41, "Ops per threads": 6572355.0, "Ops per procs": 32861776.0, "Ops/sec/procs": 6561168.75, "ns per ops/procs": 152.41}],["rdq-cycle-go", "./rdq-cycle-go -t 1 -p 1 -d 5 -r 5", {"Duration (ms)": 5000.0, "Number of processors": 1.0, "Number of threads": 5.0, "Cycle size (# thrds)": 5.0, "Total Operations(ops)": 28097680.0, "Ops per second": 5619274.9, "ns per ops": 177.96, "Ops per threads": 5619536.0, "Ops per procs": 28097680.0, "Ops/sec/procs": 5619274.9, "ns per ops/procs": 177.96}]] -
doc/theses/thierry_delisle_PhD/thesis/local.bib
r74ec742 r29d8c02 701 701 note = "[Online; accessed 12-April-2022]" 702 702 } 703 704 % RMR notes :705 % [05/04, 12:36] Trevor Brown706 % i don't know where rmr complexity was first introduced, but there are many many many papers that use the term and define it707 % [05/04, 12:37] Trevor Brown708 % here's one paper that uses the term a lot and links to many others that use it... might trace it to something useful there https://drops.dagstuhl.de/opus/volltexte/2021/14832/pdf/LIPIcs-DISC-2021-30.pdf709 % [05/04, 12:37] Trevor Brown710 % another option might be to cite a textbook711 % [05/04, 12:42] Trevor Brown712 % but i checked two textbooks in the area i'm aware of and i don't see a definition of rmr complexity in either713 % [05/04, 12:42] Trevor Brown714 % this one has a nice statement about the prevelance of rmr complexity, as well as some rough definition715 % [05/04, 12:42] Trevor Brown716 % https://dl.acm.org/doi/pdf/10.1145/3465084.3467938717 718 % Race to idle notes :719 % [13/04, 16:56] Martin Karsten720 % I don't have a citation. Google brings up this one, which might be good:721 %722 % https://doi.org/10.1137/1.9781611973099.100 -
doc/theses/thierry_delisle_PhD/thesis/text/eval_macro.tex
r74ec742 r29d8c02 7 7 Networked ZIPF 8 8 9 Nginx : 5Gb still good, 4Gb starts to suffer10 11 Cforall : 10Gb too high, 4 Gb too low12 13 9 \section{Memcached} 14 10 15 \subsection{Benchmark Environment} 16 These experiments are run on a cluster of homogenous Supermicro SYS-6017R-TDF compute nodes with the following characteristics: 17 The server runs Ubuntu 20.04.3 LTS on top of Linux Kernel 5.11.0-34. 18 Each node has 2 Intel(R) Xeon(R) CPU E5-2620 v2 running at 2.10GHz. 19 These CPUs have 6 cores per CPUs and 2 \glspl{hthrd} per core, for a total of 24 \glspl{hthrd}. 20 The cpus each have 384 KB, 3 MB and 30 MB of L1, L2 and L3 caches respectively. 21 Each node is connected to the network through a Mellanox 10 Gigabit Ethernet port. 22 The network route uses 1 Mellanox SX1012 10/40 Gigabit Ethernet cluster switch. 11 In Memory 23 12 24 25 26 \begin{figure} 27 \centering 28 \input{result.memcd.updt.qps.pstex_t} 29 \caption[Churn Benchmark : Throughput on Intel]{Churn Benchmark : Throughput on Intel\smallskip\newline Description} 30 \label{fig:memcd:updt:qps} 31 \end{figure} 32 33 \begin{figure} 34 \centering 35 \input{result.memcd.updt.lat.pstex_t} 36 \caption[Churn Benchmark : Throughput on Intel]{Churn Benchmark : Throughput on Intel\smallskip\newline Description} 37 \label{fig:memcd:updt:lat} 38 \end{figure} 39 40 \begin{figure} 41 \centering 42 \input{result.memcd.rate.qps.pstex_t} 43 \caption[Churn Benchmark : Throughput on Intel]{Churn Benchmark : Throughput on Intel\smallskip\newline Description} 44 \label{fig:memcd:rate:qps} 45 \end{figure} 46 47 \begin{figure} 48 \centering 49 \input{result.memcd.rate.99th.pstex_t} 50 \caption[Churn Benchmark : Throughput on Intel]{Churn Benchmark : Throughput on Intel\smallskip\newline Description} 51 \label{fig:memcd:rate:tail} 52 \end{figure} 13 Networked -
doc/theses/thierry_delisle_PhD/thesis/text/eval_micro.tex
r74ec742 r29d8c02 6 6 \section{Benchmark Environment} 7 7 All of these benchmarks are run on two distinct hardware environment, an AMD and an INTEL machine. 8 9 For all benchmarks, \texttt{taskset} is used to limit the experiment to 1 NUMA Node with no hyper threading.10 If more \glspl{hthrd} are needed, then 1 NUMA Node with hyperthreading is used.11 If still more \glspl{hthrd} are needed then the experiment is limited to as few NUMA Nodes as needed.12 13 8 14 9 \paragraph{AMD} The AMD machine is a server with two AMD EPYC 7662 CPUs and 256GB of DDR4 RAM. … … 28 23 29 24 \section{Cycling latency} 30 \begin{figure}31 \centering32 \input{cycle.pstex_t}33 \caption[Cycle benchmark]{Cycle benchmark\smallskip\newline Each \gls{at} unparks the next \gls{at} in the cycle before parking itself.}34 \label{fig:cycle}35 \end{figure}36 25 The most basic evaluation of any ready queue is to evaluate the latency needed to push and pop one element from the ready-queue. 37 26 Since these two operation also describe a \texttt{yield} operation, many systems use this as the most basic benchmark. … … 53 42 Note that this problem is only present on SMP machines and is significantly mitigated by the fact that there are multiple rings in the system. 54 43 44 \begin{figure} 45 \centering 46 \input{cycle.pstex_t} 47 \caption[Cycle benchmark]{Cycle benchmark\smallskip\newline Each \gls{at} unparks the next \gls{at} in the cycle before parking itself.} 48 \label{fig:cycle} 49 \end{figure} 50 55 51 To avoid this benchmark from being dominated by the idle sleep handling, the number of rings is kept at least as high as the number of \glspl{proc} available. 56 52 Beyond this point, adding more rings serves to mitigate even more the idle sleep handling. … … 58 54 59 55 The actual benchmark is more complicated to handle termination, but that simply requires using a binary semphore or a channel instead of raw \texttt{park}/\texttt{unpark} and carefully picking the order of the \texttt{P} and \texttt{V} with respect to the loop condition. 60 Figure~\ref{fig:cycle:code} shows pseudo code for this benchmark. 56 57 \begin{lstlisting} 58 Thread.main() { 59 count := 0 60 for { 61 wait() 62 this.next.wake() 63 count ++ 64 if must_stop() { break } 65 } 66 global.count += count 67 } 68 \end{lstlisting} 61 69 62 70 \begin{figure} 63 \begin{lstlisting} 64 Thread.main() { 65 count := 0 66 for { 67 wait() 68 this.next.wake() 69 count ++ 70 if must_stop() { break } 71 } 72 global.count += count 73 } 74 \end{lstlisting} 75 \caption[Cycle Benchmark : Pseudo Code]{Cycle Benchmark : Pseudo Code} 76 \label{fig:cycle:code} 71 \centering 72 \input{result.cycle.jax.ops.pstex_t} 73 \vspace*{-10pt} 74 \label{fig:cycle:ns:jax} 77 75 \end{figure} 78 79 80 81 \subsection{Results}82 \begin{figure}83 \subfloat[][Throughput, 100 \ats per \proc]{84 \resizebox{0.5\linewidth}{!}{85 \input{result.cycle.jax.ops.pstex_t}86 }87 \label{fig:cycle:jax:ops}88 }89 \subfloat[][Throughput, 1 \ats per \proc]{90 \resizebox{0.5\linewidth}{!}{91 \input{result.cycle.low.jax.ops.pstex_t}92 }93 \label{fig:cycle:jax:low:ops}94 }95 96 \subfloat[][Latency, 100 \ats per \proc]{97 \resizebox{0.5\linewidth}{!}{98 \input{result.cycle.jax.ns.pstex_t}99 }100 101 }102 \subfloat[][Latency, 1 \ats per \proc]{103 \resizebox{0.5\linewidth}{!}{104 \input{result.cycle.low.jax.ns.pstex_t}105 }106 \label{fig:cycle:jax:low:ns}107 }108 \caption[Cycle Benchmark on Intel]{Cycle Benchmark on Intel\smallskip\newline Throughput as a function of \proc count, using 100 cycles per \proc, 5 \ats per cycle.}109 \label{fig:cycle:jax}110 \end{figure}111 Figure~\ref{fig:cycle:jax} shows the throughput as a function of \proc count, with the following constants:112 Each run uses 100 cycles per \proc, 5 \ats per cycle.113 114 \todo{results discussion}115 76 116 77 \section{Yield} … … 120 81 Its only interesting variable is the number of \glspl{at} per \glspl{proc}, where ratios close to 1 means the ready queue(s) could be empty. 121 82 This sometimes puts more strain on the idle sleep handling, compared to scenarios where there is clearly plenty of work to be done. 122 Figure~\ref{fig:yield:code} shows pseudo code for this benchmark, the ``wait/wake-next'' is simply replaced by a yield.123 83 124 \begin{figure} 125 \begin{lstlisting} 126 Thread.main() { 127 count := 0 128 for { 129 yield() 130 count ++ 131 if must_stop() { break } 132 } 133 global.count += count 84 \todo{code, setup, results} 85 86 \begin{lstlisting} 87 Thread.main() { 88 count := 0 89 while !stop { 90 yield() 91 count ++ 134 92 } 135 \end{lstlisting} 136 \caption[Yield Benchmark : Pseudo Code]{Yield Benchmark : Pseudo Code} 137 \label{fig:yield:code} 138 \end{figure} 139 140 \subsection{Results} 141 \begin{figure} 142 \subfloat[][Throughput, 100 \ats per \proc]{ 143 \resizebox{0.5\linewidth}{!}{ 144 \input{result.yield.jax.ops.pstex_t} 145 } 146 \label{fig:yield:jax:ops} 93 global.count += count 147 94 } 148 \subfloat[][Throughput, 1 \ats per \proc]{ 149 \resizebox{0.5\linewidth}{!}{ 150 \input{result.yield.low.jax.ops.pstex_t} 151 } 152 \label{fig:yield:jax:low:ops} 153 } 154 155 \subfloat[][Latency, 100 \ats per \proc]{ 156 \resizebox{0.5\linewidth}{!}{ 157 \input{result.yield.jax.ns.pstex_t} 158 } 159 \label{fig:yield:jax:ns} 160 } 161 \subfloat[][Latency, 1 \ats per \proc]{ 162 \resizebox{0.5\linewidth}{!}{ 163 \input{result.yield.low.jax.ns.pstex_t} 164 } 165 \label{fig:yield:jax:low:ns} 166 } 167 \caption[Yield Benchmark on Intel]{Yield Benchmark on Intel\smallskip\newline Throughput as a function of \proc count, using 1 \ats per \proc.} 168 \label{fig:yield:jax} 169 \end{figure} 170 Figure~\ref{fig:yield:ops:jax} shows the throughput as a function of \proc count, with the following constants: 171 Each run uses 100 \ats per \proc. 172 173 \todo{results discussion} 95 \end{lstlisting} 174 96 175 97 … … 183 105 In either case, this benchmark aims to highlight how each scheduler handles these cases, since both cases can lead to performance degradation if they are not handled correctly. 184 106 185 To achieve this the benchmark uses a fixed size array of semaphores. 186 Each \gls{at} picks a random semaphore, \texttt{V}s it to unblock a \at waiting and then \texttt{P}s on the semaphore. 187 This creates a flow where \glspl{at} push each other out of the semaphores before being pushed out themselves. 188 For this benchmark to work however, the number of \glspl{at} must be equal or greater to the number of semaphores plus the number of \glspl{proc}. 189 Note that the nature of these semaphores mean the counter can go beyond 1, which could lead to calls to \texttt{P} not blocking. 107 To achieve this the benchmark uses a fixed size array of \newterm{chair}s, where a chair is a data structure that holds a single blocked \gls{at}. 108 When a \gls{at} attempts to block on the chair, it must first unblocked the \gls{at} currently blocked on said chair, if any. 109 This creates a flow where \glspl{at} push each other out of the chairs before being pushed out themselves. 110 For this benchmark to work however, the number of \glspl{at} must be equal or greater to the number of chairs plus the number of \glspl{proc}. 190 111 191 112 \todo{code, setup, results} … … 195 116 for { 196 117 r := random() % len(spots) 197 spots[r].V() 198 spots[r].P() 118 next := xchg(spots[r], this) 119 if next { next.wake() } 120 wait() 199 121 count ++ 200 122 if must_stop() { break } … … 203 125 } 204 126 \end{lstlisting} 205 206 \begin{figure}207 \subfloat[][Throughput, 100 \ats per \proc]{208 \resizebox{0.5\linewidth}{!}{209 \input{result.churn.jax.ops.pstex_t}210 }211 \label{fig:churn:jax:ops}212 }213 \subfloat[][Throughput, 1 \ats per \proc]{214 \resizebox{0.5\linewidth}{!}{215 \input{result.churn.low.jax.ops.pstex_t}216 }217 \label{fig:churn:jax:low:ops}218 }219 220 \subfloat[][Latency, 100 \ats per \proc]{221 \resizebox{0.5\linewidth}{!}{222 \input{result.churn.jax.ns.pstex_t}223 }224 225 }226 \subfloat[][Latency, 1 \ats per \proc]{227 \resizebox{0.5\linewidth}{!}{228 \input{result.churn.low.jax.ns.pstex_t}229 }230 \label{fig:churn:jax:low:ns}231 }232 \caption[Churn Benchmark on Intel]{\centering Churn Benchmark on Intel\smallskip\newline Throughput and latency of the Churn on the benchmark on the Intel machine. Throughput is the total operation per second across all cores. Latency is the duration of each opeartion.}233 \label{fig:churn:jax}234 \end{figure}235 127 236 128 \section{Locality} -
doc/theses/thierry_delisle_PhD/thesis/text/practice.tex
r74ec742 r29d8c02 7 7 More precise \CFA supports adding \procs using the RAII object @processor@. 8 8 These objects can be created at any time and can be destroyed at any time. 9 They are normally create das automatic stack variables, but this is not a requirement.9 They are normally create as automatic stack variables, but this is not a requirement. 10 10 11 11 The consequence is that the scheduler and \io subsystems must support \procs comming in and out of existence. 12 12 13 13 \section{Manual Resizing} 14 Manual resizing is expected to be a rare operation. 15 Programmers are mostly expected to resize clusters on startup or teardown. 16 Therefore dynamically changing the number of \procs is an appropriate moment to allocate or free resources to match the new state. 17 As such all internal arrays that are sized based on the number of \procs need to be \texttt{realloc}ed. 18 This also means that any references into these arrays, pointers or indexes, may need to be fixed when shrinking\footnote{Indexes may still need fixing when shrinkingbecause some indexes are expected to refer to dense contiguous resources and there is no guarantee the resource being removed has the highest index.}. 14 The consequence of dynamically changing the number of \procs is that all internal arrays that are sized based on the number of \procs neede to be \texttt{realloc}ed. 15 This also means that any references into these arrays, pointers or indexes, may need to be fixed when shrinking\footnote{Indexes may still need fixing because there is no guarantee the \proc causing the shrink had the highest index. Therefore indexes need to be reassigned to preserve contiguous indexes.}. 19 16 20 There are no performance requirements, within reason, for resizing since it is expected to be rare.17 There are no performance requirements, within reason, for resizing since this is usually considered as part of setup and teardown. 21 18 However, this operation has strict correctness requirements since shrinking and idle sleep can easily lead to deadlocks. 22 19 It should also avoid as much as possible any effect on performance when the number of \procs remain constant. 23 This later requirement pr ohibits naive solutions, like simply adding a global lock to the ready-queue arrays.20 This later requirement prehibits simple solutions, like simply adding a global lock to these arrays. 24 21 25 22 \subsection{Read-Copy-Update} … … 27 24 In this pattern, resizing is done by creating a copy of the internal data strucures, updating the copy with the desired changes, and then attempt an Idiana Jones Switch to replace the original witht the copy. 28 25 This approach potentially has the advantage that it may not need any synchronization to do the switch. 29 However, there is a race where \procs could still use the previous, original, data structure after the copy was switched in. 30 This race not only requires some added memory reclamation scheme, it also requires that operations made on the stale original version be eventually moved to the copy. 26 The switch definitely implies a race where \procs could still use the previous, original, data structure after the copy was switched in. 27 The important question then becomes whether or not this race can be recovered from. 28 If the changes that arrived late can be transferred from the original to the copy then this solution works. 31 29 32 For linked-lists, enqueing is only somewhat problematic, \ats enqueued to the original queues need to be transferred to the new, which might not preserve ordering. 33 Dequeing is more challenging. 30 For linked-lists, dequeing is somewhat of a problem. 34 31 Dequeing from the original will not necessarily update the copy which could lead to multiple \procs dequeing the same \at. 35 Fixing this requires m ore synchronization or more indirection on the queues.32 Fixing this requires making the array contain pointers to subqueues rather than the subqueues themselves. 36 33 37 34 Another challenge is that the original must be kept until all \procs have witnessed the change. … … 100 97 In addition to users manually changing the number of \procs, it is desireable to support ``removing'' \procs when there is not enough \ats for all the \procs to be useful. 101 98 While manual resizing is expected to be rare, the number of \ats is expected to vary much more which means \procs may need to be ``removed'' for only short periods of time. 102 Furthermore, race conditions that spuriously lead to the impression thatno \ats are ready are actually common in practice.103 Therefore resources associated with \procs should not be freed but \procssimply put into an idle state where the \gls{kthrd} is blocked until more \ats become ready.99 Furthermore, race conditions that spuriously lead to the impression no \ats are ready are actually common in practice. 100 Therefore \procs should not be actually \emph{removed} but simply put into an idle state where the \gls{kthrd} is blocked until more \ats become ready. 104 101 This state is referred to as \newterm{Idle-Sleep}. 105 102 … … 113 110 The \CFA scheduler simply follows the ``Race-to-Idle'\cit{https://doi.org/10.1137/1.9781611973099.100}' approach where a sleeping \proc is woken any time an \at becomes ready and \procs go to idle sleep anytime they run out of work. 114 111 115 \section{Sleeping}116 As usual, the corner-stone of any feature related to the kernel is the choice of system call.117 In terms of blocking a \gls{kthrd} until some event occurs the linux kernel has many available options:118 119 \paragraph{\texttt{pthread\_mutex}/\texttt{pthread\_cond}}120 The most classic option is to use some combination of \texttt{pthread\_mutex} and \texttt{pthread\_cond}.121 These serve as straight forward mutual exclusion and synchronization tools and allow a \gls{kthrd} to wait on a \texttt{pthread\_cond} until signalled.122 While this approach is generally perfectly appropriate for \glspl{kthrd} waiting after eachother, \io operations do not signal \texttt{pthread\_cond}s.123 For \io results to wake a \proc waiting on a \texttt{pthread\_cond} means that a different \glspl{kthrd} must be woken up first, and then the \proc can be signalled.124 125 \subsection{\texttt{io\_uring} and Epoll}126 An alternative is to flip the problem on its head and block waiting for \io, using \texttt{io\_uring} or even \texttt{epoll}.127 This creates the inverse situation, where \io operations directly wake sleeping \procs but waking \proc from a running \gls{kthrd} must use an indirect scheme.128 This generally takes the form of creating a file descriptor, \eg, a dummy file, a pipe or an event fd, and using that file descriptor when \procs need to wake eachother.129 This leads to additional complexity because there can be a race between these artificial \io operations and genuine \io operations.130 If not handled correctly, this can lead to the artificial files going out of sync.131 132 \subsection{Event FDs}133 Another interesting approach is to use an event file descriptor\cit{eventfd}.134 This is a Linux feature that is a file descriptor that behaves like \io, \ie, uses \texttt{read} and \texttt{write}, but also behaves like a semaphore.135 Indeed, all read and writes must use 64bits large values\footnote{On 64-bit Linux, a 32-bit Linux would use 32 bits values.}.136 Writes add their values to the buffer, that is arithmetic addition and not buffer append, and reads zero out the buffer and return the buffer values so far\footnote{This is without the \texttt{EFD\_SEMAPHORE} flag. This flags changes the behavior of \texttt{read} but is not needed for this work.}.137 If a read is made while the buffer is already 0, the read blocks until a non-0 value is added.138 What makes this feature particularly interesting is that \texttt{io\_uring} supports the \texttt{IORING\_REGISTER\_EVENTFD} command, to register an event fd to a particular instance.139 Once that instance is registered, any \io completion will result in \texttt{io\_uring} writing to the event FD.140 This means that a \proc waiting on the event FD can be \emph{directly} woken up by either other \procs or incomming \io.141 142 \begin{figure}143 \centering144 \input{idle1.pstex_t}145 \caption[Basic Idle Sleep Data Structure]{Basic Idle Sleep Data Structure \smallskip\newline Each idle \proc is put unto a doubly-linked stack protected by a lock.146 Each \proc has a private event FD.}147 \label{fig:idle1}148 \end{figure}149 150 112 151 113 \section{Tracking Sleepers} 152 114 Tracking which \procs are in idle sleep requires a data structure holding all the sleeping \procs, but more importantly it requires a concurrent \emph{handshake} so that no \at is stranded on a ready-queue with no active \proc. 153 115 The classic challenge is when a \at is made ready while a \proc is going to sleep, there is a race where the new \at may not see the sleeping \proc and the sleeping \proc may not see the ready \at. 154 Since \ats can be made ready by timers, \io operations or other events outside a clusre, this race can occur even if the \proc going to sleep is the only \proc awake.155 As a result, improper handling of this race can lead to all \procs going to sleep and the system deadlocking.156 116 157 Furthermore, the ``Race-to-Idle'' approach means that there may be contention on the data structure tracking sleepers. 158 Contention slowing down \procs attempting to sleep or wake-up can be tolerated. 159 These \procs are not doing useful work and therefore not contributing to overall performance. 160 However, notifying, checking if a \proc must be woken-up and doing so if needed, can significantly affect overall performance and must be low cost. 117 Furthermore, the ``Race-to-Idle'' approach means that there is some 161 118 162 \subsection{Sleepers List} 163 Each cluster maintains a list of idle \procs, organized as a stack. 164 This ordering hopefully allows \proc at the tail to stay in idle sleep for extended period of times. 165 Because of these unbalanced performance requirements, the algorithm tracking sleepers is designed to have idle \proc handle as much of the work as possible. 166 The idle \procs maintain the of sleepers among themselves and notifying a sleeping \proc takes as little work as possible. 167 This approach means that maintaining the list is fairly straightforward. 168 The list can simply use a single lock per cluster and only \procs that are getting in and out of idle state will contend for that lock. 119 \section{Sleeping} 169 120 170 This approach also simplifies notification. 171 Indeed, \procs need to be notify when a new \at is readied, but they also must be notified during resizing, so the \gls{kthrd} can be joined. 172 This means that whichever entity removes idle \procs from the sleeper list must be able to do so in any order. 173 Using a simple lock over this data structure makes the removal much simpler than using a lock-free data structure. 174 The notification process then simply needs to wake-up the desired idle \proc, using \texttt{pthread\_cond\_signal}, \texttt{write} on an fd, etc., and the \proc will handle the rest. 121 \subsection{Event FDs} 175 122 176 \subsection{Reducing Latency} 177 As mentioned in this section, \procs going idle for extremely short periods of time is likely in certain common scenarios. 178 Therefore, the latency of doing a system call to read from and writing to the event fd can actually negatively affect overall performance in a notable way. 179 Is it important to reduce latency and contention of the notification as much as possible. 180 Figure~\ref{fig:idle1} shoes the basic idle sleep data structure. 181 For the notifiers, this data structure can cause contention on the lock and the event fd syscall can cause notable latency. 123 \subsection{Epoll} 182 124 183 \begin{figure} 184 \centering 185 \input{idle2.pstex_t} 186 \caption[Improved Idle Sleep Data Structure]{Improved Idle Sleep Data Structure \smallskip\newline An atomic pointer is added to the list, pointing to the Event FD of the first \proc on the list.} 187 \label{fig:idle2} 188 \end{figure} 125 \subsection{\texttt{io\_uring}} 189 126 190 The contention is mostly due to the lock on the list needing to be held to get to the head \proc. 191 That lock can be contended by \procs attempting to go to sleep, \procs waking or notification attempts. 192 The contentention from the \procs attempting to go to sleep can be mitigated slightly by using \texttt{try\_acquire} instead, so the \procs simply continue searching for \ats if the lock is held. 193 This trick cannot be used for waking \procs since they are not in a state where they can run \ats. 194 However, it is worth nothing that notification does not strictly require accessing the list or the head \proc. 195 Therefore, contention can be reduced notably by having notifiers avoid the lock entirely and adding a pointer to the event fd of the first idle \proc, as in Figure~\ref{fig:idle2}. 196 To avoid contention between the notifiers, instead of simply reading the atomic pointer, notifiers atomically exchange it to \texttt{null} so only only notifier will contend on the system call. 197 198 \begin{figure} 199 \centering 200 \input{idle_state.pstex_t} 201 \caption[Improved Idle Sleep Data Structure]{Improved Idle Sleep Data Structure \smallskip\newline An atomic pointer is added to the list, pointing to the Event FD of the first \proc on the list.} 202 \label{fig:idle:state} 203 \end{figure} 204 205 The next optimization that can be done is to avoid the latency of the event fd when possible. 206 This can be done by adding what is effectively a benaphore\cit{benaphore} in front of the event fd. 207 A simple three state flag is added beside the event fd to avoid unnecessary system calls, as shown in Figure~\ref{fig:idle:state}. 208 The flag starts in state \texttt{SEARCH}, while the \proc is searching for \ats to run. 209 The \proc then confirms the sleep by atomically swaping the state to \texttt{SLEEP}. 210 If the previous state was still \texttt{SEARCH}, then the \proc does read the event fd. 211 Meanwhile, notifiers atomically exchange the state to \texttt{AWAKE} state. 212 if the previous state was \texttt{SLEEP}, then the notifier must write to the event fd. 213 However, if the notify arrives almost immediately after the \proc marks itself idle, then both reads and writes on the event fd can be omitted, which reduces latency notably. 214 This leads to the final data structure shown in Figure~\ref{fig:idle}. 215 216 \begin{figure} 217 \centering 218 \input{idle.pstex_t} 219 \caption[Low-latency Idle Sleep Data Structure]{Low-latency Idle Sleep Data Structure \smallskip\newline Each idle \proc is put unto a doubly-linked stack protected by a lock. 220 Each \proc has a private event FD with a benaphore in front of it. 221 The list also has an atomic pointer to the event fd and benaphore of the first \proc on the list.} 222 \label{fig:idle} 223 \end{figure} 127 \section{Reducing Latency} -
doc/theses/thierry_delisle_PhD/thesis/thesis.tex
r74ec742 r29d8c02 82 82 \usepackage{xcolor} 83 83 \usepackage{graphicx} % For including graphics 84 \usepackage{subcaption}85 84 86 85 % Hyperlinks make it very easy to navigate an electronic document. … … 205 204 \newcommand\at{\gls{at}\xspace}% 206 205 \newcommand\ats{\glspl{at}\xspace}% 207 \newcommand\Proc{\Pls{proc}\xspace}%208 206 \newcommand\proc{\gls{proc}\xspace}% 209 207 \newcommand\procs{\glspl{proc}\xspace}% -
libcfa/src/Makefile.am
r74ec742 r29d8c02 33 33 # The built sources must not depend on the installed inst_headers_src 34 34 AM_CFAFLAGS = -quiet -cfalib -I$(srcdir)/stdhdr -I$(srcdir)/concurrency $(if $(findstring ${gdbwaittarget}, ${@}), -XCFA --gdb) @CONFIG_CFAFLAGS@ 35 AM_CFLAGS = -g -Wall -Werror=return-type -Wno-unused-function -fPIC -fexceptions - fvisibility=hidden -pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@35 AM_CFLAGS = -g -Wall -Werror=return-type -Wno-unused-function -fPIC -fexceptions -pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@ 36 36 AM_CCASFLAGS = -g -Wall -Werror=return-type -Wno-unused-function @ARCH_FLAGS@ @CONFIG_CFLAGS@ 37 37 CFACC = @CFACC@ … … 194 194 195 195 prelude.o : prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@ 196 ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA,-l ${<} -c - fvisibility=default -o ${@}196 ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA,-l ${<} -c -o ${@} 197 197 198 198 prelude.lo: prelude.cfa extras.cf gcc-builtins.cf builtins.cf @LOCAL_CFACC@ @CFACPP@ 199 199 ${AM_V_GEN}$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile \ 200 $(CFACOMPILE) -quiet -XCFA,-l ${<} -c - fvisibility=default -o ${@}200 $(CFACOMPILE) -quiet -XCFA,-l ${<} -c -o ${@} 201 201 202 202 concurrency/io/call.cfa: $(srcdir)/concurrency/io/call.cfa.in -
libcfa/src/algorithms/range_iterator.cfa
r74ec742 r29d8c02 20 20 #include <fstream.hfa> 21 21 22 #include "bits/defs.hfa" 23 24 void main(RangeIter & this) libcfa_public { 22 void main(RangeIter & this) { 25 23 for() { 26 24 this._start = -1; -
libcfa/src/assert.cfa
r74ec742 r29d8c02 19 19 #include <unistd.h> // STDERR_FILENO 20 20 #include "bits/debug.hfa" 21 #include "bits/defs.hfa"22 21 23 22 extern "C" { … … 27 26 28 27 // called by macro assert in assert.h 29 // would be cool to remove libcfa_public but it's needed for libcfathread 30 void __assert_fail( const char assertion[], const char file[], unsigned int line, const char function[] ) libcfa_public { 28 void __assert_fail( const char assertion[], const char file[], unsigned int line, const char function[] ) { 31 29 __cfaabi_bits_print_safe( STDERR_FILENO, CFA_ASSERT_FMT ".\n", assertion, __progname, function, line, file ); 32 30 abort(); … … 34 32 35 33 // called by macro assertf 36 // would be cool to remove libcfa_public but it's needed for libcfathread 37 void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) libcfa_public { 34 void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) { 38 35 __cfaabi_bits_acquire(); 39 36 __cfaabi_bits_print_nolock( STDERR_FILENO, CFA_ASSERT_FMT ": ", assertion, __progname, function, line, file ); -
libcfa/src/bits/align.hfa
r74ec742 r29d8c02 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Apr 29 19:14:43 202213 // Update Count : 412 // Last Modified On : Sat Nov 16 18:58:22 2019 13 // Update Count : 3 14 14 // 15 15 // This library is free software; you can redistribute it and/or modify it … … 35 35 //#define libAlign() (sizeof(double)) 36 36 // gcc-7 uses xmms instructions, which require 16 byte alignment. 37 #define libAlign() ( __BIGGEST_ALIGNMENT__)37 #define libAlign() (16) 38 38 39 39 // Check for power of 2 -
libcfa/src/bits/debug.cfa
r74ec742 r29d8c02 21 21 #include <unistd.h> 22 22 23 #include "bits/defs.hfa"24 25 23 enum { buffer_size = 4096 }; 26 24 static char buffer[ buffer_size ]; 27 25 28 26 extern "C" { 29 // would be cool to remove libcfa_public but it's needed for libcfathread 30 void __cfaabi_bits_write( int fd, const char in_buffer[], int len ) libcfa_public { 27 void __cfaabi_bits_write( int fd, const char in_buffer[], int len ) { 31 28 // ensure all data is written 32 29 for ( int count = 0, retcode; count < len; count += retcode ) { … … 47 44 void __cfaabi_bits_release() __attribute__((__weak__)) {} 48 45 49 // would be cool to remove libcfa_public but it's needed for libcfathread 50 int __cfaabi_bits_print_safe ( int fd, const char fmt[], ... ) __attribute__(( format(printf, 2, 3) )) libcfa_public { 46 int __cfaabi_bits_print_safe ( int fd, const char fmt[], ... ) __attribute__(( format(printf, 2, 3) )) { 51 47 va_list args; 52 48 -
libcfa/src/bits/defs.hfa
r74ec742 r29d8c02 36 36 #define __cfa_dlink(x) struct { struct x * next; struct x * back; } __dlink_substitute 37 37 #endif 38 39 #define libcfa_public __attribute__((visibility("default")))40 38 41 39 #ifdef __cforall -
libcfa/src/bits/weakso_locks.cfa
r74ec742 r29d8c02 18 18 #include "bits/weakso_locks.hfa" 19 19 20 #pragma GCC visibility push(default)21 22 20 void ?{}( blocking_lock &, bool, bool ) {} 23 21 void ^?{}( blocking_lock & ) {} -
libcfa/src/common.cfa
r74ec742 r29d8c02 18 18 #include <stdlib.h> // div_t, *div 19 19 20 #pragma GCC visibility push(default)21 22 20 //--------------------------------------- 23 21 -
libcfa/src/concurrency/alarm.cfa
r74ec742 r29d8c02 141 141 //============================================================================================= 142 142 143 void sleep( Duration duration ) libcfa_public{143 void sleep( Duration duration ) { 144 144 alarm_node_t node = { active_thread(), duration, 0`s }; 145 145 -
libcfa/src/concurrency/clib/cfathread.cfa
r74ec742 r29d8c02 326 326 } 327 327 328 #pragma GCC visibility push(default)329 330 328 //================================================================================ 331 329 // Main Api 332 330 extern "C" { 333 int cfathread_cluster_create(cfathread_cluster_t * cl) __attribute__((nonnull(1))) libcfa_public{331 int cfathread_cluster_create(cfathread_cluster_t * cl) __attribute__((nonnull(1))) { 334 332 *cl = new(); 335 333 return 0; 336 334 } 337 335 338 cfathread_cluster_t cfathread_cluster_self(void) libcfa_public{336 cfathread_cluster_t cfathread_cluster_self(void) { 339 337 return active_cluster(); 340 338 } 341 339 342 int cfathread_cluster_print_stats( cfathread_cluster_t cl ) libcfa_public{340 int cfathread_cluster_print_stats( cfathread_cluster_t cl ) { 343 341 #if !defined(__CFA_NO_STATISTICS__) 344 342 print_stats_at_exit( *cl, CFA_STATS_READY_Q | CFA_STATS_IO ); -
libcfa/src/concurrency/coroutine.cfa
r74ec742 r29d8c02 48 48 //----------------------------------------------------------------------------- 49 49 forall(T &) 50 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) libcfa_public{50 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) { 51 51 dst->virtual_table = src->virtual_table; 52 52 dst->the_coroutine = src->the_coroutine; … … 55 55 56 56 forall(T &) 57 const char * msg(CoroutineCancelled(T) *) libcfa_public{57 const char * msg(CoroutineCancelled(T) *) { 58 58 return "CoroutineCancelled(...)"; 59 59 } … … 62 62 forall(T & | is_coroutine(T)) 63 63 void __cfaehm_cancelled_coroutine( 64 T & cor, coroutine$ * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) ) libcfa_public{64 T & cor, coroutine$ * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) ) { 65 65 verify( desc->cancellation ); 66 66 desc->state = Cancelled; … … 89 89 90 90 void __stack_prepare( __stack_info_t * this, size_t create_size ); 91 staticvoid __stack_clean ( __stack_info_t * this );91 void __stack_clean ( __stack_info_t * this ); 92 92 93 93 //----------------------------------------------------------------------------- … … 114 114 } 115 115 116 void ?{}( coroutine$ & this, const char name[], void * storage, size_t storageSize ) libcfa_publicwith( this ) {116 void ?{}( coroutine$ & this, const char name[], void * storage, size_t storageSize ) with( this ) { 117 117 (this.context){0p, 0p}; 118 118 (this.stack){storage, storageSize}; … … 124 124 } 125 125 126 void ^?{}(coroutine$& this) libcfa_public{126 void ^?{}(coroutine$& this) { 127 127 if(this.state != Halted && this.state != Start && this.state != Primed) { 128 128 coroutine$ * src = active_coroutine(); … … 147 147 // Not inline since only ever called once per coroutine 148 148 forall(T & | is_coroutine(T) | { EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)); }) 149 void prime(T& cor) libcfa_public{149 void prime(T& cor) { 150 150 coroutine$* this = get_coroutine(cor); 151 151 assert(this->state == Start); … … 155 155 } 156 156 157 static[void *, size_t] __stack_alloc( size_t storageSize ) {157 [void *, size_t] __stack_alloc( size_t storageSize ) { 158 158 const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment 159 159 assert(__page_size != 0l); … … 193 193 } 194 194 195 staticvoid __stack_clean ( __stack_info_t * this ) {195 void __stack_clean ( __stack_info_t * this ) { 196 196 void * storage = this->storage->limit; 197 197 … … 215 215 } 216 216 217 void __stack_prepare( __stack_info_t * this, size_t create_size ) libcfa_public{217 void __stack_prepare( __stack_info_t * this, size_t create_size ) { 218 218 const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment 219 219 bool userStack; -
libcfa/src/concurrency/coroutine.hfa
r74ec742 r29d8c02 113 113 114 114 extern void __stack_prepare( __stack_info_t * this, size_t size /* ignored if storage already allocated */); 115 extern void __stack_clean ( __stack_info_t * this ); 116 115 117 116 118 // Suspend implementation inlined for performance -
libcfa/src/concurrency/exception.cfa
r74ec742 r29d8c02 64 64 extern "C" { 65 65 66 struct exception_context_t * this_exception_context(void) libcfa_public{66 struct exception_context_t * this_exception_context(void) { 67 67 return &__get_stack( active_coroutine() )->exception_context; 68 68 } 69 69 70 _Unwind_Reason_Code __cfaehm_cancellation_unwind( struct _Unwind_Exception * unwind_exception ) libcfa_public{70 _Unwind_Reason_Code __cfaehm_cancellation_unwind( struct _Unwind_Exception * unwind_exception ) { 71 71 _Unwind_Stop_Fn stop_func; 72 72 void * stop_param; -
libcfa/src/concurrency/invoke.c
r74ec742 r29d8c02 36 36 extern void enable_interrupts( _Bool poll ); 37 37 38 libcfa_publicvoid __cfactx_invoke_coroutine(38 void __cfactx_invoke_coroutine( 39 39 void (*main)(void *), 40 40 void *this … … 70 70 } 71 71 72 libcfa_publicvoid __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct coroutine$ * cor) __attribute__ ((__noreturn__));72 void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct coroutine$ * cor) __attribute__ ((__noreturn__)); 73 73 void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct coroutine$ * cor) { 74 74 _Unwind_Reason_Code ret = _Unwind_ForcedUnwind( storage, __cfactx_coroutine_unwindstop, cor ); … … 77 77 } 78 78 79 libcfa_publicvoid __cfactx_invoke_thread(79 void __cfactx_invoke_thread( 80 80 void (*main)(void *), 81 81 void *this … … 98 98 } 99 99 100 libcfa_publicvoid __cfactx_start(100 void __cfactx_start( 101 101 void (*main)(void *), 102 102 struct coroutine$ * cor, -
libcfa/src/concurrency/io.cfa
r74ec742 r29d8c02 244 244 245 245 remote = true; 246 __STATS__( true, io.calls.helped++; )246 __STATS__( false, io.calls.helped++; ) 247 247 } 248 248 proc->io.target = MAX; … … 340 340 // for convenience, return both the index and the pointer to the sqe 341 341 // sqe == &sqes[idx] 342 struct $io_context * cfa_io_allocate(struct io_uring_sqe * sqes[], __u32 idxs[], __u32 want) libcfa_public{342 struct $io_context * cfa_io_allocate(struct io_uring_sqe * sqes[], __u32 idxs[], __u32 want) { 343 343 // __cfadbg_print_safe(io, "Kernel I/O : attempting to allocate %u\n", want); 344 344 … … 419 419 } 420 420 421 void cfa_io_submit( struct $io_context * inctx, __u32 idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1))) libcfa_public{421 void cfa_io_submit( struct $io_context * inctx, __u32 idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1))) { 422 422 // __cfadbg_print_safe(io, "Kernel I/O : attempting to submit %u (%s)\n", have, lazy ? "lazy" : "eager"); 423 423 -
libcfa/src/concurrency/io/call.cfa.in
r74ec742 r29d8c02 139 139 // I/O Interface 140 140 //============================================================================================= 141 #pragma GCC visibility push(default)142 141 """ 143 142 -
libcfa/src/concurrency/io/setup.cfa
r74ec742 r29d8c02 26 26 27 27 #if !defined(CFA_HAVE_LINUX_IO_URING_H) 28 void ?{}(io_context_params & this) libcfa_public{}28 void ?{}(io_context_params & this) {} 29 29 30 30 void ?{}($io_context & this, struct cluster & cl) {} … … 66 66 #pragma GCC diagnostic pop 67 67 68 void ?{}(io_context_params & this) libcfa_public{68 void ?{}(io_context_params & this) { 69 69 this.num_entries = 256; 70 70 } -
libcfa/src/concurrency/kernel.cfa
r74ec742 r29d8c02 389 389 390 390 // KERNEL_ONLY 391 staticvoid returnToKernel() {391 void returnToKernel() { 392 392 /* paranoid */ verify( ! __preemption_enabled() ); 393 393 coroutine$ * proc_cor = get_coroutine(kernelTLS().this_processor->runner); … … 547 547 } 548 548 549 void unpark( thread$ * thrd, unpark_hint hint ) libcfa_public{549 void unpark( thread$ * thrd, unpark_hint hint ) { 550 550 if( !thrd ) return; 551 551 … … 558 558 } 559 559 560 void park( void ) libcfa_public{560 void park( void ) { 561 561 __disable_interrupts_checked(); 562 562 /* paranoid */ verify( kernelTLS().this_thread->preempted == __NO_PREEMPTION ); … … 601 601 602 602 // KERNEL ONLY 603 bool force_yield( __Preemption_Reason reason ) libcfa_public{603 bool force_yield( __Preemption_Reason reason ) { 604 604 __disable_interrupts_checked(); 605 605 thread$ * thrd = kernelTLS().this_thread; … … 849 849 //----------------------------------------------------------------------------- 850 850 // Debug 851 bool threading_enabled(void) __attribute__((const)) libcfa_public{851 bool threading_enabled(void) __attribute__((const)) { 852 852 return true; 853 853 } … … 856 856 // Statistics 857 857 #if !defined(__CFA_NO_STATISTICS__) 858 void print_halts( processor & this ) libcfa_public{858 void print_halts( processor & this ) { 859 859 this.print_halts = true; 860 860 } … … 873 873 } 874 874 875 staticvoid crawl_cluster_stats( cluster & this ) {875 void crawl_cluster_stats( cluster & this ) { 876 876 // Stop the world, otherwise stats could get really messed-up 877 877 // this doesn't solve all problems but does solve many … … 889 889 890 890 891 void print_stats_now( cluster & this, int flags ) libcfa_public{891 void print_stats_now( cluster & this, int flags ) { 892 892 crawl_cluster_stats( this ); 893 893 __print_stats( this.stats, flags, "Cluster", this.name, (void*)&this ); -
libcfa/src/concurrency/kernel.hfa
r74ec742 r29d8c02 49 49 50 50 // Coroutine used py processors for the 2-step context switch 51 52 struct processorCtx_t { 53 struct coroutine$ self; 51 coroutine processorCtx_t { 54 52 struct processor * proc; 55 53 }; -
libcfa/src/concurrency/kernel/cluster.cfa
r74ec742 r29d8c02 49 49 50 50 // returns the maximum number of processors the RWLock support 51 __attribute__((weak)) unsigned __max_processors() libcfa_public{51 __attribute__((weak)) unsigned __max_processors() { 52 52 const char * max_cores_s = getenv("CFA_MAX_PROCESSORS"); 53 53 if(!max_cores_s) { -
libcfa/src/concurrency/kernel/private.hfa
r74ec742 r29d8c02 109 109 //----------------------------------------------------------------------------- 110 110 // Processor 111 void main(processorCtx_t &); 112 static inline coroutine$* get_coroutine(processorCtx_t & this) { return &this.self; } 111 void main(processorCtx_t *); 113 112 114 113 void * __create_pthread( pthread_t *, void * (*)(void *), void * ); -
libcfa/src/concurrency/kernel/startup.cfa
r74ec742 r29d8c02 120 120 #endif 121 121 122 cluster * mainCluster libcfa_public;122 cluster * mainCluster; 123 123 processor * mainProcessor; 124 124 thread$ * mainThread; … … 169 169 }; 170 170 171 staticvoid ?{}( current_stack_info_t & this ) {171 void ?{}( current_stack_info_t & this ) { 172 172 __stack_context_t ctx; 173 173 CtxGet( ctx ); … … 209 209 // Construct the processor context of the main processor 210 210 void ?{}(processorCtx_t & this, processor * proc) { 211 (this. self){ "Processor" };212 this. self.starter = 0p;211 (this.__cor){ "Processor" }; 212 this.__cor.starter = 0p; 213 213 this.proc = proc; 214 214 } … … 526 526 // Construct the processor context of non-main processors 527 527 static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info) { 528 (this. self){ info };528 (this.__cor){ info }; 529 529 this.proc = proc; 530 530 } … … 578 578 } 579 579 580 void ?{}(processor & this, const char name[], cluster & _cltr, thread$ * initT) libcfa_public{580 void ?{}(processor & this, const char name[], cluster & _cltr, thread$ * initT) { 581 581 ( this.terminated ){}; 582 582 ( this.runner ){}; … … 591 591 } 592 592 593 void ?{}(processor & this, const char name[], cluster & _cltr) libcfa_public{593 void ?{}(processor & this, const char name[], cluster & _cltr) { 594 594 (this){name, _cltr, 0p}; 595 595 } 596 596 597 597 extern size_t __page_size; 598 void ^?{}(processor & this) libcfa_public with( this ){598 void ^?{}(processor & this) with( this ){ 599 599 /* paranoid */ verify( !__atomic_load_n(&do_terminate, __ATOMIC_ACQUIRE) ); 600 600 __cfadbg_print_safe(runtime_core, "Kernel : core %p signaling termination\n", &this); … … 623 623 } 624 624 625 void ?{}(cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params) libcfa_publicwith( this ) {625 void ?{}(cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params) with( this ) { 626 626 this.name = name; 627 627 this.preemption_rate = preemption_rate; … … 658 658 } 659 659 660 void ^?{}(cluster & this) libcfa_public{660 void ^?{}(cluster & this) { 661 661 destroy(this.io.arbiter); 662 662 -
libcfa/src/concurrency/locks.cfa
r74ec742 r29d8c02 24 24 #include <stdlib.hfa> 25 25 26 #pragma GCC visibility push(default)27 28 26 //----------------------------------------------------------------------------- 29 27 // info_thread … … 118 116 } 119 117 120 staticvoid pop_and_set_new_owner( blocking_lock & this ) with( this ) {118 void pop_and_set_new_owner( blocking_lock & this ) with( this ) { 121 119 thread$ * t = &try_pop_front( blocked_threads ); 122 120 owner = t; … … 194 192 void ^?{}( alarm_node_wrap(L) & this ) { } 195 193 196 staticvoid timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {194 void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) { 197 195 // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin. 198 196 lock( cond->lock __cfaabi_dbg_ctx2 ); … … 218 216 219 217 // this casts the alarm node to our wrapped type since we used type erasure 220 staticvoid alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); }218 void alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); } 221 219 } 222 220 223 221 //----------------------------------------------------------------------------- 224 // Synchronization Locks222 // condition variable 225 223 forall(L & | is_blocking_lock(L)) { 226 224 227 //-----------------------------------------------------------------------------228 // condition variable229 225 void ?{}( condition_variable(L) & this ){ 230 226 this.lock{}; … … 235 231 void ^?{}( condition_variable(L) & this ){ } 236 232 237 staticvoid process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) {233 void process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) { 238 234 if(&popped != 0p) { 239 235 popped.signalled = true; … … 280 276 int counter( condition_variable(L) & this ) with(this) { return count; } 281 277 282 s tatic size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {278 size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) { 283 279 // add info_thread to waiting queue 284 280 insert_last( blocked_threads, *i ); … … 293 289 294 290 // helper for wait()'s' with no timeout 295 staticvoid queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {291 void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) { 296 292 lock( lock __cfaabi_dbg_ctx2 ); 297 293 size_t recursion_count = queue_and_get_recursion(this, &i); … … 310 306 311 307 // helper for wait()'s' with a timeout 312 staticvoid queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {308 void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) { 313 309 lock( lock __cfaabi_dbg_ctx2 ); 314 310 size_t recursion_count = queue_and_get_recursion(this, &info); … … 341 337 bool wait( condition_variable(L) & this, L & l, Duration duration ) with(this) { WAIT_TIME( 0 , &l , duration ) } 342 338 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ) with(this) { WAIT_TIME( info, &l , duration ) } 343 344 //-----------------------------------------------------------------------------345 // fast_cond_var346 void ?{}( fast_cond_var(L) & this ){347 this.blocked_threads{};348 #ifdef __CFA_DEBUG__349 this.lock_used = 0p;350 #endif351 }352 void ^?{}( fast_cond_var(L) & this ){ }353 354 bool notify_one( fast_cond_var(L) & this ) with(this) {355 bool ret = ! blocked_threads`isEmpty;356 if ( ret ) {357 info_thread(L) & popped = try_pop_front( blocked_threads );358 on_notify(*popped.lock, popped.t);359 }360 return ret;361 }362 bool notify_all( fast_cond_var(L) & this ) with(this) {363 bool ret = ! blocked_threads`isEmpty;364 while( ! blocked_threads`isEmpty ) {365 info_thread(L) & popped = try_pop_front( blocked_threads );366 on_notify(*popped.lock, popped.t);367 }368 return ret;369 }370 371 uintptr_t front( fast_cond_var(L) & this ) with(this) { return blocked_threads`isEmpty ? NULL : blocked_threads`first.info; }372 bool empty ( fast_cond_var(L) & this ) with(this) { return blocked_threads`isEmpty; }373 374 void wait( fast_cond_var(L) & this, L & l ) {375 wait( this, l, 0 );376 }377 378 void wait( fast_cond_var(L) & this, L & l, uintptr_t info ) with(this) {379 // brand cond lock with lock380 #ifdef __CFA_DEBUG__381 if ( lock_used == 0p ) lock_used = &l;382 else { assert(lock_used == &l); }383 #endif384 info_thread( L ) i = { active_thread(), info, &l };385 insert_last( blocked_threads, i );386 size_t recursion_count = on_wait( *i.lock );387 park( );388 on_wakeup(*i.lock, recursion_count);389 }390 339 } 391 340 -
libcfa/src/concurrency/locks.hfa
r74ec742 r29d8c02 73 73 static inline void on_notify( owner_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); } 74 74 75 //-----------------------------------------------------------------------------76 // MCS Lock77 75 struct mcs_node { 78 76 mcs_node * volatile next; … … 100 98 } 101 99 102 //-----------------------------------------------------------------------------103 // Linear backoff Spinlock104 100 struct linear_backoff_then_block_lock { 105 101 // Spin lock used for mutual exclusion … … 203 199 204 200 //----------------------------------------------------------------------------- 205 // Fast Block Lock206 207 // High efficiency minimal blocking lock208 // - No reacquire for cond var209 // - No recursive acquisition210 // - No ownership211 struct fast_block_lock {212 // Spin lock used for mutual exclusion213 __spinlock_t lock;214 215 // List of blocked threads216 dlist( thread$ ) blocked_threads;217 218 bool held:1;219 };220 221 static inline void ?{}( fast_block_lock & this ) with(this) {222 lock{};223 blocked_threads{};224 held = false;225 }226 static inline void ^?{}( fast_block_lock & this ) {}227 static inline void ?{}( fast_block_lock & this, fast_block_lock this2 ) = void;228 static inline void ?=?( fast_block_lock & this, fast_block_lock this2 ) = void;229 230 // if this is called recursively IT WILL DEADLOCK!!!!!231 static inline void lock(fast_block_lock & this) with(this) {232 lock( lock __cfaabi_dbg_ctx2 );233 if (held) {234 insert_last( blocked_threads, *active_thread() );235 unlock( lock );236 park( );237 return;238 }239 held = true;240 unlock( lock );241 }242 243 static inline void unlock(fast_block_lock & this) with(this) {244 lock( lock __cfaabi_dbg_ctx2 );245 /* paranoid */ verifyf( held != false, "Attempt to release lock %p that isn't held", &this );246 thread$ * t = &try_pop_front( blocked_threads );247 held = ( t ? true : false );248 unpark( t );249 unlock( lock );250 }251 252 static inline void on_notify(fast_block_lock & this, struct thread$ * t ) { unpark(t); }253 static inline size_t on_wait(fast_block_lock & this) { unlock(this); return 0; }254 static inline void on_wakeup(fast_block_lock & this, size_t recursion ) { }255 256 //-----------------------------------------------------------------------------257 201 // is_blocking_lock 258 202 trait is_blocking_lock(L & | sized(L)) { … … 282 226 // Synchronization Locks 283 227 forall(L & | is_blocking_lock(L)) { 284 285 //-----------------------------------------------------------------------------286 // condition_variable287 288 // The multi-tool condition variable289 // - can pass timeouts to wait for either a signal or timeout290 // - can wait without passing a lock291 // - can have waiters reacquire different locks while waiting on the same cond var292 // - has shadow queue293 // - can be signalled outside of critical sections with no locks held294 228 struct condition_variable { 295 229 // Spin lock used for mutual exclusion … … 324 258 bool wait( condition_variable(L) & this, L & l, Duration duration ); 325 259 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ); 326 327 //----------------------------------------------------------------------------- 328 // fast_cond_var 329 330 // The trimmed and slim condition variable 331 // - no internal lock so you must hold a lock while using this cond var 332 // - signalling without holding branded lock is UNSAFE! 333 // - only allows usage of one lock, cond var is branded after usage 334 struct fast_cond_var { 335 // List of blocked threads 336 dlist( info_thread(L) ) blocked_threads; 337 338 #ifdef __CFA_DEBUG__ 339 L * lock_used; 340 #endif 341 }; 342 343 344 void ?{}( fast_cond_var(L) & this ); 345 void ^?{}( fast_cond_var(L) & this ); 346 347 bool notify_one( fast_cond_var(L) & this ); 348 bool notify_all( fast_cond_var(L) & this ); 349 350 uintptr_t front( fast_cond_var(L) & this ); 351 352 bool empty ( fast_cond_var(L) & this ); 353 354 void wait( fast_cond_var(L) & this, L & l ); 355 void wait( fast_cond_var(L) & this, L & l, uintptr_t info ); 356 } 260 } -
libcfa/src/concurrency/monitor.cfa
r74ec742 r29d8c02 44 44 static inline void restore( monitor$ * ctx [], __lock_size_t count, __spinlock_t * locks [], unsigned int /*in */ recursions [], __waitfor_mask_t /*in */ masks [] ); 45 45 46 static inline void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info );47 static inline void ?{}(__condition_criterion_t & this );48 static inline void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t * owner );49 50 46 static inline void init ( __lock_size_t count, monitor$ * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ); 51 47 static inline void init_push( __lock_size_t count, monitor$ * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ); … … 247 243 248 244 // Leave single monitor 249 staticvoid __leave( monitor$ * this ) {245 void __leave( monitor$ * this ) { 250 246 // Lock the monitor spinlock 251 247 lock( this->lock __cfaabi_dbg_ctx2 ); … … 282 278 283 279 // Leave single monitor for the last time 284 staticvoid __dtor_leave( monitor$ * this, bool join ) {280 void __dtor_leave( monitor$ * this, bool join ) { 285 281 __cfaabi_dbg_debug_do( 286 282 if( active_thread() != this->owner ) { … … 348 344 // Ctor for monitor guard 349 345 // Sorts monitors before entering 350 void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count, fptr_t func ) libcfa_public{346 void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count, fptr_t func ) { 351 347 thread$ * thrd = active_thread(); 352 348 … … 373 369 } 374 370 375 void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count ) libcfa_public{371 void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count ) { 376 372 this{ m, count, 0p }; 377 373 } … … 379 375 380 376 // Dtor for monitor guard 381 void ^?{}( monitor_guard_t & this ) libcfa_public{377 void ^?{}( monitor_guard_t & this ) { 382 378 // __cfaabi_dbg_print_safe( "MGUARD : leaving %d\n", this.count); 383 379 … … 393 389 // Ctor for monitor guard 394 390 // Sorts monitors before entering 395 void ?{}( monitor_dtor_guard_t & this, monitor$ * m [], fptr_t func, bool join ) libcfa_public{391 void ?{}( monitor_dtor_guard_t & this, monitor$ * m [], fptr_t func, bool join ) { 396 392 // optimization 397 393 thread$ * thrd = active_thread(); … … 413 409 414 410 // Dtor for monitor guard 415 void ^?{}( monitor_dtor_guard_t & this ) libcfa_public{411 void ^?{}( monitor_dtor_guard_t & this ) { 416 412 // Leave the monitors in order 417 413 __dtor_leave( this.m, this.join ); … … 423 419 //----------------------------------------------------------------------------- 424 420 // Internal scheduling types 425 staticvoid ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info ) {421 void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info ) { 426 422 this.waiting_thread = waiting_thread; 427 423 this.count = count; … … 430 426 } 431 427 432 staticvoid ?{}(__condition_criterion_t & this ) with( this ) {428 void ?{}(__condition_criterion_t & this ) with( this ) { 433 429 ready = false; 434 430 target = 0p; … … 437 433 } 438 434 439 staticvoid ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t & owner ) {435 void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t & owner ) { 440 436 this.ready = false; 441 437 this.target = target; … … 446 442 //----------------------------------------------------------------------------- 447 443 // Internal scheduling 448 void wait( condition & this, uintptr_t user_info = 0 ) libcfa_public{444 void wait( condition & this, uintptr_t user_info = 0 ) { 449 445 brand_condition( this ); 450 446 … … 500 496 } 501 497 502 bool signal( condition & this ) libcfa_public{498 bool signal( condition & this ) { 503 499 if( is_empty( this ) ) { return false; } 504 500 … … 542 538 } 543 539 544 bool signal_block( condition & this ) libcfa_public{540 bool signal_block( condition & this ) { 545 541 if( !this.blocked.head ) { return false; } 546 542 … … 590 586 591 587 // Access the user_info of the thread waiting at the front of the queue 592 uintptr_t front( condition & this ) libcfa_public{588 uintptr_t front( condition & this ) { 593 589 verifyf( !is_empty(this), 594 590 "Attempt to access user data on an empty condition.\n" … … 612 608 // setup mask 613 609 // block 614 void __waitfor_internal( const __waitfor_mask_t & mask, int duration ) libcfa_public{610 void __waitfor_internal( const __waitfor_mask_t & mask, int duration ) { 615 611 // This statment doesn't have a contiguous list of monitors... 616 612 // Create one! … … 998 994 // Can't be accepted since a mutex stmt is effectively an anonymous routine 999 995 // Thus we do not need a monitor group 1000 void lock( monitor$ * this ) libcfa_public{996 void lock( monitor$ * this ) { 1001 997 thread$ * thrd = active_thread(); 1002 998 … … 1050 1046 // Leave routine for mutex stmt 1051 1047 // Is just a wrapper around __leave for the is_lock trait to see 1052 void unlock( monitor$ * this ) libcfa_public{ __leave( this ); }1048 void unlock( monitor$ * this ) { __leave( this ); } 1053 1049 1054 1050 // Local Variables: // -
libcfa/src/concurrency/monitor.hfa
r74ec742 r29d8c02 119 119 } 120 120 121 //void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info );122 //void ?{}(__condition_criterion_t & this );123 //void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t * owner );121 void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info ); 122 void ?{}(__condition_criterion_t & this ); 123 void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t * owner ); 124 124 125 125 struct condition { -
libcfa/src/concurrency/preemption.cfa
r74ec742 r29d8c02 38 38 #endif 39 39 40 __attribute__((weak)) Duration default_preemption() libcfa_public{40 __attribute__((weak)) Duration default_preemption() { 41 41 const char * preempt_rate_s = getenv("CFA_DEFAULT_PREEMPTION"); 42 42 if(!preempt_rate_s) { … … 238 238 //---------- 239 239 // special case for preemption since used often 240 __attribute__((optimize("no-reorder-blocks"))) bool __preemption_enabled() libcfa_public{240 __attribute__((optimize("no-reorder-blocks"))) bool __preemption_enabled() { 241 241 // create a assembler label before 242 242 // marked as clobber all to avoid movement … … 276 276 // Get data from the TLS block 277 277 // struct asm_region __cfaasm_get; 278 uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__ , visibility("default"))); //no inline to avoid problems278 uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__)); //no inline to avoid problems 279 279 uintptr_t __cfatls_get( unsigned long int offset ) { 280 280 // create a assembler label before … … 295 295 extern "C" { 296 296 // Disable interrupts by incrementing the counter 297 __attribute__((__noinline__, visibility("default"))) void disable_interrupts() libcfa_public{297 void disable_interrupts() { 298 298 // create a assembler label before 299 299 // marked as clobber all to avoid movement … … 326 326 // Enable interrupts by decrementing the counter 327 327 // If counter reaches 0, execute any pending __cfactx_switch 328 void enable_interrupts( bool poll ) libcfa_public{328 void enable_interrupts( bool poll ) { 329 329 // Cache the processor now since interrupts can start happening after the atomic store 330 330 processor * proc = __cfaabi_tls.this_processor; … … 362 362 //----------------------------------------------------------------------------- 363 363 // Kernel Signal Debug 364 void __cfaabi_check_preemption() libcfa_public{364 void __cfaabi_check_preemption() { 365 365 bool ready = __preemption_enabled(); 366 366 if(!ready) { abort("Preemption should be ready"); } -
libcfa/src/concurrency/ready_subqueue.hfa
r74ec742 r29d8c02 83 83 /* paranoid */ verify( node->link.ts != 0 ); 84 84 /* paranoid */ verify( this.anchor.ts != 0 ); 85 /* paranoid */ verify( (this.anchor.ts == MAX) == is_empty );86 85 return [node, this.anchor.ts]; 87 86 } … … 94 93 // Return the timestamp 95 94 static inline unsigned long long ts(__intrusive_lane_t & this) { 96 // Cannot verify 'emptiness'here since it may not be locked95 // Cannot verify here since it may not be locked 97 96 /* paranoid */ verify(this.anchor.ts != 0); 98 97 return this.anchor.ts; -
libcfa/src/concurrency/thread.cfa
r74ec742 r29d8c02 26 26 27 27 extern uint32_t __global_random_seed, __global_random_prime, __global_random_mask; 28 29 #pragma GCC visibility push(default)30 28 31 29 //----------------------------------------------------------------------------- -
libcfa/src/containers/maybe.cfa
r74ec742 r29d8c02 17 17 #include <assert.h> 18 18 19 #pragma GCC visibility push(default)20 19 21 20 forall(T) -
libcfa/src/containers/result.cfa
r74ec742 r29d8c02 17 17 #include <assert.h> 18 18 19 #pragma GCC visibility push(default)20 19 21 20 forall(T, E) -
libcfa/src/containers/string.cfa
r74ec742 r29d8c02 18 18 #include <stdlib.hfa> 19 19 20 #pragma GCC visibility push(default)21 20 22 21 /* -
libcfa/src/containers/string_sharectx.hfa
r74ec742 r29d8c02 16 16 #pragma once 17 17 18 #pragma GCC visibility push(default)19 20 18 //######################### String Sharing Context ######################### 21 19 22 20 struct VbyteHeap; 23 21 24 // A string_sharectx 22 // A string_sharectx 25 23 // 26 24 // Usage: -
libcfa/src/containers/vector.cfa
r74ec742 r29d8c02 18 18 #include <stdlib.hfa> 19 19 20 #pragma GCC visibility push(default)21 22 20 forall(T, allocator_t | allocator_c(T, allocator_t)) 23 staticvoid copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other);21 void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other); 24 22 25 23 //------------------------------------------------------------------------------ … … 85 83 86 84 forall(T, allocator_t | allocator_c(T, allocator_t)) 87 staticvoid copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other)85 void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other) 88 86 { 89 87 this->size = other->size; -
libcfa/src/device/cpu.cfa
r74ec742 r29d8c02 31 31 } 32 32 33 #include "bits/defs.hfa"34 33 #include "algorithms/range_iterator.hfa" 35 34 … … 457 456 } 458 457 459 libcfa_publiccpu_info_t cpu_info;458 cpu_info_t cpu_info; -
libcfa/src/exception.c
r74ec742 r29d8c02 27 27 #include "stdhdr/assert.h" 28 28 #include "virtual.h" 29 30 #pragma GCC visibility push(default)31 32 29 #include "lsda.h" 33 30 … … 264 261 #else // defined( __ARM_ARCH ) 265 262 // The return code from _Unwind_RaiseException seems to be corrupt on ARM at end of stack. 266 // This workaround tries to keep default exception handling working. 263 // This workaround tries to keep default exception handling working. 267 264 if ( ret == _URC_FATAL_PHASE1_ERROR || ret == _URC_FATAL_PHASE2_ERROR ) { 268 265 #endif -
libcfa/src/fstream.cfa
r74ec742 r29d8c02 22 22 #include <assert.h> 23 23 #include <errno.h> // errno 24 25 #pragma GCC visibility push(default)26 24 27 25 // *********************************** ofstream *********************************** … … 120 118 // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno ); 121 119 } // if 122 (os){ file }; // initialize 120 (os){ file }; // initialize 123 121 } // open 124 122 … … 159 157 va_list args; 160 158 va_start( args, format ); 161 159 162 160 int len; 163 161 for ( cnt; 10 ) { … … 243 241 // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno ); 244 242 } // if 245 (is){ file }; // initialize 243 (is){ file }; // initialize 246 244 } // open 247 245 -
libcfa/src/fstream.hfa
r74ec742 r29d8c02 18 18 #include "bits/weakso_locks.hfa" // mutex_lock 19 19 #include "iostream.hfa" 20 #include <exception.hfa> 20 21 21 22 -
libcfa/src/heap.cfa
r74ec742 r29d8c02 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Apr 29 19:05:03202213 // Update Count : 11 6712 // Last Modified On : Mon Apr 25 18:51:36 2022 13 // Update Count : 1147 14 14 // 15 15 … … 36 36 static bool traceHeap = false; 37 37 38 inline bool traceHeap() libcfa_public{ return traceHeap; }39 40 bool traceHeapOn() libcfa_public{38 inline bool traceHeap() { return traceHeap; } 39 40 bool traceHeapOn() { 41 41 bool temp = traceHeap; 42 42 traceHeap = true; … … 44 44 } // traceHeapOn 45 45 46 bool traceHeapOff() libcfa_public{46 bool traceHeapOff() { 47 47 bool temp = traceHeap; 48 48 traceHeap = false; … … 50 50 } // traceHeapOff 51 51 52 bool traceHeapTerm() libcfa_public{ return false; }52 bool traceHeapTerm() { return false; } 53 53 54 54 55 55 static bool prtFree = false; 56 56 57 staticbool prtFree() {57 bool prtFree() { 58 58 return prtFree; 59 59 } // prtFree 60 60 61 staticbool prtFreeOn() {61 bool prtFreeOn() { 62 62 bool temp = prtFree; 63 63 prtFree = true; … … 65 65 } // prtFreeOn 66 66 67 staticbool prtFreeOff() {67 bool prtFreeOff() { 68 68 bool temp = prtFree; 69 69 prtFree = false; … … 87 87 88 88 89 //####################### Heap Statistics #################### 89 #ifdef __CFA_DEBUG__ 90 static size_t allocUnfreed; // running total of allocations minus frees 91 92 static void prtUnfreed() { 93 if ( allocUnfreed != 0 ) { 94 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT. 95 char helpText[512]; 96 int len = snprintf( helpText, sizeof(helpText), "CFA warning (UNIX pid:%ld) : program terminating with %zu(0x%zx) bytes of storage allocated but not freed.\n" 97 "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n", 98 (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid 99 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug 100 } // if 101 } // prtUnfreed 102 103 extern int cfa_main_returned; // from interpose.cfa 104 extern "C" { 105 void heapAppStart() { // called by __cfaabi_appready_startup 106 allocUnfreed = 0; 107 } // heapAppStart 108 109 void heapAppStop() { // called by __cfaabi_appready_startdown 110 fclose( stdin ); fclose( stdout ); 111 if ( cfa_main_returned ) prtUnfreed(); // do not check unfreed storage if exit called 112 } // heapAppStop 113 } // extern "C" 114 #endif // __CFA_DEBUG__ 115 116 117 // statically allocated variables => zero filled. 118 static size_t heapExpand; // sbrk advance 119 static size_t mmapStart; // cross over point for mmap 120 static unsigned int maxBucketsUsed; // maximum number of buckets in use 121 // extern visibility, used by runtime kernel 122 size_t __page_size; // architecture pagesize 123 int __map_prot; // common mmap/mprotect protection 124 125 126 #define SPINLOCK 0 127 #define LOCKFREE 1 128 #define BUCKETLOCK SPINLOCK 129 #if BUCKETLOCK == SPINLOCK 130 #elif BUCKETLOCK == LOCKFREE 131 #include <stackLockFree.hfa> 132 #else 133 #error undefined lock type for bucket lock 134 #endif // LOCKFREE 135 136 // Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage. 137 // Break recursion by hardcoding number of buckets and statically checking number is correct after bucket array defined. 138 enum { NoBucketSizes = 91 }; // number of buckets sizes 139 140 struct Heap { 141 struct Storage { 142 struct Header { // header 143 union Kind { 144 struct RealHeader { 145 union { 146 struct { // 4-byte word => 8-byte header, 8-byte word => 16-byte header 147 union { 148 // 2nd low-order bit => zero filled, 3rd low-order bit => mmapped 149 // FreeHeader * home; // allocated block points back to home locations (must overlay alignment) 150 void * home; // allocated block points back to home locations (must overlay alignment) 151 size_t blockSize; // size for munmap (must overlay alignment) 152 #if BUCKETLOCK == SPINLOCK 153 Storage * next; // freed block points to next freed block of same size 154 #endif // SPINLOCK 155 }; 156 size_t size; // allocation size in bytes 157 }; 158 #if BUCKETLOCK == LOCKFREE 159 Link(Storage) next; // freed block points next freed block of same size (double-wide) 160 #endif // LOCKFREE 161 }; 162 } real; // RealHeader 163 164 struct FakeHeader { 165 uintptr_t alignment; // 1st low-order bit => fake header & alignment 166 uintptr_t offset; 167 } fake; // FakeHeader 168 } kind; // Kind 169 } header; // Header 170 171 char pad[libAlign() - sizeof( Header )]; 172 char data[0]; // storage 173 }; // Storage 174 175 static_assert( libAlign() >= sizeof( Storage ), "minimum alignment < sizeof( Storage )" ); 176 177 struct FreeHeader { 178 #if BUCKETLOCK == SPINLOCK 179 __spinlock_t lock; // must be first field for alignment 180 Storage * freeList; 181 #else 182 StackLF(Storage) freeList; 183 #endif // BUCKETLOCK 184 size_t blockSize; // size of allocations on this list 185 }; // FreeHeader 186 187 // must be first fields for alignment 188 __spinlock_t extlock; // protects allocation-buffer extension 189 FreeHeader freeLists[NoBucketSizes]; // buckets for different allocation sizes 190 191 void * heapBegin; // start of heap 192 void * heapEnd; // logical end of heap 193 size_t heapRemaining; // amount of storage not allocated in the current chunk 194 }; // Heap 195 196 #if BUCKETLOCK == LOCKFREE 197 static inline { 198 Link(Heap.Storage) * ?`next( Heap.Storage * this ) { return &this->header.kind.real.next; } 199 void ?{}( Heap.FreeHeader & ) {} 200 void ^?{}( Heap.FreeHeader & ) {} 201 } // distribution 202 #endif // LOCKFREE 203 204 static inline size_t getKey( const Heap.FreeHeader & freeheader ) { return freeheader.blockSize; } 205 206 207 #ifdef FASTLOOKUP 208 enum { LookupSizes = 65_536 + sizeof(Heap.Storage) }; // number of fast lookup sizes 209 static unsigned char lookup[LookupSizes]; // O(1) lookup for small sizes 210 #endif // FASTLOOKUP 211 212 static const off_t mmapFd = -1; // fake or actual fd for anonymous file 213 #ifdef __CFA_DEBUG__ 214 static bool heapBoot = 0; // detect recursion during boot 215 #endif // __CFA_DEBUG__ 216 217 218 // Size of array must harmonize with NoBucketSizes and individual bucket sizes must be multiple of 16. 219 // Smaller multiples of 16 and powers of 2 are common allocation sizes, so make them generate the minimum required bucket size. 220 // malloc(0) returns 0p, so no bucket is necessary for 0 bytes returning an address that can be freed. 221 static const unsigned int bucketSizes[] @= { // different bucket sizes 222 16 + sizeof(Heap.Storage), 32 + sizeof(Heap.Storage), 48 + sizeof(Heap.Storage), 64 + sizeof(Heap.Storage), // 4 223 96 + sizeof(Heap.Storage), 112 + sizeof(Heap.Storage), 128 + sizeof(Heap.Storage), // 3 224 160, 192, 224, 256 + sizeof(Heap.Storage), // 4 225 320, 384, 448, 512 + sizeof(Heap.Storage), // 4 226 640, 768, 896, 1_024 + sizeof(Heap.Storage), // 4 227 1_536, 2_048 + sizeof(Heap.Storage), // 2 228 2_560, 3_072, 3_584, 4_096 + sizeof(Heap.Storage), // 4 229 6_144, 8_192 + sizeof(Heap.Storage), // 2 230 9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360, 16_384 + sizeof(Heap.Storage), // 8 231 18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720, 32_768 + sizeof(Heap.Storage), // 8 232 36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440, 65_536 + sizeof(Heap.Storage), // 8 233 73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880, 131_072 + sizeof(Heap.Storage), // 8 234 147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760, 262_144 + sizeof(Heap.Storage), // 8 235 294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520, 524_288 + sizeof(Heap.Storage), // 8 236 655_360, 786_432, 917_504, 1_048_576 + sizeof(Heap.Storage), // 4 237 1_179_648, 1_310_720, 1_441_792, 1_572_864, 1_703_936, 1_835_008, 1_966_080, 2_097_152 + sizeof(Heap.Storage), // 8 238 2_621_440, 3_145_728, 3_670_016, 4_194_304 + sizeof(Heap.Storage), // 4 239 }; 240 241 static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0] ), "size of bucket array wrong" ); 242 243 // The constructor for heapManager is called explicitly in memory_startup. 244 static Heap heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing 245 246 247 //####################### Memory Allocation Routines Helpers #################### 90 248 91 249 … … 149 307 return lhs; 150 308 } // ?+=? 151 #endif // __STATISTICS__ 152 153 154 #define SPINLOCK 0 155 #define LOCKFREE 1 156 #define BUCKETLOCK SPINLOCK 157 #if BUCKETLOCK == SPINLOCK 158 #elif BUCKETLOCK == LOCKFREE 159 #include <stackLockFree.hfa> 160 #else 161 #error undefined lock type for bucket lock 162 #endif // LOCKFREE 163 164 // Recursive definitions: HeapManager needs size of bucket array and bucket area needs sizeof HeapManager storage. 165 // Break recursion by hardcoding number of buckets and statically checking number is correct after bucket array defined. 166 enum { NoBucketSizes = 91 }; // number of buckets sizes 167 168 struct Heap { 169 struct Storage { 170 struct Header { // header 171 union Kind { 172 struct RealHeader { 173 union { 174 struct { // 4-byte word => 8-byte header, 8-byte word => 16-byte header 175 union { 176 // 2nd low-order bit => zero filled, 3rd low-order bit => mmapped 177 // FreeHeader * home; // allocated block points back to home locations (must overlay alignment) 178 void * home; // allocated block points back to home locations (must overlay alignment) 179 size_t blockSize; // size for munmap (must overlay alignment) 180 #if BUCKETLOCK == SPINLOCK 181 Storage * next; // freed block points to next freed block of same size 182 #endif // SPINLOCK 183 }; 184 size_t size; // allocation size in bytes 185 }; 186 #if BUCKETLOCK == LOCKFREE 187 Link(Storage) next; // freed block points next freed block of same size (double-wide) 188 #endif // LOCKFREE 189 }; 190 } real; // RealHeader 191 192 struct FakeHeader { 193 uintptr_t alignment; // 1st low-order bit => fake header & alignment 194 uintptr_t offset; 195 } fake; // FakeHeader 196 } kind; // Kind 197 } header; // Header 198 199 char pad[libAlign() - sizeof( Header )]; 200 char data[0]; // storage 201 }; // Storage 202 203 static_assert( libAlign() >= sizeof( Storage ), "minimum alignment < sizeof( Storage )" ); 204 205 struct FreeHeader { 206 size_t blockSize __attribute__(( aligned (8) )); // size of allocations on this list 207 #if BUCKETLOCK == SPINLOCK 208 __spinlock_t lock; 209 Storage * freeList; 210 #else 211 StackLF(Storage) freeList; 212 #endif // BUCKETLOCK 213 } __attribute__(( aligned (8) )); // FreeHeader 214 215 FreeHeader freeLists[NoBucketSizes]; // buckets for different allocation sizes 216 217 __spinlock_t extlock; // protects allocation-buffer extension 218 void * heapBegin; // start of heap 219 void * heapEnd; // logical end of heap 220 size_t heapRemaining; // amount of storage not allocated in the current chunk 221 }; // Heap 222 223 #if BUCKETLOCK == LOCKFREE 224 static inline { 225 Link(Heap.Storage) * ?`next( Heap.Storage * this ) { return &this->header.kind.real.next; } 226 void ?{}( Heap.FreeHeader & ) {} 227 void ^?{}( Heap.FreeHeader & ) {} 228 } // distribution 229 #endif // LOCKFREE 230 231 static inline size_t getKey( const Heap.FreeHeader & freeheader ) { return freeheader.blockSize; } 232 233 234 #ifdef FASTLOOKUP 235 enum { LookupSizes = 65_536 + sizeof(Heap.Storage) }; // number of fast lookup sizes 236 static unsigned char lookup[LookupSizes]; // O(1) lookup for small sizes 237 #endif // FASTLOOKUP 238 239 static const off_t mmapFd = -1; // fake or actual fd for anonymous file 240 #ifdef __CFA_DEBUG__ 241 static bool heapBoot = 0; // detect recursion during boot 242 #endif // __CFA_DEBUG__ 243 244 245 // Size of array must harmonize with NoBucketSizes and individual bucket sizes must be multiple of 16. 246 // Smaller multiples of 16 and powers of 2 are common allocation sizes, so make them generate the minimum required bucket size. 247 // malloc(0) returns 0p, so no bucket is necessary for 0 bytes returning an address that can be freed. 248 static const unsigned int bucketSizes[] @= { // different bucket sizes 249 16 + sizeof(Heap.Storage), 32 + sizeof(Heap.Storage), 48 + sizeof(Heap.Storage), 64 + sizeof(Heap.Storage), // 4 250 96 + sizeof(Heap.Storage), 112 + sizeof(Heap.Storage), 128 + sizeof(Heap.Storage), // 3 251 160, 192, 224, 256 + sizeof(Heap.Storage), // 4 252 320, 384, 448, 512 + sizeof(Heap.Storage), // 4 253 640, 768, 896, 1_024 + sizeof(Heap.Storage), // 4 254 1_536, 2_048 + sizeof(Heap.Storage), // 2 255 2_560, 3_072, 3_584, 4_096 + sizeof(Heap.Storage), // 4 256 6_144, 8_192 + sizeof(Heap.Storage), // 2 257 9_216, 10_240, 11_264, 12_288, 13_312, 14_336, 15_360, 16_384 + sizeof(Heap.Storage), // 8 258 18_432, 20_480, 22_528, 24_576, 26_624, 28_672, 30_720, 32_768 + sizeof(Heap.Storage), // 8 259 36_864, 40_960, 45_056, 49_152, 53_248, 57_344, 61_440, 65_536 + sizeof(Heap.Storage), // 8 260 73_728, 81_920, 90_112, 98_304, 106_496, 114_688, 122_880, 131_072 + sizeof(Heap.Storage), // 8 261 147_456, 163_840, 180_224, 196_608, 212_992, 229_376, 245_760, 262_144 + sizeof(Heap.Storage), // 8 262 294_912, 327_680, 360_448, 393_216, 425_984, 458_752, 491_520, 524_288 + sizeof(Heap.Storage), // 8 263 655_360, 786_432, 917_504, 1_048_576 + sizeof(Heap.Storage), // 4 264 1_179_648, 1_310_720, 1_441_792, 1_572_864, 1_703_936, 1_835_008, 1_966_080, 2_097_152 + sizeof(Heap.Storage), // 8 265 2_621_440, 3_145_728, 3_670_016, 4_194_304 + sizeof(Heap.Storage), // 4 266 }; 267 268 static_assert( NoBucketSizes == sizeof(bucketSizes) / sizeof(bucketSizes[0] ), "size of bucket array wrong" ); 269 270 // The constructor for heapManager is called explicitly in memory_startup. 271 static Heap heapManager __attribute__(( aligned (128) )) @= {}; // size of cache line to prevent false sharing 272 273 274 //####################### Memory Allocation Routines Helpers #################### 275 276 277 #ifdef __CFA_DEBUG__ 278 static size_t allocUnfreed; // running total of allocations minus frees 279 280 static void prtUnfreed() { 281 if ( allocUnfreed != 0 ) { 282 // DO NOT USE STREAMS AS THEY MAY BE UNAVAILABLE AT THIS POINT. 283 char helpText[512]; 284 __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText), 285 "CFA warning (UNIX pid:%ld) : program terminating with %zu(0x%zx) bytes of storage allocated but not freed.\n" 286 "Possible cause is unfreed storage allocated by the program or system/library routines called from the program.\n", 287 (long int)getpid(), allocUnfreed, allocUnfreed ); // always print the UNIX pid 288 } // if 289 } // prtUnfreed 290 291 extern int cfa_main_returned; // from interpose.cfa 292 extern "C" { 293 void heapAppStart() { // called by __cfaabi_appready_startup 294 allocUnfreed = 0; 295 } // heapAppStart 296 297 void heapAppStop() { // called by __cfaabi_appready_startdown 298 fclose( stdin ); fclose( stdout ); 299 if ( cfa_main_returned ) prtUnfreed(); // do not check unfreed storage if exit called 300 } // heapAppStop 301 } // extern "C" 302 #endif // __CFA_DEBUG__ 303 304 305 #ifdef __STATISTICS__ 309 306 310 static HeapStatistics stats; // zero filled 307 311 static unsigned int sbrk_calls; … … 383 387 384 388 385 // statically allocated variables => zero filled.386 static size_t heapExpand; // sbrk advance387 static size_t mmapStart; // cross over point for mmap388 static unsigned int maxBucketsUsed; // maximum number of buckets in use389 // extern visibility, used by runtime kernel390 // would be cool to remove libcfa_public but it's needed for libcfathread391 libcfa_public size_t __page_size; // architecture pagesize392 libcfa_public int __map_prot; // common mmap/mprotect protection393 394 395 389 // thunk problem 396 390 size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) { … … 496 490 } else { 497 491 fakeHeader( header, alignment ); 498 if ( unlikely( MmappedBit( header ) ) ) { // mmapped ?499 verify( addr < heapBegin || heapEnd < addr );492 if ( unlikely( MmappedBit( header ) ) ) { 493 assert( addr < heapBegin || heapEnd < addr ); 500 494 size = ClearStickyBits( header->kind.real.blockSize ); // mmap size 501 495 return true; … … 509 503 checkHeader( header < (Heap.Storage.Header *)heapBegin || (Heap.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -) 510 504 511 Heap * homeManager; 512 if ( unlikely( freeHead == 0p || // freed and only free-list node => null link 513 // freed and link points at another free block not to a bucket in the bucket array. 514 freeHead < &freeLists[0] || &freeLists[NoBucketSizes] <= freeHead ) ) { 515 abort( "**** Error **** attempt to %s storage %p with corrupted header.\n" 516 "Possible cause is duplicate free on same block or overwriting of header information.", 517 name, addr ); 518 } // if 505 if ( freeHead < &freeLists[0] || &freeLists[NoBucketSizes] <= freeHead ) { 506 abort( "Attempt to %s storage %p with corrupted header.\n" 507 "Possible cause is duplicate free on same block or overwriting of header information.", 508 name, addr ); 509 } // if 519 510 #endif // __CFA_DEBUG__ 520 511 … … 569 560 sbrk_storage += increase; 570 561 #endif // __STATISTICS__ 571 572 562 #ifdef __CFA_DEBUG__ 573 563 // Set new memory to garbage so subsequent uninitialized usages might fail. … … 575 565 //Memset( (char *)heapEnd + heapRemaining, increase ); 576 566 #endif // __CFA_DEBUG__ 577 578 567 rem = heapRemaining + increase - size; 579 568 } // if … … 662 651 __atomic_add_fetch( &allocUnfreed, tsize, __ATOMIC_SEQ_CST ); 663 652 if ( traceHeap() ) { 664 char helpText[64]; 665 __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText), 666 "%p = Malloc( %zu ) (allocated %zu)\n", addr, size, tsize ); // print debug/nodebug 653 enum { BufferSize = 64 }; 654 char helpText[BufferSize]; 655 int len = snprintf( helpText, BufferSize, "%p = Malloc( %zu ) (allocated %zu)\n", addr, size, tsize ); 656 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug 667 657 } // if 668 658 #endif // __CFA_DEBUG__ … … 721 711 if ( traceHeap() ) { 722 712 char helpText[64]; 723 __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText),724 "Free( %p ) size:%zu\n", addr, size); // print debug/nodebug713 int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size ); 714 __cfaabi_bits_write( STDERR_FILENO, helpText, len ); // print debug/nodebug 725 715 } // if 726 716 #endif // __CFA_DEBUG__ … … 728 718 729 719 730 s tatic size_t prtFree( Heap & manager ) with( manager ) {720 size_t prtFree( Heap & manager ) with( manager ) { 731 721 size_t total = 0; 732 722 #ifdef __STATISTICS__ … … 880 870 // Allocates size bytes and returns a pointer to the allocated memory. The contents are undefined. If size is 0, 881 871 // then malloc() returns a unique pointer value that can later be successfully passed to free(). 882 void * malloc( size_t size ) libcfa_public{872 void * malloc( size_t size ) { 883 873 #ifdef __STATISTICS__ 884 874 if ( likely( size > 0 ) ) { … … 895 885 896 886 // Same as malloc() except size bytes is an array of dim elements each of elemSize bytes. 897 void * aalloc( size_t dim, size_t elemSize ) libcfa_public{887 void * aalloc( size_t dim, size_t elemSize ) { 898 888 size_t size = dim * elemSize; 899 889 #ifdef __STATISTICS__ … … 911 901 912 902 // Same as aalloc() with memory set to zero. 913 void * calloc( size_t dim, size_t elemSize ) libcfa_public{903 void * calloc( size_t dim, size_t elemSize ) { 914 904 size_t size = dim * elemSize; 915 905 if ( unlikely( size ) == 0 ) { // 0 BYTE ALLOCATION RETURNS NULL POINTER … … 952 942 // not 0p, then the call is equivalent to free(oaddr). Unless oaddr is 0p, it must have been returned by an earlier 953 943 // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done. 954 void * resize( void * oaddr, size_t size ) libcfa_public{944 void * resize( void * oaddr, size_t size ) { 955 945 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 956 946 if ( unlikely( size == 0 ) ) { // special cases … … 997 987 // Same as resize() but the contents are unchanged in the range from the start of the region up to the minimum of 998 988 // the old and new sizes. 999 void * realloc( void * oaddr, size_t size ) libcfa_public{989 void * realloc( void * oaddr, size_t size ) { 1000 990 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 1001 991 if ( unlikely( size == 0 ) ) { // special cases … … 1061 1051 1062 1052 // Same as realloc() except the new allocation size is large enough for an array of nelem elements of size elsize. 1063 void * reallocarray( void * oaddr, size_t dim, size_t elemSize ) libcfa_public{1053 void * reallocarray( void * oaddr, size_t dim, size_t elemSize ) { 1064 1054 return realloc( oaddr, dim * elemSize ); 1065 1055 } // reallocarray … … 1067 1057 1068 1058 // Same as malloc() except the memory address is a multiple of alignment, which must be a power of two. (obsolete) 1069 void * memalign( size_t alignment, size_t size ) libcfa_public{1059 void * memalign( size_t alignment, size_t size ) { 1070 1060 #ifdef __STATISTICS__ 1071 1061 if ( likely( size > 0 ) ) { … … 1082 1072 1083 1073 // Same as aalloc() with memory alignment. 1084 void * amemalign( size_t alignment, size_t dim, size_t elemSize ) libcfa_public{1074 void * amemalign( size_t alignment, size_t dim, size_t elemSize ) { 1085 1075 size_t size = dim * elemSize; 1086 1076 #ifdef __STATISTICS__ … … 1098 1088 1099 1089 // Same as calloc() with memory alignment. 1100 void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) libcfa_public{1090 void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) { 1101 1091 size_t size = dim * elemSize; 1102 1092 if ( unlikely( size ) == 0 ) { // 0 BYTE ALLOCATION RETURNS NULL POINTER … … 1137 1127 // Same as memalign(), but ISO/IEC 2011 C11 Section 7.22.2 states: the value of size shall be an integral multiple 1138 1128 // of alignment. This requirement is universally ignored. 1139 void * aligned_alloc( size_t alignment, size_t size ) libcfa_public{1129 void * aligned_alloc( size_t alignment, size_t size ) { 1140 1130 return memalign( alignment, size ); 1141 1131 } // aligned_alloc … … 1146 1136 // is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later be successfully passed to 1147 1137 // free(3). 1148 int posix_memalign( void ** memptr, size_t alignment, size_t size ) libcfa_public{1138 int posix_memalign( void ** memptr, size_t alignment, size_t size ) { 1149 1139 if ( unlikely( alignment < libAlign() || ! is_pow2( alignment ) ) ) return EINVAL; // check alignment 1150 1140 *memptr = memalign( alignment, size ); … … 1155 1145 // Allocates size bytes and returns a pointer to the allocated memory. The memory address shall be a multiple of the 1156 1146 // page size. It is equivalent to memalign(sysconf(_SC_PAGESIZE),size). 1157 void * valloc( size_t size ) libcfa_public{1147 void * valloc( size_t size ) { 1158 1148 return memalign( __page_size, size ); 1159 1149 } // valloc … … 1161 1151 1162 1152 // Same as valloc but rounds size to multiple of page size. 1163 void * pvalloc( size_t size ) libcfa_public{1153 void * pvalloc( size_t size ) { 1164 1154 return memalign( __page_size, ceiling2( size, __page_size ) ); // round size to multiple of page size 1165 1155 } // pvalloc … … 1169 1159 // or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behaviour occurs. If ptr is 1170 1160 // 0p, no operation is performed. 1171 void free( void * addr ) libcfa_public{1161 void free( void * addr ) { 1172 1162 if ( unlikely( addr == 0p ) ) { // special case 1173 1163 #ifdef __STATISTICS__ … … 1190 1180 1191 1181 // Returns the alignment of an allocation. 1192 size_t malloc_alignment( void * addr ) libcfa_public{1182 size_t malloc_alignment( void * addr ) { 1193 1183 if ( unlikely( addr == 0p ) ) return libAlign(); // minimum alignment 1194 1184 Heap.Storage.Header * header = HeaderAddr( addr ); … … 1202 1192 1203 1193 // Returns true if the allocation is zero filled, e.g., allocated by calloc(). 1204 bool malloc_zero_fill( void * addr ) libcfa_public{1194 bool malloc_zero_fill( void * addr ) { 1205 1195 if ( unlikely( addr == 0p ) ) return false; // null allocation is not zero fill 1206 1196 Heap.Storage.Header * header = HeaderAddr( addr ); … … 1213 1203 1214 1204 // Returns original total allocation size (not bucket size) => array size is dimension * sizeof(T). 1215 size_t malloc_size( void * addr ) libcfa_public{1205 size_t malloc_size( void * addr ) { 1216 1206 if ( unlikely( addr == 0p ) ) return 0; // null allocation has zero size 1217 1207 Heap.Storage.Header * header = HeaderAddr( addr ); … … 1225 1215 // Returns the number of usable bytes in the block pointed to by ptr, a pointer to a block of memory allocated by 1226 1216 // malloc or a related function. 1227 size_t malloc_usable_size( void * addr ) libcfa_public{1217 size_t malloc_usable_size( void * addr ) { 1228 1218 if ( unlikely( addr == 0p ) ) return 0; // null allocation has 0 size 1229 1219 Heap.Storage.Header * header; … … 1237 1227 1238 1228 // Prints (on default standard error) statistics about memory allocated by malloc and related functions. 1239 void malloc_stats( void ) libcfa_public{1229 void malloc_stats( void ) { 1240 1230 #ifdef __STATISTICS__ 1241 1231 printStats(); … … 1246 1236 1247 1237 // Changes the file descriptor where malloc_stats() writes statistics. 1248 int malloc_stats_fd( int fd __attribute__(( unused )) ) libcfa_public{1238 int malloc_stats_fd( int fd __attribute__(( unused )) ) { 1249 1239 #ifdef __STATISTICS__ 1250 1240 int temp = stats_fd; … … 1260 1250 // The string is printed on the file stream stream. The exported string includes information about all arenas (see 1261 1251 // malloc). 1262 int malloc_info( int options, FILE * stream __attribute__(( unused )) ) libcfa_public{1252 int malloc_info( int options, FILE * stream __attribute__(( unused )) ) { 1263 1253 if ( options != 0 ) { errno = EINVAL; return -1; } 1264 1254 #ifdef __STATISTICS__ … … 1272 1262 // Adjusts parameters that control the behaviour of the memory-allocation functions (see malloc). The param argument 1273 1263 // specifies the parameter to be modified, and value specifies the new value for that parameter. 1274 int mallopt( int option, int value ) libcfa_public{1264 int mallopt( int option, int value ) { 1275 1265 if ( value < 0 ) return 0; 1276 1266 choose( option ) { … … 1286 1276 1287 1277 // Attempt to release free memory at the top of the heap (by calling sbrk with a suitable argument). 1288 int malloc_trim( size_t ) libcfa_public{1278 int malloc_trim( size_t ) { 1289 1279 return 0; // => impossible to release memory 1290 1280 } // malloc_trim … … 1295 1285 // structure dynamically allocated via malloc, and a pointer to that data structure is returned as the function 1296 1286 // result. (The caller must free this memory.) 1297 void * malloc_get_state( void ) libcfa_public{1287 void * malloc_get_state( void ) { 1298 1288 return 0p; // unsupported 1299 1289 } // malloc_get_state … … 1302 1292 // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data 1303 1293 // structure pointed to by state. 1304 int malloc_set_state( void * ) libcfa_public{1294 int malloc_set_state( void * ) { 1305 1295 return 0; // unsupported 1306 1296 } // malloc_set_state … … 1308 1298 1309 1299 // Sets the amount (bytes) to extend the heap when there is insufficent free storage to service an allocation. 1310 __attribute__((weak)) size_t malloc_expansion() libcfa_public{ return __CFA_DEFAULT_HEAP_EXPANSION__; }1300 __attribute__((weak)) size_t malloc_expansion() { return __CFA_DEFAULT_HEAP_EXPANSION__; } 1311 1301 1312 1302 // Sets the crossover point between allocations occuring in the sbrk area or separately mmapped. 1313 __attribute__((weak)) size_t malloc_mmap_start() libcfa_public{ return __CFA_DEFAULT_MMAP_START__; }1303 __attribute__((weak)) size_t malloc_mmap_start() { return __CFA_DEFAULT_MMAP_START__; } 1314 1304 1315 1305 // Amount subtracted to adjust for unfreed program storage (debug only). 1316 __attribute__((weak)) size_t malloc_unfreed() libcfa_public{ return __CFA_DEFAULT_HEAP_UNFREED__; }1306 __attribute__((weak)) size_t malloc_unfreed() { return __CFA_DEFAULT_HEAP_UNFREED__; } 1317 1307 } // extern "C" 1318 1308 1319 1309 1320 1310 // Must have CFA linkage to overload with C linkage realloc. 1321 void * resize( void * oaddr, size_t nalign, size_t size ) libcfa_public{1311 void * resize( void * oaddr, size_t nalign, size_t size ) { 1322 1312 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 1323 1313 if ( unlikely( size == 0 ) ) { // special cases … … 1381 1371 1382 1372 1383 void * realloc( void * oaddr, size_t nalign, size_t size ) libcfa_public{1373 void * realloc( void * oaddr, size_t nalign, size_t size ) { 1384 1374 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 1385 1375 if ( unlikely( size == 0 ) ) { // special cases -
libcfa/src/interpose.cfa
r74ec742 r29d8c02 36 36 //============================================================================================= 37 37 38 staticvoid preload_libgcc(void) {38 void preload_libgcc(void) { 39 39 dlopen( "libgcc_s.so.1", RTLD_NOW ); 40 40 if ( const char * error = dlerror() ) abort( "interpose_symbol : internal error pre-loading libgcc, %s\n", error ); … … 42 42 43 43 typedef void (* generic_fptr_t)(void); 44 staticgeneric_fptr_t interpose_symbol( const char symbol[], const char version[] ) {44 generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) { 45 45 const char * error; 46 46 … … 83 83 //============================================================================================= 84 84 85 staticvoid sigHandler_segv( __CFA_SIGPARMS__ );86 staticvoid sigHandler_ill ( __CFA_SIGPARMS__ );87 staticvoid sigHandler_fpe ( __CFA_SIGPARMS__ );88 staticvoid sigHandler_abrt( __CFA_SIGPARMS__ );89 staticvoid sigHandler_term( __CFA_SIGPARMS__ );90 91 st atic struct {85 void sigHandler_segv( __CFA_SIGPARMS__ ); 86 void sigHandler_ill ( __CFA_SIGPARMS__ ); 87 void sigHandler_fpe ( __CFA_SIGPARMS__ ); 88 void sigHandler_abrt( __CFA_SIGPARMS__ ); 89 void sigHandler_term( __CFA_SIGPARMS__ ); 90 91 struct { 92 92 void (* exit)( int ) __attribute__(( __noreturn__ )); 93 93 void (* abort)( void ) __attribute__(( __noreturn__ )); 94 94 } __cabi_libc; 95 95 96 libcfa_publicint cfa_main_returned;96 int cfa_main_returned; 97 97 98 98 extern "C" { … … 148 148 149 149 // Forward declare abort after the __typeof__ call to avoid ambiguities 150 libcfa_publicvoid exit( int status, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));151 libcfa_publicvoid abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ ));152 libcfa_publicvoid abort( bool signalAbort, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ ));153 libcfa_publicvoid __abort( bool signalAbort, const char fmt[], va_list args ) __attribute__(( __nothrow__, __leaf__, __noreturn__ ));150 void exit( int status, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ )); 151 void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )); 152 void abort( bool signalAbort, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ )); 153 void __abort( bool signalAbort, const char fmt[], va_list args ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )); 154 154 155 155 extern "C" { 156 libcfa_publicvoid abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {156 void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) { 157 157 abort( false, "%s", "" ); 158 158 } 159 159 160 libcfa_publicvoid __cabi_abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )) {160 void __cabi_abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )) { 161 161 va_list argp; 162 162 va_start( argp, fmt ); … … 165 165 } 166 166 167 libcfa_publicvoid exit( int status ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {167 void exit( int status ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) { 168 168 __cabi_libc.exit( status ); 169 169 } -
libcfa/src/iostream.cfa
r74ec742 r29d8c02 32 32 #include "bitmanip.hfa" // high1 33 33 34 #pragma GCC visibility push(default)35 34 36 35 // *********************************** ostream *********************************** -
libcfa/src/limits.cfa
r74ec742 r29d8c02 20 20 #include <complex.h> 21 21 #include "limits.hfa" 22 23 #pragma GCC visibility push(default)24 22 25 23 // Integral Constants -
libcfa/src/memory.cfa
r74ec742 r29d8c02 16 16 #include "memory.hfa" 17 17 #include "stdlib.hfa" 18 19 #pragma GCC visibility push(default)20 18 21 19 // Internal data object. -
libcfa/src/parseargs.cfa
r74ec742 r29d8c02 24 24 #include "common.hfa" 25 25 #include "limits.hfa" 26 27 #pragma GCC visibility push(default)28 26 29 27 extern int cfa_args_argc __attribute__((weak)); … … 210 208 } 211 209 212 if(strcmp(arg, "Y") == 0) {213 value = true;214 return true;215 }216 217 if(strcmp(arg, "y") == 0) {218 value = true;219 return true;220 }221 222 210 if(strcmp(arg, "no") == 0) { 223 value = false;224 return true;225 }226 227 if(strcmp(arg, "N") == 0) {228 value = false;229 return true;230 }231 232 if(strcmp(arg, "n") == 0) {233 211 value = false; 234 212 return true; -
libcfa/src/parseconfig.cfa
r74ec742 r29d8c02 14 14 15 15 16 #pragma GCC visibility push(default)17 18 16 // *********************************** exceptions *********************************** 19 17 20 18 21 19 // TODO: Add names of missing config entries to exception (see further below) 22 vtable(Missing_Config_Entries) Missing_Config_Entries_vt;20 static vtable(Missing_Config_Entries) Missing_Config_Entries_vt; 23 21 24 22 [ void ] ?{}( & Missing_Config_Entries this, unsigned int num_missing ) { … … 33 31 34 32 35 vtable(Parse_Failure) Parse_Failure_vt;33 static vtable(Parse_Failure) Parse_Failure_vt; 36 34 37 35 [ void ] ?{}( & Parse_Failure this, [] char failed_key, [] char failed_value ) { … … 55 53 56 54 57 vtable(Validation_Failure) Validation_Failure_vt;55 static vtable(Validation_Failure) Validation_Failure_vt; 58 56 59 57 [ void ] ?{}( & Validation_Failure this, [] char failed_key, [] char failed_value ) { … … 112 110 113 111 114 static[ bool ] comments( & ifstream in, [] char name ) {112 [ bool ] comments( & ifstream in, [] char name ) { 115 113 while () { 116 114 in | name; -
libcfa/src/rational.cfa
r74ec742 r29d8c02 17 17 #include "fstream.hfa" 18 18 #include "stdlib.hfa" 19 20 #pragma GCC visibility push(default)21 19 22 20 forall( T | Arithmetic( T ) ) { -
libcfa/src/startup.cfa
r74ec742 r29d8c02 41 41 } // __cfaabi_appready_shutdown 42 42 43 void disable_interrupts() __attribute__(( weak )) libcfa_public{}44 void enable_interrupts() __attribute__(( weak )) libcfa_public{}43 void disable_interrupts() __attribute__(( weak )) {} 44 void enable_interrupts() __attribute__(( weak )) {} 45 45 46 46 … … 64 64 struct __spinlock_t; 65 65 extern "C" { 66 void __cfaabi_dbg_record_lock(struct __spinlock_t & this, const char prev_name[]) __attribute__(( weak )) libcfa_public{}66 void __cfaabi_dbg_record_lock(struct __spinlock_t & this, const char prev_name[]) __attribute__(( weak )) {} 67 67 } 68 68 -
libcfa/src/stdlib.cfa
r74ec742 r29d8c02 25 25 #include <complex.h> // _Complex_I 26 26 #include <assert.h> 27 28 #pragma GCC visibility push(default)29 27 30 28 //--------------------------------------- … … 227 225 #define GENERATOR LCG 228 226 229 // would be cool to make hidden but it's needed for libcfathread 230 __attribute__((visibility("default"))) uint32_t __global_random_seed; // sequential/concurrent 231 __attribute__((visibility("hidden"))) uint32_t __global_random_state; // sequential only 227 uint32_t __global_random_seed; // sequential/concurrent 228 uint32_t __global_random_state; // sequential only 232 229 233 230 void set_seed( PRNG & prng, uint32_t seed_ ) with( prng ) { state = seed = seed_; GENERATOR( state ); } // set seed -
libcfa/src/strstream.cfa
r74ec742 r29d8c02 1 // 1 // 2 2 // Cforall Version 1.0.0 Copyright (C) 2021 University of Waterloo 3 // 3 // 4 4 // The contents of this file are covered under the licence agreement in the 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // strstream.cfa -- 8 // 7 // strstream.cfa -- 8 // 9 9 // Author : Peter A. Buhr 10 10 // Created On : Thu Apr 22 22:24:35 2021 … … 12 12 // Last Modified On : Sun Oct 10 16:13:20 2021 13 13 // Update Count : 101 14 // 14 // 15 15 16 16 #include "strstream.hfa" … … 24 24 #include <unistd.h> // sbrk, sysconf 25 25 26 #pragma GCC visibility push(default)27 26 28 27 // *********************************** strstream *********************************** -
libcfa/src/time.cfa
r74ec742 r29d8c02 18 18 #include <stdio.h> // snprintf 19 19 #include <assert.h> 20 21 #pragma GCC visibility push(default)22 20 23 21 static char * nanomsd( long int ns, char * buf ) { // most significant digits -
libcfa/src/virtual.c
r74ec742 r29d8c02 16 16 #include "virtual.h" 17 17 #include "assert.h" 18 19 #pragma GCC visibility push(default)20 18 21 19 int __cfavir_is_parent( -
src/AST/Convert.cpp
r74ec742 r29d8c02 93 93 }; 94 94 95 template<typename T>96 Getter<T> get() {97 return Getter<T>{ *this };98 }95 template<typename T> 96 Getter<T> get() { 97 return Getter<T>{ *this }; 98 } 99 99 100 100 Label makeLabel(Statement * labelled, const ast::Label& label) { … … 1651 1651 // GET_ACCEPT_1(type, FunctionType), 1652 1652 std::move(forall), 1653 std::move(assertions),1654 1653 std::move(paramVars), 1655 1654 std::move(returnVars), … … 1665 1664 cache.emplace( old, decl ); 1666 1665 1666 decl->assertions = std::move(assertions); 1667 1667 decl->withExprs = GET_ACCEPT_V(withExprs, Expr); 1668 1668 decl->stmts = GET_ACCEPT_1(statements, CompoundStmt); … … 1730 1730 } 1731 1731 1732 1732 // Convert SynTree::EnumDecl to AST::EnumDecl 1733 1733 virtual void visit( const EnumDecl * old ) override final { 1734 1734 if ( inCache( old ) ) return; … … 2729 2729 ty->forall.emplace_back(new ast::TypeInstType(param)); 2730 2730 for (auto asst : param->assertions) { 2731 ty->assertions.emplace_back( 2732 new ast::VariableExpr(param->location, asst)); 2731 ty->assertions.emplace_back(new ast::VariableExpr({}, asst)); 2733 2732 } 2734 2733 } -
src/AST/Copy.cpp
r74ec742 r29d8c02 10 10 // Created On : Thr Nov 11 9:16:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T ue May 3 16:28:00 202213 // Update Count : 112 // Last Modified On : Thr Nov 11 9:28:00 2021 13 // Update Count : 0 14 14 // 15 15 … … 77 77 } 78 78 79 void postvisit( const UniqueExpr * node ) {80 readonlyInsert( &node->object );81 }82 83 79 void postvisit( const MemberExpr * node ) { 84 80 readonlyInsert( &node->member ); -
src/AST/Decl.cpp
r74ec742 r29d8c02 9 9 // Author : Aaron B. Moss 10 10 // Created On : Thu May 9 10:00:00 2019 11 // Last Modified By : Andrew Beach12 // Last Modified On : T hu May 5 12:10:00 202213 // Update Count : 2 411 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Jan 12 16:54:55 2021 13 // Update Count : 23 14 14 // 15 15 … … 53 53 // --- FunctionDecl 54 54 55 FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name, 55 FunctionDecl::FunctionDecl( const CodeLocation & loc, const std::string & name, 56 56 std::vector<ptr<TypeDecl>>&& forall, 57 57 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, … … 74 74 } 75 75 this->type = ftype; 76 }77 78 FunctionDecl::FunctionDecl( const CodeLocation & location, const std::string & name,79 std::vector<ptr<TypeDecl>>&& forall, std::vector<ptr<DeclWithType>>&& assertions,80 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,81 CompoundStmt * stmts, Storage::Classes storage, Linkage::Spec linkage,82 std::vector<ptr<Attribute>>&& attrs, Function::Specs fs, bool isVarArgs)83 : DeclWithType( location, name, storage, linkage, std::move(attrs), fs ),84 params( std::move(params) ), returns( std::move(returns) ),85 type_params( std::move( forall) ), assertions( std::move( assertions ) ),86 type( nullptr ), stmts( stmts ) {87 FunctionType * type = new FunctionType( (isVarArgs) ? VariableArgs : FixedArgs );88 for ( auto & param : this->params ) {89 type->params.emplace_back( param->get_type() );90 }91 for ( auto & ret : this->returns ) {92 type->returns.emplace_back( ret->get_type() );93 }94 for ( auto & param : this->type_params ) {95 type->forall.emplace_back( new TypeInstType( param ) );96 }97 for ( auto & assertion : this->assertions ) {98 type->assertions.emplace_back(99 new VariableExpr( assertion->location, assertion ) );100 }101 this->type = type;102 76 } 103 77 -
src/AST/Decl.hpp
r74ec742 r29d8c02 9 9 // Author : Aaron B. Moss 10 10 // Created On : Thu May 9 10:00:00 2019 11 // Last Modified By : Andrew Beach12 // Last Modified On : Thu May 5 12:09:00 202213 // Update Count : 3 311 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Mar 12 18:25:05 2021 13 // Update Count : 32 14 14 // 15 15 … … 135 135 std::vector< ptr<Expr> > withExprs; 136 136 137 // The difference between the two constructors is in how they handle138 // assertions. The first constructor uses the assertions from the type139 // parameters, in the style of the old ast, and puts them on the type.140 // The second takes an explicite list of assertions and builds a list of141 // references to them on the type.142 143 137 FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall, 144 138 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 145 139 CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C, 146 140 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false); 147 148 FunctionDecl( const CodeLocation & location, const std::string & name, 149 std::vector<ptr<TypeDecl>>&& forall, std::vector<ptr<DeclWithType>>&& assertions, 150 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 151 CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C, 152 std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false); 141 // : DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), params(std::move(params)), returns(std::move(returns)), 142 // stmts( stmts ) {} 153 143 154 144 const Type * get_type() const override; -
src/AST/Expr.cpp
r74ec742 r29d8c02 10 10 // Created On : Wed May 15 17:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Created On : Wed May 18 13:56:00 202213 // Update Count : 812 // Created On : Tue Nov 30 14:23:00 2021 13 // Update Count : 7 14 14 // 15 15 … … 21 21 22 22 #include "Copy.hpp" // for shallowCopy 23 #include "Eval.hpp" // for call 23 24 #include "GenericSubstitution.hpp" 24 25 #include "LinkageSpec.hpp" … … 66 67 // --- UntypedExpr 67 68 68 bool UntypedExpr::get_lvalue() const {69 std::string fname = InitTweak::getFunctionName( this );70 return lvalueFunctionNames.count( fname );71 }72 73 69 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) { 74 70 assert( arg ); 75 71 76 UntypedExpr * ret = c reateCall( loc, "*?", { arg });72 UntypedExpr * ret = call( loc, "*?", arg ); 77 73 if ( const Type * ty = arg->result ) { 78 74 const Type * base = InitTweak::getPointerBase( ty ); … … 91 87 } 92 88 89 bool UntypedExpr::get_lvalue() const { 90 std::string fname = InitTweak::getFunctionName( this ); 91 return lvalueFunctionNames.count( fname ); 92 } 93 93 94 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) { 94 95 assert( lhs && rhs ); 95 96 96 UntypedExpr * ret = c reateCall( loc, "?=?", { lhs, rhs });97 UntypedExpr * ret = call( loc, "?=?", lhs, rhs ); 97 98 if ( lhs->result && rhs->result ) { 98 99 // if both expressions are typed, assumes that this assignment is a C bitwise assignment, … … 101 102 } 102 103 return ret; 103 }104 105 UntypedExpr * UntypedExpr::createCall( const CodeLocation & loc,106 const std::string & name, std::vector<ptr<Expr>> && args ) {107 return new UntypedExpr( loc,108 new NameExpr( loc, name ), std::move( args ) );109 104 } 110 105 -
src/AST/Expr.hpp
r74ec742 r29d8c02 230 230 /// Creates a new assignment expression 231 231 static UntypedExpr * createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ); 232 /// Creates a new call of a variable.233 static UntypedExpr * createCall( const CodeLocation & loc,234 const std::string & name, std::vector<ptr<Expr>> && args );235 232 236 233 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 787 784 public: 788 785 ptr<Expr> expr; 789 readonly<ObjectDecl> object;786 ptr<ObjectDecl> object; 790 787 ptr<VariableExpr> var; 791 788 unsigned long long id; -
src/AST/Label.hpp
r74ec742 r29d8c02 34 34 std::vector< ptr<Attribute> > attributes; 35 35 36 Label( const CodeLocation&loc, const std::string& name = "",36 Label( CodeLocation loc, const std::string& name = "", 37 37 std::vector<ptr<Attribute>> && attrs = std::vector<ptr<Attribute>>{} ) 38 38 : location( loc ), name( name ), attributes( attrs ) {} -
src/AST/Node.hpp
r74ec742 r29d8c02 10 10 // Created On : Wed May 8 10:27:04 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon May 9 10:20:00 202213 // Update Count : 812 // Last Modified On : Fri Mar 25 10:33:00 2022 13 // Update Count : 7 14 14 // 15 15 … … 49 49 50 50 bool unique() const { return strong_count == 1; } 51 bool isManaged() const { return strong_count > 0; } 52 bool isReferenced() const { return weak_count > 0; } 53 bool isStable() const { 54 return (1 == strong_count || (1 < strong_count && 0 == weak_count)); 55 } 51 bool isManaged() const {return strong_count > 0; } 56 52 57 53 private: -
src/AST/Pass.proto.hpp
r74ec742 r29d8c02 131 131 template< typename node_t > 132 132 struct result1 { 133 bool differs = false;134 const node_t * value = nullptr;133 bool differs; 134 const node_t * value; 135 135 136 136 template< typename object_t, typename super_t, typename field_t > … … 151 151 }; 152 152 153 bool differs = false;153 bool differs; 154 154 container_t< delta > values; 155 155 … … 167 167 template< template<class...> class container_t, typename node_t > 168 168 struct resultN { 169 bool differs = false;169 bool differs; 170 170 container_t<ptr<node_t>> values; 171 171 -
src/AST/Stmt.cpp
r74ec742 r29d8c02 9 9 // Author : Aaron B. Moss 10 10 // Created On : Wed May 8 13:00:00 2019 11 // Last Modified By : Andrew Beach12 // Last Modified On : Tue May 3 15:18:20 202213 // Update Count : 411 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Feb 2 19:01:20 2022 13 // Update Count : 3 14 14 // 15 15 16 16 #include "Stmt.hpp" 17 17 18 #include "Copy.hpp" 18 19 19 #include "DeclReplacer.hpp" 20 20 #include "Type.hpp" … … 23 23 24 24 // --- CompoundStmt 25 CompoundStmt::CompoundStmt( const CompoundStmt& other ) : Stmt(other), kids() { 26 // Statements can have weak references to them, if that happens inserting 27 // the original node into the new list will put the original node in a 28 // bad state, where it cannot be mutated. To avoid this, just perform an 29 // additional shallow copy on the statement. 30 for ( const Stmt * kid : other.kids ) { 31 if ( kid->isReferenced() ) { 32 kids.emplace_back( ast::shallowCopy( kid ) ); 33 } else { 34 kids.emplace_back( kid ); 35 } 36 } 37 25 CompoundStmt::CompoundStmt( const CompoundStmt& other ) : Stmt(other), kids(other.kids) { 38 26 // when cloning a compound statement, we may end up cloning declarations which 39 27 // are referred to by VariableExprs throughout the block. Cloning a VariableExpr -
src/AST/Stmt.hpp
r74ec742 r29d8c02 58 58 // cannot be, they are sub-types of this type, for organization. 59 59 60 StmtClause( const CodeLocation & loc )60 StmtClause( const CodeLocation & loc ) 61 61 : ParseNode(loc) {} 62 62 … … 396 396 class WaitForClause final : public StmtClause { 397 397 public: 398 ptr<Expr> target_func;399 std::vector<ptr<Expr>> target_args;400 ptr<Stmt> stmt;401 ptr<Expr> cond;402 403 WaitForClause( const CodeLocation & loc )398 ptr<Expr> target_func; 399 std::vector<ptr<Expr>> target_args; 400 ptr<Stmt> stmt; 401 ptr<Expr> cond; 402 403 WaitForClause( const CodeLocation & loc ) 404 404 : StmtClause( loc ) {} 405 405 406 406 const WaitForClause * accept( Visitor & v ) const override { return v.visit( this ); } 407 407 private: 408 WaitForClause * clone() const override { return new WaitForClause{ *this }; }409 MUTATE_FRIEND408 WaitForClause * clone() const override { return new WaitForClause{ *this }; } 409 MUTATE_FRIEND 410 410 }; 411 411 -
src/AST/Util.cpp
r74ec742 r29d8c02 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Util. cpp -- General utilities for working with the AST.7 // Util.hpp -- General utilities for working with the AST. 8 8 // 9 9 // Author : Andrew Beach 10 10 // Created On : Wed Jan 19 9:46:00 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed May 11 16:16:00 202213 // Update Count : 312 // Last Modified On : Fri Mar 11 18:07:00 2022 13 // Update Count : 1 14 14 // 15 15 … … 46 46 47 47 /// Check that every note that can has a set CodeLocation. 48 void isCodeLocationSet( const ParseNode * node ) { 49 assert( node->location.isSet() ); 50 } 51 52 void areLabelLocationsSet( const Stmt * stmt ) { 53 for ( const Label& label : stmt->labels ) { 54 assert( label.location.isSet() ); 48 struct SetCodeLocationsCore { 49 void previsit( const ParseNode * node ) { 50 assert( node->location.isSet() ); 55 51 } 56 } 57 58 /// Make sure the reference counts are in a valid combination. 59 void isStable( const Node * node ) { 60 assert( node->isStable() ); 61 } 62 63 /// Check that a FunctionDecl is synchronized with it's FunctionType. 64 void functionDeclMatchesType( const FunctionDecl * decl ) { 65 // The type is a cache of sorts, if it is missing that is only a 66 // problem if isTypeFixed is set. 67 if ( decl->isTypeFixed ) { 68 assert( decl->type ); 69 } else if ( !decl->type ) { 70 return; 71 } 72 73 const FunctionType * type = decl->type; 74 75 // Check that `type->forall` corresponds with `decl->type_params`. 76 assert( type->forall.size() == decl->type_params.size() ); 77 // Check that `type->assertions` corresponds with `decl->assertions`. 78 assert( type->assertions.size() == decl->assertions.size() ); 79 // Check that `type->params` corresponds with `decl->params`. 80 assert( type->params.size() == decl->params.size() ); 81 // Check that `type->returns` corresponds with `decl->returns`. 82 assert( type->returns.size() == decl->returns.size() ); 83 } 52 }; 84 53 85 54 struct InvariantCore { … … 87 56 // None of the passes should make changes so ordering doesn't matter. 88 57 NoStrongCyclesCore no_strong_cycles; 58 SetCodeLocationsCore set_code_locations; 89 59 90 60 void previsit( const Node * node ) { 91 61 no_strong_cycles.previsit( node ); 92 isStable( node );93 62 } 94 63 95 64 void previsit( const ParseNode * node ) { 96 previsit( (const Node *)node ); 97 isCodeLocationSet( node ); 98 } 99 100 void previsit( const FunctionDecl * node ) { 101 previsit( (const ParseNode *)node ); 102 functionDeclMatchesType( node ); 103 } 104 105 void previsit( const Stmt * node ) { 106 previsit( (const ParseNode *)node ); 107 areLabelLocationsSet( node ); 65 no_strong_cycles.previsit( node ); 66 set_code_locations.previsit( node ); 108 67 } 109 68 -
src/AST/module.mk
r74ec742 r29d8c02 29 29 AST/DeclReplacer.cpp \ 30 30 AST/DeclReplacer.hpp \ 31 AST/Eval.hpp \ 31 32 AST/Expr.cpp \ 32 33 AST/Expr.hpp \ -
src/CodeGen/CodeGenerator.cc
r74ec742 r29d8c02 1238 1238 } // namespace CodeGen 1239 1239 1240 1241 unsigned Indenter::tabsize = 2; 1242 1243 std::ostream & operator<<( std::ostream & out, const BaseSyntaxNode * node ) { 1244 if ( node ) { 1245 node->print( out ); 1246 } else { 1247 out << "nullptr"; 1248 } 1249 return out; 1250 } 1251 1240 1252 // Local Variables: // 1241 1253 // tab-width: 4 // -
src/CodeGen/FixMain.cc
r74ec742 r29d8c02 49 49 50 50 } 51 52 bool FixMain::replace_main = false; 51 53 52 54 template<typename container> -
src/CodeGen/LinkOnce.cc
r74ec742 r29d8c02 53 53 new ConstantExpr( Constant::from_string( section_name ) ) 54 54 ); 55 56 // Unconditionnaly add "visibility(default)" to anything with gnu.linkonce57 // visibility is a mess otherwise58 attributes.push_back(new Attribute("visibility", {new ConstantExpr( Constant::from_string( "default" ) )}));59 60 55 } 61 56 visit_children = false; -
src/CodeGen/module.mk
r74ec742 r29d8c02 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Andrew Beach13 ## Last Modified On : Tue May 17 14:26:00 202214 ## Update Count : 512 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Sat Dec 14 07:29:42 2019 14 ## Update Count : 4 15 15 ############################################################################### 16 16 17 #SRC += ArgTweak/Rewriter.cc \ 18 # ArgTweak/Mutate.cc 19 17 20 SRC_CODEGEN = \ 18 CodeGen/FixMain2.cc \19 CodeGen/FixMain.h \20 CodeGen/OperatorTable.cc \21 CodeGen/OperatorTable.h22 23 SRC += $(SRC_CODEGEN) \24 21 CodeGen/CodeGenerator.cc \ 25 22 CodeGen/CodeGenerator.h \ 26 CodeGen/Generate.cc \27 CodeGen/Generate.h \28 23 CodeGen/FixMain.cc \ 29 CodeGen/FixNames.cc \ 30 CodeGen/FixNames.h \ 24 CodeGen/FixMain.h \ 31 25 CodeGen/GenType.cc \ 32 26 CodeGen/GenType.h \ 33 27 CodeGen/LinkOnce.cc \ 34 28 CodeGen/LinkOnce.h \ 29 CodeGen/OperatorTable.cc \ 30 CodeGen/OperatorTable.h \ 35 31 CodeGen/Options.h 36 32 33 SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/Generate.h CodeGen/FixNames.cc CodeGen/FixNames.h 37 34 SRCDEMANGLE += $(SRC_CODEGEN) -
src/Common/CodeLocationTools.cpp
r74ec742 r29d8c02 10 10 // Created On : Fri Dec 4 15:42:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed May 11 16:16:00 202213 // Update Count : 512 // Last Modified On : Mon Mar 14 15:14:00 2022 13 // Update Count : 4 14 14 // 15 15 … … 24 24 namespace { 25 25 26 // There are a lot of helpers in this file that could be used much more 27 // generally if anyone has another use for them. 28 29 // Check if a node type has a code location. 30 template<typename node_t> 31 struct has_code_location : public std::is_base_of<ast::ParseNode, node_t> {}; 32 33 template<typename node_t, bool has_location> 34 struct __GetCL; 35 36 template<typename node_t> 37 struct __GetCL<node_t, true> { 38 static inline CodeLocation const * get( node_t const * node ) { 39 return &node->location; 40 } 41 42 static inline CodeLocation * get( node_t * node ) { 43 return &node->location; 44 } 45 }; 46 47 template<typename node_t> 48 struct __GetCL<node_t, false> { 49 static inline CodeLocation * get( node_t const * ) { 50 return nullptr; 51 } 52 }; 53 54 template<typename node_t> 55 CodeLocation const * get_code_location( node_t const * node ) { 56 return __GetCL< node_t, has_code_location< node_t >::value >::get( node ); 57 } 58 59 template<typename node_t> 60 CodeLocation * get_code_location( node_t * node ) { 61 return __GetCL< node_t, has_code_location< node_t >::value >::get( node ); 62 } 63 26 64 // Fill every location with a nearby (parent) location. 27 65 class FillCore : public ast::WithGuards { 28 66 CodeLocation const * parent; 67 public: 68 FillCore() : parent( nullptr ) {} 29 69 30 70 template<typename node_t> 31 node_t const * parse_visit( node_t const * node ) { 32 if ( node->location.isUnset() ) { 71 node_t const * previsit( node_t const * node ) { 72 GuardValue( parent ); 73 CodeLocation const * location = get_code_location( node ); 74 if ( location && location->isUnset() ) { 33 75 assert( parent ); 34 76 node_t * newNode = ast::mutate( node ); 35 newNode->location = *parent; 77 CodeLocation * newLocation = get_code_location( newNode ); 78 assert( newLocation ); 79 *newLocation = *parent; 80 parent = newLocation; 36 81 return newNode; 37 } 38 GuardValue( parent ) = &node->location; 82 } else if ( location ) { 83 parent = location; 84 } 39 85 return node; 40 }41 42 bool hasUnsetLabels( const ast::Stmt * stmt ) {43 for ( const ast::Label& label : stmt->labels ) {44 if ( label.location.isUnset() ) {45 return true;46 }47 }48 return false;49 }50 51 template<typename node_t>52 node_t const * stmt_visit( node_t const * node ) {53 assert( node->location.isSet() );54 55 if ( hasUnsetLabels( node ) ) {56 node_t * newNode = ast::mutate( node );57 for ( ast::Label& label : newNode->labels ) {58 if ( label.location.isUnset() ) {59 label.location = newNode->location;60 }61 }62 return newNode;63 }64 return node;65 }66 67 template<typename node_t>68 auto visit( node_t const * node, long ) {69 return node;70 }71 72 template<typename node_t>73 auto visit( node_t const * node, int ) -> typename74 std::remove_reference< decltype( node->location, node ) >::type {75 return parse_visit( node );76 }77 78 template<typename node_t>79 auto visit( node_t const * node, char ) -> typename80 std::remove_reference< decltype( node->labels, node ) >::type {81 return stmt_visit( parse_visit( node ) );82 }83 84 public:85 FillCore() : parent( nullptr ) {}86 FillCore( const CodeLocation& location ) : parent( &location ) {87 assert( location.isSet() );88 }89 90 template<typename node_t>91 node_t const * previsit( node_t const * node ) {92 return visit( node, '\0' );93 86 } 94 87 }; … … 240 233 241 234 template<typename node_t> 242 auto previsit( node_t const * node ) -> decltype( node->location, void() ) { 243 if ( node->location.isUnset() ) { 235 void previsit( node_t const * node ) { 236 CodeLocation const * location = get_code_location( node ); 237 if ( location && location->isUnset() ) { 244 238 unset.push_back( node ); 239 } 240 } 241 }; 242 243 class LocalFillCore : public ast::WithGuards { 244 CodeLocation const * parent; 245 public: 246 LocalFillCore( CodeLocation const & location ) : parent( &location ) { 247 assert( location.isSet() ); 248 } 249 250 template<typename node_t> 251 auto previsit( node_t const * node ) 252 -> typename std::enable_if<has_code_location<node_t>::value, node_t const *>::type { 253 if ( node->location.isSet() ) { 254 GuardValue( parent ) = &node->location; 255 return node; 256 } else { 257 node_t * mut = ast::mutate( node ); 258 mut->location = *parent; 259 return mut; 245 260 } 246 261 } … … 289 304 ast::Node const * localFillCodeLocations( 290 305 CodeLocation const & location , ast::Node const * node ) { 291 ast::Pass< FillCore> visitor( location );306 ast::Pass<LocalFillCore> visitor( location ); 292 307 return node->accept( visitor ); 293 308 } -
src/Common/Indenter.h
r74ec742 r29d8c02 10 10 // Created On : Fri Jun 30 16:55:23 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri May 13 14:10:00 202213 // Update Count : 212 // Last Modified On : Fri Aug 11 11:15:00 2017 13 // Update Count : 1 14 14 // 15 15 16 #pragma once 17 18 #include <ostream> 16 #ifndef INDENTER_H 17 #define INDENTER_H 19 18 20 19 struct Indenter { … … 38 37 return out << std::string(indent.indent * indent.amt, ' '); 39 38 } 39 40 #endif // INDENTER_H -
src/Common/SemanticError.h
r74ec742 r29d8c02 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed May 4 14:08:26 202213 // Update Count : 3 512 // Last Modified On : Thu Jul 19 10:09:17 2018 13 // Update Count : 31 14 14 // 15 15 … … 59 59 {"aggregate-forward-decl" , Severity::Warn , "forward declaration of nested aggregate: %s" }, 60 60 {"superfluous-decl" , Severity::Warn , "declaration does not allocate storage: %s" }, 61 {"superfluous-else" , Severity::Warn , "else clause never executed for empty loop conditional" },62 61 {"gcc-attributes" , Severity::Warn , "invalid attribute: %s" }, 63 62 {"c++-like-copy" , Severity::Warn , "Constructor from reference is not a valid copy constructor" }, … … 70 69 AggrForwardDecl, 71 70 SuperfluousDecl, 72 SuperfluousElse,73 71 GccAttributes, 74 72 CppCopy, … … 81 79 ); 82 80 83 #define SemanticWarning(loc, id, ...) SemanticWarningImpl(loc, id, WarningFormats[(int)id].message, ##__VA_ARGS__)81 #define SemanticWarning(loc, id, ...) SemanticWarningImpl(loc, id, WarningFormats[(int)id].message, __VA_ARGS__) 84 82 85 83 void SemanticWarningImpl (CodeLocation loc, Warning warn, const char * const fmt, ...) __attribute__((format(printf, 3, 4))); -
src/Common/module.mk
r74ec742 r29d8c02 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Andrew Beach13 ## Last Modified On : Tue May 17 14:27:00 202214 ## Update Count : 512 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Tue Sep 27 11:06:38 2016 14 ## Update Count : 4 15 15 ############################################################################### 16 16 17 17 SRC_COMMON = \ 18 Common/Assert.cc \ 19 Common/CodeLocation.h \ 20 Common/CodeLocationTools.hpp \ 21 Common/CodeLocationTools.cpp \ 22 Common/CompilerError.h \ 23 Common/Debug.h \ 24 Common/DeclStats.hpp \ 25 Common/DeclStats.cpp \ 26 Common/ErrorObjects.h \ 27 Common/Eval.cc \ 28 Common/Examine.cc \ 29 Common/Examine.h \ 30 Common/FilterCombos.h \ 31 Common/Indenter.h \ 32 Common/Indenter.cc \ 33 Common/PassVisitor.cc \ 34 Common/PassVisitor.h \ 35 Common/PassVisitor.impl.h \ 36 Common/PassVisitor.proto.h \ 37 Common/PersistentMap.h \ 38 Common/ResolvProtoDump.hpp \ 39 Common/ResolvProtoDump.cpp \ 40 Common/ScopedMap.h \ 41 Common/SemanticError.cc \ 42 Common/SemanticError.h \ 43 Common/Stats.h \ 44 Common/Stats/Base.h \ 45 Common/Stats/Counter.cc \ 46 Common/Stats/Counter.h \ 47 Common/Stats/Heap.cc \ 48 Common/Stats/Heap.h \ 49 Common/Stats/ResolveTime.cc \ 50 Common/Stats/ResolveTime.h \ 51 Common/Stats/Stats.cc \ 52 Common/Stats/Time.cc \ 53 Common/Stats/Time.h \ 54 Common/UnimplementedError.h \ 55 Common/UniqueName.cc \ 56 Common/UniqueName.h \ 57 Common/utility.h \ 58 Common/VectorMap.h 18 Common/Assert.cc \ 19 Common/CodeLocation.h \ 20 Common/CodeLocationTools.hpp \ 21 Common/CodeLocationTools.cpp \ 22 Common/CompilerError.h \ 23 Common/Debug.h \ 24 Common/DeclStats.hpp \ 25 Common/DeclStats.cpp \ 26 Common/ErrorObjects.h \ 27 Common/Eval.cc \ 28 Common/Examine.cc \ 29 Common/Examine.h \ 30 Common/FilterCombos.h \ 31 Common/Indenter.h \ 32 Common/PassVisitor.cc \ 33 Common/PassVisitor.h \ 34 Common/PassVisitor.impl.h \ 35 Common/PassVisitor.proto.h \ 36 Common/PersistentMap.h \ 37 Common/ResolvProtoDump.hpp \ 38 Common/ResolvProtoDump.cpp \ 39 Common/ScopedMap.h \ 40 Common/SemanticError.cc \ 41 Common/SemanticError.h \ 42 Common/Stats.h \ 43 Common/Stats/Base.h \ 44 Common/Stats/Counter.cc \ 45 Common/Stats/Counter.h \ 46 Common/Stats/Heap.cc \ 47 Common/Stats/Heap.h \ 48 Common/Stats/ResolveTime.cc \ 49 Common/Stats/ResolveTime.h \ 50 Common/Stats/Stats.cc \ 51 Common/Stats/Time.cc \ 52 Common/Stats/Time.h \ 53 Common/UnimplementedError.h \ 54 Common/UniqueName.cc \ 55 Common/UniqueName.h \ 56 Common/utility.h \ 57 Common/VectorMap.h 59 58 60 SRC += $(SRC_COMMON) \ 61 Common/DebugMalloc.cc 62 59 SRC += $(SRC_COMMON) Common/DebugMalloc.cc 63 60 SRCDEMANGLE += $(SRC_COMMON) -
src/Common/utility.h
r74ec742 r29d8c02 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Mon Apr 25 14:26:00 202213 // Update Count : 5 111 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Feb 11 13:00:36 2020 13 // Update Count : 50 14 14 // 15 15 … … 230 230 } 231 231 232 template<typename Container, typename Pred>233 void erase_if( Container & cont, Pred && pred ) {234 auto keep_end = std::remove_if( cont.begin(), cont.end(), pred );235 cont.erase( keep_end, cont.end() );236 }237 238 232 template< typename... Args > 239 233 auto zip(Args&&... args) -> decltype(zipWith(std::forward<Args>(args)..., std::make_pair)) { -
src/Concurrency/module.mk
r74ec742 r29d8c02 10 10 ## Author : Thierry Delisle 11 11 ## Created On : Mon Mar 13 12:48:40 2017 12 ## Last Modified By : Andrew Beach13 ## Last Modified On : Tue May 17 13:28:00 202214 ## Update Count : 112 ## Last Modified By : 13 ## Last Modified On : 14 ## Update Count : 0 15 15 ############################################################################### 16 16 17 SRC += \17 SRC_CONCURRENCY = \ 18 18 Concurrency/KeywordsNew.cpp \ 19 Concurrency/Keywords.cc \ 19 Concurrency/Keywords.cc 20 21 SRC += $(SRC_CONCURRENCY) \ 20 22 Concurrency/Keywords.h \ 21 23 Concurrency/Waitfor.cc \ 22 24 Concurrency/Waitfor.h 25 26 SRCDEMANGLE += $(SRC_CONCURRENCY) 27 -
src/ControlStruct/LabelGeneratorNew.hpp
r74ec742 r29d8c02 18 18 #include <string> // for string 19 19 20 structCodeLocation;20 class CodeLocation; 21 21 22 22 namespace ast { -
src/ControlStruct/MultiLevelExit.cpp
r74ec742 r29d8c02 18 18 #include "AST/Pass.hpp" 19 19 #include "AST/Stmt.hpp" 20 #include "Common/CodeLocationTools.hpp"21 20 #include "LabelGeneratorNew.hpp" 22 21 … … 229 228 // Labels on different stmts require different approaches to access 230 229 switch ( stmt->kind ) { 231 case BranchStmt::Goto:230 case BranchStmt::Goto: 232 231 return stmt; 233 case BranchStmt::Continue:234 case BranchStmt::Break: {235 bool isContinue = stmt->kind == BranchStmt::Continue;236 // Handle unlabeled break and continue.237 if ( stmt->target.empty() ) {238 if ( isContinue ) {239 targetEntry = findEnclosingControlStructure( isContinueTarget );240 } else {241 if ( enclosing_control_structures.empty() ) {232 case BranchStmt::Continue: 233 case BranchStmt::Break: { 234 bool isContinue = stmt->kind == BranchStmt::Continue; 235 // Handle unlabeled break and continue. 236 if ( stmt->target.empty() ) { 237 if ( isContinue ) { 238 targetEntry = findEnclosingControlStructure( isContinueTarget ); 239 } else { 240 if ( enclosing_control_structures.empty() ) { 242 241 SemanticError( stmt->location, 243 242 "'break' outside a loop, 'switch', or labelled block" ); 244 }245 targetEntry = findEnclosingControlStructure( isBreakTarget );246 }247 // Handle labeled break and continue.248 } else {249 // Lookup label in table to find attached control structure.250 targetEntry = findEnclosingControlStructure(251 [ targetStmt = target_table.at(stmt->target) ](auto entry){243 } 244 targetEntry = findEnclosingControlStructure( isBreakTarget ); 245 } 246 // Handle labeled break and continue. 247 } else { 248 // Lookup label in table to find attached control structure. 249 targetEntry = findEnclosingControlStructure( 250 [ targetStmt = target_table.at(stmt->target) ](auto entry){ 252 251 return entry.stmt == targetStmt; 253 } );254 }255 // Ensure that selected target is valid.256 if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && ! isContinueTarget( *targetEntry ) ) ) {257 SemanticError( stmt->location, toString( (isContinue ? "'continue'" : "'break'"),252 } ); 253 } 254 // Ensure that selected target is valid. 255 if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && ! isContinueTarget( *targetEntry ) ) ) { 256 SemanticError( stmt->location, toString( (isContinue ? "'continue'" : "'break'"), 258 257 " target must be an enclosing ", (isContinue ? "loop: " : "control structure: "), 259 258 stmt->originalTarget ) ); 260 }261 break;262 }263 // handle fallthrough in case/switch stmts264 case BranchStmt::FallThrough: {265 targetEntry = findEnclosingControlStructure( isFallthroughTarget );266 // Check that target is valid.267 if ( targetEntry == enclosing_control_structures.rend() ) {268 SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );269 }270 if ( ! stmt->target.empty() ) {271 // Labelled fallthrough: target must be a valid fallthough label.272 if ( ! fallthrough_labels.count( stmt->target ) ) {273 SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ",259 } 260 break; 261 } 262 // handle fallthrough in case/switch stmts 263 case BranchStmt::FallThrough: { 264 targetEntry = findEnclosingControlStructure( isFallthroughTarget ); 265 // Check that target is valid. 266 if ( targetEntry == enclosing_control_structures.rend() ) { 267 SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" ); 268 } 269 if ( ! stmt->target.empty() ) { 270 // Labelled fallthrough: target must be a valid fallthough label. 271 if ( ! fallthrough_labels.count( stmt->target ) ) { 272 SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ", 274 273 stmt->originalTarget ) ); 275 }276 return new BranchStmt( stmt->location, BranchStmt::Goto, stmt->originalTarget );277 }278 break;279 }280 case BranchStmt::FallThroughDefault: {281 targetEntry = findEnclosingControlStructure( isFallthroughDefaultTarget );282 283 // Check if in switch or choose statement.284 if ( targetEntry == enclosing_control_structures.rend() ) {285 SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );286 }287 288 // Check if switch or choose has default clause.289 auto switchStmt = strict_dynamic_cast< const SwitchStmt * >( targetEntry->stmt );290 bool foundDefault = false;291 for ( auto caseStmt : switchStmt->cases ) {292 if ( caseStmt->isDefault() ) {293 foundDefault = true;294 break;295 }296 }297 if ( ! foundDefault ) {298 SemanticError( stmt->location, "'fallthrough default' must be enclosed in a 'switch' or 'choose'"299 "control structure with a 'default' clause" );300 }301 break;302 }303 default:274 } 275 return new BranchStmt( stmt->location, BranchStmt::Goto, stmt->originalTarget ); 276 } 277 break; 278 } 279 case BranchStmt::FallThroughDefault: { 280 targetEntry = findEnclosingControlStructure( isFallthroughDefaultTarget ); 281 282 // Check if in switch or choose statement. 283 if ( targetEntry == enclosing_control_structures.rend() ) { 284 SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" ); 285 } 286 287 // Check if switch or choose has default clause. 288 auto switchStmt = strict_dynamic_cast< const SwitchStmt * >( targetEntry->stmt ); 289 bool foundDefault = false; 290 for ( auto caseStmt : switchStmt->cases ) { 291 if ( caseStmt->isDefault() ) { 292 foundDefault = true; 293 break; 294 } 295 } 296 if ( ! foundDefault ) { 297 SemanticError( stmt->location, "'fallthrough default' must be enclosed in a 'switch' or 'choose'" 298 "control structure with a 'default' clause" ); 299 } 300 break; 301 } 302 default: 304 303 assert( false ); 305 304 } … … 308 307 Label exitLabel( CodeLocation(), "" ); 309 308 switch ( stmt->kind ) { 310 case BranchStmt::Break:309 case BranchStmt::Break: 311 310 assert( ! targetEntry->useBreakExit().empty() ); 312 311 exitLabel = targetEntry->useBreakExit(); 313 312 break; 314 case BranchStmt::Continue:313 case BranchStmt::Continue: 315 314 assert( ! targetEntry->useContExit().empty() ); 316 315 exitLabel = targetEntry->useContExit(); 317 316 break; 318 case BranchStmt::FallThrough:317 case BranchStmt::FallThrough: 319 318 assert( ! targetEntry->useFallExit().empty() ); 320 319 exitLabel = targetEntry->useFallExit(); 321 320 break; 322 case BranchStmt::FallThroughDefault:321 case BranchStmt::FallThroughDefault: 323 322 assert( ! targetEntry->useFallDefaultExit().empty() ); 324 323 exitLabel = targetEntry->useFallDefaultExit(); … … 328 327 } 329 328 break; 330 default:329 default: 331 330 assert(0); 332 331 } … … 589 588 } 590 589 591 ptr<Stmt> else_stmt = nullptr;592 Stmt * loop_kid = nullptr;593 // check if loop node and if so add else clause if it exists594 const WhileDoStmt * whilePtr = dynamic_cast<const WhileDoStmt *>(kid.get());595 if ( whilePtr && whilePtr->else_) {596 else_stmt = whilePtr->else_;597 WhileDoStmt * mutate_ptr = mutate(whilePtr);598 mutate_ptr->else_ = nullptr;599 loop_kid = mutate_ptr;600 }601 const ForStmt * forPtr = dynamic_cast<const ForStmt *>(kid.get());602 if ( forPtr && forPtr->else_) {603 else_stmt = forPtr->else_;604 ForStmt * mutate_ptr = mutate(forPtr);605 mutate_ptr->else_ = nullptr;606 loop_kid = mutate_ptr;607 }608 609 590 try { 610 if (else_stmt) ret.push_back( loop_kid->accept( *visitor ) ); 611 else ret.push_back( kid->accept( *visitor ) ); 591 ret.push_back( kid->accept( *visitor ) ); 612 592 } catch ( SemanticErrorException & e ) { 613 593 errors.append( e ); 614 594 } 615 616 if (else_stmt) ret.push_back(else_stmt);617 595 618 596 if ( ! break_label.empty() ) { … … 634 612 Pass<MultiLevelExitCore> visitor( labelTable ); 635 613 const CompoundStmt * ret = stmt->accept( visitor ); 636 // There are some unset code locations slipping in, possibly by Labels. 637 const Node * node = localFillCodeLocations( ret->location, ret ); 638 return strict_dynamic_cast<const CompoundStmt *>( node ); 614 return ret; 639 615 } 640 616 } // namespace ControlStruct -
src/ControlStruct/module.mk
r74ec742 r29d8c02 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Andrew Beach13 ## Last Modified On : Tue May 17 14:30:00202214 ## Update Count : 812 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Sat Jan 29 12:04:19 2022 14 ## Update Count : 7 15 15 ############################################################################### 16 16 17 SRC += \17 SRC_CONTROLSTRUCT = \ 18 18 ControlStruct/ExceptDecl.cc \ 19 19 ControlStruct/ExceptDecl.h \ 20 ControlStruct/ExceptTranslateNew.cpp \21 ControlStruct/ExceptTranslate.cc \22 ControlStruct/ExceptTranslate.h \23 20 ControlStruct/FixLabels.cpp \ 24 21 ControlStruct/FixLabels.hpp \ … … 40 37 ControlStruct/Mutate.h 41 38 39 SRC += $(SRC_CONTROLSTRUCT) \ 40 ControlStruct/ExceptTranslateNew.cpp \ 41 ControlStruct/ExceptTranslate.cc \ 42 ControlStruct/ExceptTranslate.h 43 44 SRCDEMANGLE += $(SRC_CONTROLSTRUCT) 45 -
src/GenPoly/Lvalue.cc
r74ec742 r29d8c02 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Mon May 16 14:09:00 202213 // Update Count : 811 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 13 23:14:38 2019 13 // Update Count : 7 14 14 // 15 15 … … 125 125 } // namespace 126 126 127 // Stored elsewhere (Lvalue2, initially false). 128 extern bool referencesEliminated; 127 static bool referencesEliminated = false; 128 // used by UntypedExpr::createDeref to determine whether result type of dereference should be ReferenceType or value type. 129 bool referencesPermissable() { 130 return ! referencesEliminated; 131 } 129 132 130 133 void convertLvalue( std::list< Declaration* > & translationUnit ) { -
src/GenPoly/module.mk
r74ec742 r29d8c02 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Andrew Beach13 ## Last Modified On : Tue May 17 14:31:00 202214 ## Update Count : 212 ## Last Modified By : Peter A. Buhr 13 ## Last Modified On : Mon Jun 1 17:52:30 2015 14 ## Update Count : 1 15 15 ############################################################################### 16 16 17 SRC_GENPOLY = \ 18 GenPoly/GenPoly.cc \ 19 GenPoly/GenPoly.h \ 20 GenPoly/Lvalue2.cc \ 21 GenPoly/Lvalue.h 17 SRC += GenPoly/Box.cc \ 18 GenPoly/Box.h \ 19 GenPoly/ErasableScopedMap.h \ 20 GenPoly/FindFunction.cc \ 21 GenPoly/FindFunction.h \ 22 GenPoly/GenPoly.cc \ 23 GenPoly/GenPoly.h \ 24 GenPoly/InstantiateGeneric.cc \ 25 GenPoly/InstantiateGeneric.h \ 26 GenPoly/Lvalue.cc \ 27 GenPoly/Lvalue.h \ 28 GenPoly/ScopedSet.h \ 29 GenPoly/ScrubTyVars.cc \ 30 GenPoly/ScrubTyVars.h \ 31 GenPoly/Specialize.cc \ 32 GenPoly/Specialize.h 22 33 23 SRC += $(SRC_GENPOLY) \ 24 GenPoly/Box.cc \ 25 GenPoly/Box.h \ 26 GenPoly/ErasableScopedMap.h \ 27 GenPoly/FindFunction.cc \ 28 GenPoly/FindFunction.h \ 29 GenPoly/InstantiateGeneric.cc \ 30 GenPoly/InstantiateGeneric.h \ 31 GenPoly/Lvalue.cc \ 32 GenPoly/ScopedSet.h \ 33 GenPoly/ScrubTyVars.cc \ 34 GenPoly/ScrubTyVars.h \ 35 GenPoly/Specialize.cc \ 36 GenPoly/Specialize.h 34 SRCDEMANGLE += GenPoly/GenPoly.cc GenPoly/GenPoly.h GenPoly/Lvalue.cc GenPoly/Lvalue.h 37 35 38 SRCDEMANGLE += $(SRC_GENPOLY) -
src/InitTweak/FixInitNew.cpp
r74ec742 r29d8c02 454 454 455 455 auto expr = new ast::ImplicitCopyCtorExpr( appExpr->location, mutExpr ); 456 // Move the type substitution to the new top-level. The substitution 457 // is needed to obtain the type of temporary variables so that copy 458 // constructor calls can be resolved. 456 // Move the type substitution to the new top-level, if it is attached to the appExpr. 457 // Ensure it is not deleted with the ImplicitCopyCtorExpr by removing it before deletion. 458 // The substitution is needed to obtain the type of temporary variables so that copy constructor 459 // calls can be resolved. 459 460 assert( typeSubs ); 461 // assert (mutExpr->env); 460 462 expr->env = tmp; 463 // mutExpr->env = nullptr; 464 //std::swap( expr->env, appExpr->env ); 461 465 return expr; 462 466 } 463 467 464 468 void ResolveCopyCtors::previsit(const ast::Expr * expr) { 465 if ( nullptr == expr->env ) { 466 return; 467 } 468 GuardValue( env ) = expr->env->clone(); 469 GuardValue( envModified ) = false; 469 if (expr->env) { 470 GuardValue(env); 471 GuardValue(envModified); 472 env = expr->env->clone(); 473 envModified = false; 474 } 470 475 } 471 476 472 477 const ast::Expr * ResolveCopyCtors::postvisit(const ast::Expr * expr) { 473 // No local environment, skip. 474 if ( nullptr == expr->env ) { 475 return expr; 476 // Environment was modified, mutate and replace. 477 } else if ( envModified ) { 478 auto mutExpr = mutate(expr); 479 mutExpr->env = env; 480 return mutExpr; 481 // Environment was not mutated, delete the shallow copy before guard. 482 } else { 483 delete env; 478 if (expr->env) { 479 if (envModified) { 480 auto mutExpr = mutate(expr); 481 mutExpr->env = env; 482 return mutExpr; 483 } 484 else { 485 // env was not mutated, skip and delete the shallow copy 486 delete env; 487 return expr; 488 } 489 } 490 else { 484 491 return expr; 485 492 } … … 490 497 const ast::Expr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, const ast::ObjectDecl * var, const ast::Expr * cpArg ) { 491 498 assert( var ); 492 assert ( var->isManaged());493 assert ( !cpArg || cpArg->isManaged());499 assert (var->isManaged()); 500 assert (!cpArg || cpArg->isManaged()); 494 501 // arrays are not copy constructed, so this should always be an ExprStmt 495 502 ast::ptr< ast::Stmt > stmt = genCtorDtor(var->location, fname, var, cpArg ); … … 497 504 auto exprStmt = stmt.strict_as<ast::ImplicitCtorDtorStmt>()->callStmt.strict_as<ast::ExprStmt>(); 498 505 ast::ptr<ast::Expr> untyped = exprStmt->expr; // take ownership of expr 506 // exprStmt->expr = nullptr; 499 507 500 508 // resolve copy constructor … … 508 516 env->add( *resolved->env ); 509 517 envModified = true; 518 // delete resolved->env; 510 519 auto mut = mutate(resolved.get()); 511 520 assertf(mut == resolved.get(), "newly resolved expression must be unique"); 512 521 mut->env = nullptr; 513 522 } // if 523 // delete stmt; 514 524 if ( auto assign = resolved.as<ast::TupleAssignExpr>() ) { 515 525 // fix newly generated StmtExpr -
src/InitTweak/module.mk
r74ec742 r29d8c02 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Andrew Beach13 ## Last Modified On : Tue May 17 14:31:00 202214 ## Update Count : 412 ## Last Modified By : Rob Schluntz 13 ## Last Modified On : Fri May 13 11:36:24 2016 14 ## Update Count : 3 15 15 ############################################################################### 16 16 17 SRC_INITTWEAK = \ 17 SRC += \ 18 InitTweak/FixGlobalInit.cc \ 19 InitTweak/FixGlobalInit.h \ 20 InitTweak/FixInit.cc \ 21 InitTweak/FixInit.h \ 22 InitTweak/GenInit.cc \ 23 InitTweak/GenInit.h \ 24 InitTweak/InitTweak.cc \ 25 InitTweak/InitTweak.h \ 26 InitTweak/FixInitNew.cpp 27 28 SRCDEMANGLE += \ 18 29 InitTweak/GenInit.cc \ 19 30 InitTweak/GenInit.h \ … … 21 32 InitTweak/InitTweak.h 22 33 23 SRC += $(SRC_INITTWEAK) \24 InitTweak/FixGlobalInit.cc \25 InitTweak/FixGlobalInit.h \26 InitTweak/FixInit.cc \27 InitTweak/FixInit.h \28 InitTweak/FixInitNew.cpp29 30 SRCDEMANGLE += $(SRC_INITTWEAK) -
src/Parser/DeclarationNode.cc
r74ec742 r29d8c02 253 253 } // DeclarationNode::newAggregate 254 254 255 DeclarationNode * DeclarationNode::newEnum( const string * name, DeclarationNode * constants, bool body , DeclarationNode * base) {255 DeclarationNode * DeclarationNode::newEnum( const string * name, DeclarationNode * constants, bool body) { 256 256 DeclarationNode * newnode = new DeclarationNode; 257 257 newnode->type = new TypeData( TypeData::Enum ); … … 260 260 newnode->type->enumeration.body = body; 261 261 newnode->type->enumeration.anon = name == nullptr; 262 if ( base && base->type) {263 newnode->type->base = base->type;264 } // if265 266 // Check: if base has TypeData267 262 return newnode; 268 263 } // DeclarationNode::newEnum … … 295 290 return newName( name ); // Not explicitly inited enum value; 296 291 } // if 297 } // DeclarationNode::newEnum ValueGeneric292 } // DeclarationNode::newEnumGeneric 298 293 299 294 DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) { -
src/Parser/ParseNode.h
r74ec742 r29d8c02 235 235 static DeclarationNode * newFunction( const std::string * name, DeclarationNode * ret, DeclarationNode * param, StatementNode * body ); 236 236 static DeclarationNode * newAggregate( AggregateDecl::Aggregate kind, const std::string * name, ExpressionNode * actuals, DeclarationNode * fields, bool body ); 237 static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body , DeclarationNode * base = nullptr);237 static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body ); 238 238 static DeclarationNode * newEnumConstant( const std::string * name, ExpressionNode * constant ); 239 239 static DeclarationNode * newEnumValueGeneric( const std::string * name, InitializerNode * init ); -
src/Parser/TypeData.cc
r74ec742 r29d8c02 388 388 if ( enumeration.body ) { 389 389 os << string( indent + 2, ' ' ) << " with body" << endl; 390 } // if391 if ( base ) {392 os << "for ";393 base->print( os, indent + 2 );394 390 } // if 395 391 break; … … 930 926 ObjectDecl * member = dynamic_cast< ObjectDecl * >(* members); 931 927 member->set_init( new SingleInit( maybeMoveBuild< Expression >( cur->consume_enumeratorValue() ) ) ); 932 } else if ( !cur->initializer ){928 } else { 933 929 if ( baseType && (!dynamic_cast<BasicType *>(baseType) || !dynamic_cast<BasicType *>(baseType)->isWholeNumber())) { 934 930 SemanticError( td->location, "A non whole number enum value decl must be explicitly initialized." ); 935 931 } 936 } 937 // else cur is a List Initializer and has been set as init in buildList() 938 // if 932 } // if 939 933 } // for 940 ret->set_body( td->enumeration.body ); 934 ret->set_body( td->enumeration.body ); // Boolean; if it has body 941 935 return ret; 942 936 } // buildEnum -
src/Parser/parser.yy
r74ec742 r29d8c02 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat May 14 09:16:22202213 // Update Count : 5 40112 // Last Modified On : Mon Mar 14 16:35:29 2022 13 // Update Count : 5276 14 14 // 15 15 … … 54 54 #include "Common/SemanticError.h" // error_str 55 55 #include "Common/utility.h" // for maybeMoveBuild, maybeBuild, CodeLo... 56 57 #include "SynTree/Attribute.h" // for Attribute58 56 59 57 extern DeclarationNode * parseTree; … … 95 93 } // appendStr 96 94 97 DeclarationNode * distAttr( DeclarationNode * typeSpec, DeclarationNode * declList ) { 98 // distribute declaration_specifier across all declared variables, e.g., static, const, but not __attribute__. 99 assert( declList ); 100 // printf( "distAttr1 typeSpec %p\n", typeSpec ); typeSpec->print( std::cout ); 101 DeclarationNode * cur = declList, * cl = (new DeclarationNode)->addType( typeSpec ); 102 // printf( "distAttr2 cl %p\n", cl ); cl->type->print( std::cout ); 103 // cl->type->aggregate.name = cl->type->aggInst.aggregate->aggregate.name; 104 95 DeclarationNode * distAttr( DeclarationNode * specifier, DeclarationNode * declList ) { 96 // distribute declaration_specifier across all declared variables, e.g., static, const, __attribute__. 97 DeclarationNode * cur = declList, * cl = (new DeclarationNode)->addType( specifier ); 105 98 for ( cur = dynamic_cast<DeclarationNode *>( cur->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) { 106 99 cl->cloneBaseType( cur ); 107 100 } // for 108 101 declList->addType( cl ); 109 // printf( "distAttr3 declList %p\n", declList ); declList->print( std::cout, 0 );110 102 return declList; 111 103 } // distAttr … … 119 111 120 112 void distInl( DeclarationNode * declaration ) { 121 // distribute INLINEacross all declarations113 // distribute EXTENSION across all declarations 122 114 for ( DeclarationNode *iter = declaration; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) { 123 115 iter->set_inLine( true ); … … 179 171 if ( ! ( typeSpec->type && (typeSpec->type->kind == TypeData::Aggregate || typeSpec->type->kind == TypeData::Enum) ) ) { 180 172 stringstream ss; 181 // printf( "fieldDecl1 typeSpec %p\n", typeSpec ); typeSpec->type->print( std::cout);173 typeSpec->type->print( ss ); 182 174 SemanticWarning( yylloc, Warning::SuperfluousDecl, ss.str().c_str() ); 183 175 return nullptr; 184 176 } // if 185 // printf( "fieldDecl2 typeSpec %p\n", typeSpec ); typeSpec->type->print( std::cout );186 177 fieldList = DeclarationNode::newName( nullptr ); 187 178 } // if 188 // return distAttr( typeSpec, fieldList ); // mark all fields in list 189 190 // printf( "fieldDecl3 typeSpec %p\n", typeSpec ); typeSpec->print( std::cout, 0 ); 191 DeclarationNode * temp = distAttr( typeSpec, fieldList ); // mark all fields in list 192 // printf( "fieldDecl4 temp %p\n", temp ); temp->print( std::cout, 0 ); 193 return temp; 179 return distAttr( typeSpec, fieldList ); // mark all fields in list 194 180 } // fieldDecl 195 181 … … 1235 1221 1236 1222 iteration_statement: 1237 WHILE '(' ')' statement %prec THEN// CFA => while ( 1 )1223 WHILE '(' ')' statement // CFA => while ( 1 ) 1238 1224 { $$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); } 1239 | WHILE '(' ')' statement ELSE statement // CFA1240 {1241 $$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) );1242 SemanticWarning( yylloc, Warning::SuperfluousElse );1243 }1244 1225 | WHILE '(' conditional_declaration ')' statement %prec THEN 1245 1226 { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); } … … 1248 1229 | DO statement WHILE '(' ')' ';' // CFA => do while( 1 ) 1249 1230 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); } 1250 | DO statement WHILE '(' ')' ELSE statement // CFA 1251 { 1252 $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); 1253 SemanticWarning( yylloc, Warning::SuperfluousElse ); 1254 } 1255 | DO statement WHILE '(' comma_expression ')' ';' 1231 | DO statement WHILE '(' comma_expression ')' ';' %prec THEN 1256 1232 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); } 1257 1233 | DO statement WHILE '(' comma_expression ')' ELSE statement // CFA 1258 1234 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ), $8 ) ); } 1259 | FOR '(' ')' statement %prec THEN// CFA => for ( ;; )1235 | FOR '(' ')' statement // CFA => for ( ;; ) 1260 1236 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); } 1261 | FOR '(' ')' statement ELSE statement // CFA1262 {1263 $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) );1264 SemanticWarning( yylloc, Warning::SuperfluousElse );1265 }1266 1237 | FOR '(' for_control_expression_list ')' statement %prec THEN 1267 1238 { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ) ) ); } … … 1634 1605 declaration: // old & new style declarations 1635 1606 c_declaration ';' 1636 {1637 // printf( "C_DECLARATION1 %p %s\n", $$, $$->name ? $$->name->c_str() : "(nil)" );1638 // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {1639 // printf( "\tattr %s\n", attr->name.c_str() );1640 // } // for1641 }1642 1607 | cfa_declaration ';' // CFA 1643 1608 | static_assert // C11 … … 1845 1810 basic_type_specifier 1846 1811 | sue_type_specifier 1847 {1848 // printf( "sue_type_specifier2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );1849 // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {1850 // printf( "\tattr %s\n", attr->name.c_str() );1851 // } // for1852 }1853 1812 | type_type_specifier 1854 1813 ; … … 2067 2026 sue_declaration_specifier: // struct, union, enum + storage class + type specifier 2068 2027 sue_type_specifier 2069 {2070 // printf( "sue_declaration_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );2071 // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {2072 // printf( "\tattr %s\n", attr->name.c_str() );2073 // } // for2074 }2075 2028 | declaration_qualifier_list sue_type_specifier 2076 2029 { $$ = $2->addQualifiers( $1 ); } … … 2083 2036 sue_type_specifier: // struct, union, enum + type specifier 2084 2037 elaborated_type 2085 {2086 // printf( "sue_type_specifier %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );2087 // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {2088 // printf( "\tattr %s\n", attr->name.c_str() );2089 // } // for2090 }2091 2038 | type_qualifier_list 2092 2039 { if ( $1->type != nullptr && $1->type->forall ) forall = true; } // remember generic type … … 2161 2108 elaborated_type: // struct, union, enum 2162 2109 aggregate_type 2163 {2164 // printf( "elaborated_type %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" );2165 // for ( Attribute * attr: reverseIterate( $$->attributes ) ) {2166 // printf( "\tattr %s\n", attr->name.c_str() );2167 // } // for2168 }2169 2110 | enum_type 2170 2111 ; … … 2186 2127 } 2187 2128 '{' field_declaration_list_opt '}' type_parameters_opt 2188 { 2189 // printf( "aggregate_type1 %s\n", $3.str->c_str() ); 2190 // if ( $2 ) 2191 // for ( Attribute * attr: reverseIterate( $2->attributes ) ) { 2192 // printf( "copySpecifiers12 %s\n", attr->name.c_str() ); 2193 // } // for 2194 $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); 2195 // printf( "aggregate_type2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" ); 2196 // for ( Attribute * attr: reverseIterate( $$->attributes ) ) { 2197 // printf( "aggregate_type3 %s\n", attr->name.c_str() ); 2198 // } // for 2199 } 2129 { $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); } 2200 2130 | aggregate_key attribute_list_opt TYPEDEFname // unqualified type name 2201 2131 { … … 2205 2135 '{' field_declaration_list_opt '}' type_parameters_opt 2206 2136 { 2207 // printf( "AGG3\n" );2208 2137 DeclarationNode::newFromTypedef( $3 ); 2209 2138 $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); … … 2216 2145 '{' field_declaration_list_opt '}' type_parameters_opt 2217 2146 { 2218 // printf( "AGG4\n" );2219 2147 DeclarationNode::newFromTypeGen( $3, nullptr ); 2220 2148 $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); … … 2293 2221 field_declaration: 2294 2222 type_specifier field_declaring_list_opt ';' 2295 { 2296 // printf( "type_specifier1 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" ); 2297 $$ = fieldDecl( $1, $2 ); 2298 // printf( "type_specifier2 %p %s\n", $$, $$->type->aggregate.name ? $$->type->aggregate.name->c_str() : "(nil)" ); 2299 // for ( Attribute * attr: reverseIterate( $$->attributes ) ) { 2300 // printf( "\tattr %s\n", attr->name.c_str() ); 2301 // } // for 2302 } 2223 { $$ = fieldDecl( $1, $2 ); } 2303 2224 | EXTENSION type_specifier field_declaring_list_opt ';' // GCC 2304 2225 { $$ = fieldDecl( $2, $3 ); distExt( $$ ); } … … 2382 2303 ; 2383 2304 2384 enum_type: 2305 enum_type: // static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body, bool typed ); // enum 2385 2306 ENUM attribute_list_opt '{' enumerator_list comma_opt '}' 2386 2307 { $$ = DeclarationNode::newEnum( nullptr, $4, true )->addQualifiers( $2 ); } … … 2397 2318 { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); } 2398 2319 2399 $$ = DeclarationNode::newEnum( nullptr, $7, true , $3 )->addQualifiers( $5);2400 } 2401 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt 2320 $$ = DeclarationNode::newEnum( nullptr, $7, true ) ->addQualifiers( $5 ) -> addEnumBase( $3 ); 2321 } 2322 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt // Question: why attributes/qualifier after identifier 2402 2323 { 2403 2324 if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); } … … 2406 2327 '{' enumerator_list comma_opt '}' 2407 2328 { 2408 $$ = DeclarationNode::newEnum( $6, $10, true , $3 )->addQualifiers( $5 )->addQualifiers( $7);2329 $$ = DeclarationNode::newEnum( $6, $10, true ) -> addQualifiers( $5 ) -> addQualifiers( $7 ) -> addEnumBase( $3 ); 2409 2330 } 2410 2331 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}' … … 2412 2333 if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); } 2413 2334 typedefTable.makeTypedef( *$6->name ); 2414 $$ = DeclarationNode::newEnum( $6->name, $9, true , $3 )->addQualifiers( $5 )->addQualifiers( $7);2335 $$ = DeclarationNode::newEnum( $6->name, $9, true ) -> addQualifiers( $5 ) -> addQualifiers( $7 ) -> addEnumBase( $3 ); 2415 2336 } 2416 2337 | enum_type_nobody … … 2909 2830 // empty 2910 2831 { $$ = nullptr; forall = false; } 2911 | WITH '(' tuple_expression_list ')' attribute_list_opt 2912 { 2913 $$ = $3; forall = false; 2914 if ( $5 ) { 2915 SemanticError( yylloc, "Attributes cannot be associated with function body. Move attribute(s) before \"with\" clause." ); 2916 $$ = nullptr; 2917 } // if 2918 } 2832 | WITH '(' tuple_expression_list ')' 2833 { $$ = $3; forall = false; } 2919 2834 ; 2920 2835 -
src/ResolvExpr/AlternativeFinder.cc
r74ec742 r29d8c02 42 42 #include "SymTab/Indexer.h" // for Indexer 43 43 #include "SymTab/Mangler.h" // for Mangler 44 #include "SymTab/Validate Type.h"// for validateType44 #include "SymTab/Validate.h" // for validateType 45 45 #include "SynTree/Constant.h" // for Constant 46 46 #include "SynTree/Declaration.h" // for DeclarationWithType, TypeDecl, Dec... -
src/ResolvExpr/Resolver.cc
r74ec742 r29d8c02 427 427 // enumerator initializers should not use the enum type to initialize, since 428 428 // the enum type is still incomplete at this point. Use signed int instead. 429 // TODO: BasicType::SignedInt may not longer be true430 429 currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) ); 431 430 } … … 1478 1477 // enum type is still incomplete at this point. Use `int` instead. 1479 1478 1480 if (dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() )->base->base) { 1479 if (dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() )->base->base) { // const ast::PointerType & 1480 // const ast::Type * enumBase = (dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() )->base->base.get()); 1481 // const ast::PointerType * enumBaseAsPtr = dynamic_cast<const ast::PointerType *>(enumBase); 1482 1483 // if ( enumBaseAsPtr ) { 1484 // const ast::Type * pointerBase = enumBaseAsPtr->base.get(); 1485 // if ( dynamic_cast<const ast::BasicType *>(pointerBase) ) { 1486 // objectDecl = fixObjectType(objectDecl, context); 1487 // if (dynamic_cast<const ast::BasicType *>(pointerBase)->kind == ast::BasicType::Char) 1488 // currentObject = ast::CurrentObject{ 1489 // objectDecl->location, new ast::PointerType{ 1490 // new ast::BasicType{ ast::BasicType::Char } 1491 // } }; 1492 // } else { 1493 // objectDecl = fixObjectType(objectDecl, context); 1494 // currentObject = ast::CurrentObject{objectDecl->location, new ast::BasicType{ ast::BasicType::SignedInt } }; 1495 // } 1496 // } 1481 1497 objectDecl = fixObjectType( objectDecl, context ); 1482 1498 const ast::Type * enumBase = (dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() )->base->base.get()); -
src/SymTab/Autogen.h
r74ec742 r29d8c02 21 21 22 22 #include "AST/Decl.hpp" 23 #include "AST/Eval.hpp" 23 24 #include "AST/Expr.hpp" 24 25 #include "AST/Init.hpp" … … 70 71 template< typename OutIter > 71 72 ast::ptr< ast::Stmt > genCall( 72 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 73 const CodeLocation & loc, const std::string & fname, OutIter && out, 73 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 74 const CodeLocation & loc, const std::string & fname, OutIter && out, 74 75 const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward ); 75 76 … … 127 128 } 128 129 129 /// inserts into out a generated call expression to function fname with arguments dstParam and 130 /// inserts into out a generated call expression to function fname with arguments dstParam and 130 131 /// srcParam. Should only be called with non-array types. 131 /// optionally returns a statement which must be inserted prior to the containing loop, if 132 /// optionally returns a statement which must be inserted prior to the containing loop, if 132 133 /// there is one 133 134 template< typename OutIter > 134 ast::ptr< ast::Stmt > genScalarCall( 135 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 136 const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type, 135 ast::ptr< ast::Stmt > genScalarCall( 136 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 137 const CodeLocation & loc, std::string fname, OutIter && out, const ast::Type * type, 137 138 const ast::Type * addCast = nullptr 138 139 ) { … … 152 153 153 154 if ( addCast ) { 154 // cast to T& with qualifiers removed, so that qualified objects can be constructed and 155 // destructed with the same functions as non-qualified objects. Unfortunately, lvalue 156 // is considered a qualifier - for AddressExpr to resolve, its argument must have an 155 // cast to T& with qualifiers removed, so that qualified objects can be constructed and 156 // destructed with the same functions as non-qualified objects. Unfortunately, lvalue 157 // is considered a qualifier - for AddressExpr to resolve, its argument must have an 157 158 // lvalue-qualified type, so remove all qualifiers except lvalue. 158 159 // xxx -- old code actually removed lvalue too... 159 160 ast::ptr< ast::Type > guard = addCast; // prevent castType from mutating addCast 160 161 ast::ptr< ast::Type > castType = addCast; 161 ast::remove_qualifiers( 162 castType, 162 ast::remove_qualifiers( 163 castType, 163 164 ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Atomic ); 164 165 dstParam = new ast::CastExpr{ dstParam, new ast::ReferenceType{ castType } }; … … 180 181 181 182 srcParam.clearArrayIndices(); 182 183 183 184 return listInit; 184 185 } … … 248 249 } 249 250 250 /// Store in out a loop which calls fname on each element of the array with srcParam and 251 /// Store in out a loop which calls fname on each element of the array with srcParam and 251 252 /// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0 252 253 template< typename OutIter > 253 254 void genArrayCall( 254 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 255 const CodeLocation & loc, const std::string & fname, OutIter && out, 256 const ast::ArrayType * array, const ast::Type * addCast = nullptr, 257 LoopDirection forward = LoopForward 255 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 256 const CodeLocation & loc, const std::string & fname, OutIter && out, 257 const ast::ArrayType * array, const ast::Type * addCast = nullptr, 258 LoopDirection forward = LoopForward 258 259 ) { 259 260 static UniqueName indexName( "_index" ); … … 278 279 } else { 279 280 // generate: for ( int i = N-1; i >= 0; --i ) 280 begin = ast:: UntypedExpr::createCall( loc, "?-?",281 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) });281 begin = ast::call( 282 loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) ); 282 283 end = ast::ConstantExpr::from_int( loc, 0 ); 283 284 cmp = "?>=?"; … … 285 286 } 286 287 287 ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{ 288 loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 288 ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{ 289 loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 289 290 new ast::SingleInit{ loc, begin } }; 290 291 ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index }; 291 292 ast::ptr< ast::Expr > cond = ast::UntypedExpr::createCall( 293 loc, cmp, { indexVar, end } ); 294 295 ast::ptr< ast::Expr > inc = ast::UntypedExpr::createCall( 296 loc, update, { indexVar } ); 297 298 ast::ptr< ast::Expr > dstIndex = ast::UntypedExpr::createCall( 299 loc, "?[?]", { dstParam, indexVar } ); 300 301 // srcParam must keep track of the array indices to build the source parameter and/or 292 293 ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end ); 294 295 ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar ); 296 297 ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar ); 298 299 // srcParam must keep track of the array indices to build the source parameter and/or 302 300 // array list initializer 303 301 srcParam.addArrayIndex( indexVar, array->dimension ); … … 305 303 // for stmt's body, eventually containing call 306 304 ast::CompoundStmt * body = new ast::CompoundStmt{ loc }; 307 ast::ptr< ast::Stmt > listInit = genCall( 308 srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast, 305 ast::ptr< ast::Stmt > listInit = genCall( 306 srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast, 309 307 forward ); 310 308 311 309 // block containing the stmt and index variable 312 310 ast::CompoundStmt * block = new ast::CompoundStmt{ loc }; … … 330 328 template< typename OutIter > 331 329 ast::ptr< ast::Stmt > genCall( 332 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 333 const CodeLocation & loc, const std::string & fname, OutIter && out, 330 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 331 const CodeLocation & loc, const std::string & fname, OutIter && out, 334 332 const ast::Type * type, const ast::Type * addCast, LoopDirection forward 335 333 ) { 336 334 if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) { 337 genArrayCall( 338 srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast, 335 genArrayCall( 336 srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast, 339 337 forward ); 340 338 return {}; 341 339 } else { 342 return genScalarCall( 340 return genScalarCall( 343 341 srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast ); 344 342 } … … 379 377 } 380 378 381 static inline ast::ptr< ast::Stmt > genImplicitCall( 382 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 383 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj, 384 LoopDirection forward = LoopForward 379 static inline ast::ptr< ast::Stmt > genImplicitCall( 380 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 381 const CodeLocation & loc, const std::string & fname, const ast::ObjectDecl * obj, 382 LoopDirection forward = LoopForward 385 383 ) { 386 384 // unnamed bit fields are not copied as they cannot be accessed … … 394 392 395 393 std::vector< ast::ptr< ast::Stmt > > stmts; 396 genCall( 394 genCall( 397 395 srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward ); 398 396 … … 402 400 const ast::Stmt * callStmt = stmts.front(); 403 401 if ( addCast ) { 404 // implicitly generated ctor/dtor calls should be wrapped so that later passes are 402 // implicitly generated ctor/dtor calls should be wrapped so that later passes are 405 403 // aware they were generated. 406 404 callStmt = new ast::ImplicitCtorDtorStmt{ callStmt->location, callStmt }; … … 419 417 // compile-command: "make install" // 420 418 // End: // 419 -
src/SymTab/Demangle.cc
r74ec742 r29d8c02 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Demangle .cc -- Convert a mangled name into a human readable name.7 // Demangler.cc -- 8 8 // 9 9 // Author : Rob Schluntz -
src/SymTab/Mangler.h
r74ec742 r29d8c02 111 111 } 112 112 113 extern "C" { 114 char * cforall_demangle(const char *, int); 115 } 116 113 117 // Local Variables: // 114 118 // tab-width: 4 // -
src/SymTab/Validate.cc
r74ec742 r29d8c02 10 10 // Created On : Sun May 17 21:50:04 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue May 17 14:36:00 202213 // Update Count : 36 612 // Last Modified On : Fri Nov 12 11:00:00 2021 13 // Update Count : 364 14 14 // 15 15 … … 74 74 #include "ResolvExpr/ResolveTypeof.h" // for resolveTypeof 75 75 #include "SymTab/Autogen.h" // for SizeType 76 #include "SymTab/ValidateType.h" // for decayEnumsAndPointers, decayFo...77 76 #include "SynTree/LinkageSpec.h" // for C 78 77 #include "SynTree/Attribute.h" // for noAttributes, Attribute … … 135 134 }; 136 135 136 /// Replaces enum types by int, and function or array types in function parameter and return lists by appropriate pointers. 137 struct EnumAndPointerDecay_old { 138 void previsit( EnumDecl * aggregateDecl ); 139 void previsit( FunctionType * func ); 140 }; 141 142 /// Associates forward declarations of aggregates with their definitions 143 struct LinkReferenceToTypes_old final : public WithIndexer, public WithGuards, public WithVisitorRef<LinkReferenceToTypes_old>, public WithShortCircuiting { 144 LinkReferenceToTypes_old( const Indexer * indexer ); 145 void postvisit( TypeInstType * typeInst ); 146 147 void postvisit( EnumInstType * enumInst ); 148 void postvisit( StructInstType * structInst ); 149 void postvisit( UnionInstType * unionInst ); 150 void postvisit( TraitInstType * traitInst ); 151 void previsit( QualifiedType * qualType ); 152 void postvisit( QualifiedType * qualType ); 153 154 void postvisit( EnumDecl * enumDecl ); 155 void postvisit( StructDecl * structDecl ); 156 void postvisit( UnionDecl * unionDecl ); 157 void postvisit( TraitDecl * traitDecl ); 158 159 void previsit( StructDecl * structDecl ); 160 void previsit( UnionDecl * unionDecl ); 161 162 void renameGenericParams( std::list< TypeDecl * > & params ); 163 164 private: 165 const Indexer * local_indexer; 166 167 typedef std::map< std::string, std::list< EnumInstType * > > ForwardEnumsType; 168 typedef std::map< std::string, std::list< StructInstType * > > ForwardStructsType; 169 typedef std::map< std::string, std::list< UnionInstType * > > ForwardUnionsType; 170 ForwardEnumsType forwardEnums; 171 ForwardStructsType forwardStructs; 172 ForwardUnionsType forwardUnions; 173 /// true if currently in a generic type body, so that type parameter instances can be renamed appropriately 174 bool inGeneric = false; 175 }; 176 137 177 /// Does early resolution on the expressions that give enumeration constants their values 138 178 struct ResolveEnumInitializers final : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveEnumInitializers>, public WithShortCircuiting { … … 152 192 void previsit( StructDecl * aggrDecl ); 153 193 void previsit( UnionDecl * aggrDecl ); 194 }; 195 196 // These structs are the sub-sub-passes of ForallPointerDecay_old. 197 198 struct TraitExpander_old final { 199 void previsit( FunctionType * ); 200 void previsit( StructDecl * ); 201 void previsit( UnionDecl * ); 202 }; 203 204 struct AssertionFixer_old final { 205 void previsit( FunctionType * ); 206 void previsit( StructDecl * ); 207 void previsit( UnionDecl * ); 208 }; 209 210 struct CheckOperatorTypes_old final { 211 void previsit( ObjectDecl * ); 212 }; 213 214 struct FixUniqueIds_old final { 215 void previsit( DeclarationWithType * ); 154 216 }; 155 217 … … 295 357 296 358 void validate_A( std::list< Declaration * > & translationUnit ) { 359 PassVisitor<EnumAndPointerDecay_old> epc; 297 360 PassVisitor<HoistTypeDecls> hoistDecls; 298 361 { … … 303 366 ReplaceTypedef::replaceTypedef( translationUnit ); 304 367 ReturnTypeFixer::fix( translationUnit ); // must happen before autogen 305 decayEnumsAndPointers( translationUnit); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes_old because it is an indexer and needs correct types for mangling368 acceptAll( translationUnit, epc ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes_old because it is an indexer and needs correct types for mangling 306 369 } 307 370 } 308 371 309 372 void validate_B( std::list< Declaration * > & translationUnit ) { 373 PassVisitor<LinkReferenceToTypes_old> lrt( nullptr ); 310 374 PassVisitor<FixQualifiedTypes> fixQual; 311 375 { 312 376 Stats::Heap::newPass("validate-B"); 313 377 Stats::Time::BlockGuard guard("validate-B"); 314 //linkReferenceToTypes( translationUnit );378 acceptAll( translationUnit, lrt ); // must happen before autogen, because sized flag needs to propagate to generated functions 315 379 mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes_old, because aggregate members are accessed 316 380 HoistStruct::hoistStruct( translationUnit ); … … 343 407 }); 344 408 } 409 } 410 411 static void decayForallPointers( std::list< Declaration * > & translationUnit ) { 412 PassVisitor<TraitExpander_old> te; 413 acceptAll( translationUnit, te ); 414 PassVisitor<AssertionFixer_old> af; 415 acceptAll( translationUnit, af ); 416 PassVisitor<CheckOperatorTypes_old> cot; 417 acceptAll( translationUnit, cot ); 418 PassVisitor<FixUniqueIds_old> fui; 419 acceptAll( translationUnit, fui ); 345 420 } 346 421 … … 421 496 } 422 497 498 void validateType( Type * type, const Indexer * indexer ) { 499 PassVisitor<EnumAndPointerDecay_old> epc; 500 PassVisitor<LinkReferenceToTypes_old> lrt( indexer ); 501 PassVisitor<TraitExpander_old> te; 502 PassVisitor<AssertionFixer_old> af; 503 PassVisitor<CheckOperatorTypes_old> cot; 504 PassVisitor<FixUniqueIds_old> fui; 505 type->accept( epc ); 506 type->accept( lrt ); 507 type->accept( te ); 508 type->accept( af ); 509 type->accept( cot ); 510 type->accept( fui ); 511 } 512 423 513 void HoistTypeDecls::handleType( Type * type ) { 424 514 // some type declarations are buried in expressions and not easy to hoist during parsing; hoist them here … … 613 703 } 614 704 705 void EnumAndPointerDecay_old::previsit( EnumDecl * enumDecl ) { 706 // Set the type of each member of the enumeration to be EnumConstant 707 for ( std::list< Declaration * >::iterator i = enumDecl->members.begin(); i != enumDecl->members.end(); ++i ) { 708 ObjectDecl * obj = dynamic_cast< ObjectDecl * >( * i ); 709 assert( obj ); 710 obj->set_type( new EnumInstType( Type::Qualifiers( Type::Const ), enumDecl->name ) ); 711 } // for 712 } 713 714 namespace { 715 template< typename DWTList > 716 void fixFunctionList( DWTList & dwts, bool isVarArgs, FunctionType * func ) { 717 auto nvals = dwts.size(); 718 bool containsVoid = false; 719 for ( auto & dwt : dwts ) { 720 // fix each DWT and record whether a void was found 721 containsVoid |= fixFunction( dwt ); 722 } 723 724 // the only case in which "void" is valid is where it is the only one in the list 725 if ( containsVoid && ( nvals > 1 || isVarArgs ) ) { 726 SemanticError( func, "invalid type void in function type " ); 727 } 728 729 // one void is the only thing in the list; remove it. 730 if ( containsVoid ) { 731 delete dwts.front(); 732 dwts.clear(); 733 } 734 } 735 } 736 737 void EnumAndPointerDecay_old::previsit( FunctionType * func ) { 738 // Fix up parameters and return types 739 fixFunctionList( func->parameters, func->isVarArgs, func ); 740 fixFunctionList( func->returnVals, false, func ); 741 } 742 743 LinkReferenceToTypes_old::LinkReferenceToTypes_old( const Indexer * other_indexer ) : WithIndexer( false ) { 744 if ( other_indexer ) { 745 local_indexer = other_indexer; 746 } else { 747 local_indexer = &indexer; 748 } // if 749 } 750 751 void LinkReferenceToTypes_old::postvisit( EnumInstType * enumInst ) { 752 const EnumDecl * st = local_indexer->lookupEnum( enumInst->name ); 753 // it's not a semantic error if the enum is not found, just an implicit forward declaration 754 if ( st ) { 755 enumInst->baseEnum = const_cast<EnumDecl *>(st); // Just linking in the node 756 } // if 757 if ( ! st || ! st->body ) { 758 // use of forward declaration 759 forwardEnums[ enumInst->name ].push_back( enumInst ); 760 } // if 761 } 762 763 void LinkReferenceToTypes_old::postvisit( StructInstType * structInst ) { 764 const StructDecl * st = local_indexer->lookupStruct( structInst->name ); 765 // it's not a semantic error if the struct is not found, just an implicit forward declaration 766 if ( st ) { 767 structInst->baseStruct = const_cast<StructDecl *>(st); // Just linking in the node 768 } // if 769 if ( ! st || ! st->body ) { 770 // use of forward declaration 771 forwardStructs[ structInst->name ].push_back( structInst ); 772 } // if 773 } 774 775 void LinkReferenceToTypes_old::postvisit( UnionInstType * unionInst ) { 776 const UnionDecl * un = local_indexer->lookupUnion( unionInst->name ); 777 // it's not a semantic error if the union is not found, just an implicit forward declaration 778 if ( un ) { 779 unionInst->baseUnion = const_cast<UnionDecl *>(un); // Just linking in the node 780 } // if 781 if ( ! un || ! un->body ) { 782 // use of forward declaration 783 forwardUnions[ unionInst->name ].push_back( unionInst ); 784 } // if 785 } 786 787 void LinkReferenceToTypes_old::previsit( QualifiedType * ) { 788 visit_children = false; 789 } 790 791 void LinkReferenceToTypes_old::postvisit( QualifiedType * qualType ) { 792 // linking only makes sense for the 'oldest ancestor' of the qualified type 793 qualType->parent->accept( * visitor ); 794 } 795 796 template< typename Decl > 797 void normalizeAssertions( std::list< Decl * > & assertions ) { 798 // ensure no duplicate trait members after the clone 799 auto pred = [](Decl * d1, Decl * d2) { 800 // only care if they're equal 801 DeclarationWithType * dwt1 = dynamic_cast<DeclarationWithType *>( d1 ); 802 DeclarationWithType * dwt2 = dynamic_cast<DeclarationWithType *>( d2 ); 803 if ( dwt1 && dwt2 ) { 804 if ( dwt1->name == dwt2->name && ResolvExpr::typesCompatible( dwt1->get_type(), dwt2->get_type(), SymTab::Indexer() ) ) { 805 // std::cerr << "=========== equal:" << std::endl; 806 // std::cerr << "d1: " << d1 << std::endl; 807 // std::cerr << "d2: " << d2 << std::endl; 808 return false; 809 } 810 } 811 return d1 < d2; 812 }; 813 std::set<Decl *, decltype(pred)> unique_members( assertions.begin(), assertions.end(), pred ); 814 // if ( unique_members.size() != assertions.size() ) { 815 // std::cerr << "============different" << std::endl; 816 // std::cerr << unique_members.size() << " " << assertions.size() << std::endl; 817 // } 818 819 std::list< Decl * > order; 820 order.splice( order.end(), assertions ); 821 std::copy_if( order.begin(), order.end(), back_inserter( assertions ), [&]( Decl * decl ) { 822 return unique_members.count( decl ); 823 }); 824 } 825 615 826 // expand assertions from trait instance, performing the appropriate type variable substitutions 616 827 template< typename Iterator > … … 623 834 // substitute trait decl parameters for instance parameters 624 835 applySubstitution( inst->baseTrait->parameters.begin(), inst->baseTrait->parameters.end(), inst->parameters.begin(), asserts.begin(), asserts.end(), out ); 836 } 837 838 void LinkReferenceToTypes_old::postvisit( TraitDecl * traitDecl ) { 839 if ( traitDecl->name == "sized" ) { 840 // "sized" is a special trait - flick the sized status on for the type variable 841 assertf( traitDecl->parameters.size() == 1, "Built-in trait 'sized' has incorrect number of parameters: %zd", traitDecl->parameters.size() ); 842 TypeDecl * td = traitDecl->parameters.front(); 843 td->set_sized( true ); 844 } 845 846 // move assertions from type parameters into the body of the trait 847 for ( TypeDecl * td : traitDecl->parameters ) { 848 for ( DeclarationWithType * assert : td->assertions ) { 849 if ( TraitInstType * inst = dynamic_cast< TraitInstType * >( assert->get_type() ) ) { 850 expandAssertions( inst, back_inserter( traitDecl->members ) ); 851 } else { 852 traitDecl->members.push_back( assert->clone() ); 853 } 854 } 855 deleteAll( td->assertions ); 856 td->assertions.clear(); 857 } // for 858 } 859 860 void LinkReferenceToTypes_old::postvisit( TraitInstType * traitInst ) { 861 // handle other traits 862 const TraitDecl * traitDecl = local_indexer->lookupTrait( traitInst->name ); 863 if ( ! traitDecl ) { 864 SemanticError( traitInst->location, "use of undeclared trait " + traitInst->name ); 865 } // if 866 if ( traitDecl->parameters.size() != traitInst->parameters.size() ) { 867 SemanticError( traitInst, "incorrect number of trait parameters: " ); 868 } // if 869 traitInst->baseTrait = const_cast<TraitDecl *>(traitDecl); // Just linking in the node 870 871 // need to carry over the 'sized' status of each decl in the instance 872 for ( auto p : group_iterate( traitDecl->parameters, traitInst->parameters ) ) { 873 TypeExpr * expr = dynamic_cast< TypeExpr * >( std::get<1>(p) ); 874 if ( ! expr ) { 875 SemanticError( std::get<1>(p), "Expression parameters for trait instances are currently unsupported: " ); 876 } 877 if ( TypeInstType * inst = dynamic_cast< TypeInstType * >( expr->get_type() ) ) { 878 TypeDecl * formalDecl = std::get<0>(p); 879 TypeDecl * instDecl = inst->baseType; 880 if ( formalDecl->get_sized() ) instDecl->set_sized( true ); 881 } 882 } 883 // normalizeAssertions( traitInst->members ); 884 } 885 886 void LinkReferenceToTypes_old::postvisit( EnumDecl * enumDecl ) { 887 // visit enum members first so that the types of self-referencing members are updated properly 888 if ( enumDecl->body ) { 889 ForwardEnumsType::iterator fwds = forwardEnums.find( enumDecl->name ); 890 if ( fwds != forwardEnums.end() ) { 891 for ( std::list< EnumInstType * >::iterator inst = fwds->second.begin(); inst != fwds->second.end(); ++inst ) { 892 (* inst)->baseEnum = enumDecl; 893 } // for 894 forwardEnums.erase( fwds ); 895 } // if 896 } // if 897 } 898 899 void LinkReferenceToTypes_old::renameGenericParams( std::list< TypeDecl * > & params ) { 900 // rename generic type parameters uniquely so that they do not conflict with user-defined function forall parameters, e.g. 901 // forall(otype T) 902 // struct Box { 903 // T x; 904 // }; 905 // forall(otype T) 906 // void f(Box(T) b) { 907 // ... 908 // } 909 // The T in Box and the T in f are different, so internally the naming must reflect that. 910 GuardValue( inGeneric ); 911 inGeneric = ! params.empty(); 912 for ( TypeDecl * td : params ) { 913 td->name = "__" + td->name + "_generic_"; 914 } 915 } 916 917 void LinkReferenceToTypes_old::previsit( StructDecl * structDecl ) { 918 renameGenericParams( structDecl->parameters ); 919 } 920 921 void LinkReferenceToTypes_old::previsit( UnionDecl * unionDecl ) { 922 renameGenericParams( unionDecl->parameters ); 923 } 924 925 void LinkReferenceToTypes_old::postvisit( StructDecl * structDecl ) { 926 // visit struct members first so that the types of self-referencing members are updated properly 927 // xxx - need to ensure that type parameters match up between forward declarations and definition (most importantly, number of type parameters and their defaults) 928 if ( structDecl->body ) { 929 ForwardStructsType::iterator fwds = forwardStructs.find( structDecl->name ); 930 if ( fwds != forwardStructs.end() ) { 931 for ( std::list< StructInstType * >::iterator inst = fwds->second.begin(); inst != fwds->second.end(); ++inst ) { 932 (* inst)->baseStruct = structDecl; 933 } // for 934 forwardStructs.erase( fwds ); 935 } // if 936 } // if 937 } 938 939 void LinkReferenceToTypes_old::postvisit( UnionDecl * unionDecl ) { 940 if ( unionDecl->body ) { 941 ForwardUnionsType::iterator fwds = forwardUnions.find( unionDecl->name ); 942 if ( fwds != forwardUnions.end() ) { 943 for ( std::list< UnionInstType * >::iterator inst = fwds->second.begin(); inst != fwds->second.end(); ++inst ) { 944 (* inst)->baseUnion = unionDecl; 945 } // for 946 forwardUnions.erase( fwds ); 947 } // if 948 } // if 949 } 950 951 void LinkReferenceToTypes_old::postvisit( TypeInstType * typeInst ) { 952 // ensure generic parameter instances are renamed like the base type 953 if ( inGeneric && typeInst->baseType ) typeInst->name = typeInst->baseType->name; 954 if ( const NamedTypeDecl * namedTypeDecl = local_indexer->lookupType( typeInst->name ) ) { 955 if ( const TypeDecl * typeDecl = dynamic_cast< const TypeDecl * >( namedTypeDecl ) ) { 956 typeInst->set_isFtype( typeDecl->kind == TypeDecl::Ftype ); 957 } // if 958 } // if 625 959 } 626 960 … … 651 985 } 652 986 } 987 653 988 } 654 989 } … … 738 1073 void ForallPointerDecay_old::previsit( UnionDecl * aggrDecl ) { 739 1074 forallFixer( aggrDecl->parameters, aggrDecl ); 1075 } 1076 1077 void TraitExpander_old::previsit( FunctionType * ftype ) { 1078 expandTraits( ftype->forall ); 1079 } 1080 1081 void TraitExpander_old::previsit( StructDecl * aggrDecl ) { 1082 expandTraits( aggrDecl->parameters ); 1083 } 1084 1085 void TraitExpander_old::previsit( UnionDecl * aggrDecl ) { 1086 expandTraits( aggrDecl->parameters ); 1087 } 1088 1089 void AssertionFixer_old::previsit( FunctionType * ftype ) { 1090 fixAssertions( ftype->forall, ftype ); 1091 } 1092 1093 void AssertionFixer_old::previsit( StructDecl * aggrDecl ) { 1094 fixAssertions( aggrDecl->parameters, aggrDecl ); 1095 } 1096 1097 void AssertionFixer_old::previsit( UnionDecl * aggrDecl ) { 1098 fixAssertions( aggrDecl->parameters, aggrDecl ); 1099 } 1100 1101 void CheckOperatorTypes_old::previsit( ObjectDecl * object ) { 1102 // ensure that operator names only apply to functions or function pointers 1103 if ( CodeGen::isOperator( object->name ) && ! dynamic_cast< FunctionType * >( object->type->stripDeclarator() ) ) { 1104 SemanticError( object->location, toCString( "operator ", object->name.c_str(), " is not a function or function pointer." ) ); 1105 } 1106 } 1107 1108 void FixUniqueIds_old::previsit( DeclarationWithType * decl ) { 1109 decl->fixUniqueId(); 740 1110 } 741 1111 -
src/SymTab/Validate.h
r74ec742 r29d8c02 10 10 // Author : Richard C. Bilson 11 11 // Created On : Sun May 17 21:53:34 2015 12 // Last Modified By : Andrew Beach13 // Last Modified On : Tue May 17 14:35:00 202214 // Update Count : 512 // Last Modified By : Peter A. Buhr 13 // Last Modified On : Sat Jul 22 09:46:07 2017 14 // Update Count : 4 15 15 // 16 16 … … 33 33 /// Normalizes struct and function declarations 34 34 void validate( std::list< Declaration * > &translationUnit, bool doDebug = false ); 35 void validateType( Type *type, const Indexer *indexer ); 35 36 36 37 // Sub-passes of validate. … … 41 42 void validate_E( std::list< Declaration * > &translationUnit ); 42 43 void validate_F( std::list< Declaration * > &translationUnit ); 44 45 const ast::Type * validateType( 46 const CodeLocation & loc, const ast::Type * type, const ast::SymbolTable & symtab ); 43 47 } // namespace SymTab 44 48 -
src/SymTab/demangler.cc
r74ec742 r29d8c02 1 #include " Demangle.h"1 #include "Mangler.h" 2 2 #include <iostream> 3 3 #include <fstream> -
src/SymTab/module.mk
r74ec742 r29d8c02 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 12 ## Last Modified By : Andrew Beach 13 ## Last Modified On : T ue May 17 14:46:00 202214 ## Update Count : 513 ## Last Modified On : Thr Aug 10 16:08:00 2017 14 ## Update Count : 4 15 15 ############################################################################### 16 16 17 17 SRC_SYMTAB = \ 18 SymTab/Autogen.cc \19 SymTab/Autogen.h \20 SymTab/FixFunction.cc \21 SymTab/FixFunction.h \22 SymTab/Indexer.cc \23 SymTab/Indexer.h \24 SymTab/Mangler.cc \25 SymTab/ManglerCommon.cc \26 SymTab/Mangler.h \27 SymTab/ValidateType.cc \28 SymTab/ValidateType.h18 SymTab/Autogen.cc \ 19 SymTab/Autogen.h \ 20 SymTab/FixFunction.cc \ 21 SymTab/FixFunction.h \ 22 SymTab/Indexer.cc \ 23 SymTab/Indexer.h \ 24 SymTab/Mangler.cc \ 25 SymTab/ManglerCommon.cc \ 26 SymTab/Mangler.h \ 27 SymTab/Validate.cc \ 28 SymTab/Validate.h 29 29 30 SRC += $(SRC_SYMTAB) \ 31 SymTab/Validate.cc \ 32 SymTab/Validate.h 33 34 SRCDEMANGLE += $(SRC_SYMTAB) \ 35 SymTab/Demangle.cc \ 36 SymTab/Demangle.h 30 SRC += $(SRC_SYMTAB) 31 SRCDEMANGLE += $(SRC_SYMTAB) SymTab/Demangle.cc -
src/SynTree/module.mk
r74ec742 r29d8c02 24 24 SynTree/AttrType.cc \ 25 25 SynTree/BaseSyntaxNode.h \ 26 SynTree/BaseSyntaxNode.cc \27 26 SynTree/BasicType.cc \ 28 27 SynTree/CommaExpr.cc \ -
src/Tuples/TupleExpansion.cc
r74ec742 r29d8c02 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Andrew Beach12 // Last Modified On : Tue May 17 15:02:00 202213 // Update Count : 2 511 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Fri Dec 13 23:45:51 2019 13 // Update Count : 24 14 14 // 15 15 … … 367 367 return nullptr; 368 368 } 369 370 namespace { 371 /// determines if impurity (read: side-effects) may exist in a piece of code. Currently gives a very crude approximation, wherein any function call expression means the code may be impure 372 struct ImpurityDetector : public WithShortCircuiting { 373 ImpurityDetector( bool ignoreUnique ) : ignoreUnique( ignoreUnique ) {} 374 375 void previsit( const ApplicationExpr * appExpr ) { 376 visit_children = false; 377 if ( const DeclarationWithType * function = InitTweak::getFunction( appExpr ) ) { 378 if ( function->linkage == LinkageSpec::Intrinsic ) { 379 if ( function->name == "*?" || function->name == "?[?]" ) { 380 // intrinsic dereference, subscript are pure, but need to recursively look for impurity 381 visit_children = true; 382 return; 383 } 384 } 385 } 386 maybeImpure = true; 387 } 388 void previsit( const UntypedExpr * ) { maybeImpure = true; visit_children = false; } 389 void previsit( const UniqueExpr * ) { 390 if ( ignoreUnique ) { 391 // bottom out at unique expression. 392 // The existence of a unique expression doesn't change the purity of an expression. 393 // That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression. 394 visit_children = false; 395 return; 396 } 397 } 398 399 bool maybeImpure = false; 400 bool ignoreUnique; 401 }; 402 } // namespace 403 404 bool maybeImpure( const Expression * expr ) { 405 PassVisitor<ImpurityDetector> detector( false ); 406 expr->accept( detector ); 407 return detector.pass.maybeImpure; 408 } 409 410 bool maybeImpureIgnoreUnique( const Expression * expr ) { 411 PassVisitor<ImpurityDetector> detector( true ); 412 expr->accept( detector ); 413 return detector.pass.maybeImpure; 414 } 369 415 } // namespace Tuples 370 416 -
src/Tuples/Tuples.cc
r74ec742 r29d8c02 10 10 // Created On : Mon Jun 17 14:41:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon May 16 16:15:00 202213 // Update Count : 212 // Last Modified On : Tue Jun 18 9:31:00 2019 13 // Update Count : 1 14 14 // 15 15 … … 18 18 #include "AST/Pass.hpp" 19 19 #include "AST/LinkageSpec.hpp" 20 #include "Common/PassVisitor.h"21 20 #include "InitTweak/InitTweak.h" 22 21 … … 24 23 25 24 namespace { 26 /// Checks if impurity (read: side-effects) may exist in a piece of code.27 /// Currently gives a very crude approximation, wherein any function28 /// call expression means the code may be impure.29 struct ImpurityDetector_old : public WithShortCircuiting {30 bool const ignoreUnique;31 bool maybeImpure;32 33 ImpurityDetector_old( bool ignoreUnique ) :34 ignoreUnique( ignoreUnique ), maybeImpure( false )35 {}36 37 void previsit( const ApplicationExpr * appExpr ) {38 visit_children = false;39 if ( const DeclarationWithType * function =40 InitTweak::getFunction( appExpr ) ) {41 if ( function->linkage == LinkageSpec::Intrinsic ) {42 if ( function->name == "*?" || function->name == "?[?]" ) {43 // intrinsic dereference, subscript are pure,44 // but need to recursively look for impurity45 visit_children = true;46 return;47 }48 }49 }50 maybeImpure = true;51 }52 53 void previsit( const UntypedExpr * ) {54 maybeImpure = true;55 visit_children = false;56 }57 58 void previsit( const UniqueExpr * ) {59 if ( ignoreUnique ) {60 // bottom out at unique expression.61 // The existence of a unique expression doesn't change the purity of an expression.62 // That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression.63 visit_children = false;64 return;65 }66 }67 };68 69 bool detectImpurity( const Expression * expr, bool ignoreUnique ) {70 PassVisitor<ImpurityDetector_old> detector( ignoreUnique );71 expr->accept( detector );72 return detector.pass.maybeImpure;73 }74 75 25 /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives 76 26 /// a very crude approximation, wherein any function call expression means the code may be 77 27 /// impure. 78 28 struct ImpurityDetector : public ast::WithShortCircuiting { 79 bool result= false;29 bool maybeImpure = false; 80 30 81 31 void previsit( ast::ApplicationExpr const * appExpr ) { … … 86 36 } 87 37 } 88 result= true; visit_children = false;38 maybeImpure = true; visit_children = false; 89 39 } 90 40 void previsit( ast::UntypedExpr const * ) { 91 result= true; visit_children = false;41 maybeImpure = true; visit_children = false; 92 42 } 93 43 }; 94 95 44 struct ImpurityDetectorIgnoreUnique : public ImpurityDetector { 96 45 using ImpurityDetector::previsit; … … 99 48 } 100 49 }; 50 51 template<typename Detector> 52 bool detectImpurity( const ast::Expr * expr ) { 53 ast::Pass<Detector> detector; 54 expr->accept( detector ); 55 return detector.core.maybeImpure; 56 } 101 57 } // namespace 102 58 103 59 bool maybeImpure( const ast::Expr * expr ) { 104 return ast::Pass<ImpurityDetector>::read( expr );60 return detectImpurity<ImpurityDetector>( expr ); 105 61 } 106 62 107 63 bool maybeImpureIgnoreUnique( const ast::Expr * expr ) { 108 return ast::Pass<ImpurityDetectorIgnoreUnique>::read( expr ); 109 } 110 111 bool maybeImpure( const Expression * expr ) { 112 return detectImpurity( expr, false ); 113 } 114 115 bool maybeImpureIgnoreUnique( const Expression * expr ) { 116 return detectImpurity( expr, true ); 64 return detectImpurity<ImpurityDetectorIgnoreUnique>( expr ); 117 65 } 118 66 -
src/Tuples/module.mk
r74ec742 r29d8c02 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Andrew Beach13 ## Last Modified On : Mon May 17 15:00:00 202214 ## Update Count : 312 ## Last Modified By : Henry Xue 13 ## Last Modified On : Mon Aug 23 15:36:09 2021 14 ## Update Count : 2 15 15 ############################################################################### 16 16 … … 24 24 Tuples/Tuples.h 25 25 26 26 27 SRC += $(SRC_TUPLES) 27 28 28 SRCDEMANGLE += $(SRC_TUPLES) -
src/Validate/Autogen.cpp
r74ec742 r29d8c02 350 350 name, 351 351 std::move( type_params ), 352 std::move( assertions ),353 352 std::move( params ), 354 353 std::move( returns ), … … 361 360 // Auto-generated routines are inline to avoid conflicts. 362 361 ast::Function::Specs( ast::Function::Inline ) ); 362 decl->assertions = std::move( assertions ); 363 363 decl->fixUniqueId(); 364 364 return decl; -
src/Validate/ForallPointerDecay.cpp
r74ec742 r29d8c02 10 10 // Created On : Tue Dec 7 16:15:00 2021 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Sat Apr 23 13:10:00 202213 // Update Count : 112 // Last Modified On : Fri Feb 11 10:59:00 2022 13 // Update Count : 0 14 14 // 15 15 … … 237 237 } 238 238 239 std::vector<ast::ptr<ast::DeclWithType>> expandAssertions(240 std::vector<ast::ptr<ast::DeclWithType>> const & old ) {241 return TraitExpander::expandAssertions( old );242 }243 244 239 } // namespace Validate 245 240 -
src/Validate/ForallPointerDecay.hpp
r74ec742 r29d8c02 10 10 // Created On : Tue Dec 7 16:15:00 2021 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Sat Apr 23 13:13:00 202213 // Update Count : 112 // Last Modified On : Tue Dec 8 11:50:00 2021 13 // Update Count : 0 14 14 // 15 15 16 16 #pragma once 17 17 18 #include <vector>19 #include "AST/Node.hpp"20 21 18 namespace ast { 22 class DeclWithType;23 19 class TranslationUnit; 24 20 } … … 31 27 void decayForallPointers( ast::TranslationUnit & transUnit ); 32 28 33 /// Expand all traits in an assertion list.34 std::vector<ast::ptr<ast::DeclWithType>> expandAssertions(35 std::vector<ast::ptr<ast::DeclWithType>> const & );36 37 29 } 38 30 -
src/Validate/GenericParameter.cpp
r74ec742 r29d8c02 10 10 // Created On : Fri Mar 21 10:02:00 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Apr 22 16:43:00 202213 // Update Count : 112 // Last Modified On : Wed Apr 13 10:09:00 2022 13 // Update Count : 0 14 14 // 15 15 … … 22 22 #include "AST/TranslationUnit.hpp" 23 23 #include "AST/Type.hpp" 24 #include "Validate/NoIdSymbolTable.hpp"25 24 26 25 namespace Validate { … … 139 138 // -------------------------------------------------------------------------- 140 139 141 struct TranslateDimensionCore : 142 public WithNoIdSymbolTable, public ast::WithGuards { 140 // A SymbolTable that only has the operations used in the Translate Dimension 141 // pass. More importantly, it doesn't have some methods that should no be 142 // called by the Pass template (lookupId and addId). 143 class NoIdSymbolTable { 144 ast::SymbolTable base; 145 public: 146 # define FORWARD_X( func, types_and_names, just_names ) \ 147 inline auto func types_and_names -> decltype( base.func just_names ) { \ 148 return base.func just_names ; \ 149 } 150 # define FORWARD_0( func ) FORWARD_X( func, (), () ) 151 # define FORWARD_1( func, type ) FORWARD_X( func, (type arg), (arg) ) 152 # define FORWARD_2( func, t0, t1 ) FORWARD_X( func, (t0 a0, t1 a1), (a0, a1) ) 153 154 FORWARD_0( enterScope ) 155 FORWARD_0( leaveScope ) 156 FORWARD_1( lookupType, const std::string & ) 157 FORWARD_1( addType , const ast::NamedTypeDecl * ) 158 FORWARD_1( addStruct , const ast::StructDecl * ) 159 FORWARD_1( addEnum , const ast::EnumDecl * ) 160 FORWARD_1( addUnion , const ast::UnionDecl * ) 161 FORWARD_1( addTrait , const ast::TraitDecl * ) 162 FORWARD_2( addWith , const std::vector< ast::ptr<ast::Expr> > &, const ast::Decl * ) 163 }; 164 165 struct TranslateDimensionCore : public ast::WithGuards { 166 NoIdSymbolTable symtab; 143 167 144 168 // SUIT: Struct- or Union- InstType -
src/Validate/module.mk
r74ec742 r29d8c02 10 10 ## Author : Rob Schluntz 11 11 ## Created On : Fri Jul 27 10:10:10 2018 12 ## Last Modified By : Andrew Beach13 ## Last Modified On : Tue May 17 14:59:00 202214 ## Update Count : 312 ## Last Modified By : Rob Schluntz 13 ## Last Modified On : Fri Jul 27 10:10:26 2018 14 ## Update Count : 2 15 15 ############################################################################### 16 16 17 17 SRC_VALIDATE = \ 18 Validate/FindSpecialDecls.cc \19 Validate/FindSpecialDecls.h20 21 SRC += $(SRC_VALIDATE) \22 18 Validate/Autogen.cpp \ 23 19 Validate/Autogen.hpp \ 24 20 Validate/CompoundLiteral.cpp \ 25 21 Validate/CompoundLiteral.hpp \ 26 Validate/EliminateTypedef.cpp \27 Validate/EliminateTypedef.hpp \28 Validate/FindSpecialDeclsNew.cpp \29 Validate/FixQualifiedTypes.cpp \30 Validate/FixQualifiedTypes.hpp \31 22 Validate/ForallPointerDecay.cpp \ 32 23 Validate/ForallPointerDecay.hpp \ … … 35 26 Validate/HandleAttributes.cc \ 36 27 Validate/HandleAttributes.h \ 37 Validate/HoistStruct.cpp \38 Validate/HoistStruct.hpp \39 28 Validate/InitializerLength.cpp \ 40 29 Validate/InitializerLength.hpp \ 41 30 Validate/LabelAddressFixer.cpp \ 42 31 Validate/LabelAddressFixer.hpp \ 43 Validate/NoIdSymbolTable.hpp \44 32 Validate/ReturnCheck.cpp \ 45 Validate/ReturnCheck.hpp 33 Validate/ReturnCheck.hpp \ 34 Validate/FindSpecialDeclsNew.cpp \ 35 Validate/FindSpecialDecls.cc \ 36 Validate/FindSpecialDecls.h 46 37 38 SRC += $(SRC_VALIDATE) 47 39 SRCDEMANGLE += $(SRC_VALIDATE) -
src/Virtual/module.mk
r74ec742 r29d8c02 11 11 ## Created On : Tus Jul 25 10:18:00 2017 12 12 ## Last Modified By : Andrew Beach 13 ## Last Modified On : Tus May 17 14:59:00 202214 ## Update Count : 113 ## Last Modified On : Tus Jul 25 10:18:00 2017 14 ## Update Count : 0 15 15 ############################################################################### 16 16 17 SRC += \ 18 Virtual/ExpandCasts.cc \ 19 Virtual/ExpandCasts.h \ 20 Virtual/Tables.cc \ 21 Virtual/Tables.h 17 SRC += Virtual/ExpandCasts.cc Virtual/ExpandCasts.h \ 18 Virtual/Tables.cc Virtual/Tables.h 19 20 SRCDEMANGLE += Virtual/Tables.cc -
src/main.cc
r74ec742 r29d8c02 10 10 // Created On : Fri May 15 23:12:02 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Apr 29 9:52:00 202213 // Update Count : 67 312 // Last Modified On : Wed Apr 13 11:11:00 2022 13 // Update Count : 672 14 14 // 15 15 … … 70 70 #include "ResolvExpr/Resolver.h" // for resolve 71 71 #include "SymTab/Validate.h" // for validate 72 #include "SymTab/ValidateType.h" // for linkReferenceToTypes73 72 #include "SynTree/LinkageSpec.h" // for Spec, Cforall, Intrinsic 74 73 #include "SynTree/Declaration.h" // for Declaration … … 76 75 #include "Tuples/Tuples.h" // for expandMemberTuples, expan... 77 76 #include "Validate/Autogen.hpp" // for autogenerateRoutines 77 #include "Validate/GenericParameter.hpp" // for fillGenericParameters, tr... 78 #include "Validate/FindSpecialDecls.h" // for findGlobalDecls 79 #include "Validate/ForallPointerDecay.hpp" // for decayForallPointers 78 80 #include "Validate/CompoundLiteral.hpp" // for handleCompoundLiterals 79 #include "Validate/EliminateTypedef.hpp" // for eliminateTypedef80 #include "Validate/FindSpecialDecls.h" // for findGlobalDecls81 #include "Validate/FixQualifiedTypes.hpp" // for fixQualifiedTypes82 #include "Validate/ForallPointerDecay.hpp" // for decayForallPointers83 #include "Validate/GenericParameter.hpp" // for fillGenericParameters, tr...84 #include "Validate/HoistStruct.hpp" // for hoistStruct85 81 #include "Validate/InitializerLength.hpp" // for setLengthFromInitializer 86 82 #include "Validate/LabelAddressFixer.hpp" // for fixLabelAddresses … … 332 328 // add the assignment statement after the initialization of a type parameter 333 329 PASS( "Validate-A", SymTab::validate_A( translationUnit ) ); 334 335 // Must happen before auto-gen, because it uses the sized flag. 336 PASS( "Link Reference To Types", SymTab::linkReferenceToTypes( translationUnit ) ); 330 PASS( "Validate-B", SymTab::validate_B( translationUnit ) ); 337 331 338 332 CodeTools::fillLocations( translationUnit ); … … 348 342 349 343 forceFillCodeLocations( transUnit ); 350 351 // Must happen after Link References To Types,352 // because aggregate members are accessed.353 PASS( "Fix Qualified Types", Validate::fixQualifiedTypes( transUnit ) );354 355 PASS( "Hoist Struct", Validate::hoistStruct( transUnit ) );356 PASS( "Eliminate Typedef", Validate::eliminateTypedef( transUnit ) );357 344 358 345 // Check as early as possible. Can't happen before … … 451 438 translationUnit = convert( move( transUnit ) ); 452 439 } else { 453 PASS( "Validate-B", SymTab::validate_B( translationUnit ) );454 440 PASS( "Validate-C", SymTab::validate_C( translationUnit ) ); 455 441 PASS( "Validate-D", SymTab::validate_D( translationUnit ) ); -
tests/.expect/forall.txt
r74ec742 r29d8c02 1 forall.cfa:24 4:25: warning: Compiled1 forall.cfa:242:25: warning: Compiled -
tests/forall.cfa
r74ec742 r29d8c02 1 // 1 // 2 2 // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo 3 3 // 4 4 // The contents of this file are covered under the licence agreement in the 5 5 // file "LICENCE" distributed with Cforall. 6 // 7 // forall.cfa -- 8 // 6 // 7 // forall.cfa -- 8 // 9 9 // Author : Peter A. Buhr 10 10 // Created On : Wed May 9 08:48:15 2018 … … 12 12 // Last Modified On : Sat Jun 5 10:06:08 2021 13 13 // Update Count : 36 14 // 14 // 15 15 16 16 void g1() { … … 45 45 } 46 46 47 // commented this out since it is not clearly meaningful 48 // and not really representable in the ast 49 // typedef forall ( T ) int (* f)( int ); 47 typedef forall ( T ) int (* f)( int ); 50 48 51 49 forall( T ) … … 172 170 } 173 171 174 forall( T | { T ?+?( T, T ); } ) forall( S | { T ?+?( T, S ); } ) 172 forall( T | { T ?+?( T, T ); } ) forall( S | { T ?+?( T, S ); } ) 175 173 struct XW { T t; }; 176 174 XW(int,int) xww; -
tests/include/.expect/includes.nast.txt
r74ec742 r29d8c02 1 include/includes.cfa:1 69:25: warning: Compiled1 include/includes.cfa:153:25: warning: Compiled -
tests/include/includes.cfa
r74ec742 r29d8c02 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue May 10 16:36:44202213 // Update Count : 77 612 // Last Modified On : Thu Feb 3 22:06:07 2022 13 // Update Count : 774 14 14 // 15 15 … … 32 32 #include <crypt.h> 33 33 #include <ctype.h> 34 #if __has_include( "curses.h" ) 35 #include <curses.h> // may not be installed 36 #endif 34 //#include <curses.h> // may not be installed 37 35 #include <dirent.h> 38 36 #include <dlfcn.h> … … 43 41 #include <errno.h> 44 42 #include <error.h> 45 #if __has_include( "eti.h" ) 46 #include <eti.h> // may not be installed, comes with ncurses 47 #endif 43 //#include <eti.h> // may not be installed, comes with ncurses 48 44 #include <execinfo.h> 49 45 #include <expat.h> … … 54 50 #include <fmtmsg.h> 55 51 #include <fnmatch.h> 56 #if __has_include( "form.h" ) 57 #include <form.h> // may not be installed, comes with ncurses 58 #endif 52 //#include <form.h> // may not be installed, comes with ncurses 59 53 #include <fstab.h> 60 54 #include <fts.h> … … 84 78 #include <mcheck.h> 85 79 #include <memory.h> 86 #if __has_include( "menu.h" ) 87 #include <menu.h> // may not be installed, comes with ncurses 88 #endif 80 //#include <menu.h> // may not be installed, comes with ncurses 89 81 #include <mntent.h> 90 82 #include <monetary.h> 91 83 #include <mqueue.h> 92 #if __has_include( "ncurses_dll.h" ) 93 #include <ncurses_dll.h> // may not be installed, comes with ncurses 94 #endif 84 //#include <ncurses_dll.h> // may not be installed, comes with ncurses 95 85 #include <netdb.h> 96 86 #include <nl_types.h> 97 87 #include <nss.h> 98 88 #include <obstack.h> 99 #if __has_include( "panel.h" ) 100 #include <panel.h> // may not be installed, comes with ncurses 101 #endif 89 //#include <panel.h> // may not be installed, comes with ncurses 102 90 #include <paths.h> 103 91 #include <poll.h> … … 130 118 #include <syslog.h> 131 119 #include <tar.h> 132 #if __has_include( "term.h" ) 133 #include <term.h> // may not be installed, comes with ncurses 134 #include <termcap.h> // may not be installed, comes with ncurses 135 #endif 120 //#include <term.h> // may not be installed, comes with ncurses 121 //#include <termcap.h> // may not be installed, comes with ncurses 136 122 #include <termio.h> 137 123 #include <termios.h> … … 145 131 #include <ucontext.h> 146 132 #include <ulimit.h> 147 #if __has_include( "unctrl.h" ) 148 #include <unctrl.h> // may not be installed, comes with ncurses 149 #endif 133 //#include <unctrl.h> // may not be installed, comes with ncurses 150 134 #include <unistd.h> 151 135 #include <utime.h> -
tests/pybin/settings.py
r74ec742 r29d8c02 201 201 global output_width 202 202 output_width = max(map(lambda t: len(t.target()), tests)) 203 # 35 is the maximum width of the name field before we get line wrapping.204 output_width = min(output_width, 35) -
tests/pybin/test_run.py
r74ec742 r29d8c02 43 43 return os.path.normpath( os.path.join(settings.BUILDDIR, self.path, self.name) ) 44 44 45 def format_target(self, width):46 target = self.target()47 length = len(target)48 if length < width:49 return '{0:{width}}'.format(target, width=width)50 elif length == width:51 return target52 else:53 return '...' + target[3-width:]54 55 45 @staticmethod 56 46 def valid_name(name): -
tests/test.py
r74ec742 r29d8c02 132 132 parser.add_argument('--install', help='Run all tests based on installed binaries or tree binaries', type=comma_separated(yes_no), default='no') 133 133 parser.add_argument('--continue', help='When multiple specifications are passed (debug/install/arch), sets whether or not to continue if the last specification failed', type=yes_no, default='yes', dest='continue_') 134 parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=1 80)134 parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=120) 135 135 parser.add_argument('--global-timeout', help='Maximum cumulative duration in seconds after the ALL tests are considered to have timed out', type=int, default=7200) 136 136 parser.add_argument('--timeout-with-gdb', help='Instead of killing the command when it times out, orphan it and print process id to allow gdb to attach', type=yes_no, default="no") … … 252 252 try : 253 253 # print formated name 254 name_txt = t.format_target(width=settings.output_width) + ' '254 name_txt = '{0:{width}} '.format(t.target(), width=settings.output_width) 255 255 256 256 retcode, error, duration = run_single_test(t) -
tests/unified_locking/.expect/locks.txt
r74ec742 r29d8c02 23 23 Start Test 12: locked condition variable wait/notify with front() 24 24 Done Test 12 25 Start Test 13: fast block lock and fast cond var single wait/notify26 Done Test 13 -
tests/unified_locking/locks.cfa
r74ec742 r29d8c02 18 18 condition_variable( linear_backoff_then_block_lock ) c_l; 19 19 20 fast_block_lock f;21 fast_cond_var( fast_block_lock ) f_c_f;22 23 20 thread T_C_M_WS1 {}; 24 21 … … 102 99 } 103 100 unlock(l); 104 }105 }106 107 thread T_F_C_F_WS1 {};108 109 void main( T_F_C_F_WS1 & this ) {110 for (unsigned int i = 0; i < num_times; i++) {111 lock(f);112 if(empty(f_c_f) && i != num_times - 1) {113 wait(f_c_f,f);114 }else{115 notify_one(f_c_f);116 unlock(f);117 }118 101 } 119 102 } … … 339 322 } 340 323 printf("Done Test 12\n"); 341 342 printf("Start Test 13: fast block lock and fast cond var single wait/notify\n"); 343 { 344 T_F_C_F_WS1 t1[2]; 345 } 346 printf("Done Test 13\n"); 347 348 } 324 }
Note:
See TracChangeset
for help on using the changeset viewer.