Changeset 74ec742
- Timestamp:
- May 20, 2022, 10:36:45 AM (3 years ago)
- Branches:
- ADT, ast-experimental, master, pthread-emulation, qualifiedEnum
- Children:
- 25fa20a
- Parents:
- 29d8c02 (diff), 7831e8fb (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - Files:
-
- 35 added
- 3 deleted
- 137 edited
- 1 moved
-
benchmark/Cargo.toml.in (modified) (1 diff)
-
benchmark/Makefile.am (modified) (1 diff)
-
benchmark/c.c (deleted)
-
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 (added)
-
benchmark/readyQ/churn.go (added)
-
benchmark/readyQ/churn.rs (added)
-
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 (deleted)
-
doc/theses/thierry_delisle_PhD/thesis/Makefile (modified) (3 diffs)
-
doc/theses/thierry_delisle_PhD/thesis/data/churn.jax (added)
-
doc/theses/thierry_delisle_PhD/thesis/data/churn.low.jax (added)
-
doc/theses/thierry_delisle_PhD/thesis/data/cycle.jax (modified) (1 diff)
-
doc/theses/thierry_delisle_PhD/thesis/data/cycle.low.jax (added)
-
doc/theses/thierry_delisle_PhD/thesis/data/memcd.rate (added)
-
doc/theses/thierry_delisle_PhD/thesis/data/memcd.updt (added)
-
doc/theses/thierry_delisle_PhD/thesis/data/yield.jax (added)
-
doc/theses/thierry_delisle_PhD/thesis/data/yield.low.jax (added)
-
doc/theses/thierry_delisle_PhD/thesis/fig/SAVE.fig (added)
-
doc/theses/thierry_delisle_PhD/thesis/fig/idle.fig (added)
-
doc/theses/thierry_delisle_PhD/thesis/fig/idle1.fig (added)
-
doc/theses/thierry_delisle_PhD/thesis/fig/idle2.fig (added)
-
doc/theses/thierry_delisle_PhD/thesis/fig/idle_state.fig (added)
-
doc/theses/thierry_delisle_PhD/thesis/local.bib (modified) (1 diff)
-
doc/theses/thierry_delisle_PhD/thesis/test.svg (added)
-
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 (deleted)
-
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 (added)
-
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 (added)
-
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 (added)
-
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 (added)
-
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 (added)
-
src/SymTab/ValidateType.h (added)
-
src/SymTab/demangler.cc (modified) (1 diff)
-
src/SymTab/module.mk (modified) (1 diff)
-
src/SynTree/BaseSyntaxNode.cc (added)
-
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 (added)
-
src/Validate/EliminateTypedef.hpp (added)
-
src/Validate/FixQualifiedTypes.cpp (added)
-
src/Validate/FixQualifiedTypes.hpp (added)
-
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 (added)
-
src/Validate/HoistStruct.hpp (added)
-
src/Validate/NoIdSymbolTable.hpp (added)
-
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 (added)
-
tests/.expect/nested-types-ERR2.nast.txt (added)
-
tests/.expect/nested-types-ERR2.oast.txt (moved) (moved from tests/.expect/nested-types-ERR2.txt )
-
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 (added)
-
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 (added)
-
tests/unified_locking/.expect/locks.txt (modified) (1 diff)
-
tests/unified_locking/fast_block_lock.cfa (added)
-
tests/unified_locking/locks.cfa (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
benchmark/Cargo.toml.in
r29d8c02 r74ec742 4 4 authors = ["Cforall"] 5 5 edition = "2018" 6 7 [[bin]] 8 name = "rdq-churn-tokio" 9 path = "@abs_srcdir@/readyQ/churn.rs" 6 10 7 11 [[bin]] -
benchmark/Makefile.am
r29d8c02 r74ec742 614 614 RDQBENCHES = \ 615 615 rdq-churn-cfa \ 616 rdq-churn-tokio \ 617 rdq-churn-go \ 618 rdq-churn-fibre \ 616 619 rdq-cycle-cfa \ 617 620 rdq-cycle-tokio \ -
benchmark/plot.py
r29d8c02 r74ec742 22 22 23 23 class Field: 24 def __init__(self, unit, _min, _log ):24 def __init__(self, unit, _min, _log, _name=None): 25 25 self.unit = unit 26 26 self.min = _min 27 27 self.log = _log 28 self.name = _name 28 29 29 30 field_names = { … … 32 33 "Ops per procs" : Field('Ops' , 0, False), 33 34 "Ops per threads" : Field('Ops' , 0, False), 34 "ns per ops/procs" : Field(' ns' , 0, False),35 "Number of threads" : Field(' thrd', 1, False),35 "ns per ops/procs" : Field('' , 0, False, _name = "Latency (ns $/$ (Processor $\\times$ Operation))" ), 36 "Number of threads" : Field('' , 1, False), 36 37 "Total Operations(ops)" : Field('Ops' , 0, False), 37 38 "Ops/sec/procs" : Field('Ops' , 0, False), 38 39 "Total blocks" : Field('Blocks', 0, False), 39 "Ops per second" : Field(' Ops' , 0, False),40 "Ops per second" : Field('' , 0, False), 40 41 "Cycle size (# thrds)" : Field('thrd' , 1, False), 41 42 "Duration (ms)" : Field('ms' , 0, False), 42 "Target QPS" : Field('QPS' , 0, False), 43 "Actual QPS" : Field('QPS' , 0, False), 43 "Target QPS" : Field('' , 0, False), 44 "Actual QPS" : Field('' , 0, False), 45 "Average Read Latency" : Field('us' , 0, True), 44 46 "Median Read Latency" : Field('us' , 0, True), 45 47 "Tail Read Latency" : Field('us' , 0, True), 48 "Average Update Latency": Field('us' , 0, True), 46 49 "Median Update Latency" : Field('us' , 0, True), 47 50 "Tail Update Latency" : Field('us' , 0, True), 51 "Update Ratio" : Field('\%' , 0, False), 48 52 } 49 53 50 def plot(in_data, x, y, o ut):54 def plot(in_data, x, y, options): 51 55 fig, ax = plt.subplots() 52 56 colors = itertools.cycle(['#0095e3','#006cb4','#69df00','#0aa000','#fb0300','#e30002','#fd8f00','#ff7f00','#8f00d6','#4b009a','#ffff00','#b13f00']) … … 92 96 print("Making Plots") 93 97 94 for name, data in s eries.items():98 for name, data in sorted(series.items()): 95 99 _col = next(colors) 96 100 plt.scatter(data['x'], data['y'], color=_col, label=name, marker='x') … … 106 110 print("Finishing Plots") 107 111 108 plt.ylabel( y)112 plt.ylabel(field_names[y].name if field_names[y].name else y) 109 113 # plt.xticks(range(1, math.ceil(mx) + 1)) 110 plt.xlabel( x)114 plt.xlabel(field_names[x].name if field_names[x].name else x) 111 115 plt.grid(b = True) 112 116 ax.xaxis.set_major_formatter( EngFormatter(unit=field_names[x].unit) ) 113 if field_names[x].log: 117 if options.logx: 118 ax.set_xscale('log') 119 elif field_names[x].log: 114 120 ax.set_xscale('log') 115 121 else: … … 117 123 118 124 ax.yaxis.set_major_formatter( EngFormatter(unit=field_names[y].unit) ) 119 if field_names[y].log: 125 if options.logy: 126 ax.set_yscale('log') 127 elif field_names[y].log: 120 128 ax.set_yscale('log') 121 129 else: 122 plt.ylim(field_names[y].min, my*1.2)130 plt.ylim(field_names[y].min, options.MaxY if options.MaxY else my*1.2) 123 131 124 132 plt.legend(loc='upper left') 125 133 126 134 print("Results Ready") 127 if o ut:128 plt.savefig(o ut)135 if options.out: 136 plt.savefig(options.out, bbox_inches='tight') 129 137 else: 130 138 plt.show() … … 139 147 parser.add_argument('-y', nargs='?', type=str, default="", help="Which field to use as the Y axis") 140 148 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") 141 152 142 153 options = parser.parse_args() … … 182 193 183 194 184 plot(data, wantx, wanty, options .out)195 plot(data, wantx, wanty, options) -
benchmark/process-mutilate.py
r29d8c02 r74ec742 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') 16 17 try: 17 18 options = parser.parse_args() … … 31 32 32 33 try: 34 latAvs = fields[1] 33 35 lat50s = fields[6] 34 36 lat99s = fields[9] … … 37 39 38 40 try: 41 latAv = locale.atof(latAvs) 39 42 lat50 = locale.atof(lat50s) 40 43 lat99 = locale.atof(lat99s) … … 42 45 raise Warning("Warning: \"{}\" \"{}\"! can't convert to float".format(lat50s, lat99s)) 43 46 44 return lat 50, lat9947 return latAv, lat50, lat99 45 48 46 49 def want0(line): … … 58 61 try: 59 62 if line.startswith("read"): 60 rlat 50, rlat99 = precentile(line)63 rlatAv, rlat50, rlat99 = precentile(line) 61 64 62 65 elif line.startswith("update"): 63 ulat 50, ulat99 = precentile(line)66 ulatAv, ulat50, ulat99 = precentile(line) 64 67 65 68 elif line.startswith("Total QPS"): … … 84 87 85 88 try: 89 out['Average Read Latency'] = rlatAv 86 90 out['Median Read Latency'] = rlat50 87 91 out['Tail Read Latency'] = rlat99 … … 90 94 91 95 try: 96 out['Average Update Latency'] = ulatAv 92 97 out['Median Update Latency'] = ulat50 93 98 out['Tail Update Latency'] = ulat99 … … 112 117 continue 113 118 114 d = { 'Target QPS': int(rate) }119 d = { options.var : int(rate) } 115 120 116 121 w = extract( f, d ) -
benchmark/readyQ/bench.go
r29d8c02 r74ec742 71 71 duration = 5 72 72 clock_mode = true 73 fmt.Printf("Running for %f seconds \n", duration)73 fmt.Printf("Running for %f seconds (default)\n", duration) 74 74 } 75 75 -
benchmark/readyQ/churn.cfa
r29d8c02 r74ec742 1 1 #include "rq_bench.hfa" 2 2 3 #include <locks.hfa> 4 3 5 unsigned spot_cnt = 2; 4 bench_sem * volatile * spots;6 semaphore * spots; 5 7 6 8 thread BThrd { 7 9 unsigned long long count; 8 10 unsigned long long blocks; 9 b ench_sem sem;11 bool skip; 10 12 }; 11 13 … … 14 16 this.count = 0; 15 17 this.blocks = 0; 18 this.skip = false; 16 19 } 17 20 … … 19 22 20 23 void main( BThrd & this ) with( this ) { 21 wait( sem);24 park(); 22 25 for() { 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 ); 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 27 32 count ++; 28 33 if( clock_mode && stop) break; … … 39 44 { 's', "spots", "Number of spots in the system", spot_cnt } 40 45 }; 41 BENCH_OPT_PARSE("cforall c yclebenchmark");46 BENCH_OPT_PARSE("cforall churn benchmark"); 42 47 43 48 { … … 49 54 spots = aalloc(spot_cnt); 50 55 for(i; spot_cnt) { 51 spots[i] = 0p;56 (spots[i]){ 0 }; 52 57 } 53 58 … … 55 60 BThrd * threads[nthreads]; 56 61 for(i; nthreads ) { 57 threads[i] = malloc(); 58 (*threads[i]){}; 62 BThrd & t = *(threads[i] = malloc()); 63 (t){}; 64 t.skip = i < spot_cnt; 59 65 } 60 66 printf("Starting\n"); … … 64 70 65 71 for(i; nthreads) { 66 post( threads[i]->sem);72 unpark( *threads[i] ); 67 73 } 68 74 wait(start, is_tty); … … 72 78 printf("\nDone\n"); 73 79 80 for(i; spot_cnt) { 81 for(10000) V( spots[i] ); 82 } 83 74 84 for(i; nthreads) { 75 post( threads[i]->sem );76 85 BThrd & thrd = join( *threads[i] ); 77 86 global_counter += thrd.count; -
benchmark/readyQ/cycle.cpp
r29d8c02 r74ec742 46 46 } 47 47 for(unsigned i = 0; i < tthreads; i++) { 48 threads[i] = new Fibre( reinterpret_cast<void (*)(void *)>(partner_main), &thddata[i] ); 48 threads[i] = new Fibre(); 49 threads[i]->run( partner_main, &thddata[i] ); 49 50 } 50 51 printf("Starting\n"); -
benchmark/readyQ/rq_bench.hpp
r29d8c02 r74ec742 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 145 155 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) { 146 166 value = false; 147 167 return true; -
benchmark/readyQ/transfer.cfa
r29d8c02 r74ec742 14 14 15 15 bool exhaust = false; 16 volatile bool estop = false; 17 16 18 17 19 thread$ * the_main; … … 35 37 static void waitgroup() { 36 38 Time start = timeHiRes(); 37 for(i; nthreads) {39 OUTER: for(i; nthreads) { 38 40 PRINT( sout | "Waiting for :" | i | "(" | threads[i]->idx | ")"; ) 39 41 while( threads[i]->idx != lead_idx ) { … … 42 44 print_stats_now( bench_cluster, CFA_STATS_READY_Q | CFA_STATS_IO ); 43 45 serr | "Programs has been blocked for more than 5 secs"; 44 exit(1); 46 estop = true; 47 unpark( the_main ); 48 break OUTER; 45 49 } 46 50 } … … 59 63 static void lead(MyThread & this) { 60 64 this.idx = ++lead_idx; 61 if(lead_idx > stop_count ) {65 if(lead_idx > stop_count || estop) { 62 66 PRINT( sout | "Leader" | this.id | "done"; ) 63 67 unpark( the_main ); … … 100 104 wait( this ); 101 105 } 102 if(lead_idx > stop_count ) break;106 if(lead_idx > stop_count || estop) break; 103 107 } 104 108 } … … 172 176 sout | "Number of processors : " | nprocs; 173 177 sout | "Number of threads : " | nthreads; 174 sout | "Total Operations(ops) : " | stop_count;178 sout | "Total Operations(ops) : " | lead_idx - 1; 175 179 sout | "Threads parking on wait : " | (exhaust ? "yes" : "no"); 176 180 sout | "Rechecking : " | rechecks; 181 sout | "ns per transfer : " | (end - start)`dms / lead_idx; 177 182 178 183 -
benchmark/readyQ/transfer.cpp
r29d8c02 r74ec742 12 12 13 13 bool exhaust = false; 14 volatile bool estop = false; 14 15 15 16 bench_sem the_main; … … 42 43 if( to_miliseconds(timeHiRes() - start) > 5'000 ) { 43 44 std::cerr << "Programs has been blocked for more than 5 secs" << std::endl; 44 std::exit(1); 45 estop = true; 46 the_main.post(); 47 goto END; 45 48 } 46 49 } 47 50 } 51 END:; 48 52 PRINT( std::cout | "Waiting done"; ) 49 53 } … … 59 63 void lead() { 60 64 this->idx = ++lead_idx; 61 if(lead_idx > stop_count ) {65 if(lead_idx > stop_count || estop) { 62 66 PRINT( std::cout << "Leader " << this->id << " done" << std::endl; ) 63 67 the_main.post(); … … 88 92 } 89 93 90 static void main( void * arg) {91 MyThread & self = * reinterpret_cast<MyThread*>(arg);94 static void main(MyThread * arg) { 95 MyThread & self = *arg; 92 96 self.park(); 93 97 … … 101 105 self.wait(); 102 106 } 103 if(lead_idx > stop_count ) break;107 if(lead_idx > stop_count || estop) break; 104 108 } 105 109 } … … 144 148 for(size_t i = 0; i < nthreads; i++) { 145 149 threads[i] = new MyThread( i ); 146 handles[i] = new Fibre( MyThread::main, threads[i] ); 150 handles[i] = new Fibre(); 151 handles[i]->run( MyThread::main, threads[i] ); 147 152 } 148 153 … … 164 169 PRINT( std::cout << i << " joined" << std::endl; ) 165 170 rechecks += thrd.rechecks; 166 // delete( handles[i] );167 171 delete( threads[i] ); 168 172 } … … 176 180 std::cout << "Number of processors : " << nprocs << std::endl; 177 181 std::cout << "Number of threads : " << nthreads << std::endl; 178 std::cout << "Total Operations(ops) : " << stop_count<< std::endl;182 std::cout << "Total Operations(ops) : " << (lead_idx - 1) << std::endl; 179 183 std::cout << "Threads parking on wait : " << (exhaust ? "yes" : "no") << std::endl; 180 184 std::cout << "Rechecking : " << rechecks << std::endl; 185 std::cout << "ns per transfer : " << std::fixed << (((double)(end - start)) / (lead_idx)) << std::endl; 181 186 182 187 -
benchmark/readyQ/transfer.go
r29d8c02 r74ec742 6 6 "math/rand" 7 7 "os" 8 "regexp" 8 9 "runtime" 9 10 "sync/atomic" … … 16 17 id uint64 17 18 idx uint64 19 estop uint64 18 20 seed uint64 19 21 } … … 34 36 35 37 func NewLeader(size uint64) (*LeaderInfo) { 36 this := &LeaderInfo{0, 0, uint64(os.Getpid())}38 this := &LeaderInfo{0, 0, 0, uint64(os.Getpid())} 37 39 38 40 r := rand.Intn(10) … … 51 53 } 52 54 53 func waitgroup( idx uint64, threads [] MyThread) {55 func waitgroup(leader * LeaderInfo, idx uint64, threads [] MyThread, main_sem chan struct {}) { 54 56 start := time.Now() 57 Outer: 55 58 for i := 0; i < len(threads); i++ { 56 59 // fmt.Fprintf(os.Stderr, "Waiting for :%d (%d)\n", threads[i].id, atomic.LoadUint64(&threads[i].idx) ); … … 61 64 if delta.Seconds() > 5 { 62 65 fmt.Fprintf(os.Stderr, "Programs has been blocked for more than 5 secs") 63 os.Exit(1) 66 atomic.StoreUint64(&leader.estop, 1); 67 main_sem <- (struct {}{}) 68 break Outer 64 69 } 65 70 } … … 74 79 if i != me { 75 80 // 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 }() 76 86 threads[i].sem <- (struct {}{}) 77 87 } … … 84 94 atomic.StoreUint64(&leader.idx, nidx); 85 95 86 if nidx > stop_count {96 if nidx > stop_count || atomic.LoadUint64(&leader.estop) != 0 { 87 97 // debug!( "Leader {} done", this.id); 88 98 main_sem <- (struct {}{}) … … 92 102 // debug!( "====================\nLeader no {} : {}", nidx, this.id); 93 103 94 waitgroup( nidx, threads);104 waitgroup(leader, nidx, threads, main_sem); 95 105 96 106 leader.next( uint64(len(threads)) ); … … 146 156 waitleader( exhaust, leader, &threads[me], &r ) 147 157 } 148 if atomic.LoadUint64(&leader.idx) > stop_count { break; }158 if atomic.LoadUint64(&leader.idx) > stop_count || atomic.LoadUint64(&leader.estop) != 0 { break; } 149 159 } 150 160 … … 155 165 func main() { 156 166 // Benchmark specific command line arguments 157 exhaustOpt := flag. Bool("e", false, "Whether or not threads that have seen the new epoch should park instead of yielding.")167 exhaustOpt := flag.String("e", "no", "Whether or not threads that have seen the new epoch should park instead of yielding.") 158 168 159 169 // General benchmark initialization and deinitialization 160 defer bench_init()() 161 162 exhaust := *exhaustOpt; 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 163 186 if clock_mode { 164 fmt.Fprintf(os.Stderr, "Programs does not support fixed duration mode ")187 fmt.Fprintf(os.Stderr, "Programs does not support fixed duration mode\n") 165 188 os.Exit(1) 166 189 } … … 215 238 ws = "no" 216 239 } 217 p.Printf("Duration (ms) : % f\n", delta.Milliseconds() )240 p.Printf("Duration (ms) : %d\n", delta.Milliseconds() ) 218 241 p.Printf("Number of processors : %d\n", nprocs ) 219 242 p.Printf("Number of threads : %d\n", nthreads ) 220 p.Printf("Total Operations(ops) : %15d\n", stop_count)243 p.Printf("Total Operations(ops) : %15d\n", (leader.idx - 1) ) 221 244 p.Printf("Threads parking on wait : %s\n", ws) 222 245 p.Printf("Rechecking : %d\n", rechecks ) 223 } 246 p.Printf("ns per transfer : %f\n", float64(delta.Nanoseconds()) / float64(leader.idx) ) 247 } -
benchmark/readyQ/transfer.rs
r29d8c02 r74ec742 6 6 use std::hint; 7 7 use std::sync::Arc; 8 use std::sync::atomic::{Atomic Usize, Ordering};8 use std::sync::atomic::{AtomicBool, 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, 46 48 "no" => false, 49 "N" => false, 50 "n" => false, 47 51 "maybe" | "I don't know" | "Can you repeat the question?" => { 48 52 eprintln!("Lines for 'Malcolm in the Middle' are not acceptable values of parameter 'exhaust'"); … … 64 68 id: AtomicUsize, 65 69 idx: AtomicUsize, 70 estop: AtomicBool, 66 71 seed: u128, 67 72 } … … 72 77 id: AtomicUsize::new(nthreads), 73 78 idx: AtomicUsize::new(0), 79 estop: AtomicBool::new(false), 74 80 seed: process::id() as u128 75 81 }; … … 100 106 } 101 107 102 fn waitgroup( idx: usize, threads: &Vec<Arc<MyThread>>) {108 fn waitgroup(leader: &LeaderInfo, idx: usize, threads: &Vec<Arc<MyThread>>, main_sem: &sync::Semaphore) { 103 109 let start = Instant::now(); 104 for t in threads {110 'outer: for t in threads { 105 111 debug!( "Waiting for :{} ({})", t.id, t.idx.load(Ordering::Relaxed) ); 106 112 while t.idx.load(Ordering::Relaxed) != idx { … … 108 114 if start.elapsed() > Duration::from_secs(5) { 109 115 eprintln!("Programs has been blocked for more than 5 secs"); 110 std::process::exit(1); 116 leader.estop.store(true, Ordering::Relaxed); 117 main_sem.add_permits(1); 118 break 'outer; 111 119 } 112 120 } … … 131 139 leader.idx.store(nidx, Ordering::Relaxed); 132 140 133 if nidx as u64 > exp.stop_count {141 if nidx as u64 > exp.stop_count || leader.estop.load(Ordering::Relaxed) { 134 142 debug!( "Leader {} done", this.id); 135 143 main_sem.add_permits(1); … … 139 147 debug!( "====================\nLeader no {} : {}", nidx, this.id); 140 148 141 waitgroup( nidx, threads);149 waitgroup(leader, nidx, threads, main_sem); 142 150 143 151 leader.next( threads.len() ); … … 192 200 wait( exhaust, &leader, &threads[me], &mut rechecks ).await; 193 201 } 194 if leader.idx.load(Ordering::Relaxed) as u64 > exp.stop_count { break; }202 if leader.idx.load(Ordering::Relaxed) as u64 > exp.stop_count || leader.estop.load(Ordering::Relaxed) { break; } 195 203 } 196 204 … … 273 281 println!("Number of processors : {}", (nprocs).to_formatted_string(&Locale::en)); 274 282 println!("Number of threads : {}", (nthreads).to_formatted_string(&Locale::en)); 275 println!("Total Operations(ops) : {:>15}", ( exp.stop_count).to_formatted_string(&Locale::en));283 println!("Total Operations(ops) : {:>15}", (leader.idx.load(Ordering::Relaxed) - 1).to_formatted_string(&Locale::en)); 276 284 println!("Threads parking on wait : {}", if exhaust { "yes" } else { "no" }); 277 285 println!("Rechecking : {}", rechecks ); 278 } 286 println!("ns per transfer : {}", ((duration.as_nanos() as f64) / leader.idx.load(Ordering::Relaxed) as f64)); 287 288 } -
benchmark/readyQ/yield.cfa
r29d8c02 r74ec742 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; 1 #include "rq_bench.hfa" 24 2 25 3 thread __attribute__((aligned(128))) Yielder { 26 unsigned long long count er;4 unsigned long long count; 27 5 }; 28 6 void ?{}( Yielder & this ) { 29 this.counter = 0;30 ((thread&)this){ "Yielder Thread", *the_benchmark_cluster };7 ((thread&)this){ "Yielder Thread", bench_cluster }; 8 this.count = 0; 31 9 } 32 10 33 11 void main( Yielder & this ) { 34 12 park(); 35 /* paranoid */ assert( true == __atomic_load_n(&run, __ATOMIC_RELAXED) ); 13 for() { 14 yield(); 15 this.count++; 16 if( clock_mode && stop) break; 17 if(!clock_mode && this.count >= stop_count) break; 18 } 36 19 37 while(__atomic_load_n(&run, __ATOMIC_RELAXED)) { 38 yield(); 39 this.counter++; 40 } 41 __atomic_fetch_add(&global_counter, this.counter, __ATOMIC_SEQ_CST); 20 __atomic_fetch_add(&threads_left, -1, __ATOMIC_SEQ_CST); 42 21 } 43 22 44 23 int main(int argc, char * argv[]) { 45 unsigned num_io = 1;46 io_context_params params;47 48 24 cfa_option opt[] = { 49 BENCH_OPT _CFA25 BENCH_OPT 50 26 }; 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 ); 27 BENCH_OPT_PARSE("cforall yield benchmark"); 55 28 56 29 { 57 printf("Running %d threads on %d processors for %f seconds\n", nthreads, nprocs, duration);30 unsigned long long global_counter = 0; 58 31 59 32 Time start, end; 60 BenchCluster cl = { num_io, params, CFA_STATS_READY_Q};33 BenchCluster bc = { nprocs }; 61 34 { 62 BenchProc procs[nprocs]; 63 { 64 Yielder threads[nthreads]; 65 printf("Starting\n"); 35 threads_left = nthreads; 36 Yielder threads[nthreads]; 37 printf("Starting\n"); 66 38 67 bool is_tty = isatty(STDOUT_FILENO); 68 start = timeHiRes(); 69 run = true; 39 bool is_tty = isatty(STDOUT_FILENO); 40 start = timeHiRes(); 70 41 71 for(i; nthreads) {72 unpark( threads[i] );73 }74 wait(duration, start, end, is_tty);42 for(i; nthreads) { 43 unpark( threads[i] ); 44 } 45 wait(start, is_tty); 75 46 76 run = false; 77 end = timeHiRes(); 78 printf("\nDone\n"); 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; 79 54 } 80 55 } 81 56 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)); 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)); 91 67 fflush(stdout); 92 68 } -
benchmark/readyQ/yield.cpp
r29d8c02 r74ec742 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 } 1 #include "rq_bench.hpp" 2 #include <libfibre/fibre.h> 25 3 26 4 volatile bool run = false; 27 5 volatile unsigned long long global_counter; 28 6 29 #include "libfibre/fibre.h"30 7 31 FredBarrier * barrier; 32 struct __attribute__((aligned(128))) counter_t { 33 int value = 0; 34 }; 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; 16 } 35 17 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++; 44 } 45 __atomic_fetch_add(&global_counter, counter->value, __ATOMIC_SEQ_CST); 18 __atomic_fetch_add(&global_counter, count, __ATOMIC_SEQ_CST); 19 __atomic_fetch_add(&threads_left, -1, __ATOMIC_SEQ_CST); 46 20 } 47 21 48 22 int main(int argc, char * argv[]) { 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: 23 option_t opt[] = { 24 BENCH_OPT 25 }; 26 BENCH_OPT_PARSE("libfibre yield benchmark"); 107 27 108 28 { 109 29 printf("Running %d threads on %d processors for %lf seconds\n", nthreads, nprocs, duration); 110 30 111 FibreInit( );112 barrier = new FredBarrier(nthreads + 1);31 FibreInit(1, nprocs); 32 uint64_t start, end; 113 33 { 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; 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(); 125 43 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 } 44 for(unsigned i = 0; i < nthreads; i++ ) { 45 fibre_unpark( threads[i] ); 46 } 47 wait<Fibre>(start, is_tty); 139 48 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 // } 49 stop = true; 50 end = timeHiRes(); 51 for(unsigned i = 0; i < nthreads; i++ ) { 52 fibre_join( threads[i], nullptr ); 152 53 } 153 54 } 154 55 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 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); 166 67 } 167 68 } -
benchmark/readyQ/yield.rs
r29d8c02 r74ec742 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 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));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)); 102 102 } -
benchmark/rmit.py
r29d8c02 r74ec742 46 46 pass 47 47 48 if re.search("^[0-9-,]+$", values): 48 if values.startswith('\\'): 49 return key, values[1:].split(',') 50 elif re.search("^[0-9-,]+$", values): 49 51 values = parse_range(values) 50 52 return key, [v for v in values] … … 63 65 return eval(fmt) 64 66 67 # Evaluate all the options 68 # 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 value 65 70 def eval_options(opts): 71 # Find all the options with dependencies 66 72 dependents = [d for d in opts.values() if type(d) is DependentOpt] 73 74 # we need to find all the straglers 67 75 processed = [] 68 nopts = [] 76 77 # extract all the necessary inputs 78 input_keys = {} 69 79 for d in dependents: 80 # Mark the dependent as seen 70 81 processed.append(d.key) 71 lists = [] 82 83 # process each of the dependencies 72 84 for dvar in d.vars: 85 # Check that it depends on something that exists 73 86 if not dvar in opts.keys(): 74 87 print('ERROR: extra pattern option {}:{} uses unknown key {}'.format(d.key,d.value,dvar), file=sys.stderr) 75 88 sys.exit(1) 76 89 77 lists.append([(dvar, o) for o in opts[dvar]]) 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 78 104 processed.append(dvar) 79 105 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 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 97 153 98 154 # returns the first option with key 'opt' … … 122 178 known_hosts = { 123 179 "jax": { 124 range( 1, 2 4) : "48-71",125 range( 25, 4 8) : "48-71,144-167",126 range( 49, 9 6) : "48-95,144-191",127 range( 97, 14 4) : "24-95,120-191",128 range(145, 19 2) : "0-95,96-191",180 range( 1, 25) : "48-71", 181 range( 25, 49) : "48-71,144-167", 182 range( 49, 97) : "48-95,144-191", 183 range( 97, 145) : "24-95,120-191", 184 range(145, 193) : "0-95,96-191", 129 185 }, 130 186 } … … 184 240 185 241 except: 186 print('ERROR: invalid arguments', file=sys.stderr)187 parser.print_help(sys.stderr)188 242 sys.exit(1) 189 243 … … 215 269 # Figure out all the combinations to run 216 270 actions = [] 217 for p in itertools.product(range(options.trials), commands, *opts):271 for p in itertools.product(range(options.trials), commands, opts): 218 272 act = [p[1]] 219 273 for o in p[2:]: … … 281 335 282 336 if options.file != sys.stdout: 283 print("Done ");")337 print("Done ") -
doc/theses/thierry_delisle_PhD/thesis/Makefile
r29d8c02 r74ec742 37 37 emptytree \ 38 38 fairness \ 39 idle \ 40 idle1 \ 41 idle2 \ 42 idle_state \ 39 43 io_uring \ 40 44 pivot_ring \ … … 42 46 cycle \ 43 47 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 \ 44 63 } 45 64 … … 116 135 python3 $< $@ 117 136 118 build/result.%.ns.svg : data/% | ${Build} 119 ../../../../benchmark/plot.py -f $< -o $@ -y "ns per ops" 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 120 141 121 build/result.%.ops.svg : data/% | ${Build} 122 ../../../../benchmark/plot.py -f $< -o $@ -y "Ops per second" 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" 123 164 124 165 ## pstex with inverted colors -
doc/theses/thierry_delisle_PhD/thesis/data/cycle.jax
r29d8c02 r74ec742 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}]]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}]] -
doc/theses/thierry_delisle_PhD/thesis/local.bib
r29d8c02 r74ec742 701 701 note = "[Online; accessed 12-April-2022]" 702 702 } 703 704 % RMR notes : 705 % [05/04, 12:36] Trevor Brown 706 % i don't know where rmr complexity was first introduced, but there are many many many papers that use the term and define it 707 % [05/04, 12:37] Trevor Brown 708 % 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.pdf 709 % [05/04, 12:37] Trevor Brown 710 % another option might be to cite a textbook 711 % [05/04, 12:42] Trevor Brown 712 % but i checked two textbooks in the area i'm aware of and i don't see a definition of rmr complexity in either 713 % [05/04, 12:42] Trevor Brown 714 % this one has a nice statement about the prevelance of rmr complexity, as well as some rough definition 715 % [05/04, 12:42] Trevor Brown 716 % https://dl.acm.org/doi/pdf/10.1145/3465084.3467938 717 718 % Race to idle notes : 719 % [13/04, 16:56] Martin Karsten 720 % 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
r29d8c02 r74ec742 7 7 Networked ZIPF 8 8 9 Nginx : 5Gb still good, 4Gb starts to suffer 10 11 Cforall : 10Gb too high, 4 Gb too low 12 9 13 \section{Memcached} 10 14 11 In Memory 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. 12 23 13 Networked 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} -
doc/theses/thierry_delisle_PhD/thesis/text/eval_micro.tex
r29d8c02 r74ec742 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 8 13 9 14 \paragraph{AMD} The AMD machine is a server with two AMD EPYC 7662 CPUs and 256GB of DDR4 RAM. … … 23 28 24 29 \section{Cycling latency} 30 \begin{figure} 31 \centering 32 \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} 25 36 The most basic evaluation of any ready queue is to evaluate the latency needed to push and pop one element from the ready-queue. 26 37 Since these two operation also describe a \texttt{yield} operation, many systems use this as the most basic benchmark. … … 42 53 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. 43 54 44 \begin{figure}45 \centering46 \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 51 55 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. 52 56 Beyond this point, adding more rings serves to mitigate even more the idle sleep handling. … … 54 58 55 59 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. 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} 69 70 \begin{figure} 71 \centering 72 \input{result.cycle.jax.ops.pstex_t} 73 \vspace*{-10pt} 74 \label{fig:cycle:ns:jax} 75 \end{figure} 60 Figure~\ref{fig:cycle:code} shows pseudo code for this benchmark. 61 62 \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} 77 \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} 76 115 77 116 \section{Yield} … … 81 120 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. 82 121 This sometimes puts more strain on the idle sleep handling, compared to scenarios where there is clearly plenty of work to be done. 83 84 \todo{code, setup, results} 85 86 \begin{lstlisting} 87 Thread.main() { 88 count := 0 89 while !stop { 90 yield() 91 count ++ 92 } 93 global.count += count 94 } 95 \end{lstlisting} 122 Figure~\ref{fig:yield:code} shows pseudo code for this benchmark, the ``wait/wake-next'' is simply replaced by a yield. 123 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 134 } 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} 147 } 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} 96 174 97 175 … … 105 183 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. 106 184 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}. 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. 111 190 112 191 \todo{code, setup, results} … … 116 195 for { 117 196 r := random() % len(spots) 118 next := xchg(spots[r], this) 119 if next { next.wake() } 120 wait() 197 spots[r].V() 198 spots[r].P() 121 199 count ++ 122 200 if must_stop() { break } … … 125 203 } 126 204 \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} 127 235 128 236 \section{Locality} -
doc/theses/thierry_delisle_PhD/thesis/text/practice.tex
r29d8c02 r74ec742 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 as automatic stack variables, but this is not a requirement.9 They are normally created 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 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.}. 16 17 There are no performance requirements, within reason, for resizing since this is usually considered as part of setup and teardown. 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.}. 19 20 There are no performance requirements, within reason, for resizing since it is expected to be rare. 18 21 However, this operation has strict correctness requirements since shrinking and idle sleep can easily lead to deadlocks. 19 22 It should also avoid as much as possible any effect on performance when the number of \procs remain constant. 20 This later requirement pr ehibits simple solutions, like simply adding a global lock to these arrays.23 This later requirement prohibits naive solutions, like simply adding a global lock to the ready-queue arrays. 21 24 22 25 \subsection{Read-Copy-Update} … … 24 27 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. 25 28 This approach potentially has the advantage that it may not need any synchronization to do the switch. 26 The switch definitely implies a race where \procs could still use the previous, original, data structure after the copy was switched in.27 Th e 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. 29 30 For linked-lists, dequeing is somewhat of a problem.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. 31 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. 31 34 Dequeing from the original will not necessarily update the copy which could lead to multiple \procs dequeing the same \at. 32 Fixing this requires m aking the array contain pointers to subqueues rather than the subqueues themselves.35 Fixing this requires more synchronization or more indirection on the queues. 33 36 34 37 Another challenge is that the original must be kept until all \procs have witnessed the change. … … 97 100 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. 98 101 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. 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} butsimply put into an idle state where the \gls{kthrd} is blocked until more \ats become ready.102 Furthermore, race conditions that spuriously lead to the impression that no \ats are ready are actually common in practice. 103 Therefore resources associated with \procs should not be freed but \procs simply put into an idle state where the \gls{kthrd} is blocked until more \ats become ready. 101 104 This state is referred to as \newterm{Idle-Sleep}. 102 105 … … 110 113 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. 111 114 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 \centering 144 \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 112 150 113 151 \section{Tracking Sleepers} 114 152 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. 115 153 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. 116 117 Furthermore, the ``Race-to-Idle'' approach means that there is some 118 119 \section{Sleeping} 120 121 \subsection{Event FDs} 122 123 \subsection{Epoll} 124 125 \subsection{\texttt{io\_uring}} 126 127 \section{Reducing Latency} 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 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. 161 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. 169 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. 175 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. 182 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} 189 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} -
doc/theses/thierry_delisle_PhD/thesis/thesis.tex
r29d8c02 r74ec742 82 82 \usepackage{xcolor} 83 83 \usepackage{graphicx} % For including graphics 84 \usepackage{subcaption} 84 85 85 86 % Hyperlinks make it very easy to navigate an electronic document. … … 204 205 \newcommand\at{\gls{at}\xspace}% 205 206 \newcommand\ats{\glspl{at}\xspace}% 207 \newcommand\Proc{\Pls{proc}\xspace}% 206 208 \newcommand\proc{\gls{proc}\xspace}% 207 209 \newcommand\procs{\glspl{proc}\xspace}% -
libcfa/src/Makefile.am
r29d8c02 r74ec742 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 - pthread @ARCH_FLAGS@ @CONFIG_CFLAGS@35 AM_CFLAGS = -g -Wall -Werror=return-type -Wno-unused-function -fPIC -fexceptions -fvisibility=hidden -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 - o ${@}196 ${AM_V_GEN}$(CFACOMPILE) -quiet -XCFA,-l ${<} -c -fvisibility=default -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 - o ${@}200 $(CFACOMPILE) -quiet -XCFA,-l ${<} -c -fvisibility=default -o ${@} 201 201 202 202 concurrency/io/call.cfa: $(srcdir)/concurrency/io/call.cfa.in -
libcfa/src/algorithms/range_iterator.cfa
r29d8c02 r74ec742 20 20 #include <fstream.hfa> 21 21 22 void main(RangeIter & this) { 22 #include "bits/defs.hfa" 23 24 void main(RangeIter & this) libcfa_public { 23 25 for() { 24 26 this._start = -1; -
libcfa/src/assert.cfa
r29d8c02 r74ec742 19 19 #include <unistd.h> // STDERR_FILENO 20 20 #include "bits/debug.hfa" 21 #include "bits/defs.hfa" 21 22 22 23 extern "C" { … … 26 27 27 28 // called by macro assert in assert.h 28 void __assert_fail( const char assertion[], const char file[], unsigned int line, const char function[] ) { 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 { 29 31 __cfaabi_bits_print_safe( STDERR_FILENO, CFA_ASSERT_FMT ".\n", assertion, __progname, function, line, file ); 30 32 abort(); … … 32 34 33 35 // called by macro assertf 34 void __assert_fail_f( const char assertion[], const char file[], unsigned int line, const char function[], const char fmt[], ... ) { 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 { 35 38 __cfaabi_bits_acquire(); 36 39 __cfaabi_bits_print_nolock( STDERR_FILENO, CFA_ASSERT_FMT ": ", assertion, __progname, function, line, file ); -
libcfa/src/bits/align.hfa
r29d8c02 r74ec742 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Sat Nov 16 18:58:22 201913 // Update Count : 312 // Last Modified On : Fri Apr 29 19:14:43 2022 13 // Update Count : 4 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() ( 16)37 #define libAlign() (__BIGGEST_ALIGNMENT__) 38 38 39 39 // Check for power of 2 -
libcfa/src/bits/debug.cfa
r29d8c02 r74ec742 21 21 #include <unistd.h> 22 22 23 #include "bits/defs.hfa" 24 23 25 enum { buffer_size = 4096 }; 24 26 static char buffer[ buffer_size ]; 25 27 26 28 extern "C" { 27 void __cfaabi_bits_write( int fd, const char in_buffer[], int len ) { 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 { 28 31 // ensure all data is written 29 32 for ( int count = 0, retcode; count < len; count += retcode ) { … … 44 47 void __cfaabi_bits_release() __attribute__((__weak__)) {} 45 48 46 int __cfaabi_bits_print_safe ( int fd, const char fmt[], ... ) __attribute__(( format(printf, 2, 3) )) { 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 { 47 51 va_list args; 48 52 -
libcfa/src/bits/defs.hfa
r29d8c02 r74ec742 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"))) 38 40 39 41 #ifdef __cforall -
libcfa/src/bits/weakso_locks.cfa
r29d8c02 r74ec742 18 18 #include "bits/weakso_locks.hfa" 19 19 20 #pragma GCC visibility push(default) 21 20 22 void ?{}( blocking_lock &, bool, bool ) {} 21 23 void ^?{}( blocking_lock & ) {} -
libcfa/src/common.cfa
r29d8c02 r74ec742 18 18 #include <stdlib.h> // div_t, *div 19 19 20 #pragma GCC visibility push(default) 21 20 22 //--------------------------------------- 21 23 -
libcfa/src/concurrency/alarm.cfa
r29d8c02 r74ec742 141 141 //============================================================================================= 142 142 143 void sleep( Duration duration ) {143 void sleep( Duration duration ) libcfa_public { 144 144 alarm_node_t node = { active_thread(), duration, 0`s }; 145 145 -
libcfa/src/concurrency/clib/cfathread.cfa
r29d8c02 r74ec742 326 326 } 327 327 328 #pragma GCC visibility push(default) 329 328 330 //================================================================================ 329 331 // Main Api 330 332 extern "C" { 331 int cfathread_cluster_create(cfathread_cluster_t * cl) __attribute__((nonnull(1))) {333 int cfathread_cluster_create(cfathread_cluster_t * cl) __attribute__((nonnull(1))) libcfa_public { 332 334 *cl = new(); 333 335 return 0; 334 336 } 335 337 336 cfathread_cluster_t cfathread_cluster_self(void) {338 cfathread_cluster_t cfathread_cluster_self(void) libcfa_public { 337 339 return active_cluster(); 338 340 } 339 341 340 int cfathread_cluster_print_stats( cfathread_cluster_t cl ) {342 int cfathread_cluster_print_stats( cfathread_cluster_t cl ) libcfa_public { 341 343 #if !defined(__CFA_NO_STATISTICS__) 342 344 print_stats_at_exit( *cl, CFA_STATS_READY_Q | CFA_STATS_IO ); -
libcfa/src/concurrency/coroutine.cfa
r29d8c02 r74ec742 48 48 //----------------------------------------------------------------------------- 49 49 forall(T &) 50 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) {50 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) libcfa_public { 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) *) {57 const char * msg(CoroutineCancelled(T) *) libcfa_public { 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)) ) {64 T & cor, coroutine$ * desc, EHM_DEFAULT_VTABLE(CoroutineCancelled, (T)) ) libcfa_public { 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 void __stack_clean ( __stack_info_t * this );91 static 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 ) with( this ) {116 void ?{}( coroutine$ & this, const char name[], void * storage, size_t storageSize ) libcfa_public with( this ) { 117 117 (this.context){0p, 0p}; 118 118 (this.stack){storage, storageSize}; … … 124 124 } 125 125 126 void ^?{}(coroutine$& this) {126 void ^?{}(coroutine$& this) libcfa_public { 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) {149 void prime(T& cor) libcfa_public { 150 150 coroutine$* this = get_coroutine(cor); 151 151 assert(this->state == Start); … … 155 155 } 156 156 157 [void *, size_t] __stack_alloc( size_t storageSize ) {157 static [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 void __stack_clean ( __stack_info_t * this ) {195 static 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 ) {217 void __stack_prepare( __stack_info_t * this, size_t create_size ) libcfa_public { 218 218 const size_t stack_data_size = libCeiling( sizeof(__stack_t), 16 ); // minimum alignment 219 219 bool userStack; -
libcfa/src/concurrency/coroutine.hfa
r29d8c02 r74ec742 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 117 115 118 116 // Suspend implementation inlined for performance -
libcfa/src/concurrency/exception.cfa
r29d8c02 r74ec742 64 64 extern "C" { 65 65 66 struct exception_context_t * this_exception_context(void) {66 struct exception_context_t * this_exception_context(void) libcfa_public { 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 ) {70 _Unwind_Reason_Code __cfaehm_cancellation_unwind( struct _Unwind_Exception * unwind_exception ) libcfa_public { 71 71 _Unwind_Stop_Fn stop_func; 72 72 void * stop_param; -
libcfa/src/concurrency/invoke.c
r29d8c02 r74ec742 36 36 extern void enable_interrupts( _Bool poll ); 37 37 38 void __cfactx_invoke_coroutine(38 libcfa_public void __cfactx_invoke_coroutine( 39 39 void (*main)(void *), 40 40 void *this … … 70 70 } 71 71 72 void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct coroutine$ * cor) __attribute__ ((__noreturn__));72 libcfa_public 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 void __cfactx_invoke_thread(79 libcfa_public void __cfactx_invoke_thread( 80 80 void (*main)(void *), 81 81 void *this … … 98 98 } 99 99 100 void __cfactx_start(100 libcfa_public void __cfactx_start( 101 101 void (*main)(void *), 102 102 struct coroutine$ * cor, -
libcfa/src/concurrency/io.cfa
r29d8c02 r74ec742 244 244 245 245 remote = true; 246 __STATS__( false, io.calls.helped++; )246 __STATS__( true, 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) {342 struct $io_context * cfa_io_allocate(struct io_uring_sqe * sqes[], __u32 idxs[], __u32 want) libcfa_public { 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))) {421 void cfa_io_submit( struct $io_context * inctx, __u32 idxs[], __u32 have, bool lazy ) __attribute__((nonnull (1))) libcfa_public { 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
r29d8c02 r74ec742 139 139 // I/O Interface 140 140 //============================================================================================= 141 #pragma GCC visibility push(default) 141 142 """ 142 143 -
libcfa/src/concurrency/io/setup.cfa
r29d8c02 r74ec742 26 26 27 27 #if !defined(CFA_HAVE_LINUX_IO_URING_H) 28 void ?{}(io_context_params & this) {}28 void ?{}(io_context_params & this) libcfa_public {} 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) {68 void ?{}(io_context_params & this) libcfa_public { 69 69 this.num_entries = 256; 70 70 } -
libcfa/src/concurrency/kernel.cfa
r29d8c02 r74ec742 389 389 390 390 // KERNEL_ONLY 391 void returnToKernel() {391 static 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 ) {549 void unpark( thread$ * thrd, unpark_hint hint ) libcfa_public { 550 550 if( !thrd ) return; 551 551 … … 558 558 } 559 559 560 void park( void ) {560 void park( void ) libcfa_public { 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 ) {603 bool force_yield( __Preemption_Reason reason ) libcfa_public { 604 604 __disable_interrupts_checked(); 605 605 thread$ * thrd = kernelTLS().this_thread; … … 849 849 //----------------------------------------------------------------------------- 850 850 // Debug 851 bool threading_enabled(void) __attribute__((const)) {851 bool threading_enabled(void) __attribute__((const)) libcfa_public { 852 852 return true; 853 853 } … … 856 856 // Statistics 857 857 #if !defined(__CFA_NO_STATISTICS__) 858 void print_halts( processor & this ) {858 void print_halts( processor & this ) libcfa_public { 859 859 this.print_halts = true; 860 860 } … … 873 873 } 874 874 875 void crawl_cluster_stats( cluster & this ) {875 static 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 ) {891 void print_stats_now( cluster & this, int flags ) libcfa_public { 892 892 crawl_cluster_stats( this ); 893 893 __print_stats( this.stats, flags, "Cluster", this.name, (void*)&this ); -
libcfa/src/concurrency/kernel.hfa
r29d8c02 r74ec742 49 49 50 50 // Coroutine used py processors for the 2-step context switch 51 coroutine processorCtx_t { 51 52 struct processorCtx_t { 53 struct coroutine$ self; 52 54 struct processor * proc; 53 55 }; -
libcfa/src/concurrency/kernel/cluster.cfa
r29d8c02 r74ec742 49 49 50 50 // returns the maximum number of processors the RWLock support 51 __attribute__((weak)) unsigned __max_processors() {51 __attribute__((weak)) unsigned __max_processors() libcfa_public { 52 52 const char * max_cores_s = getenv("CFA_MAX_PROCESSORS"); 53 53 if(!max_cores_s) { -
libcfa/src/concurrency/kernel/private.hfa
r29d8c02 r74ec742 109 109 //----------------------------------------------------------------------------- 110 110 // Processor 111 void main(processorCtx_t *); 111 void main(processorCtx_t &); 112 static inline coroutine$* get_coroutine(processorCtx_t & this) { return &this.self; } 112 113 113 114 void * __create_pthread( pthread_t *, void * (*)(void *), void * ); -
libcfa/src/concurrency/kernel/startup.cfa
r29d8c02 r74ec742 120 120 #endif 121 121 122 cluster * mainCluster ;122 cluster * mainCluster libcfa_public; 123 123 processor * mainProcessor; 124 124 thread$ * mainThread; … … 169 169 }; 170 170 171 void ?{}( current_stack_info_t & this ) {171 static 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. __cor){ "Processor" };212 this. __cor.starter = 0p;211 (this.self){ "Processor" }; 212 this.self.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. __cor){ info };528 (this.self){ info }; 529 529 this.proc = proc; 530 530 } … … 578 578 } 579 579 580 void ?{}(processor & this, const char name[], cluster & _cltr, thread$ * initT) {580 void ?{}(processor & this, const char name[], cluster & _cltr, thread$ * initT) libcfa_public { 581 581 ( this.terminated ){}; 582 582 ( this.runner ){}; … … 591 591 } 592 592 593 void ?{}(processor & this, const char name[], cluster & _cltr) {593 void ?{}(processor & this, const char name[], cluster & _cltr) libcfa_public { 594 594 (this){name, _cltr, 0p}; 595 595 } 596 596 597 597 extern size_t __page_size; 598 void ^?{}(processor & this) with( this ){598 void ^?{}(processor & this) libcfa_public 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) with( this ) {625 void ?{}(cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params) libcfa_public with( this ) { 626 626 this.name = name; 627 627 this.preemption_rate = preemption_rate; … … 658 658 } 659 659 660 void ^?{}(cluster & this) {660 void ^?{}(cluster & this) libcfa_public { 661 661 destroy(this.io.arbiter); 662 662 -
libcfa/src/concurrency/locks.cfa
r29d8c02 r74ec742 24 24 #include <stdlib.hfa> 25 25 26 #pragma GCC visibility push(default) 27 26 28 //----------------------------------------------------------------------------- 27 29 // info_thread … … 116 118 } 117 119 118 void pop_and_set_new_owner( blocking_lock & this ) with( this ) {120 static void pop_and_set_new_owner( blocking_lock & this ) with( this ) { 119 121 thread$ * t = &try_pop_front( blocked_threads ); 120 122 owner = t; … … 192 194 void ^?{}( alarm_node_wrap(L) & this ) { } 193 195 194 void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) {196 static void timeout_handler ( alarm_node_wrap(L) & this ) with( this ) { 195 197 // This condition_variable member is called from the kernel, and therefore, cannot block, but it can spin. 196 198 lock( cond->lock __cfaabi_dbg_ctx2 ); … … 216 218 217 219 // this casts the alarm node to our wrapped type since we used type erasure 218 void alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); }220 static void alarm_node_wrap_cast( alarm_node_t & a ) { timeout_handler( (alarm_node_wrap(L) &)a ); } 219 221 } 220 222 221 223 //----------------------------------------------------------------------------- 222 // condition variable224 // Synchronization Locks 223 225 forall(L & | is_blocking_lock(L)) { 224 226 227 //----------------------------------------------------------------------------- 228 // condition variable 225 229 void ?{}( condition_variable(L) & this ){ 226 230 this.lock{}; … … 231 235 void ^?{}( condition_variable(L) & this ){ } 232 236 233 void process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) {237 static void process_popped( condition_variable(L) & this, info_thread(L) & popped ) with( this ) { 234 238 if(&popped != 0p) { 235 239 popped.signalled = true; … … 276 280 int counter( condition_variable(L) & this ) with(this) { return count; } 277 281 278 s ize_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {282 static size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) { 279 283 // add info_thread to waiting queue 280 284 insert_last( blocked_threads, *i ); … … 289 293 290 294 // helper for wait()'s' with no timeout 291 void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {295 static void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) { 292 296 lock( lock __cfaabi_dbg_ctx2 ); 293 297 size_t recursion_count = queue_and_get_recursion(this, &i); … … 306 310 307 311 // helper for wait()'s' with a timeout 308 void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {312 static void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) { 309 313 lock( lock __cfaabi_dbg_ctx2 ); 310 314 size_t recursion_count = queue_and_get_recursion(this, &info); … … 337 341 bool wait( condition_variable(L) & this, L & l, Duration duration ) with(this) { WAIT_TIME( 0 , &l , duration ) } 338 342 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_var 346 void ?{}( fast_cond_var(L) & this ){ 347 this.blocked_threads{}; 348 #ifdef __CFA_DEBUG__ 349 this.lock_used = 0p; 350 #endif 351 } 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 lock 380 #ifdef __CFA_DEBUG__ 381 if ( lock_used == 0p ) lock_used = &l; 382 else { assert(lock_used == &l); } 383 #endif 384 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 } 339 390 } 340 391 -
libcfa/src/concurrency/locks.hfa
r29d8c02 r74ec742 73 73 static inline void on_notify( owner_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); } 74 74 75 //----------------------------------------------------------------------------- 76 // MCS Lock 75 77 struct mcs_node { 76 78 mcs_node * volatile next; … … 98 100 } 99 101 102 //----------------------------------------------------------------------------- 103 // Linear backoff Spinlock 100 104 struct linear_backoff_then_block_lock { 101 105 // Spin lock used for mutual exclusion … … 199 203 200 204 //----------------------------------------------------------------------------- 205 // Fast Block Lock 206 207 // High efficiency minimal blocking lock 208 // - No reacquire for cond var 209 // - No recursive acquisition 210 // - No ownership 211 struct fast_block_lock { 212 // Spin lock used for mutual exclusion 213 __spinlock_t lock; 214 215 // List of blocked threads 216 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 //----------------------------------------------------------------------------- 201 257 // is_blocking_lock 202 258 trait is_blocking_lock(L & | sized(L)) { … … 226 282 // Synchronization Locks 227 283 forall(L & | is_blocking_lock(L)) { 284 285 //----------------------------------------------------------------------------- 286 // condition_variable 287 288 // The multi-tool condition variable 289 // - can pass timeouts to wait for either a signal or timeout 290 // - can wait without passing a lock 291 // - can have waiters reacquire different locks while waiting on the same cond var 292 // - has shadow queue 293 // - can be signalled outside of critical sections with no locks held 228 294 struct condition_variable { 229 295 // Spin lock used for mutual exclusion … … 258 324 bool wait( condition_variable(L) & this, L & l, Duration duration ); 259 325 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Duration duration ); 260 } 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 } -
libcfa/src/concurrency/monitor.cfa
r29d8c02 r74ec742 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 46 50 static inline void init ( __lock_size_t count, monitor$ * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ); 47 51 static inline void init_push( __lock_size_t count, monitor$ * monitors [], __condition_node_t & waiter, __condition_criterion_t criteria [] ); … … 243 247 244 248 // Leave single monitor 245 void __leave( monitor$ * this ) {249 static void __leave( monitor$ * this ) { 246 250 // Lock the monitor spinlock 247 251 lock( this->lock __cfaabi_dbg_ctx2 ); … … 278 282 279 283 // Leave single monitor for the last time 280 void __dtor_leave( monitor$ * this, bool join ) {284 static void __dtor_leave( monitor$ * this, bool join ) { 281 285 __cfaabi_dbg_debug_do( 282 286 if( active_thread() != this->owner ) { … … 344 348 // Ctor for monitor guard 345 349 // Sorts monitors before entering 346 void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count, fptr_t func ) {350 void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count, fptr_t func ) libcfa_public { 347 351 thread$ * thrd = active_thread(); 348 352 … … 369 373 } 370 374 371 void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count ) {375 void ?{}( monitor_guard_t & this, monitor$ * m [], __lock_size_t count ) libcfa_public { 372 376 this{ m, count, 0p }; 373 377 } … … 375 379 376 380 // Dtor for monitor guard 377 void ^?{}( monitor_guard_t & this ) {381 void ^?{}( monitor_guard_t & this ) libcfa_public { 378 382 // __cfaabi_dbg_print_safe( "MGUARD : leaving %d\n", this.count); 379 383 … … 389 393 // Ctor for monitor guard 390 394 // Sorts monitors before entering 391 void ?{}( monitor_dtor_guard_t & this, monitor$ * m [], fptr_t func, bool join ) {395 void ?{}( monitor_dtor_guard_t & this, monitor$ * m [], fptr_t func, bool join ) libcfa_public { 392 396 // optimization 393 397 thread$ * thrd = active_thread(); … … 409 413 410 414 // Dtor for monitor guard 411 void ^?{}( monitor_dtor_guard_t & this ) {415 void ^?{}( monitor_dtor_guard_t & this ) libcfa_public { 412 416 // Leave the monitors in order 413 417 __dtor_leave( this.m, this.join ); … … 419 423 //----------------------------------------------------------------------------- 420 424 // Internal scheduling types 421 void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info ) {425 static void ?{}(__condition_node_t & this, thread$ * waiting_thread, __lock_size_t count, uintptr_t user_info ) { 422 426 this.waiting_thread = waiting_thread; 423 427 this.count = count; … … 426 430 } 427 431 428 void ?{}(__condition_criterion_t & this ) with( this ) {432 static void ?{}(__condition_criterion_t & this ) with( this ) { 429 433 ready = false; 430 434 target = 0p; … … 433 437 } 434 438 435 void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t & owner ) {439 static void ?{}(__condition_criterion_t & this, monitor$ * target, __condition_node_t & owner ) { 436 440 this.ready = false; 437 441 this.target = target; … … 442 446 //----------------------------------------------------------------------------- 443 447 // Internal scheduling 444 void wait( condition & this, uintptr_t user_info = 0 ) {448 void wait( condition & this, uintptr_t user_info = 0 ) libcfa_public { 445 449 brand_condition( this ); 446 450 … … 496 500 } 497 501 498 bool signal( condition & this ) {502 bool signal( condition & this ) libcfa_public { 499 503 if( is_empty( this ) ) { return false; } 500 504 … … 538 542 } 539 543 540 bool signal_block( condition & this ) {544 bool signal_block( condition & this ) libcfa_public { 541 545 if( !this.blocked.head ) { return false; } 542 546 … … 586 590 587 591 // Access the user_info of the thread waiting at the front of the queue 588 uintptr_t front( condition & this ) {592 uintptr_t front( condition & this ) libcfa_public { 589 593 verifyf( !is_empty(this), 590 594 "Attempt to access user data on an empty condition.\n" … … 608 612 // setup mask 609 613 // block 610 void __waitfor_internal( const __waitfor_mask_t & mask, int duration ) {614 void __waitfor_internal( const __waitfor_mask_t & mask, int duration ) libcfa_public { 611 615 // This statment doesn't have a contiguous list of monitors... 612 616 // Create one! … … 994 998 // Can't be accepted since a mutex stmt is effectively an anonymous routine 995 999 // Thus we do not need a monitor group 996 void lock( monitor$ * this ) {1000 void lock( monitor$ * this ) libcfa_public { 997 1001 thread$ * thrd = active_thread(); 998 1002 … … 1046 1050 // Leave routine for mutex stmt 1047 1051 // Is just a wrapper around __leave for the is_lock trait to see 1048 void unlock( monitor$ * this ) { __leave( this ); }1052 void unlock( monitor$ * this ) libcfa_public { __leave( this ); } 1049 1053 1050 1054 // Local Variables: // -
libcfa/src/concurrency/monitor.hfa
r29d8c02 r74ec742 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
r29d8c02 r74ec742 38 38 #endif 39 39 40 __attribute__((weak)) Duration default_preemption() {40 __attribute__((weak)) Duration default_preemption() libcfa_public { 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() {240 __attribute__((optimize("no-reorder-blocks"))) bool __preemption_enabled() libcfa_public { 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__ )); //no inline to avoid problems278 uintptr_t __cfatls_get( unsigned long int offset ) __attribute__((__noinline__, visibility("default"))); //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 void disable_interrupts(){297 __attribute__((__noinline__, visibility("default"))) void disable_interrupts() libcfa_public { 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 ) {328 void enable_interrupts( bool poll ) libcfa_public { 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() {364 void __cfaabi_check_preemption() libcfa_public { 365 365 bool ready = __preemption_enabled(); 366 366 if(!ready) { abort("Preemption should be ready"); } -
libcfa/src/concurrency/ready_subqueue.hfa
r29d8c02 r74ec742 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 ); 85 86 return [node, this.anchor.ts]; 86 87 } … … 93 94 // Return the timestamp 94 95 static inline unsigned long long ts(__intrusive_lane_t & this) { 95 // Cannot verify here since it may not be locked96 // Cannot verify 'emptiness' here since it may not be locked 96 97 /* paranoid */ verify(this.anchor.ts != 0); 97 98 return this.anchor.ts; -
libcfa/src/concurrency/thread.cfa
r29d8c02 r74ec742 26 26 27 27 extern uint32_t __global_random_seed, __global_random_prime, __global_random_mask; 28 29 #pragma GCC visibility push(default) 28 30 29 31 //----------------------------------------------------------------------------- -
libcfa/src/containers/maybe.cfa
r29d8c02 r74ec742 17 17 #include <assert.h> 18 18 19 #pragma GCC visibility push(default) 19 20 20 21 forall(T) -
libcfa/src/containers/result.cfa
r29d8c02 r74ec742 17 17 #include <assert.h> 18 18 19 #pragma GCC visibility push(default) 19 20 20 21 forall(T, E) -
libcfa/src/containers/string.cfa
r29d8c02 r74ec742 18 18 #include <stdlib.hfa> 19 19 20 #pragma GCC visibility push(default) 20 21 21 22 /* -
libcfa/src/containers/string_sharectx.hfa
r29d8c02 r74ec742 16 16 #pragma once 17 17 18 #pragma GCC visibility push(default) 19 18 20 //######################### String Sharing Context ######################### 19 21 20 22 struct VbyteHeap; 21 23 22 // A string_sharectx 24 // A string_sharectx 23 25 // 24 26 // Usage: -
libcfa/src/containers/vector.cfa
r29d8c02 r74ec742 18 18 #include <stdlib.hfa> 19 19 20 #pragma GCC visibility push(default) 21 20 22 forall(T, allocator_t | allocator_c(T, allocator_t)) 21 void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other);23 static void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other); 22 24 23 25 //------------------------------------------------------------------------------ … … 83 85 84 86 forall(T, allocator_t | allocator_c(T, allocator_t)) 85 void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other)87 static void copy_internal(vector(T, allocator_t)* this, vector(T, allocator_t)* other) 86 88 { 87 89 this->size = other->size; -
libcfa/src/device/cpu.cfa
r29d8c02 r74ec742 31 31 } 32 32 33 #include "bits/defs.hfa" 33 34 #include "algorithms/range_iterator.hfa" 34 35 … … 456 457 } 457 458 458 cpu_info_t cpu_info;459 libcfa_public cpu_info_t cpu_info; -
libcfa/src/exception.c
r29d8c02 r74ec742 27 27 #include "stdhdr/assert.h" 28 28 #include "virtual.h" 29 30 #pragma GCC visibility push(default) 31 29 32 #include "lsda.h" 30 33 … … 261 264 #else // defined( __ARM_ARCH ) 262 265 // The return code from _Unwind_RaiseException seems to be corrupt on ARM at end of stack. 263 // This workaround tries to keep default exception handling working. 266 // This workaround tries to keep default exception handling working. 264 267 if ( ret == _URC_FATAL_PHASE1_ERROR || ret == _URC_FATAL_PHASE2_ERROR ) { 265 268 #endif -
libcfa/src/fstream.cfa
r29d8c02 r74ec742 22 22 #include <assert.h> 23 23 #include <errno.h> // errno 24 25 #pragma GCC visibility push(default) 24 26 25 27 // *********************************** ofstream *********************************** … … 118 120 // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno ); 119 121 } // if 120 (os){ file }; // initialize 122 (os){ file }; // initialize 121 123 } // open 122 124 … … 157 159 va_list args; 158 160 va_start( args, format ); 159 161 160 162 int len; 161 163 for ( cnt; 10 ) { … … 241 243 // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno ); 242 244 } // if 243 (is){ file }; // initialize 245 (is){ file }; // initialize 244 246 } // open 245 247 -
libcfa/src/fstream.hfa
r29d8c02 r74ec742 18 18 #include "bits/weakso_locks.hfa" // mutex_lock 19 19 #include "iostream.hfa" 20 #include <exception.hfa>21 20 22 21 -
libcfa/src/heap.cfa
r29d8c02 r74ec742 10 10 // Created On : Tue Dec 19 21:58:35 2017 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Apr 25 18:51:36202213 // Update Count : 11 4712 // Last Modified On : Fri Apr 29 19:05:03 2022 13 // Update Count : 1167 14 14 // 15 15 … … 36 36 static bool traceHeap = false; 37 37 38 inline bool traceHeap() { return traceHeap; }39 40 bool traceHeapOn() {38 inline bool traceHeap() libcfa_public { return traceHeap; } 39 40 bool traceHeapOn() libcfa_public { 41 41 bool temp = traceHeap; 42 42 traceHeap = true; … … 44 44 } // traceHeapOn 45 45 46 bool traceHeapOff() {46 bool traceHeapOff() libcfa_public { 47 47 bool temp = traceHeap; 48 48 traceHeap = false; … … 50 50 } // traceHeapOff 51 51 52 bool traceHeapTerm() { return false; }52 bool traceHeapTerm() libcfa_public { return false; } 53 53 54 54 55 55 static bool prtFree = false; 56 56 57 bool prtFree() {57 static bool prtFree() { 58 58 return prtFree; 59 59 } // prtFree 60 60 61 bool prtFreeOn() {61 static bool prtFreeOn() { 62 62 bool temp = prtFree; 63 63 prtFree = true; … … 65 65 } // prtFreeOn 66 66 67 bool prtFreeOff() {67 static bool prtFreeOff() { 68 68 bool temp = prtFree; 69 69 prtFree = false; … … 87 87 88 88 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 #################### 89 //####################### Heap Statistics #################### 248 90 249 91 … … 307 149 return lhs; 308 150 } // ?+=? 309 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__ 310 306 static HeapStatistics stats; // zero filled 311 307 static unsigned int sbrk_calls; … … 387 383 388 384 385 // statically allocated variables => zero filled. 386 static size_t heapExpand; // sbrk advance 387 static size_t mmapStart; // cross over point for mmap 388 static unsigned int maxBucketsUsed; // maximum number of buckets in use 389 // extern visibility, used by runtime kernel 390 // would be cool to remove libcfa_public but it's needed for libcfathread 391 libcfa_public size_t __page_size; // architecture pagesize 392 libcfa_public int __map_prot; // common mmap/mprotect protection 393 394 389 395 // thunk problem 390 396 size_t Bsearchl( unsigned int key, const unsigned int * vals, size_t dim ) { … … 490 496 } else { 491 497 fakeHeader( header, alignment ); 492 if ( unlikely( MmappedBit( header ) ) ) { 493 assert( addr < heapBegin || heapEnd < addr );498 if ( unlikely( MmappedBit( header ) ) ) { // mmapped ? 499 verify( addr < heapBegin || heapEnd < addr ); 494 500 size = ClearStickyBits( header->kind.real.blockSize ); // mmap size 495 501 return true; … … 503 509 checkHeader( header < (Heap.Storage.Header *)heapBegin || (Heap.Storage.Header *)heapEnd < header, name, addr ); // bad address ? (offset could be + or -) 504 510 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 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 510 519 #endif // __CFA_DEBUG__ 511 520 … … 560 569 sbrk_storage += increase; 561 570 #endif // __STATISTICS__ 571 562 572 #ifdef __CFA_DEBUG__ 563 573 // Set new memory to garbage so subsequent uninitialized usages might fail. … … 565 575 //Memset( (char *)heapEnd + heapRemaining, increase ); 566 576 #endif // __CFA_DEBUG__ 577 567 578 rem = heapRemaining + increase - size; 568 579 } // if … … 651 662 __atomic_add_fetch( &allocUnfreed, tsize, __ATOMIC_SEQ_CST ); 652 663 if ( traceHeap() ) { 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 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 657 667 } // if 658 668 #endif // __CFA_DEBUG__ … … 711 721 if ( traceHeap() ) { 712 722 char helpText[64]; 713 int len = snprintf( helpText, sizeof(helpText), "Free( %p ) size:%zu\n", addr, size );714 __cfaabi_bits_write( STDERR_FILENO, helpText, len); // print debug/nodebug723 __cfaabi_bits_print_buffer( STDERR_FILENO, helpText, sizeof(helpText), 724 "Free( %p ) size:%zu\n", addr, size ); // print debug/nodebug 715 725 } // if 716 726 #endif // __CFA_DEBUG__ … … 718 728 719 729 720 s ize_t prtFree( Heap & manager ) with( manager ) {730 static size_t prtFree( Heap & manager ) with( manager ) { 721 731 size_t total = 0; 722 732 #ifdef __STATISTICS__ … … 870 880 // Allocates size bytes and returns a pointer to the allocated memory. The contents are undefined. If size is 0, 871 881 // then malloc() returns a unique pointer value that can later be successfully passed to free(). 872 void * malloc( size_t size ) {882 void * malloc( size_t size ) libcfa_public { 873 883 #ifdef __STATISTICS__ 874 884 if ( likely( size > 0 ) ) { … … 885 895 886 896 // Same as malloc() except size bytes is an array of dim elements each of elemSize bytes. 887 void * aalloc( size_t dim, size_t elemSize ) {897 void * aalloc( size_t dim, size_t elemSize ) libcfa_public { 888 898 size_t size = dim * elemSize; 889 899 #ifdef __STATISTICS__ … … 901 911 902 912 // Same as aalloc() with memory set to zero. 903 void * calloc( size_t dim, size_t elemSize ) {913 void * calloc( size_t dim, size_t elemSize ) libcfa_public { 904 914 size_t size = dim * elemSize; 905 915 if ( unlikely( size ) == 0 ) { // 0 BYTE ALLOCATION RETURNS NULL POINTER … … 942 952 // not 0p, then the call is equivalent to free(oaddr). Unless oaddr is 0p, it must have been returned by an earlier 943 953 // call to malloc(), alloc(), calloc() or realloc(). If the area pointed to was moved, a free(oaddr) is done. 944 void * resize( void * oaddr, size_t size ) {954 void * resize( void * oaddr, size_t size ) libcfa_public { 945 955 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 946 956 if ( unlikely( size == 0 ) ) { // special cases … … 987 997 // Same as resize() but the contents are unchanged in the range from the start of the region up to the minimum of 988 998 // the old and new sizes. 989 void * realloc( void * oaddr, size_t size ) {999 void * realloc( void * oaddr, size_t size ) libcfa_public { 990 1000 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 991 1001 if ( unlikely( size == 0 ) ) { // special cases … … 1051 1061 1052 1062 // Same as realloc() except the new allocation size is large enough for an array of nelem elements of size elsize. 1053 void * reallocarray( void * oaddr, size_t dim, size_t elemSize ) {1063 void * reallocarray( void * oaddr, size_t dim, size_t elemSize ) libcfa_public { 1054 1064 return realloc( oaddr, dim * elemSize ); 1055 1065 } // reallocarray … … 1057 1067 1058 1068 // Same as malloc() except the memory address is a multiple of alignment, which must be a power of two. (obsolete) 1059 void * memalign( size_t alignment, size_t size ) {1069 void * memalign( size_t alignment, size_t size ) libcfa_public { 1060 1070 #ifdef __STATISTICS__ 1061 1071 if ( likely( size > 0 ) ) { … … 1072 1082 1073 1083 // Same as aalloc() with memory alignment. 1074 void * amemalign( size_t alignment, size_t dim, size_t elemSize ) {1084 void * amemalign( size_t alignment, size_t dim, size_t elemSize ) libcfa_public { 1075 1085 size_t size = dim * elemSize; 1076 1086 #ifdef __STATISTICS__ … … 1088 1098 1089 1099 // Same as calloc() with memory alignment. 1090 void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) {1100 void * cmemalign( size_t alignment, size_t dim, size_t elemSize ) libcfa_public { 1091 1101 size_t size = dim * elemSize; 1092 1102 if ( unlikely( size ) == 0 ) { // 0 BYTE ALLOCATION RETURNS NULL POINTER … … 1127 1137 // Same as memalign(), but ISO/IEC 2011 C11 Section 7.22.2 states: the value of size shall be an integral multiple 1128 1138 // of alignment. This requirement is universally ignored. 1129 void * aligned_alloc( size_t alignment, size_t size ) {1139 void * aligned_alloc( size_t alignment, size_t size ) libcfa_public { 1130 1140 return memalign( alignment, size ); 1131 1141 } // aligned_alloc … … 1136 1146 // is 0, then posix_memalign() returns either 0p, or a unique pointer value that can later be successfully passed to 1137 1147 // free(3). 1138 int posix_memalign( void ** memptr, size_t alignment, size_t size ) {1148 int posix_memalign( void ** memptr, size_t alignment, size_t size ) libcfa_public { 1139 1149 if ( unlikely( alignment < libAlign() || ! is_pow2( alignment ) ) ) return EINVAL; // check alignment 1140 1150 *memptr = memalign( alignment, size ); … … 1145 1155 // Allocates size bytes and returns a pointer to the allocated memory. The memory address shall be a multiple of the 1146 1156 // page size. It is equivalent to memalign(sysconf(_SC_PAGESIZE),size). 1147 void * valloc( size_t size ) {1157 void * valloc( size_t size ) libcfa_public { 1148 1158 return memalign( __page_size, size ); 1149 1159 } // valloc … … 1151 1161 1152 1162 // Same as valloc but rounds size to multiple of page size. 1153 void * pvalloc( size_t size ) {1163 void * pvalloc( size_t size ) libcfa_public { 1154 1164 return memalign( __page_size, ceiling2( size, __page_size ) ); // round size to multiple of page size 1155 1165 } // pvalloc … … 1159 1169 // or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behaviour occurs. If ptr is 1160 1170 // 0p, no operation is performed. 1161 void free( void * addr ) {1171 void free( void * addr ) libcfa_public { 1162 1172 if ( unlikely( addr == 0p ) ) { // special case 1163 1173 #ifdef __STATISTICS__ … … 1180 1190 1181 1191 // Returns the alignment of an allocation. 1182 size_t malloc_alignment( void * addr ) {1192 size_t malloc_alignment( void * addr ) libcfa_public { 1183 1193 if ( unlikely( addr == 0p ) ) return libAlign(); // minimum alignment 1184 1194 Heap.Storage.Header * header = HeaderAddr( addr ); … … 1192 1202 1193 1203 // Returns true if the allocation is zero filled, e.g., allocated by calloc(). 1194 bool malloc_zero_fill( void * addr ) {1204 bool malloc_zero_fill( void * addr ) libcfa_public { 1195 1205 if ( unlikely( addr == 0p ) ) return false; // null allocation is not zero fill 1196 1206 Heap.Storage.Header * header = HeaderAddr( addr ); … … 1203 1213 1204 1214 // Returns original total allocation size (not bucket size) => array size is dimension * sizeof(T). 1205 size_t malloc_size( void * addr ) {1215 size_t malloc_size( void * addr ) libcfa_public { 1206 1216 if ( unlikely( addr == 0p ) ) return 0; // null allocation has zero size 1207 1217 Heap.Storage.Header * header = HeaderAddr( addr ); … … 1215 1225 // Returns the number of usable bytes in the block pointed to by ptr, a pointer to a block of memory allocated by 1216 1226 // malloc or a related function. 1217 size_t malloc_usable_size( void * addr ) {1227 size_t malloc_usable_size( void * addr ) libcfa_public { 1218 1228 if ( unlikely( addr == 0p ) ) return 0; // null allocation has 0 size 1219 1229 Heap.Storage.Header * header; … … 1227 1237 1228 1238 // Prints (on default standard error) statistics about memory allocated by malloc and related functions. 1229 void malloc_stats( void ) {1239 void malloc_stats( void ) libcfa_public { 1230 1240 #ifdef __STATISTICS__ 1231 1241 printStats(); … … 1236 1246 1237 1247 // Changes the file descriptor where malloc_stats() writes statistics. 1238 int malloc_stats_fd( int fd __attribute__(( unused )) ) {1248 int malloc_stats_fd( int fd __attribute__(( unused )) ) libcfa_public { 1239 1249 #ifdef __STATISTICS__ 1240 1250 int temp = stats_fd; … … 1250 1260 // The string is printed on the file stream stream. The exported string includes information about all arenas (see 1251 1261 // malloc). 1252 int malloc_info( int options, FILE * stream __attribute__(( unused )) ) {1262 int malloc_info( int options, FILE * stream __attribute__(( unused )) ) libcfa_public { 1253 1263 if ( options != 0 ) { errno = EINVAL; return -1; } 1254 1264 #ifdef __STATISTICS__ … … 1262 1272 // Adjusts parameters that control the behaviour of the memory-allocation functions (see malloc). The param argument 1263 1273 // specifies the parameter to be modified, and value specifies the new value for that parameter. 1264 int mallopt( int option, int value ) {1274 int mallopt( int option, int value ) libcfa_public { 1265 1275 if ( value < 0 ) return 0; 1266 1276 choose( option ) { … … 1276 1286 1277 1287 // Attempt to release free memory at the top of the heap (by calling sbrk with a suitable argument). 1278 int malloc_trim( size_t ) {1288 int malloc_trim( size_t ) libcfa_public { 1279 1289 return 0; // => impossible to release memory 1280 1290 } // malloc_trim … … 1285 1295 // structure dynamically allocated via malloc, and a pointer to that data structure is returned as the function 1286 1296 // result. (The caller must free this memory.) 1287 void * malloc_get_state( void ) {1297 void * malloc_get_state( void ) libcfa_public { 1288 1298 return 0p; // unsupported 1289 1299 } // malloc_get_state … … 1292 1302 // Restores the state of all malloc internal bookkeeping variables to the values recorded in the opaque data 1293 1303 // structure pointed to by state. 1294 int malloc_set_state( void * ) {1304 int malloc_set_state( void * ) libcfa_public { 1295 1305 return 0; // unsupported 1296 1306 } // malloc_set_state … … 1298 1308 1299 1309 // Sets the amount (bytes) to extend the heap when there is insufficent free storage to service an allocation. 1300 __attribute__((weak)) size_t malloc_expansion() { return __CFA_DEFAULT_HEAP_EXPANSION__; }1310 __attribute__((weak)) size_t malloc_expansion() libcfa_public { return __CFA_DEFAULT_HEAP_EXPANSION__; } 1301 1311 1302 1312 // Sets the crossover point between allocations occuring in the sbrk area or separately mmapped. 1303 __attribute__((weak)) size_t malloc_mmap_start() { return __CFA_DEFAULT_MMAP_START__; }1313 __attribute__((weak)) size_t malloc_mmap_start() libcfa_public { return __CFA_DEFAULT_MMAP_START__; } 1304 1314 1305 1315 // Amount subtracted to adjust for unfreed program storage (debug only). 1306 __attribute__((weak)) size_t malloc_unfreed() { return __CFA_DEFAULT_HEAP_UNFREED__; }1316 __attribute__((weak)) size_t malloc_unfreed() libcfa_public { return __CFA_DEFAULT_HEAP_UNFREED__; } 1307 1317 } // extern "C" 1308 1318 1309 1319 1310 1320 // Must have CFA linkage to overload with C linkage realloc. 1311 void * resize( void * oaddr, size_t nalign, size_t size ) {1321 void * resize( void * oaddr, size_t nalign, size_t size ) libcfa_public { 1312 1322 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 1313 1323 if ( unlikely( size == 0 ) ) { // special cases … … 1371 1381 1372 1382 1373 void * realloc( void * oaddr, size_t nalign, size_t size ) {1383 void * realloc( void * oaddr, size_t nalign, size_t size ) libcfa_public { 1374 1384 // If size is equal to 0, either NULL or a pointer suitable to be passed to free() is returned. 1375 1385 if ( unlikely( size == 0 ) ) { // special cases -
libcfa/src/interpose.cfa
r29d8c02 r74ec742 36 36 //============================================================================================= 37 37 38 void preload_libgcc(void) {38 static 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 generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) {44 static generic_fptr_t interpose_symbol( const char symbol[], const char version[] ) { 45 45 const char * error; 46 46 … … 83 83 //============================================================================================= 84 84 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 st ruct {85 static void sigHandler_segv( __CFA_SIGPARMS__ ); 86 static void sigHandler_ill ( __CFA_SIGPARMS__ ); 87 static void sigHandler_fpe ( __CFA_SIGPARMS__ ); 88 static void sigHandler_abrt( __CFA_SIGPARMS__ ); 89 static void sigHandler_term( __CFA_SIGPARMS__ ); 90 91 static struct { 92 92 void (* exit)( int ) __attribute__(( __noreturn__ )); 93 93 void (* abort)( void ) __attribute__(( __noreturn__ )); 94 94 } __cabi_libc; 95 95 96 int cfa_main_returned;96 libcfa_public 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 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__ ));150 libcfa_public void exit( int status, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ )); 151 libcfa_public void abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )); 152 libcfa_public void abort( bool signalAbort, const char fmt[], ... ) __attribute__(( format(printf, 2, 3), __nothrow__, __leaf__, __noreturn__ )); 153 libcfa_public void __abort( bool signalAbort, const char fmt[], va_list args ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )); 154 154 155 155 extern "C" { 156 void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {156 libcfa_public void abort( void ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) { 157 157 abort( false, "%s", "" ); 158 158 } 159 159 160 void __cabi_abort( const char fmt[], ... ) __attribute__(( format(printf, 1, 2), __nothrow__, __leaf__, __noreturn__ )) {160 libcfa_public 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 void exit( int status ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) {167 libcfa_public void exit( int status ) __attribute__(( __nothrow__, __leaf__, __noreturn__ )) { 168 168 __cabi_libc.exit( status ); 169 169 } -
libcfa/src/iostream.cfa
r29d8c02 r74ec742 32 32 #include "bitmanip.hfa" // high1 33 33 34 #pragma GCC visibility push(default) 34 35 35 36 // *********************************** ostream *********************************** -
libcfa/src/limits.cfa
r29d8c02 r74ec742 20 20 #include <complex.h> 21 21 #include "limits.hfa" 22 23 #pragma GCC visibility push(default) 22 24 23 25 // Integral Constants -
libcfa/src/memory.cfa
r29d8c02 r74ec742 16 16 #include "memory.hfa" 17 17 #include "stdlib.hfa" 18 19 #pragma GCC visibility push(default) 18 20 19 21 // Internal data object. -
libcfa/src/parseargs.cfa
r29d8c02 r74ec742 24 24 #include "common.hfa" 25 25 #include "limits.hfa" 26 27 #pragma GCC visibility push(default) 26 28 27 29 extern int cfa_args_argc __attribute__((weak)); … … 208 210 } 209 211 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 210 222 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) { 211 233 value = false; 212 234 return true; -
libcfa/src/parseconfig.cfa
r29d8c02 r74ec742 14 14 15 15 16 #pragma GCC visibility push(default) 17 16 18 // *********************************** exceptions *********************************** 17 19 18 20 19 21 // TODO: Add names of missing config entries to exception (see further below) 20 staticvtable(Missing_Config_Entries) Missing_Config_Entries_vt;22 vtable(Missing_Config_Entries) Missing_Config_Entries_vt; 21 23 22 24 [ void ] ?{}( & Missing_Config_Entries this, unsigned int num_missing ) { … … 31 33 32 34 33 staticvtable(Parse_Failure) Parse_Failure_vt;35 vtable(Parse_Failure) Parse_Failure_vt; 34 36 35 37 [ void ] ?{}( & Parse_Failure this, [] char failed_key, [] char failed_value ) { … … 53 55 54 56 55 staticvtable(Validation_Failure) Validation_Failure_vt;57 vtable(Validation_Failure) Validation_Failure_vt; 56 58 57 59 [ void ] ?{}( & Validation_Failure this, [] char failed_key, [] char failed_value ) { … … 110 112 111 113 112 [ bool ] comments( & ifstream in, [] char name ) {114 static [ bool ] comments( & ifstream in, [] char name ) { 113 115 while () { 114 116 in | name; -
libcfa/src/rational.cfa
r29d8c02 r74ec742 17 17 #include "fstream.hfa" 18 18 #include "stdlib.hfa" 19 20 #pragma GCC visibility push(default) 19 21 20 22 forall( T | Arithmetic( T ) ) { -
libcfa/src/startup.cfa
r29d8c02 r74ec742 41 41 } // __cfaabi_appready_shutdown 42 42 43 void disable_interrupts() __attribute__(( weak )) {}44 void enable_interrupts() __attribute__(( weak )) {}43 void disable_interrupts() __attribute__(( weak )) libcfa_public {} 44 void enable_interrupts() __attribute__(( weak )) libcfa_public {} 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 )) {}66 void __cfaabi_dbg_record_lock(struct __spinlock_t & this, const char prev_name[]) __attribute__(( weak )) libcfa_public {} 67 67 } 68 68 -
libcfa/src/stdlib.cfa
r29d8c02 r74ec742 25 25 #include <complex.h> // _Complex_I 26 26 #include <assert.h> 27 28 #pragma GCC visibility push(default) 27 29 28 30 //--------------------------------------- … … 225 227 #define GENERATOR LCG 226 228 227 uint32_t __global_random_seed; // sequential/concurrent 228 uint32_t __global_random_state; // sequential only 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 229 232 230 233 void set_seed( PRNG & prng, uint32_t seed_ ) with( prng ) { state = seed = seed_; GENERATOR( state ); } // set seed -
libcfa/src/strstream.cfa
r29d8c02 r74ec742 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) 26 27 27 28 // *********************************** strstream *********************************** -
libcfa/src/time.cfa
r29d8c02 r74ec742 18 18 #include <stdio.h> // snprintf 19 19 #include <assert.h> 20 21 #pragma GCC visibility push(default) 20 22 21 23 static char * nanomsd( long int ns, char * buf ) { // most significant digits -
libcfa/src/virtual.c
r29d8c02 r74ec742 16 16 #include "virtual.h" 17 17 #include "assert.h" 18 19 #pragma GCC visibility push(default) 18 20 19 21 int __cfavir_is_parent( -
src/AST/Convert.cpp
r29d8c02 r74ec742 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), 1653 1654 std::move(paramVars), 1654 1655 std::move(returnVars), … … 1664 1665 cache.emplace( old, decl ); 1665 1666 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 // Convert SynTree::EnumDecl to AST::EnumDecl 1732 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(new ast::VariableExpr({}, asst)); 2731 ty->assertions.emplace_back( 2732 new ast::VariableExpr(param->location, asst)); 2732 2733 } 2733 2734 } -
src/AST/Copy.cpp
r29d8c02 r74ec742 10 10 // Created On : Thr Nov 11 9:16:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : T hr Nov 11 9:28:00 202113 // Update Count : 012 // Last Modified On : Tue May 3 16:28:00 2022 13 // Update Count : 1 14 14 // 15 15 … … 77 77 } 78 78 79 void postvisit( const UniqueExpr * node ) { 80 readonlyInsert( &node->object ); 81 } 82 79 83 void postvisit( const MemberExpr * node ) { 80 84 readonlyInsert( &node->member ); -
src/AST/Decl.cpp
r29d8c02 r74ec742 9 9 // Author : Aaron B. Moss 10 10 // Created On : Thu May 9 10:00:00 2019 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : T ue Jan 12 16:54:55 202113 // Update Count : 2 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu May 5 12:10:00 2022 13 // Update Count : 24 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; 76 102 } 77 103 -
src/AST/Decl.hpp
r29d8c02 r74ec742 9 9 // Author : Aaron B. Moss 10 10 // Created On : Thu May 9 10:00:00 2019 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Mar 12 18:25:05 202113 // Update Count : 3 211 // Last Modified By : Andrew Beach 12 // Last Modified On : Thu May 5 12:09:00 2022 13 // Update Count : 33 14 14 // 15 15 … … 135 135 std::vector< ptr<Expr> > withExprs; 136 136 137 // The difference between the two constructors is in how they handle 138 // assertions. The first constructor uses the assertions from the type 139 // 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 of 141 // references to them on the type. 142 137 143 FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall, 138 144 std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns, 139 145 CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C, 140 146 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 ) {} 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); 143 153 144 154 const Type * get_type() const override; -
src/AST/Expr.cpp
r29d8c02 r74ec742 10 10 // Created On : Wed May 15 17:00:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Created On : Tue Nov 30 14:23:00 202113 // Update Count : 712 // Created On : Wed May 18 13:56:00 2022 13 // Update Count : 8 14 14 // 15 15 … … 21 21 22 22 #include "Copy.hpp" // for shallowCopy 23 #include "Eval.hpp" // for call24 23 #include "GenericSubstitution.hpp" 25 24 #include "LinkageSpec.hpp" … … 67 66 // --- UntypedExpr 68 67 68 bool UntypedExpr::get_lvalue() const { 69 std::string fname = InitTweak::getFunctionName( this ); 70 return lvalueFunctionNames.count( fname ); 71 } 72 69 73 UntypedExpr * UntypedExpr::createDeref( const CodeLocation & loc, const Expr * arg ) { 70 74 assert( arg ); 71 75 72 UntypedExpr * ret = c all( loc, "*?", arg);76 UntypedExpr * ret = createCall( loc, "*?", { arg } ); 73 77 if ( const Type * ty = arg->result ) { 74 78 const Type * base = InitTweak::getPointerBase( ty ); … … 87 91 } 88 92 89 bool UntypedExpr::get_lvalue() const {90 std::string fname = InitTweak::getFunctionName( this );91 return lvalueFunctionNames.count( fname );92 }93 94 93 UntypedExpr * UntypedExpr::createAssign( const CodeLocation & loc, const Expr * lhs, const Expr * rhs ) { 95 94 assert( lhs && rhs ); 96 95 97 UntypedExpr * ret = c all( loc, "?=?", lhs, rhs);96 UntypedExpr * ret = createCall( loc, "?=?", { lhs, rhs } ); 98 97 if ( lhs->result && rhs->result ) { 99 98 // if both expressions are typed, assumes that this assignment is a C bitwise assignment, … … 102 101 } 103 102 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 ) ); 104 109 } 105 110 -
src/AST/Expr.hpp
r29d8c02 r74ec742 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 ); 232 235 233 236 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } … … 784 787 public: 785 788 ptr<Expr> expr; 786 ptr<ObjectDecl> object;789 readonly<ObjectDecl> object; 787 790 ptr<VariableExpr> var; 788 791 unsigned long long id; -
src/AST/Label.hpp
r29d8c02 r74ec742 34 34 std::vector< ptr<Attribute> > attributes; 35 35 36 Label( CodeLocationloc, const std::string& name = "",36 Label( const 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
r29d8c02 r74ec742 10 10 // Created On : Wed May 8 10:27:04 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Mar 25 10:33:00 202213 // Update Count : 712 // Last Modified On : Mon May 9 10:20:00 2022 13 // Update Count : 8 14 14 // 15 15 … … 49 49 50 50 bool unique() const { return strong_count == 1; } 51 bool isManaged() const {return strong_count > 0; } 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 } 52 56 53 57 private: -
src/AST/Pass.proto.hpp
r29d8c02 r74ec742 131 131 template< typename node_t > 132 132 struct result1 { 133 bool differs ;134 const node_t * value ;133 bool differs = false; 134 const node_t * value = nullptr; 135 135 136 136 template< typename object_t, typename super_t, typename field_t > … … 151 151 }; 152 152 153 bool differs ;153 bool differs = false; 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 ;169 bool differs = false; 170 170 container_t<ptr<node_t>> values; 171 171 -
src/AST/Stmt.cpp
r29d8c02 r74ec742 9 9 // Author : Aaron B. Moss 10 10 // Created On : Wed May 8 13:00:00 2019 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Wed Feb 2 19:01:20 202213 // Update Count : 311 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue May 3 15:18:20 2022 13 // Update Count : 4 14 14 // 15 15 16 16 #include "Stmt.hpp" 17 17 18 18 #include "Copy.hpp" 19 19 #include "DeclReplacer.hpp" 20 20 #include "Type.hpp" … … 23 23 24 24 // --- CompoundStmt 25 CompoundStmt::CompoundStmt( const CompoundStmt& other ) : Stmt(other), kids(other.kids) { 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 26 38 // when cloning a compound statement, we may end up cloning declarations which 27 39 // are referred to by VariableExprs throughout the block. Cloning a VariableExpr -
src/AST/Stmt.hpp
r29d8c02 r74ec742 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
r29d8c02 r74ec742 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Util. hpp -- General utilities for working with the AST.7 // Util.cpp -- 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 : Fri Mar 11 18:07:00 202213 // Update Count : 112 // Last Modified On : Wed May 11 16:16:00 2022 13 // Update Count : 3 14 14 // 15 15 … … 46 46 47 47 /// Check that every note that can has a set CodeLocation. 48 struct SetCodeLocationsCore { 49 void previsit( const ParseNode * node ) { 50 assert( node->location.isSet() ); 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() ); 51 55 } 52 }; 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 } 53 84 54 85 struct InvariantCore { … … 56 87 // None of the passes should make changes so ordering doesn't matter. 57 88 NoStrongCyclesCore no_strong_cycles; 58 SetCodeLocationsCore set_code_locations;59 89 60 90 void previsit( const Node * node ) { 61 91 no_strong_cycles.previsit( node ); 92 isStable( node ); 62 93 } 63 94 64 95 void previsit( const ParseNode * node ) { 65 no_strong_cycles.previsit( node ); 66 set_code_locations.previsit( 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 ); 67 108 } 68 109 -
src/AST/module.mk
r29d8c02 r74ec742 29 29 AST/DeclReplacer.cpp \ 30 30 AST/DeclReplacer.hpp \ 31 AST/Eval.hpp \32 31 AST/Expr.cpp \ 33 32 AST/Expr.hpp \ -
src/CodeGen/CodeGenerator.cc
r29d8c02 r74ec742 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 1252 1240 // Local Variables: // 1253 1241 // tab-width: 4 // -
src/CodeGen/FixMain.cc
r29d8c02 r74ec742 49 49 50 50 } 51 52 bool FixMain::replace_main = false;53 51 54 52 template<typename container> -
src/CodeGen/LinkOnce.cc
r29d8c02 r74ec742 53 53 new ConstantExpr( Constant::from_string( section_name ) ) 54 54 ); 55 56 // Unconditionnaly add "visibility(default)" to anything with gnu.linkonce 57 // visibility is a mess otherwise 58 attributes.push_back(new Attribute("visibility", {new ConstantExpr( Constant::from_string( "default" ) )})); 59 55 60 } 56 61 visit_children = false; -
src/CodeGen/module.mk
r29d8c02 r74ec742 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Peter A. Buhr13 ## Last Modified On : Sat Dec 14 07:29:42 201914 ## Update Count : 412 ## Last Modified By : Andrew Beach 13 ## Last Modified On : Tue May 17 14:26:00 2022 14 ## Update Count : 5 15 15 ############################################################################### 16 16 17 #SRC += ArgTweak/Rewriter.cc \ 18 # ArgTweak/Mutate.cc 17 SRC_CODEGEN = \ 18 CodeGen/FixMain2.cc \ 19 CodeGen/FixMain.h \ 20 CodeGen/OperatorTable.cc \ 21 CodeGen/OperatorTable.h 19 22 20 SRC _CODEGEN =\23 SRC += $(SRC_CODEGEN) \ 21 24 CodeGen/CodeGenerator.cc \ 22 25 CodeGen/CodeGenerator.h \ 26 CodeGen/Generate.cc \ 27 CodeGen/Generate.h \ 23 28 CodeGen/FixMain.cc \ 24 CodeGen/FixMain.h \ 29 CodeGen/FixNames.cc \ 30 CodeGen/FixNames.h \ 25 31 CodeGen/GenType.cc \ 26 32 CodeGen/GenType.h \ 27 33 CodeGen/LinkOnce.cc \ 28 34 CodeGen/LinkOnce.h \ 29 CodeGen/OperatorTable.cc \30 CodeGen/OperatorTable.h \31 35 CodeGen/Options.h 32 36 33 SRC += $(SRC_CODEGEN) CodeGen/Generate.cc CodeGen/Generate.h CodeGen/FixNames.cc CodeGen/FixNames.h34 37 SRCDEMANGLE += $(SRC_CODEGEN) -
src/Common/CodeLocationTools.cpp
r29d8c02 r74ec742 10 10 // Created On : Fri Dec 4 15:42:00 2020 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Mar 14 15:14:00 202213 // Update Count : 412 // Last Modified On : Wed May 11 16:16:00 2022 13 // Update Count : 5 14 14 // 15 15 … … 24 24 namespace { 25 25 26 // There are a lot of helpers in this file that could be used much more27 // 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 64 26 // Fill every location with a nearby (parent) location. 65 27 class FillCore : public ast::WithGuards { 66 28 CodeLocation const * parent; 29 30 template<typename node_t> 31 node_t const * parse_visit( node_t const * node ) { 32 if ( node->location.isUnset() ) { 33 assert( parent ); 34 node_t * newNode = ast::mutate( node ); 35 newNode->location = *parent; 36 return newNode; 37 } 38 GuardValue( parent ) = &node->location; 39 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 ) -> typename 74 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 ) -> typename 80 std::remove_reference< decltype( node->labels, node ) >::type { 81 return stmt_visit( parse_visit( node ) ); 82 } 83 67 84 public: 68 85 FillCore() : parent( nullptr ) {} 86 FillCore( const CodeLocation& location ) : parent( &location ) { 87 assert( location.isSet() ); 88 } 69 89 70 90 template<typename node_t> 71 91 node_t const * previsit( node_t const * node ) { 72 GuardValue( parent ); 73 CodeLocation const * location = get_code_location( node ); 74 if ( location && location->isUnset() ) { 75 assert( parent ); 76 node_t * newNode = ast::mutate( node ); 77 CodeLocation * newLocation = get_code_location( newNode ); 78 assert( newLocation ); 79 *newLocation = *parent; 80 parent = newLocation; 81 return newNode; 82 } else if ( location ) { 83 parent = location; 84 } 85 return node; 92 return visit( node, '\0' ); 86 93 } 87 94 }; … … 233 240 234 241 template<typename node_t> 235 void previsit( node_t const * node ) { 236 CodeLocation const * location = get_code_location( node ); 237 if ( location && location->isUnset() ) { 242 auto previsit( node_t const * node ) -> decltype( node->location, void() ) { 243 if ( node->location.isUnset() ) { 238 244 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;260 245 } 261 246 } … … 304 289 ast::Node const * localFillCodeLocations( 305 290 CodeLocation const & location , ast::Node const * node ) { 306 ast::Pass< LocalFillCore> visitor( location );291 ast::Pass<FillCore> visitor( location ); 307 292 return node->accept( visitor ); 308 293 } -
src/Common/Indenter.h
r29d8c02 r74ec742 10 10 // Created On : Fri Jun 30 16:55:23 2017 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Aug 11 11:15:00 201713 // Update Count : 112 // Last Modified On : Fri May 13 14:10:00 2022 13 // Update Count : 2 14 14 // 15 15 16 #ifndef INDENTER_H 17 #define INDENTER_H 16 #pragma once 17 18 #include <ostream> 18 19 19 20 struct Indenter { … … 37 38 return out << std::string(indent.indent * indent.amt, ' '); 38 39 } 39 40 #endif // INDENTER_H -
src/Common/SemanticError.h
r29d8c02 r74ec742 10 10 // Created On : Mon May 18 07:44:20 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Jul 19 10:09:17 201813 // Update Count : 3 112 // Last Modified On : Wed May 4 14:08:26 2022 13 // Update Count : 35 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" }, 61 62 {"gcc-attributes" , Severity::Warn , "invalid attribute: %s" }, 62 63 {"c++-like-copy" , Severity::Warn , "Constructor from reference is not a valid copy constructor" }, … … 69 70 AggrForwardDecl, 70 71 SuperfluousDecl, 72 SuperfluousElse, 71 73 GccAttributes, 72 74 CppCopy, … … 79 81 ); 80 82 81 #define SemanticWarning(loc, id, ...) SemanticWarningImpl(loc, id, WarningFormats[(int)id].message, __VA_ARGS__)83 #define SemanticWarning(loc, id, ...) SemanticWarningImpl(loc, id, WarningFormats[(int)id].message, ##__VA_ARGS__) 82 84 83 85 void SemanticWarningImpl (CodeLocation loc, Warning warn, const char * const fmt, ...) __attribute__((format(printf, 3, 4))); -
src/Common/module.mk
r29d8c02 r74ec742 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Peter A. Buhr13 ## Last Modified On : Tue Sep 27 11:06:38 201614 ## Update Count : 412 ## Last Modified By : Andrew Beach 13 ## Last Modified On : Tue May 17 14:27:00 2022 14 ## Update Count : 5 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/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 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 58 59 59 SRC += $(SRC_COMMON) Common/DebugMalloc.cc 60 SRC += $(SRC_COMMON) \ 61 Common/DebugMalloc.cc 62 60 63 SRCDEMANGLE += $(SRC_COMMON) -
src/Common/utility.h
r29d8c02 r74ec742 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Tue Feb 11 13:00:36 202013 // Update Count : 5 011 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon Apr 25 14:26:00 2022 13 // Update Count : 51 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 232 238 template< typename... Args > 233 239 auto zip(Args&&... args) -> decltype(zipWith(std::forward<Args>(args)..., std::make_pair)) { -
src/Concurrency/module.mk
r29d8c02 r74ec742 10 10 ## Author : Thierry Delisle 11 11 ## Created On : Mon Mar 13 12:48:40 2017 12 ## Last Modified By : 13 ## Last Modified On : 14 ## Update Count : 012 ## Last Modified By : Andrew Beach 13 ## Last Modified On : Tue May 17 13:28:00 2022 14 ## Update Count : 1 15 15 ############################################################################### 16 16 17 SRC _CONCURRENCY= \17 SRC += \ 18 18 Concurrency/KeywordsNew.cpp \ 19 Concurrency/Keywords.cc 20 21 SRC += $(SRC_CONCURRENCY) \ 19 Concurrency/Keywords.cc \ 22 20 Concurrency/Keywords.h \ 23 21 Concurrency/Waitfor.cc \ 24 22 Concurrency/Waitfor.h 25 26 SRCDEMANGLE += $(SRC_CONCURRENCY)27 -
src/ControlStruct/LabelGeneratorNew.hpp
r29d8c02 r74ec742 18 18 #include <string> // for string 19 19 20 classCodeLocation;20 struct CodeLocation; 21 21 22 22 namespace ast { -
src/ControlStruct/MultiLevelExit.cpp
r29d8c02 r74ec742 18 18 #include "AST/Pass.hpp" 19 19 #include "AST/Stmt.hpp" 20 #include "Common/CodeLocationTools.hpp" 20 21 #include "LabelGeneratorNew.hpp" 21 22 … … 228 229 // Labels on different stmts require different approaches to access 229 230 switch ( stmt->kind ) { 230 case BranchStmt::Goto:231 case BranchStmt::Goto: 231 232 return stmt; 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() ) {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() ) { 241 242 SemanticError( stmt->location, 242 243 "'break' outside a loop, 'switch', or labelled block" ); 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){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){ 251 252 return entry.stmt == targetStmt; 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'"),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'"), 257 258 " target must be an enclosing ", (isContinue ? "loop: " : "control structure: "), 258 259 stmt->originalTarget ) ); 259 }260 break;261 }262 // handle fallthrough in case/switch stmts263 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: ",260 } 261 break; 262 } 263 // handle fallthrough in case/switch stmts 264 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: ", 273 274 stmt->originalTarget ) ); 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: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: 303 304 assert( false ); 304 305 } … … 307 308 Label exitLabel( CodeLocation(), "" ); 308 309 switch ( stmt->kind ) { 309 case BranchStmt::Break:310 case BranchStmt::Break: 310 311 assert( ! targetEntry->useBreakExit().empty() ); 311 312 exitLabel = targetEntry->useBreakExit(); 312 313 break; 313 case BranchStmt::Continue:314 case BranchStmt::Continue: 314 315 assert( ! targetEntry->useContExit().empty() ); 315 316 exitLabel = targetEntry->useContExit(); 316 317 break; 317 case BranchStmt::FallThrough:318 case BranchStmt::FallThrough: 318 319 assert( ! targetEntry->useFallExit().empty() ); 319 320 exitLabel = targetEntry->useFallExit(); 320 321 break; 321 case BranchStmt::FallThroughDefault:322 case BranchStmt::FallThroughDefault: 322 323 assert( ! targetEntry->useFallDefaultExit().empty() ); 323 324 exitLabel = targetEntry->useFallDefaultExit(); … … 327 328 } 328 329 break; 329 default:330 default: 330 331 assert(0); 331 332 } … … 588 589 } 589 590 591 ptr<Stmt> else_stmt = nullptr; 592 Stmt * loop_kid = nullptr; 593 // check if loop node and if so add else clause if it exists 594 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 590 609 try { 591 ret.push_back( kid->accept( *visitor ) ); 610 if (else_stmt) ret.push_back( loop_kid->accept( *visitor ) ); 611 else ret.push_back( kid->accept( *visitor ) ); 592 612 } catch ( SemanticErrorException & e ) { 593 613 errors.append( e ); 594 614 } 615 616 if (else_stmt) ret.push_back(else_stmt); 595 617 596 618 if ( ! break_label.empty() ) { … … 612 634 Pass<MultiLevelExitCore> visitor( labelTable ); 613 635 const CompoundStmt * ret = stmt->accept( visitor ); 614 return ret; 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 ); 615 639 } 616 640 } // namespace ControlStruct -
src/ControlStruct/module.mk
r29d8c02 r74ec742 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Peter A. Buhr13 ## Last Modified On : Sat Jan 29 12:04:19202214 ## Update Count : 712 ## Last Modified By : Andrew Beach 13 ## Last Modified On : Tue May 17 14:30:00 2022 14 ## Update Count : 8 15 15 ############################################################################### 16 16 17 SRC _CONTROLSTRUCT= \17 SRC += \ 18 18 ControlStruct/ExceptDecl.cc \ 19 19 ControlStruct/ExceptDecl.h \ 20 ControlStruct/ExceptTranslateNew.cpp \ 21 ControlStruct/ExceptTranslate.cc \ 22 ControlStruct/ExceptTranslate.h \ 20 23 ControlStruct/FixLabels.cpp \ 21 24 ControlStruct/FixLabels.hpp \ … … 37 40 ControlStruct/Mutate.h 38 41 39 SRC += $(SRC_CONTROLSTRUCT) \40 ControlStruct/ExceptTranslateNew.cpp \41 ControlStruct/ExceptTranslate.cc \42 ControlStruct/ExceptTranslate.h43 44 SRCDEMANGLE += $(SRC_CONTROLSTRUCT)45 -
src/GenPoly/Lvalue.cc
r29d8c02 r74ec742 9 9 // Author : Richard C. Bilson 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Dec 13 23:14:38 201913 // Update Count : 711 // Last Modified By : Andrew Beach 12 // Last Modified On : Mon May 16 14:09:00 2022 13 // Update Count : 8 14 14 // 15 15 … … 125 125 } // namespace 126 126 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 } 127 // Stored elsewhere (Lvalue2, initially false). 128 extern bool referencesEliminated; 132 129 133 130 void convertLvalue( std::list< Declaration* > & translationUnit ) { -
src/GenPoly/module.mk
r29d8c02 r74ec742 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Peter A. Buhr13 ## Last Modified On : Mon Jun 1 17:52:30 201514 ## Update Count : 112 ## Last Modified By : Andrew Beach 13 ## Last Modified On : Tue May 17 14:31:00 2022 14 ## Update Count : 2 15 15 ############################################################################### 16 16 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 17 SRC_GENPOLY = \ 18 GenPoly/GenPoly.cc \ 19 GenPoly/GenPoly.h \ 20 GenPoly/Lvalue2.cc \ 21 GenPoly/Lvalue.h 33 22 34 SRCDEMANGLE += GenPoly/GenPoly.cc GenPoly/GenPoly.h GenPoly/Lvalue.cc GenPoly/Lvalue.h 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 35 37 38 SRCDEMANGLE += $(SRC_GENPOLY) -
src/InitTweak/FixInitNew.cpp
r29d8c02 r74ec742 454 454 455 455 auto expr = new ast::ImplicitCopyCtorExpr( appExpr->location, mutExpr ); 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. 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. 460 459 assert( typeSubs ); 461 // assert (mutExpr->env);462 460 expr->env = tmp; 463 // mutExpr->env = nullptr;464 //std::swap( expr->env, appExpr->env );465 461 return expr; 466 462 } 467 463 468 464 void ResolveCopyCtors::previsit(const ast::Expr * expr) { 469 if (expr->env) { 470 GuardValue(env); 471 GuardValue(envModified); 472 env = expr->env->clone(); 473 envModified = false; 474 } 465 if ( nullptr == expr->env ) { 466 return; 467 } 468 GuardValue( env ) = expr->env->clone(); 469 GuardValue( envModified ) = false; 475 470 } 476 471 477 472 const ast::Expr * ResolveCopyCtors::postvisit(const ast::Expr * expr) { 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 { 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; 491 484 return expr; 492 485 } … … 497 490 const ast::Expr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, const ast::ObjectDecl * var, const ast::Expr * cpArg ) { 498 491 assert( var ); 499 assert (var->isManaged());500 assert (!cpArg || cpArg->isManaged());492 assert( var->isManaged() ); 493 assert( !cpArg || cpArg->isManaged() ); 501 494 // arrays are not copy constructed, so this should always be an ExprStmt 502 495 ast::ptr< ast::Stmt > stmt = genCtorDtor(var->location, fname, var, cpArg ); … … 504 497 auto exprStmt = stmt.strict_as<ast::ImplicitCtorDtorStmt>()->callStmt.strict_as<ast::ExprStmt>(); 505 498 ast::ptr<ast::Expr> untyped = exprStmt->expr; // take ownership of expr 506 // exprStmt->expr = nullptr;507 499 508 500 // resolve copy constructor … … 516 508 env->add( *resolved->env ); 517 509 envModified = true; 518 // delete resolved->env;519 510 auto mut = mutate(resolved.get()); 520 511 assertf(mut == resolved.get(), "newly resolved expression must be unique"); 521 512 mut->env = nullptr; 522 513 } // if 523 // delete stmt;524 514 if ( auto assign = resolved.as<ast::TupleAssignExpr>() ) { 525 515 // fix newly generated StmtExpr -
src/InitTweak/module.mk
r29d8c02 r74ec742 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Rob Schluntz13 ## Last Modified On : Fri May 13 11:36:24 201614 ## Update Count : 312 ## Last Modified By : Andrew Beach 13 ## Last Modified On : Tue May 17 14:31:00 2022 14 ## Update Count : 4 15 15 ############################################################################### 16 16 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 += \ 17 SRC_INITTWEAK = \ 29 18 InitTweak/GenInit.cc \ 30 19 InitTweak/GenInit.h \ … … 32 21 InitTweak/InitTweak.h 33 22 23 SRC += $(SRC_INITTWEAK) \ 24 InitTweak/FixGlobalInit.cc \ 25 InitTweak/FixGlobalInit.h \ 26 InitTweak/FixInit.cc \ 27 InitTweak/FixInit.h \ 28 InitTweak/FixInitNew.cpp 29 30 SRCDEMANGLE += $(SRC_INITTWEAK) -
src/Parser/DeclarationNode.cc
r29d8c02 r74ec742 253 253 } // DeclarationNode::newAggregate 254 254 255 DeclarationNode * DeclarationNode::newEnum( const string * name, DeclarationNode * constants, bool body ) {255 DeclarationNode * DeclarationNode::newEnum( const string * name, DeclarationNode * constants, bool body, DeclarationNode * base) { 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 } // if 265 266 // Check: if base has TypeData 262 267 return newnode; 263 268 } // DeclarationNode::newEnum … … 290 295 return newName( name ); // Not explicitly inited enum value; 291 296 } // if 292 } // DeclarationNode::newEnum Generic297 } // DeclarationNode::newEnumValueGeneric 293 298 294 299 DeclarationNode * DeclarationNode::newFromTypedef( const string * name ) { -
src/Parser/ParseNode.h
r29d8c02 r74ec742 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 );237 static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body, DeclarationNode * base = nullptr ); 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
r29d8c02 r74ec742 388 388 if ( enumeration.body ) { 389 389 os << string( indent + 2, ' ' ) << " with body" << endl; 390 } // if 391 if ( base ) { 392 os << "for "; 393 base->print( os, indent + 2 ); 390 394 } // if 391 395 break; … … 926 930 ObjectDecl * member = dynamic_cast< ObjectDecl * >(* members); 927 931 member->set_init( new SingleInit( maybeMoveBuild< Expression >( cur->consume_enumeratorValue() ) ) ); 928 } else {932 } else if ( !cur->initializer ) { 929 933 if ( baseType && (!dynamic_cast<BasicType *>(baseType) || !dynamic_cast<BasicType *>(baseType)->isWholeNumber())) { 930 934 SemanticError( td->location, "A non whole number enum value decl must be explicitly initialized." ); 931 935 } 932 } // if 936 } 937 // else cur is a List Initializer and has been set as init in buildList() 938 // if 933 939 } // for 934 ret->set_body( td->enumeration.body ); // Boolean; if it has body940 ret->set_body( td->enumeration.body ); 935 941 return ret; 936 942 } // buildEnum -
src/Parser/parser.yy
r29d8c02 r74ec742 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Mon Mar 14 16:35:29202213 // Update Count : 5 27612 // Last Modified On : Sat May 14 09:16:22 2022 13 // Update Count : 5401 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 Attribute 56 58 57 59 extern DeclarationNode * parseTree; … … 93 95 } // appendStr 94 96 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 ); 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 98 105 for ( cur = dynamic_cast<DeclarationNode *>( cur->get_next() ); cur != nullptr; cur = dynamic_cast<DeclarationNode *>( cur->get_next() ) ) { 99 106 cl->cloneBaseType( cur ); 100 107 } // for 101 108 declList->addType( cl ); 109 // printf( "distAttr3 declList %p\n", declList ); declList->print( std::cout, 0 ); 102 110 return declList; 103 111 } // distAttr … … 111 119 112 120 void distInl( DeclarationNode * declaration ) { 113 // distribute EXTENSIONacross all declarations121 // distribute INLINE across all declarations 114 122 for ( DeclarationNode *iter = declaration; iter != nullptr; iter = (DeclarationNode *)iter->get_next() ) { 115 123 iter->set_inLine( true ); … … 171 179 if ( ! ( typeSpec->type && (typeSpec->type->kind == TypeData::Aggregate || typeSpec->type->kind == TypeData::Enum) ) ) { 172 180 stringstream ss; 173 typeSpec->type->print( ss);181 // printf( "fieldDecl1 typeSpec %p\n", typeSpec ); typeSpec->type->print( std::cout ); 174 182 SemanticWarning( yylloc, Warning::SuperfluousDecl, ss.str().c_str() ); 175 183 return nullptr; 176 184 } // if 185 // printf( "fieldDecl2 typeSpec %p\n", typeSpec ); typeSpec->type->print( std::cout ); 177 186 fieldList = DeclarationNode::newName( nullptr ); 178 187 } // if 179 return distAttr( typeSpec, fieldList ); // mark all fields in list 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; 180 194 } // fieldDecl 181 195 … … 1221 1235 1222 1236 iteration_statement: 1223 WHILE '(' ')' statement // CFA => while ( 1 )1237 WHILE '(' ')' statement %prec THEN // CFA => while ( 1 ) 1224 1238 { $$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); } 1239 | WHILE '(' ')' statement ELSE statement // CFA 1240 { 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 } 1225 1244 | WHILE '(' conditional_declaration ')' statement %prec THEN 1226 1245 { $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ) ) ); } … … 1229 1248 | DO statement WHILE '(' ')' ';' // CFA => do while( 1 ) 1230 1249 { $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); } 1231 | DO statement WHILE '(' comma_expression ')' ';' %prec THEN 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 ')' ';' 1232 1256 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ) ) ); } 1233 1257 | DO statement WHILE '(' comma_expression ')' ELSE statement // CFA 1234 1258 { $$ = new StatementNode( build_do_while( $5, maybe_build_compound( $2 ), $8 ) ); } 1235 | FOR '(' ')' statement // CFA => for ( ;; )1259 | FOR '(' ')' statement %prec THEN // CFA => for ( ;; ) 1236 1260 { $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); } 1261 | FOR '(' ')' statement ELSE statement // CFA 1262 { 1263 $$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) ); 1264 SemanticWarning( yylloc, Warning::SuperfluousElse ); 1265 } 1237 1266 | FOR '(' for_control_expression_list ')' statement %prec THEN 1238 1267 { $$ = new StatementNode( build_for( $3, maybe_build_compound( $5 ) ) ); } … … 1605 1634 declaration: // old & new style declarations 1606 1635 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 // } // for 1641 } 1607 1642 | cfa_declaration ';' // CFA 1608 1643 | static_assert // C11 … … 1810 1845 basic_type_specifier 1811 1846 | 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 // } // for 1852 } 1812 1853 | type_type_specifier 1813 1854 ; … … 2026 2067 sue_declaration_specifier: // struct, union, enum + storage class + type specifier 2027 2068 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 // } // for 2074 } 2028 2075 | declaration_qualifier_list sue_type_specifier 2029 2076 { $$ = $2->addQualifiers( $1 ); } … … 2036 2083 sue_type_specifier: // struct, union, enum + type specifier 2037 2084 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 // } // for 2090 } 2038 2091 | type_qualifier_list 2039 2092 { if ( $1->type != nullptr && $1->type->forall ) forall = true; } // remember generic type … … 2108 2161 elaborated_type: // struct, union, enum 2109 2162 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 // } // for 2168 } 2110 2169 | enum_type 2111 2170 ; … … 2127 2186 } 2128 2187 '{' field_declaration_list_opt '}' type_parameters_opt 2129 { $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); } 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 } 2130 2200 | aggregate_key attribute_list_opt TYPEDEFname // unqualified type name 2131 2201 { … … 2135 2205 '{' field_declaration_list_opt '}' type_parameters_opt 2136 2206 { 2207 // printf( "AGG3\n" ); 2137 2208 DeclarationNode::newFromTypedef( $3 ); 2138 2209 $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); … … 2145 2216 '{' field_declaration_list_opt '}' type_parameters_opt 2146 2217 { 2218 // printf( "AGG4\n" ); 2147 2219 DeclarationNode::newFromTypeGen( $3, nullptr ); 2148 2220 $$ = DeclarationNode::newAggregate( $1, $3, $8, $6, true )->addQualifiers( $2 ); … … 2221 2293 field_declaration: 2222 2294 type_specifier field_declaring_list_opt ';' 2223 { $$ = fieldDecl( $1, $2 ); } 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 } 2224 2303 | EXTENSION type_specifier field_declaring_list_opt ';' // GCC 2225 2304 { $$ = fieldDecl( $2, $3 ); distExt( $$ ); } … … 2303 2382 ; 2304 2383 2305 enum_type: // static DeclarationNode * newEnum( const std::string * name, DeclarationNode * constants, bool body, bool typed ); // enum2384 enum_type: 2306 2385 ENUM attribute_list_opt '{' enumerator_list comma_opt '}' 2307 2386 { $$ = DeclarationNode::newEnum( nullptr, $4, true )->addQualifiers( $2 ); } … … 2318 2397 { SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); } 2319 2398 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 identifier2399 $$ = DeclarationNode::newEnum( nullptr, $7, true, $3 )->addQualifiers( $5 ); 2400 } 2401 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt identifier attribute_list_opt 2323 2402 { 2324 2403 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." ); } … … 2327 2406 '{' enumerator_list comma_opt '}' 2328 2407 { 2329 $$ = DeclarationNode::newEnum( $6, $10, true ) -> addQualifiers( $5 ) -> addQualifiers( $7 ) -> addEnumBase( $3);2408 $$ = DeclarationNode::newEnum( $6, $10, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 ); 2330 2409 } 2331 2410 | ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt typedef_name attribute_list_opt '{' enumerator_list comma_opt '}' … … 2333 2412 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." ); } 2334 2413 typedefTable.makeTypedef( *$6->name ); 2335 $$ = DeclarationNode::newEnum( $6->name, $9, true ) -> addQualifiers( $5 ) -> addQualifiers( $7 ) -> addEnumBase( $3);2414 $$ = DeclarationNode::newEnum( $6->name, $9, true, $3 )->addQualifiers( $5 )->addQualifiers( $7 ); 2336 2415 } 2337 2416 | enum_type_nobody … … 2830 2909 // empty 2831 2910 { $$ = nullptr; forall = false; } 2832 | WITH '(' tuple_expression_list ')' 2833 { $$ = $3; 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 } 2834 2919 ; 2835 2920 -
src/ResolvExpr/AlternativeFinder.cc
r29d8c02 r74ec742 42 42 #include "SymTab/Indexer.h" // for Indexer 43 43 #include "SymTab/Mangler.h" // for Mangler 44 #include "SymTab/Validate .h"// for validateType44 #include "SymTab/ValidateType.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
r29d8c02 r74ec742 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 true 429 430 currentObject = CurrentObject( new BasicType( Type::Qualifiers(), BasicType::SignedInt ) ); 430 431 } … … 1477 1478 // enum type is still incomplete at this point. Use `int` instead. 1478 1479 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 // } 1480 if (dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() )->base->base) { 1497 1481 objectDecl = fixObjectType( objectDecl, context ); 1498 1482 const ast::Type * enumBase = (dynamic_cast< const ast::EnumInstType * >( objectDecl->get_type() )->base->base.get()); -
src/SymTab/Autogen.h
r29d8c02 r74ec742 21 21 22 22 #include "AST/Decl.hpp" 23 #include "AST/Eval.hpp"24 23 #include "AST/Expr.hpp" 25 24 #include "AST/Init.hpp" … … 71 70 template< typename OutIter > 72 71 ast::ptr< ast::Stmt > genCall( 73 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 74 const CodeLocation & loc, const std::string & fname, OutIter && out, 72 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 73 const CodeLocation & loc, const std::string & fname, OutIter && out, 75 74 const ast::Type * type, const ast::Type * addCast, LoopDirection forward = LoopForward ); 76 75 … … 128 127 } 129 128 130 /// inserts into out a generated call expression to function fname with arguments dstParam and 129 /// inserts into out a generated call expression to function fname with arguments dstParam and 131 130 /// srcParam. Should only be called with non-array types. 132 /// optionally returns a statement which must be inserted prior to the containing loop, if 131 /// optionally returns a statement which must be inserted prior to the containing loop, if 133 132 /// there is one 134 133 template< typename OutIter > 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, 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, 138 137 const ast::Type * addCast = nullptr 139 138 ) { … … 153 152 154 153 if ( addCast ) { 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 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 158 157 // lvalue-qualified type, so remove all qualifiers except lvalue. 159 158 // xxx -- old code actually removed lvalue too... 160 159 ast::ptr< ast::Type > guard = addCast; // prevent castType from mutating addCast 161 160 ast::ptr< ast::Type > castType = addCast; 162 ast::remove_qualifiers( 163 castType, 161 ast::remove_qualifiers( 162 castType, 164 163 ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Atomic ); 165 164 dstParam = new ast::CastExpr{ dstParam, new ast::ReferenceType{ castType } }; … … 181 180 182 181 srcParam.clearArrayIndices(); 183 182 184 183 return listInit; 185 184 } … … 249 248 } 250 249 251 /// Store in out a loop which calls fname on each element of the array with srcParam and 250 /// Store in out a loop which calls fname on each element of the array with srcParam and 252 251 /// dstParam as arguments. If forward is true, loop goes from 0 to N-1, else N-1 to 0 253 252 template< typename OutIter > 254 253 void genArrayCall( 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 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 259 258 ) { 260 259 static UniqueName indexName( "_index" ); … … 279 278 } else { 280 279 // generate: for ( int i = N-1; i >= 0; --i ) 281 begin = ast:: call(282 loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ));280 begin = ast::UntypedExpr::createCall( loc, "?-?", 281 { array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } ); 283 282 end = ast::ConstantExpr::from_int( loc, 0 ); 284 283 cmp = "?>=?"; … … 286 285 } 287 286 288 ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{ 289 loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 287 ast::ptr< ast::DeclWithType > index = new ast::ObjectDecl{ 288 loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 290 289 new ast::SingleInit{ loc, begin } }; 291 290 ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index }; 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 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 300 302 // array list initializer 301 303 srcParam.addArrayIndex( indexVar, array->dimension ); … … 303 305 // for stmt's body, eventually containing call 304 306 ast::CompoundStmt * body = new ast::CompoundStmt{ loc }; 305 ast::ptr< ast::Stmt > listInit = genCall( 306 srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast, 307 ast::ptr< ast::Stmt > listInit = genCall( 308 srcParam, dstIndex, loc, fname, std::back_inserter( body->kids ), array->base, addCast, 307 309 forward ); 308 310 309 311 // block containing the stmt and index variable 310 312 ast::CompoundStmt * block = new ast::CompoundStmt{ loc }; … … 328 330 template< typename OutIter > 329 331 ast::ptr< ast::Stmt > genCall( 330 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 331 const CodeLocation & loc, const std::string & fname, OutIter && out, 332 InitTweak::InitExpander_new & srcParam, const ast::Expr * dstParam, 333 const CodeLocation & loc, const std::string & fname, OutIter && out, 332 334 const ast::Type * type, const ast::Type * addCast, LoopDirection forward 333 335 ) { 334 336 if ( auto at = dynamic_cast< const ast::ArrayType * >( type ) ) { 335 genArrayCall( 336 srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast, 337 genArrayCall( 338 srcParam, dstParam, loc, fname, std::forward< OutIter >(out), at, addCast, 337 339 forward ); 338 340 return {}; 339 341 } else { 340 return genScalarCall( 342 return genScalarCall( 341 343 srcParam, dstParam, loc, fname, std::forward< OutIter >( out ), type, addCast ); 342 344 } … … 377 379 } 378 380 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 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 383 385 ) { 384 386 // unnamed bit fields are not copied as they cannot be accessed … … 392 394 393 395 std::vector< ast::ptr< ast::Stmt > > stmts; 394 genCall( 396 genCall( 395 397 srcParam, dstParam, loc, fname, back_inserter( stmts ), obj->type, addCast, forward ); 396 398 … … 400 402 const ast::Stmt * callStmt = stmts.front(); 401 403 if ( addCast ) { 402 // implicitly generated ctor/dtor calls should be wrapped so that later passes are 404 // implicitly generated ctor/dtor calls should be wrapped so that later passes are 403 405 // aware they were generated. 404 406 callStmt = new ast::ImplicitCtorDtorStmt{ callStmt->location, callStmt }; … … 417 419 // compile-command: "make install" // 418 420 // End: // 419 -
src/SymTab/Demangle.cc
r29d8c02 r74ec742 5 5 // file "LICENCE" distributed with Cforall. 6 6 // 7 // Demangle r.cc --7 // Demangle.cc -- Convert a mangled name into a human readable name. 8 8 // 9 9 // Author : Rob Schluntz -
src/SymTab/Mangler.h
r29d8c02 r74ec742 111 111 } 112 112 113 extern "C" {114 char * cforall_demangle(const char *, int);115 }116 117 113 // Local Variables: // 118 114 // tab-width: 4 // -
src/SymTab/Validate.cc
r29d8c02 r74ec742 10 10 // Created On : Sun May 17 21:50:04 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Nov 12 11:00:00 202113 // Update Count : 36 412 // Last Modified On : Tue May 17 14:36:00 2022 13 // Update Count : 366 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... 76 77 #include "SynTree/LinkageSpec.h" // for C 77 78 #include "SynTree/Attribute.h" // for noAttributes, Attribute … … 134 135 }; 135 136 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 definitions143 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 appropriately174 bool inGeneric = false;175 };176 177 137 /// Does early resolution on the expressions that give enumeration constants their values 178 138 struct ResolveEnumInitializers final : public WithIndexer, public WithGuards, public WithVisitorRef<ResolveEnumInitializers>, public WithShortCircuiting { … … 192 152 void previsit( StructDecl * aggrDecl ); 193 153 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 * );216 154 }; 217 155 … … 357 295 358 296 void validate_A( std::list< Declaration * > & translationUnit ) { 359 PassVisitor<EnumAndPointerDecay_old> epc;360 297 PassVisitor<HoistTypeDecls> hoistDecls; 361 298 { … … 366 303 ReplaceTypedef::replaceTypedef( translationUnit ); 367 304 ReturnTypeFixer::fix( translationUnit ); // must happen before autogen 368 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 mangling305 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 mangling 369 306 } 370 307 } 371 308 372 309 void validate_B( std::list< Declaration * > & translationUnit ) { 373 PassVisitor<LinkReferenceToTypes_old> lrt( nullptr );374 310 PassVisitor<FixQualifiedTypes> fixQual; 375 311 { 376 312 Stats::Heap::newPass("validate-B"); 377 313 Stats::Time::BlockGuard guard("validate-B"); 378 acceptAll( translationUnit, lrt ); // must happen before autogen, because sized flag needs to propagate to generated functions314 //linkReferenceToTypes( translationUnit ); 379 315 mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes_old, because aggregate members are accessed 380 316 HoistStruct::hoistStruct( translationUnit ); … … 407 343 }); 408 344 } 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 );420 345 } 421 346 … … 496 421 } 497 422 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 513 423 void HoistTypeDecls::handleType( Type * type ) { 514 424 // some type declarations are buried in expressions and not easy to hoist during parsing; hoist them here … … 703 613 } 704 614 705 void EnumAndPointerDecay_old::previsit( EnumDecl * enumDecl ) {706 // Set the type of each member of the enumeration to be EnumConstant707 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 } // for712 }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 found721 containsVoid |= fixFunction( dwt );722 }723 724 // the only case in which "void" is valid is where it is the only one in the list725 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 types739 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 } // if749 }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 declaration754 if ( st ) {755 enumInst->baseEnum = const_cast<EnumDecl *>(st); // Just linking in the node756 } // if757 if ( ! st || ! st->body ) {758 // use of forward declaration759 forwardEnums[ enumInst->name ].push_back( enumInst );760 } // if761 }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 declaration766 if ( st ) {767 structInst->baseStruct = const_cast<StructDecl *>(st); // Just linking in the node768 } // if769 if ( ! st || ! st->body ) {770 // use of forward declaration771 forwardStructs[ structInst->name ].push_back( structInst );772 } // if773 }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 declaration778 if ( un ) {779 unionInst->baseUnion = const_cast<UnionDecl *>(un); // Just linking in the node780 } // if781 if ( ! un || ! un->body ) {782 // use of forward declaration783 forwardUnions[ unionInst->name ].push_back( unionInst );784 } // if785 }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 type793 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 clone799 auto pred = [](Decl * d1, Decl * d2) {800 // only care if they're equal801 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 826 615 // expand assertions from trait instance, performing the appropriate type variable substitutions 827 616 template< typename Iterator > … … 834 623 // substitute trait decl parameters for instance parameters 835 624 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 variable841 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 trait847 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 } // for858 }859 860 void LinkReferenceToTypes_old::postvisit( TraitInstType * traitInst ) {861 // handle other traits862 const TraitDecl * traitDecl = local_indexer->lookupTrait( traitInst->name );863 if ( ! traitDecl ) {864 SemanticError( traitInst->location, "use of undeclared trait " + traitInst->name );865 } // if866 if ( traitDecl->parameters.size() != traitInst->parameters.size() ) {867 SemanticError( traitInst, "incorrect number of trait parameters: " );868 } // if869 traitInst->baseTrait = const_cast<TraitDecl *>(traitDecl); // Just linking in the node870 871 // need to carry over the 'sized' status of each decl in the instance872 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 properly888 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 } // for894 forwardEnums.erase( fwds );895 } // if896 } // if897 }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 properly927 // 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 } // for934 forwardStructs.erase( fwds );935 } // if936 } // if937 }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 } // for946 forwardUnions.erase( fwds );947 } // if948 } // if949 }950 951 void LinkReferenceToTypes_old::postvisit( TypeInstType * typeInst ) {952 // ensure generic parameter instances are renamed like the base type953 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 } // if958 } // if959 625 } 960 626 … … 985 651 } 986 652 } 987 988 653 } 989 654 } … … 1073 738 void ForallPointerDecay_old::previsit( UnionDecl * aggrDecl ) { 1074 739 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 pointers1103 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();1110 740 } 1111 741 -
src/SymTab/Validate.h
r29d8c02 r74ec742 10 10 // Author : Richard C. Bilson 11 11 // Created On : Sun May 17 21:53:34 2015 12 // Last Modified By : Peter A. Buhr13 // Last Modified On : Sat Jul 22 09:46:07 201714 // Update Count : 412 // Last Modified By : Andrew Beach 13 // Last Modified On : Tue May 17 14:35:00 2022 14 // Update Count : 5 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 );36 35 37 36 // Sub-passes of validate. … … 42 41 void validate_E( std::list< Declaration * > &translationUnit ); 43 42 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 );47 43 } // namespace SymTab 48 44 -
src/SymTab/demangler.cc
r29d8c02 r74ec742 1 #include " Mangler.h"1 #include "Demangle.h" 2 2 #include <iostream> 3 3 #include <fstream> -
src/SymTab/module.mk
r29d8c02 r74ec742 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 12 ## Last Modified By : Andrew Beach 13 ## Last Modified On : T hr Aug 10 16:08:00 201714 ## Update Count : 413 ## Last Modified On : Tue May 17 14:46:00 2022 14 ## Update Count : 5 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/Validate.cc \28 SymTab/Validate.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/ValidateType.cc \ 28 SymTab/ValidateType.h 29 29 30 SRC += $(SRC_SYMTAB) 31 SRCDEMANGLE += $(SRC_SYMTAB) SymTab/Demangle.cc 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 -
src/SynTree/module.mk
r29d8c02 r74ec742 24 24 SynTree/AttrType.cc \ 25 25 SynTree/BaseSyntaxNode.h \ 26 SynTree/BaseSyntaxNode.cc \ 26 27 SynTree/BasicType.cc \ 27 28 SynTree/CommaExpr.cc \ -
src/Tuples/TupleExpansion.cc
r29d8c02 r74ec742 9 9 // Author : Rodolfo G. Esteves 10 10 // Created On : Mon May 18 07:44:20 2015 11 // Last Modified By : Peter A. Buhr12 // Last Modified On : Fri Dec 13 23:45:51 201913 // Update Count : 2 411 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue May 17 15:02:00 2022 13 // Update Count : 25 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 impure372 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 impurity381 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 } // namespace403 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 }415 369 } // namespace Tuples 416 370 -
src/Tuples/Tuples.cc
r29d8c02 r74ec742 10 10 // Created On : Mon Jun 17 14:41:00 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Jun 18 9:31:00 201913 // Update Count : 112 // Last Modified On : Mon May 16 16:15:00 2022 13 // Update Count : 2 14 14 // 15 15 … … 18 18 #include "AST/Pass.hpp" 19 19 #include "AST/LinkageSpec.hpp" 20 #include "Common/PassVisitor.h" 20 21 #include "InitTweak/InitTweak.h" 21 22 … … 23 24 24 25 namespace { 26 /// Checks if impurity (read: side-effects) may exist in a piece of code. 27 /// Currently gives a very crude approximation, wherein any function 28 /// 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 impurity 45 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 25 75 /// Determines if impurity (read: side-effects) may exist in a piece of code. Currently gives 26 76 /// a very crude approximation, wherein any function call expression means the code may be 27 77 /// impure. 28 78 struct ImpurityDetector : public ast::WithShortCircuiting { 29 bool maybeImpure= false;79 bool result = false; 30 80 31 81 void previsit( ast::ApplicationExpr const * appExpr ) { … … 36 86 } 37 87 } 38 maybeImpure= true; visit_children = false;88 result = true; visit_children = false; 39 89 } 40 90 void previsit( ast::UntypedExpr const * ) { 41 maybeImpure= true; visit_children = false;91 result = true; visit_children = false; 42 92 } 43 93 }; 94 44 95 struct ImpurityDetectorIgnoreUnique : public ImpurityDetector { 45 96 using ImpurityDetector::previsit; … … 48 99 } 49 100 }; 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 }57 101 } // namespace 58 102 59 103 bool maybeImpure( const ast::Expr * expr ) { 60 return detectImpurity<ImpurityDetector>( expr );104 return ast::Pass<ImpurityDetector>::read( expr ); 61 105 } 62 106 63 107 bool maybeImpureIgnoreUnique( const ast::Expr * expr ) { 64 return detectImpurity<ImpurityDetectorIgnoreUnique>( 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 ); 65 117 } 66 118 -
src/Tuples/module.mk
r29d8c02 r74ec742 10 10 ## Author : Richard C. Bilson 11 11 ## Created On : Mon Jun 1 17:49:17 2015 12 ## Last Modified By : Henry Xue13 ## Last Modified On : Mon Aug 23 15:36:09 202114 ## Update Count : 212 ## Last Modified By : Andrew Beach 13 ## Last Modified On : Mon May 17 15:00:00 2022 14 ## Update Count : 3 15 15 ############################################################################### 16 16 … … 24 24 Tuples/Tuples.h 25 25 26 SRC += $(SRC_TUPLES) 26 27 27 SRC += $(SRC_TUPLES)28 28 SRCDEMANGLE += $(SRC_TUPLES) -
src/Validate/Autogen.cpp
r29d8c02 r74ec742 350 350 name, 351 351 std::move( type_params ), 352 std::move( assertions ), 352 353 std::move( params ), 353 354 std::move( returns ), … … 360 361 // Auto-generated routines are inline to avoid conflicts. 361 362 ast::Function::Specs( ast::Function::Inline ) ); 362 decl->assertions = std::move( assertions );363 363 decl->fixUniqueId(); 364 364 return decl; -
src/Validate/ForallPointerDecay.cpp
r29d8c02 r74ec742 10 10 // Created On : Tue Dec 7 16:15:00 2021 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri Feb 11 10:59:00 202213 // Update Count : 012 // Last Modified On : Sat Apr 23 13:10:00 2022 13 // Update Count : 1 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 239 244 } // namespace Validate 240 245 -
src/Validate/ForallPointerDecay.hpp
r29d8c02 r74ec742 10 10 // Created On : Tue Dec 7 16:15:00 2021 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Tue Dec 8 11:50:00 202113 // Update Count : 012 // Last Modified On : Sat Apr 23 13:13:00 2022 13 // Update Count : 1 14 14 // 15 15 16 16 #pragma once 17 17 18 #include <vector> 19 #include "AST/Node.hpp" 20 18 21 namespace ast { 22 class DeclWithType; 19 23 class TranslationUnit; 20 24 } … … 27 31 void decayForallPointers( ast::TranslationUnit & transUnit ); 28 32 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 29 37 } 30 38 -
src/Validate/GenericParameter.cpp
r29d8c02 r74ec742 10 10 // Created On : Fri Mar 21 10:02:00 2022 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Apr 13 10:09:00 202213 // Update Count : 012 // Last Modified On : Fri Apr 22 16:43:00 2022 13 // Update Count : 1 14 14 // 15 15 … … 22 22 #include "AST/TranslationUnit.hpp" 23 23 #include "AST/Type.hpp" 24 #include "Validate/NoIdSymbolTable.hpp" 24 25 25 26 namespace Validate { … … 138 139 // -------------------------------------------------------------------------- 139 140 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; 141 struct TranslateDimensionCore : 142 public WithNoIdSymbolTable, public ast::WithGuards { 167 143 168 144 // SUIT: Struct- or Union- InstType -
src/Validate/module.mk
r29d8c02 r74ec742 10 10 ## Author : Rob Schluntz 11 11 ## Created On : Fri Jul 27 10:10:10 2018 12 ## Last Modified By : Rob Schluntz13 ## Last Modified On : Fri Jul 27 10:10:26 201814 ## Update Count : 212 ## Last Modified By : Andrew Beach 13 ## Last Modified On : Tue May 17 14:59:00 2022 14 ## Update Count : 3 15 15 ############################################################################### 16 16 17 17 SRC_VALIDATE = \ 18 Validate/FindSpecialDecls.cc \ 19 Validate/FindSpecialDecls.h 20 21 SRC += $(SRC_VALIDATE) \ 18 22 Validate/Autogen.cpp \ 19 23 Validate/Autogen.hpp \ 20 24 Validate/CompoundLiteral.cpp \ 21 25 Validate/CompoundLiteral.hpp \ 26 Validate/EliminateTypedef.cpp \ 27 Validate/EliminateTypedef.hpp \ 28 Validate/FindSpecialDeclsNew.cpp \ 29 Validate/FixQualifiedTypes.cpp \ 30 Validate/FixQualifiedTypes.hpp \ 22 31 Validate/ForallPointerDecay.cpp \ 23 32 Validate/ForallPointerDecay.hpp \ … … 26 35 Validate/HandleAttributes.cc \ 27 36 Validate/HandleAttributes.h \ 37 Validate/HoistStruct.cpp \ 38 Validate/HoistStruct.hpp \ 28 39 Validate/InitializerLength.cpp \ 29 40 Validate/InitializerLength.hpp \ 30 41 Validate/LabelAddressFixer.cpp \ 31 42 Validate/LabelAddressFixer.hpp \ 43 Validate/NoIdSymbolTable.hpp \ 32 44 Validate/ReturnCheck.cpp \ 33 Validate/ReturnCheck.hpp \ 34 Validate/FindSpecialDeclsNew.cpp \ 35 Validate/FindSpecialDecls.cc \ 36 Validate/FindSpecialDecls.h 45 Validate/ReturnCheck.hpp 37 46 38 SRC += $(SRC_VALIDATE)39 47 SRCDEMANGLE += $(SRC_VALIDATE) -
src/Virtual/module.mk
r29d8c02 r74ec742 11 11 ## Created On : Tus Jul 25 10:18:00 2017 12 12 ## Last Modified By : Andrew Beach 13 ## Last Modified On : Tus Jul 25 10:18:00 201714 ## Update Count : 013 ## Last Modified On : Tus May 17 14:59:00 2022 14 ## Update Count : 1 15 15 ############################################################################### 16 16 17 SRC += Virtual/ExpandCasts.cc Virtual/ExpandCasts.h \ 18 Virtual/Tables.cc Virtual/Tables.h 19 20 SRCDEMANGLE += Virtual/Tables.cc 17 SRC += \ 18 Virtual/ExpandCasts.cc \ 19 Virtual/ExpandCasts.h \ 20 Virtual/Tables.cc \ 21 Virtual/Tables.h -
src/main.cc
r29d8c02 r74ec742 10 10 // Created On : Fri May 15 23:12:02 2015 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Apr 13 11:11:00 202213 // Update Count : 67 212 // Last Modified On : Fri Apr 29 9:52:00 2022 13 // Update Count : 673 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 linkReferenceToTypes 72 73 #include "SynTree/LinkageSpec.h" // for Spec, Cforall, Intrinsic 73 74 #include "SynTree/Declaration.h" // for Declaration … … 75 76 #include "Tuples/Tuples.h" // for expandMemberTuples, expan... 76 77 #include "Validate/Autogen.hpp" // for autogenerateRoutines 78 #include "Validate/CompoundLiteral.hpp" // for handleCompoundLiterals 79 #include "Validate/EliminateTypedef.hpp" // for eliminateTypedef 80 #include "Validate/FindSpecialDecls.h" // for findGlobalDecls 81 #include "Validate/FixQualifiedTypes.hpp" // for fixQualifiedTypes 82 #include "Validate/ForallPointerDecay.hpp" // for decayForallPointers 77 83 #include "Validate/GenericParameter.hpp" // for fillGenericParameters, tr... 78 #include "Validate/FindSpecialDecls.h" // for findGlobalDecls 79 #include "Validate/ForallPointerDecay.hpp" // for decayForallPointers 80 #include "Validate/CompoundLiteral.hpp" // for handleCompoundLiterals 84 #include "Validate/HoistStruct.hpp" // for hoistStruct 81 85 #include "Validate/InitializerLength.hpp" // for setLengthFromInitializer 82 86 #include "Validate/LabelAddressFixer.hpp" // for fixLabelAddresses … … 328 332 // add the assignment statement after the initialization of a type parameter 329 333 PASS( "Validate-A", SymTab::validate_A( translationUnit ) ); 330 PASS( "Validate-B", SymTab::validate_B( translationUnit ) ); 334 335 // Must happen before auto-gen, because it uses the sized flag. 336 PASS( "Link Reference To Types", SymTab::linkReferenceToTypes( translationUnit ) ); 331 337 332 338 CodeTools::fillLocations( translationUnit ); … … 342 348 343 349 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 ) ); 344 357 345 358 // Check as early as possible. Can't happen before … … 438 451 translationUnit = convert( move( transUnit ) ); 439 452 } else { 453 PASS( "Validate-B", SymTab::validate_B( translationUnit ) ); 440 454 PASS( "Validate-C", SymTab::validate_C( translationUnit ) ); 441 455 PASS( "Validate-D", SymTab::validate_D( translationUnit ) ); -
tests/.expect/forall.txt
r29d8c02 r74ec742 1 forall.cfa:24 2:25: warning: Compiled1 forall.cfa:244:25: warning: Compiled -
tests/forall.cfa
r29d8c02 r74ec742 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 typedef forall ( T ) int (* f)( int ); 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 ); 48 50 49 51 forall( T ) … … 170 172 } 171 173 172 forall( T | { T ?+?( T, T ); } ) forall( S | { T ?+?( T, S ); } ) 174 forall( T | { T ?+?( T, T ); } ) forall( S | { T ?+?( T, S ); } ) 173 175 struct XW { T t; }; 174 176 XW(int,int) xww; -
tests/include/.expect/includes.nast.txt
r29d8c02 r74ec742 1 include/includes.cfa:1 53:25: warning: Compiled1 include/includes.cfa:169:25: warning: Compiled -
tests/include/includes.cfa
r29d8c02 r74ec742 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T hu Feb 3 22:06:07202213 // Update Count : 77 412 // Last Modified On : Tue May 10 16:36:44 2022 13 // Update Count : 776 14 14 // 15 15 … … 32 32 #include <crypt.h> 33 33 #include <ctype.h> 34 //#include <curses.h> // may not be installed 34 #if __has_include( "curses.h" ) 35 #include <curses.h> // may not be installed 36 #endif 35 37 #include <dirent.h> 36 38 #include <dlfcn.h> … … 41 43 #include <errno.h> 42 44 #include <error.h> 43 //#include <eti.h> // may not be installed, comes with ncurses 45 #if __has_include( "eti.h" ) 46 #include <eti.h> // may not be installed, comes with ncurses 47 #endif 44 48 #include <execinfo.h> 45 49 #include <expat.h> … … 50 54 #include <fmtmsg.h> 51 55 #include <fnmatch.h> 52 //#include <form.h> // may not be installed, comes with ncurses 56 #if __has_include( "form.h" ) 57 #include <form.h> // may not be installed, comes with ncurses 58 #endif 53 59 #include <fstab.h> 54 60 #include <fts.h> … … 78 84 #include <mcheck.h> 79 85 #include <memory.h> 80 //#include <menu.h> // may not be installed, comes with ncurses 86 #if __has_include( "menu.h" ) 87 #include <menu.h> // may not be installed, comes with ncurses 88 #endif 81 89 #include <mntent.h> 82 90 #include <monetary.h> 83 91 #include <mqueue.h> 84 //#include <ncurses_dll.h> // may not be installed, comes with ncurses 92 #if __has_include( "ncurses_dll.h" ) 93 #include <ncurses_dll.h> // may not be installed, comes with ncurses 94 #endif 85 95 #include <netdb.h> 86 96 #include <nl_types.h> 87 97 #include <nss.h> 88 98 #include <obstack.h> 89 //#include <panel.h> // may not be installed, comes with ncurses 99 #if __has_include( "panel.h" ) 100 #include <panel.h> // may not be installed, comes with ncurses 101 #endif 90 102 #include <paths.h> 91 103 #include <poll.h> … … 118 130 #include <syslog.h> 119 131 #include <tar.h> 120 //#include <term.h> // may not be installed, comes with ncurses 121 //#include <termcap.h> // may not be installed, comes with ncurses 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 122 136 #include <termio.h> 123 137 #include <termios.h> … … 131 145 #include <ucontext.h> 132 146 #include <ulimit.h> 133 //#include <unctrl.h> // may not be installed, comes with ncurses 147 #if __has_include( "unctrl.h" ) 148 #include <unctrl.h> // may not be installed, comes with ncurses 149 #endif 134 150 #include <unistd.h> 135 151 #include <utime.h> -
tests/pybin/settings.py
r29d8c02 r74ec742 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
r29d8c02 r74ec742 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 target 52 else: 53 return '...' + target[3-width:] 54 45 55 @staticmethod 46 56 def valid_name(name): -
tests/test.py
r29d8c02 r74ec742 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 20)134 parser.add_argument('--timeout', help='Maximum duration in seconds after a single test is considered to have timed out', type=int, default=180) 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 = '{0:{width}} '.format(t.target(), width=settings.output_width)254 name_txt = t.format_target(width=settings.output_width) + ' ' 255 255 256 256 retcode, error, duration = run_single_test(t) -
tests/unified_locking/.expect/locks.txt
r29d8c02 r74ec742 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/notify 26 Done Test 13 -
tests/unified_locking/locks.cfa
r29d8c02 r74ec742 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 20 23 thread T_C_M_WS1 {}; 21 24 … … 99 102 } 100 103 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 } 101 118 } 102 119 } … … 322 339 } 323 340 printf("Done Test 12\n"); 324 } 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 }
Note:
See TracChangeset
for help on using the changeset viewer.