Changes in / [949339b:4e28d2e9]
- Files:
-
- 10 added
- 55 deleted
- 63 edited
-
benchmark/Cargo.toml.in (modified) (1 diff)
-
benchmark/Makefile.am (modified) (4 diffs)
-
benchmark/bench.h (modified) (1 diff)
-
benchmark/bench.rs (modified) (4 diffs)
-
benchmark/mutexStmt/JavaThread.java (deleted)
-
benchmark/mutexStmt/cpp1.cc (deleted)
-
benchmark/mutexStmt/cpp2.cc (deleted)
-
benchmark/mutexStmt/cpp4.cc (deleted)
-
benchmark/mutexStmt/cpp8.cc (deleted)
-
benchmark/mutexStmt/cppLock.hpp (deleted)
-
benchmark/mutexStmt/lock1.cfa (deleted)
-
benchmark/mutexStmt/lock2.cfa (deleted)
-
benchmark/mutexStmt/lock4.cfa (deleted)
-
benchmark/mutexStmt/lock8.cfa (deleted)
-
benchmark/mutexStmt/monitor1.cfa (deleted)
-
benchmark/mutexStmt/monitor2.cfa (deleted)
-
benchmark/mutexStmt/monitor4.cfa (deleted)
-
benchmark/mutexStmt/no_stmt_lock1.cfa (deleted)
-
benchmark/mutexStmt/no_stmt_lock2.cfa (deleted)
-
benchmark/mutexStmt/no_stmt_lock4.cfa (deleted)
-
benchmark/mutexStmt/no_stmt_lock8.cfa (deleted)
-
benchmark/readyQ/cycle.cpp (modified) (3 diffs)
-
benchmark/readyQ/cycle.go (modified) (2 diffs)
-
benchmark/readyQ/cycle.rs (modified) (1 diff)
-
benchmark/readyQ/locality.go (modified) (1 diff)
-
benchmark/readyQ/locality.rs (modified) (2 diffs)
-
benchmark/readyQ/transfer.cfa (modified) (3 diffs)
-
benchmark/readyQ/transfer.cpp (modified) (1 diff)
-
benchmark/readyQ/transfer.go (deleted)
-
benchmark/readyQ/transfer.rs (deleted)
-
benchmark/readyQ/yield.cfa (modified) (1 diff)
-
benchmark/readyQ/yield.cpp (modified) (1 diff)
-
benchmark/readyQ/yield.go (deleted)
-
benchmark/readyQ/yield.rs (deleted)
-
benchmark/rmit.py (modified) (7 diffs)
-
doc/theses/andrew_beach_MMath/Makefile (modified) (2 diffs)
-
doc/theses/andrew_beach_MMath/code/FixupEmpty.java (deleted)
-
doc/theses/andrew_beach_MMath/code/FixupOther.java (deleted)
-
doc/theses/andrew_beach_MMath/code/ResumeFixupEmpty.java (added)
-
doc/theses/andrew_beach_MMath/code/ResumeFixupOther.java (added)
-
doc/theses/andrew_beach_MMath/code/cond-catch.py (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/code/fixup-empty-f.cfa (deleted)
-
doc/theses/andrew_beach_MMath/code/fixup-empty-r.cfa (deleted)
-
doc/theses/andrew_beach_MMath/code/fixup-empty.cpp (deleted)
-
doc/theses/andrew_beach_MMath/code/fixup-empty.py (deleted)
-
doc/theses/andrew_beach_MMath/code/fixup-other-f.cfa (deleted)
-
doc/theses/andrew_beach_MMath/code/fixup-other-r.cfa (deleted)
-
doc/theses/andrew_beach_MMath/code/fixup-other.cpp (deleted)
-
doc/theses/andrew_beach_MMath/code/fixup-other.py (deleted)
-
doc/theses/andrew_beach_MMath/code/resume-empty.cfa (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/code/resume-fixup-empty-f.cfa (added)
-
doc/theses/andrew_beach_MMath/code/resume-fixup-empty-r.cfa (added)
-
doc/theses/andrew_beach_MMath/code/resume-fixup-empty.cpp (added)
-
doc/theses/andrew_beach_MMath/code/resume-fixup-empty.py (added)
-
doc/theses/andrew_beach_MMath/code/resume-fixup-other-f.cfa (added)
-
doc/theses/andrew_beach_MMath/code/resume-fixup-other-r.cfa (added)
-
doc/theses/andrew_beach_MMath/code/resume-fixup-other.cpp (added)
-
doc/theses/andrew_beach_MMath/code/resume-fixup-other.py (added)
-
doc/theses/andrew_beach_MMath/code/run.sh (modified) (2 diffs)
-
doc/theses/andrew_beach_MMath/code/test.sh (modified) (11 diffs)
-
doc/theses/andrew_beach_MMath/code/throw-empty.cfa (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/code/throw-empty.cpp (modified) (2 diffs)
-
doc/theses/andrew_beach_MMath/code/throw-empty.py (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/code/throw-finally.py (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/code/throw-other.py (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/code/throw-with.py (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/code/try-catch.py (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/code/try-finally.py (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/conclusion.tex (modified) (1 diff)
-
doc/theses/andrew_beach_MMath/existing.tex (modified) (15 diffs)
-
doc/theses/andrew_beach_MMath/features.tex (modified) (37 diffs)
-
doc/theses/andrew_beach_MMath/future.tex (modified) (8 diffs)
-
doc/theses/andrew_beach_MMath/implement.tex (modified) (32 diffs)
-
doc/theses/andrew_beach_MMath/intro.tex (modified) (18 diffs)
-
doc/theses/andrew_beach_MMath/performance.tex (modified) (25 diffs)
-
doc/theses/andrew_beach_MMath/resumhandle.fig (deleted)
-
doc/theses/andrew_beach_MMath/termhandle.fig (deleted)
-
doc/theses/andrew_beach_MMath/uw-ethesis-frontpgs.tex (modified) (2 diffs)
-
doc/theses/andrew_beach_MMath/uw-ethesis.bib (modified) (1 diff)
-
example/cpu.cfa (deleted)
-
example/maybe-await.rs (deleted)
-
example/unnecessary-arc.rs (deleted)
-
libcfa/src/Makefile.am (modified) (7 diffs)
-
libcfa/src/concurrency/clib/cfathread.cfa (modified) (9 diffs)
-
libcfa/src/concurrency/invoke.h (modified) (2 diffs)
-
libcfa/src/concurrency/io.cfa (modified) (2 diffs)
-
libcfa/src/concurrency/kernel.cfa (modified) (13 diffs)
-
libcfa/src/concurrency/kernel.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/kernel/fwd.hfa (modified) (1 diff)
-
libcfa/src/concurrency/kernel/startup.cfa (modified) (4 diffs)
-
libcfa/src/concurrency/kernel_private.hfa (modified) (3 diffs)
-
libcfa/src/concurrency/locks.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/mutex_stmt.hfa (modified) (1 diff)
-
libcfa/src/concurrency/ready_queue.cfa (modified) (15 diffs)
-
libcfa/src/concurrency/ready_subqueue.hfa (modified) (2 diffs)
-
libcfa/src/concurrency/stats.cfa (modified) (3 diffs)
-
libcfa/src/concurrency/stats.hfa (modified) (1 diff)
-
libcfa/src/concurrency/thread.cfa (modified) (4 diffs)
-
libcfa/src/containers/string.cfa (deleted)
-
libcfa/src/containers/string.hfa (deleted)
-
libcfa/src/containers/string_res.cfa (deleted)
-
libcfa/src/containers/string_res.hfa (deleted)
-
libcfa/src/device/cpu.cfa (modified) (1 diff)
-
libcfa/src/device/cpu.hfa (modified) (1 diff)
-
libcfa/src/fstream.cfa (modified) (15 diffs)
-
libcfa/src/fstream.hfa (modified) (1 diff)
-
libcfa/src/memory.cfa (modified) (1 diff)
-
libcfa/src/memory.hfa (modified) (1 diff)
-
libcfa/src/parseconfig.cfa (deleted)
-
libcfa/src/parseconfig.hfa (deleted)
-
src/Concurrency/Keywords.cc (modified) (3 diffs)
-
src/Parser/parser.yy (modified) (3 diffs)
-
tests/.expect/parseconfig.txt (deleted)
-
tests/.in/parseconfig-all.txt (deleted)
-
tests/.in/parseconfig-errors.txt (deleted)
-
tests/.in/parseconfig-missing.txt (deleted)
-
tests/Makefile.am (modified) (2 diffs)
-
tests/collections/.expect/string-api-coverage.txt (deleted)
-
tests/collections/.expect/string-gc.txt (deleted)
-
tests/collections/.expect/string-overwrite.txt (deleted)
-
tests/collections/string-api-coverage.cfa (deleted)
-
tests/collections/string-gc.cfa (deleted)
-
tests/collections/string-overwrite.cfa (deleted)
-
tests/concurrent/mutexstmt/locks.cfa (modified) (2 diffs)
-
tests/parseconfig.cfa (deleted)
-
tools/perf/png.py (deleted)
-
tools/perf/process_stat_array.py (modified) (5 diffs)
-
tools/perf/sample.py (deleted)
Legend:
- Unmodified
- Added
- Removed
-
benchmark/Cargo.toml.in
r949339b r4e28d2e9 6 6 7 7 [[bin]] 8 name = " rdq-cycle-tokio"8 name = "cycle-tokio" 9 9 path = "@abs_srcdir@/readyQ/cycle.rs" 10 10 11 11 [[bin]] 12 name = " rdq-locality-tokio"12 name = "locality-tokio" 13 13 path = "@abs_srcdir@/readyQ/locality.rs" 14 15 [[bin]]16 name = "rdq-transfer-tokio"17 path = "@abs_srcdir@/readyQ/transfer.rs"18 19 [[bin]]20 name = "rdq-yield-tokio"21 path = "@abs_srcdir@/readyQ/yield.rs"22 14 23 15 [features] -
benchmark/Makefile.am
r949339b r4e28d2e9 21 21 include $(top_srcdir)/tools/build/cfa.make 22 22 23 AM_CFLAGS = -O 3-Wall -Wextra -I$(srcdir) -lrt -pthread # -Werror23 AM_CFLAGS = -O2 -Wall -Wextra -I$(srcdir) -lrt -pthread # -Werror 24 24 AM_CFAFLAGS = -quiet -nodebug 25 25 AM_UPPFLAGS = -quiet -nodebug -multi -std=c++14 … … 197 197 $(srcdir)/fixcsv.sh $@ 198 198 199 # use --no-print-directory to generate csv appropriately200 mutexStmt.csv:201 echo "building $@"202 echo "1-lock,2-lock,4-lock,8-lock,1-no-stmt-lock,2-no-stmt-lock,4-no-stmt-lock,8-no-stmt-lock,1-monitor,2-monitor,4-monitor" > $@203 +make mutexStmt-lock1.runquiet >> $@ && echo -n ',' >> $@204 +make mutexStmt-lock2.runquiet >> $@ && echo -n ',' >> $@205 +make mutexStmt-lock4.runquiet >> $@ && echo -n ',' >> $@206 +make mutexStmt-lock8.runquiet >> $@ && echo -n ',' >> $@207 +make mutexStmt-no-stmt-lock1.runquiet >> $@ && echo -n ',' >> $@208 +make mutexStmt-no-stmt-lock2.runquiet >> $@ && echo -n ',' >> $@209 +make mutexStmt-no-stmt-lock4.runquiet >> $@ && echo -n ',' >> $@210 +make mutexStmt-no-stmt-lock8.runquiet >> $@ && echo -n ',' >> $@211 +make mutexStmt-monitor1.runquiet >> $@ && echo -n ',' >> $@212 +make mutexStmt-monitor2.runquiet >> $@ && echo -n ',' >> $@213 +make mutexStmt-monitor4.runquiet >> $@214 $(srcdir)/fixcsv.sh $@215 216 199 schedint.csv: 217 200 echo "building $@" … … 374 357 ## ========================================================================================================= 375 358 376 mutexStmt$(EXEEXT) : \377 mutexStmt-cpp1.run \378 mutexStmt-cpp2.run \379 mutexStmt-cpp4.run \380 mutexStmt-cpp8.run \381 mutexStmt-java.run \382 mutexStmt-lock1.run \383 mutexStmt-lock2.run \384 mutexStmt-lock4.run \385 mutexStmt-lock8.run \386 mutexStmt-no-stmt-lock1.run \387 mutexStmt-no-stmt-lock2.run \388 mutexStmt-no-stmt-lock4.run \389 mutexStmt-no-stmt-lock8.run \390 mutexStmt-monitor1.run \391 mutexStmt-monitor2.run \392 mutexStmt-monitor4.run393 394 mutexStmt-lock1$(EXEEXT):395 $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutexStmt/lock1.cfa396 397 mutexStmt-lock2$(EXEEXT):398 $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutexStmt/lock2.cfa399 400 mutexStmt-lock4$(EXEEXT):401 $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutexStmt/lock4.cfa402 403 mutexStmt-lock8$(EXEEXT):404 $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutexStmt/lock8.cfa405 406 mutexStmt-cpp1$(EXEEXT):407 $(BENCH_V_CXX)$(CXXCOMPILE) -std=c++17 $(srcdir)/mutexStmt/cpp1.cc408 409 mutexStmt-cpp2$(EXEEXT):410 $(BENCH_V_CXX)$(CXXCOMPILE) -std=c++17 $(srcdir)/mutexStmt/cpp2.cc411 412 mutexStmt-cpp4$(EXEEXT):413 $(BENCH_V_CXX)$(CXXCOMPILE) -std=c++17 $(srcdir)/mutexStmt/cpp4.cc414 415 mutexStmt-cpp8$(EXEEXT):416 $(BENCH_V_CXX)$(CXXCOMPILE) -std=c++17 $(srcdir)/mutexStmt/cpp8.cc417 418 mutexStmt-monitor1$(EXEEXT):419 $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutexStmt/monitor1.cfa420 421 mutexStmt-monitor2$(EXEEXT):422 $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutexStmt/monitor2.cfa423 424 mutexStmt-monitor4$(EXEEXT):425 $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutexStmt/monitor4.cfa426 427 mutexStmt-no-stmt-lock1$(EXEEXT):428 $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutexStmt/no_stmt_lock1.cfa429 430 mutexStmt-no-stmt-lock2$(EXEEXT):431 $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutexStmt/no_stmt_lock2.cfa432 433 mutexStmt-no-stmt-lock4$(EXEEXT):434 $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutexStmt/no_stmt_lock4.cfa435 436 mutexStmt-no-stmt-lock8$(EXEEXT):437 $(BENCH_V_CFA)$(CFACOMPILE) $(srcdir)/mutexStmt/no_stmt_lock8.cfa438 439 mutexStmt-java$(EXEEXT):440 $(BENCH_V_JAVAC)javac -d $(builddir) $(srcdir)/mutexStmt/JavaThread.java441 echo "#!/bin/sh" > a.out442 echo "java JavaThread \"$$""@\"" >> a.out443 chmod a+x a.out444 445 ## =========================================================================================================446 447 359 schedint$(EXEEXT) : \ 448 360 schedint-cfa1.run \ … … 612 524 ## ========================================================================================================= 613 525 614 RDQBENCHES = \ 615 rdq-cycle-cfa \ 616 rdq-cycle-tokio \ 617 rdq-cycle-go \ 618 rdq-cycle-fibre \ 619 rdq-yield-cfa \ 620 rdq-yield-tokio \ 621 rdq-yield-go \ 622 rdq-yield-fibre \ 623 rdq-locality-cfa \ 624 rdq-locality-tokio \ 625 rdq-locality-go \ 626 rdq-locality-fibre \ 627 rdq-transfer-cfa \ 628 rdq-transfer-tokio \ 629 rdq-transfer-go \ 630 rdq-transfer-fibre 631 632 rdq-benches: 633 +make $(RDQBENCHES) 634 635 clean-rdq-benches: 636 rm -rf $(RDQBENCHES) $(builddir)/target go.mod 637 638 rdq-%-tokio$(EXEEXT): $(builddir)/target/release/rdq-%-tokio$(EXEEXT) 639 $(BENCH_V_RUSTC)cp $(builddir)/target/release/$(basename $@) $@ 640 641 $(builddir)/target/release/rdq-%-tokio$(EXEEXT): $(srcdir)/readyQ/%.rs $(srcdir)/bench.rs 642 $(BENCH_V_RUSTC)cd $(builddir) && cargo build --release 643 644 rdq-%-cfa$(EXEEXT): $(srcdir)/readyQ/%.cfa $(srcdir)/readyQ/rq_bench.hfa 645 $(BENCH_V_CFA)$(CFACOMPILE) $< -o $@ 646 647 go.mod: 648 touch $@ 649 go mod edit -module=rdq.bench 650 go get golang.org/x/sync/semaphore 651 go get golang.org/x/text/language 652 go get golang.org/x/text/message 653 654 rdq-%-go$(EXEEXT): $(srcdir)/readyQ/%.go $(srcdir)/readyQ/bench.go go.mod 655 $(BENCH_V_GOC)go build -o $@ $< $(srcdir)/readyQ/bench.go 656 657 rdq-%-fibre$(EXEEXT): $(srcdir)/readyQ/%.cpp 658 $(BENCH_V_CXX)$(CXXCOMPILE) $< -o $@ -lfibre -std=c++17 $(AM_CFLAGS) 659 660 # ## ========================================================================================================= 661 662 CLEANFILES = $(RDQBENCHES) go.mod go.sum 663 664 clean-local: 665 -rm -rf target 526 %-tokio$(EXEEXT): $(srcdir)/readyQ/%.rs $(srcdir)/bench.rs 527 cd $(builddir) && cargo build --release 528 cp $(builddir)/target/release/$(basename $@) $@ -
benchmark/bench.h
r949339b r4e28d2e9 21 21 return 1000000000LL * ts.tv_sec + ts.tv_nsec; 22 22 } // bench_time 23 24 25 #if defined(__cforall)26 struct test_spinlock {27 volatile bool lock;28 };29 30 static inline void lock( test_spinlock & this ) {31 for ( ;; ) {32 if ( (this.lock == 0) && (__atomic_test_and_set( &this.lock, __ATOMIC_ACQUIRE ) == 0) ) break;33 }34 }35 36 static inline void unlock( test_spinlock & this ) {37 __atomic_clear( &this.lock, __ATOMIC_RELEASE );38 }39 #endif40 23 41 24 #ifndef BENCH_N -
benchmark/bench.rs
r949339b r4e28d2e9 1 1 use std::io::{self, Write}; 2 use std::option;3 2 use std::sync::atomic::{AtomicU64, AtomicBool, Ordering}; 4 3 use std::time::{Instant,Duration}; 5 use std::u128;6 4 7 5 use clap::{Arg, ArgMatches}; … … 29 27 30 28 impl BenchData { 31 pub fn new(options: ArgMatches, nthreads: usize , default_it: option::Option<u64>) -> BenchData {29 pub fn new(options: ArgMatches, nthreads: usize) -> BenchData { 32 30 let (clock_mode, stop_count, duration) = if options.is_present("iterations") { 33 31 (false, 34 32 options.value_of("iterations").unwrap().parse::<u64>().unwrap(), 35 -1.0)36 } else if !default_it.is_none() {37 (false,38 default_it.unwrap(),39 33 -1.0) 40 34 } else { … … 54 48 } 55 49 56 #[allow(dead_code)]57 50 pub async fn wait(&self, start: &Instant) -> Duration{ 58 51 loop { … … 76 69 } 77 70 78 // ==================================================79 pub fn _lehmer64( state: &mut u128 ) -> u64 {80 *state = state.wrapping_mul(0xda942042e4dd58b5);81 return (*state >> 64) as u64;82 } -
benchmark/readyQ/cycle.cpp
r949339b r4e28d2e9 41 41 Fibre * threads[tthreads]; 42 42 Partner thddata[tthreads]; 43 for( unsignedi = 0; i < tthreads; i++) {43 for(int i = 0; i < tthreads; i++) { 44 44 unsigned pi = (i + nthreads) % tthreads; 45 45 thddata[i].next = &thddata[pi].self; 46 46 } 47 for( unsignedi = 0; i < tthreads; i++) {47 for(int i = 0; i < tthreads; i++) { 48 48 threads[i] = new Fibre( reinterpret_cast<void (*)(void *)>(partner_main), &thddata[i] ); 49 49 } … … 53 53 start = timeHiRes(); 54 54 55 for( unsignedi = 0; i < nthreads; i++) {55 for(int i = 0; i < nthreads; i++) { 56 56 thddata[i].self.post(); 57 57 } … … 62 62 printf("\nDone\n"); 63 63 64 for( unsignedi = 0; i < tthreads; i++) {64 for(int i = 0; i < tthreads; i++) { 65 65 thddata[i].self.post(); 66 66 fibre_join( threads[i], nullptr ); -
benchmark/readyQ/cycle.go
r949339b r4e28d2e9 60 60 atomic.StoreInt32(&stop, 1) 61 61 end := time.Now() 62 d uration:= end.Sub(start)62 delta := end.Sub(start) 63 63 64 64 fmt.Printf("\nDone\n") … … 74 74 75 75 p := message.NewPrinter(language.English) 76 p.Printf("Duration (ms) : % d\n", duration.Milliseconds())76 p.Printf("Duration (ms) : %f\n", delta.Seconds()); 77 77 p.Printf("Number of processors : %d\n", nprocs); 78 78 p.Printf("Number of threads : %d\n", tthreads); 79 79 p.Printf("Cycle size (# thrds) : %d\n", ring_size); 80 80 p.Printf("Total Operations(ops): %15d\n", global_counter) 81 p.Printf("Ops per second : %18.2f\n", float64(global_counter) / d uration.Seconds())82 p.Printf("ns per ops : %18.2f\n", float64(d uration.Nanoseconds()) / float64(global_counter))81 p.Printf("Ops per second : %18.2f\n", float64(global_counter) / delta.Seconds()) 82 p.Printf("ns per ops : %18.2f\n", float64(delta.Nanoseconds()) / float64(global_counter)) 83 83 p.Printf("Ops per threads : %15d\n", global_counter / uint64(tthreads)) 84 84 p.Printf("Ops per procs : %15d\n", global_counter / uint64(nprocs)) 85 p.Printf("Ops/sec/procs : %18.2f\n", (float64(global_counter) / float64(nprocs)) / d uration.Seconds())86 p.Printf("ns per ops/procs : %18.2f\n", float64(d uration.Nanoseconds()) / (float64(global_counter) / float64(nprocs)))85 p.Printf("Ops/sec/procs : %18.2f\n", (float64(global_counter) / float64(nprocs)) / delta.Seconds()) 86 p.Printf("ns per ops/procs : %18.2f\n", float64(delta.Nanoseconds()) / (float64(global_counter) / float64(nprocs))) 87 87 88 88 } -
benchmark/readyQ/cycle.rs
r949339b r4e28d2e9 46 46 47 47 let tthreads = nthreads * ring_size; 48 let exp = Arc::new(bench::BenchData::new(options, tthreads , None));48 let exp = Arc::new(bench::BenchData::new(options, tthreads)); 49 49 50 50 let s = (1000000 as u64).to_formatted_string(&Locale::en); -
benchmark/readyQ/locality.go
r949339b r4e28d2e9 286 286 // Print with nice 's, i.e. 1'000'000 instead of 1000000 287 287 p := message.NewPrinter(language.English) 288 p.Printf("Duration ( ms) : %f\n", delta.Milliseconds());288 p.Printf("Duration (s) : %f\n", delta.Seconds()); 289 289 p.Printf("Number of processors : %d\n", nprocs); 290 290 p.Printf("Number of threads : %d\n", nthreads); -
benchmark/readyQ/locality.rs
r949339b r4e28d2e9 124 124 return (r as *mut MyData, true); 125 125 } 126 let got = self.ptr.compare_ exchange_weak(expected, ctx as *mut MyCtx as u64, Ordering::SeqCst, Ordering::SeqCst);127 if got == Ok(expected){126 let got = self.ptr.compare_and_swap(expected, ctx as *mut MyCtx as u64, Ordering::SeqCst); 127 if got == expected { 128 128 break expected;// We got the seat 129 129 } … … 285 285 assert_eq!(&s, "1,000,000"); 286 286 287 let exp = Arc::new(bench::BenchData::new(options, nprocs , None));287 let exp = Arc::new(bench::BenchData::new(options, nprocs)); 288 288 let mut results = Result::new(); 289 289 -
benchmark/readyQ/transfer.cfa
r949339b r4e28d2e9 39 39 Pause(); 40 40 if( (timeHiRes() - start) > 5`s ) { 41 print_stats_now( bench_cluster, CFA_STATS_READY_Q | CFA_STATS_IO );42 41 serr | "Programs has been blocked for more than 5 secs"; 43 42 exit(1); … … 111 110 cfa_option opt[] = { 112 111 BENCH_OPT, 113 { 'e', "exhaust", "Whether or not threads that have seen the new epoch should park instead of yielding.", exhaust, parse_yesno}112 { 'e', "exhaust", "Whether or not threads that have seen the new epoch should yield or park.", exhaust, parse_yesno} 114 113 }; 115 114 BENCH_OPT_PARSE("cforall transition benchmark"); … … 167 166 } 168 167 169 sout | "Duration (ms) : " | ws(3, 3, unit(eng((end - start)`dms)));168 sout | "Duration : " | ws(3, 3, unit(eng((end - start)`ds))) | 's'; 170 169 sout | "Number of processors : " | nprocs; 171 170 sout | "Number of threads : " | nthreads; -
benchmark/readyQ/transfer.cpp
r949339b r4e28d2e9 173 173 } 174 174 175 std::cout << "Duration (ms) : " << to_miliseconds(end - start)<< std::endl;175 std::cout << "Duration : " << to_miliseconds(end - start) << "ms" << std::endl; 176 176 std::cout << "Number of processors : " << nprocs << std::endl; 177 177 std::cout << "Number of threads : " << nthreads << std::endl; -
benchmark/readyQ/yield.cfa
r949339b r4e28d2e9 80 80 } 81 81 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); 82 printf("Took %'ld ms\n", (end - start)`ms); 86 83 printf("Yields per second : %'18.2lf\n", ((double)global_counter) / (end - start)`s); 87 84 printf("ns per yields : %'18.2lf\n", ((double)(end - start)`ns) / global_counter); 85 printf("Total yields : %'15llu\n", global_counter); 88 86 printf("Yields per procs : %'15llu\n", global_counter / nprocs); 89 87 printf("Yields/sec/procs : %'18.2lf\n", (((double)global_counter) / nprocs) / (end - start)`s); -
benchmark/readyQ/yield.cpp
r949339b r4e28d2e9 154 154 155 155 auto dur_nano = duration_cast<std::nano>(duration); 156 auto dur_dms = duration_cast<std::milli>(duration);157 156 158 printf("Duration (ms) : %'.2lf\n", dur_dms );157 std::cout << "Took " << duration << " s\n"; 159 158 printf("Total yields : %'15llu\n", global_counter ); 160 159 printf("Yields per procs : %'15llu\n", global_counter / nprocs ); -
benchmark/rmit.py
r949339b r4e28d2e9 16 16 import random 17 17 import re 18 import socket19 18 import subprocess 20 19 import sys … … 96 95 return nopts 97 96 98 # returns the first option with key 'opt'99 def search_option(action, opt):100 i = 0101 while i < len(action):102 if action[i] == opt:103 i += 1104 if i != len(action):105 return action[i]106 i += 1107 108 return None109 110 97 def actions_eta(actions): 111 98 time = 0 112 99 for a in actions: 113 o = search_option(a, '-d') 114 if o : 115 time += int(o) 100 i = 0 101 while i < len(a): 102 if a[i] == '-d': 103 i += 1 104 if i != len(a): 105 time += int(a[i]) 106 i += 1 116 107 return time 117 118 taskset_maps = None119 120 def init_taskset_maps():121 global taskset_maps122 known_hosts = {123 "jax": {124 range( 1, 24) : "48-71",125 range( 25, 48) : "48-71,144-167",126 range( 49, 96) : "48-95,144-191",127 range( 97, 144) : "24-95,120-191",128 range(145, 192) : "0-95,96-191",129 },130 }131 132 if (host := socket.gethostname()) in known_hosts:133 taskset_maps = known_hosts[host]134 return True135 136 print("Warning unknown host '{}', disable taskset usage".format(host), file=sys.stderr)137 return False138 139 140 def settaskset_one(action):141 o = search_option(action, '-p')142 if not o:143 return action144 try:145 oi = int(o)146 except ValueError:147 return action148 149 m = "Not found"150 for key in taskset_maps:151 if oi in key:152 return ['taskset', '-c', taskset_maps[key], *action]153 154 print("Warning no mapping for {} cores".format(oi), file=sys.stderr)155 return action156 157 def settaskset(actions):158 return [settaskset_one(a) for a in actions]159 108 160 109 if __name__ == "__main__": … … 166 115 parser.add_argument('--file', nargs='?', type=argparse.FileType('w'), default=sys.stdout) 167 116 parser.add_argument('--trials', help='Number of trials to run per combinaison', type=int, default=3) 168 parser.add_argument('--notaskset', help='If specified, the trial will not use taskset to match the -p option', action='store_true')169 117 parser.add_argument('command', metavar='command', type=str, nargs=1, help='the command prefix to run') 170 118 parser.add_argument('candidates', metavar='candidates', type=str, nargs='*', help='the candidate suffix to run') … … 222 170 223 171 # ================================================================================ 224 # Fixup the different commands 225 226 # Add tasksets 227 withtaskset = False 228 if not options.notaskset and init_taskset_maps(): 229 withtaskset = True 230 actions = settaskset(actions) 231 232 # ================================================================================ 233 # Now that we know what to run, print it. 234 # find expected time 235 time = actions_eta(actions) 236 print("Running {} trials{}".format(len(actions), "" if time == 0 else " (expecting to take {})".format(str(datetime.timedelta(seconds=int(time)))) )) 237 238 # dry run if options ask for it 172 # Figure out all the combinations to run 239 173 if options.list: 240 174 for a in actions: … … 246 180 # Prepare to run 247 181 182 # find expected time 183 time = actions_eta(actions) 184 print("Running {} trials{}".format(len(actions), "" if time == 0 else " (expecting to take {})".format(str(datetime.timedelta(seconds=int(time)))) )) 185 248 186 random.shuffle(actions) 249 187 … … 253 191 first = True 254 192 for i, a in enumerate(actions): 255 sa = " ".join(a [3:] if withtaskset else a)193 sa = " ".join(a) 256 194 if first: 257 195 first = False … … 270 208 match = re.search("^(.*):(.*)$", s) 271 209 if match: 272 try: 273 fields[match.group(1).strip()] = float(match.group(2).strip().replace(',','')) 274 except: 275 pass 276 277 options.file.write(json.dumps([a[3 if withtaskset else 0][2:], sa, fields])) 210 fields[match.group(1).strip()] = float(match.group(2).strip().replace(',','')) 211 212 options.file.write(json.dumps([a[0][2:], sa, fields])) 278 213 options.file.flush() 279 214 -
doc/theses/andrew_beach_MMath/Makefile
r949339b r4e28d2e9 31 31 32 32 # The main rule, it does all the tex/latex processing. 33 ${BUILD}/${BASE}.dvi: ${RAWSRC} ${FIGTEX} termhandle.pstex resumhandle.pstexMakefile | ${BUILD}33 ${BUILD}/${BASE}.dvi: ${RAWSRC} ${FIGTEX} Makefile | ${BUILD} 34 34 ${LATEX} ${BASE} 35 35 ${BIBTEX} ${BUILD}/${BASE} … … 40 40 ${FIGTEX}: ${BUILD}/%.tex: %.fig | ${BUILD} 41 41 fig2dev -L eepic $< > $@ 42 43 %.pstex : %.fig | ${Build}44 fig2dev -L pstex $< > ${BUILD}/$@45 fig2dev -L pstex_t -p ${BUILD}/$@ $< > ${BUILD}/$@_t46 42 47 43 # Step through dvi & postscript to handle xfig specials. -
doc/theses/andrew_beach_MMath/code/cond-catch.py
r949339b r4e28d2e9 32 32 33 33 end_time = thread_time_ns() 34 print('Run-Time (s) : {:.1f}'.format((end_time - start_time) / 1_000_000_000.))34 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.)) 35 35 36 36 -
doc/theses/andrew_beach_MMath/code/resume-empty.cfa
r949339b r4e28d2e9 11 11 if (frames) { 12 12 nounwind_empty(frames - 1); 13 if ( frames == -1 ) printf( "42" ); // prevent recursion optimizations14 13 } else { 15 14 throwResume (empty_exception){&empty_vt}; -
doc/theses/andrew_beach_MMath/code/run.sh
r949339b r4e28d2e9 1 1 #!/usr/bin/env bash 2 2 3 readonly ALL_TESTS=(raise-{empty,detor,finally,other} try-{catch,finally} \4 cond-match-{all,none} fixup-{empty,other})3 readonly ALL_TESTS=(raise-{empty,detor,finally,other} try-{catch,finally} cond-match-{all,none} \ 4 raise-{fixup-empty,fixup-other}) 5 5 6 6 gen-file-name() ( … … 18 18 ) 19 19 20 #readonly N=${1:-5} 20 21 readonly N=${1:-1} 21 22 readonly OUT_FILE=$(gen-file-name ${2:-run-%-$N}) -
doc/theses/andrew_beach_MMath/code/test.sh
r949339b r4e28d2e9 13 13 # View the result from TEST in LANGUAGE stored in FILE. 14 14 15 readonly DIR=$(dirname "$(readlink -f "$0")") 16 cd $DIR 17 18 readonly MIL=000000 19 # Various preset values used as arguments. 20 readonly ITERS_1M=1$MIL 21 readonly ITERS_10M=10$MIL 22 readonly ITERS_100M=100$MIL 23 readonly ITERS_1000M=1000$MIL 15 readonly ITERS_1M=1000000 # 1 000 000, one million 16 readonly ITERS_10M=10000000 # 10 000 000, ten million 17 readonly ITERS_100M=100000000 # 100 000 000, hundred million 18 readonly ITERS_1000M=1000000000 # 1 000 000 000, billion 24 19 readonly STACK_HEIGHT=100 25 20 … … 35 30 case "$1" in 36 31 *.cfa) 37 # A symbolic link/local copy can be used as an override. 38 cmd=./cfa 39 if [ ! -x $cmd ]; then 40 cmd=cfa 41 fi 42 mmake "${1%.cfa}" "$1" $cmd -DNDEBUG -nodebug -O3 "$1" -o "${1%.cfa}" 32 # Requires a symbolic link. 33 mmake "${1%.cfa}" "$1" cfa -DNDEBUG -nodebug -O3 "$1" -o "${1%.cfa}" 43 34 ;; 44 35 *.cpp) … … 55 46 ) 56 47 57 if [ "-a" = "$1" ]; then 48 if [ "-a" = "$1" ]; then # build all 58 49 for file in *.cfa *.cpp *.java; do 59 50 build $file 60 51 done 61 52 exit 0 62 elif [ "-b" = "$1" ]; then 53 elif [ "-b" = "$1" ]; then # build given 63 54 for file in "${@:2}"; do 64 55 build $file 65 56 done 66 57 exit 0 67 elif [ "-c" = "$1" ]; then 58 elif [ "-c" = "$1" ]; then # clean all 68 59 rm $(basename -s ".cfa" -a *.cfa) 69 60 rm $(basename -s ".cpp" -a *.cpp) … … 92 83 raise-empty) 93 84 CFAT="./throw-empty $ITERS_1M $STACK_HEIGHT" 94 CFAR="./resume-empty $ITERS_10M $STACK_HEIGHT"85 # see resume-fixup-empty-r CFAR="./resume-empty $ITERS_1M $STACK_HEIGHT" 95 86 CPP="./throw-empty-cpp $ITERS_1M $STACK_HEIGHT" 96 87 JAVA="java ThrowEmpty $ITERS_1M $STACK_HEIGHT" … … 99 90 raise-detor) 100 91 CFAT="./throw-detor $ITERS_1M $STACK_HEIGHT" 101 CFAR="./resume-detor $ITERS_10M $STACK_HEIGHT"92 # N/A CFAR="./resume-detor $ITERS_1M $STACK_HEIGHT" 102 93 CPP="./throw-detor-cpp $ITERS_1M $STACK_HEIGHT" 103 94 JAVA=unsupported … … 106 97 raise-finally) 107 98 CFAT="./throw-finally $ITERS_1M $STACK_HEIGHT" 108 CFAR="./resume-finally $ITERS_10M $STACK_HEIGHT"99 # N/A CFAR="./resume-finally $ITERS_1M $STACK_HEIGHT" 109 100 CPP=unsupported 110 101 JAVA="java ThrowFinally $ITERS_1M $STACK_HEIGHT" … … 113 104 raise-other) 114 105 CFAT="./throw-other $ITERS_1M $STACK_HEIGHT" 115 CFAR="./resume-other $ITERS_10M $STACK_HEIGHT"106 # N/A CFAR="./resume-other $ITERS_1M $STACK_HEIGHT" 116 107 CPP="./throw-other-cpp $ITERS_1M $STACK_HEIGHT" 117 108 JAVA="java ThrowOther $ITERS_1M $STACK_HEIGHT" … … 134 125 cond-match-all) 135 126 CFAT="./cond-catch $ITERS_10M 1" 136 CFAR="./cond-fixup $ITERS_10 0M 1"127 CFAR="./cond-fixup $ITERS_10M 1" 137 128 CPP="./cond-catch-cpp $ITERS_10M 1" 138 129 JAVA="java CondCatch $ITERS_10M 1" … … 141 132 cond-match-none) 142 133 CFAT="./cond-catch $ITERS_10M 0" 143 CFAR="./cond-fixup $ITERS_10 0M 0"134 CFAR="./cond-fixup $ITERS_10M 0" 144 135 CPP="./cond-catch-cpp $ITERS_10M 0" 145 136 JAVA="java CondCatch $ITERS_10M 0" 146 137 PYTHON="./cond-catch.py $ITERS_10M 0" 147 138 ;; 148 fixup-empty)149 CFAT="./ fixup-empty-f $ITERS_10M $STACK_HEIGHT"150 CFAR="./ fixup-empty-r $ITERS_10M $STACK_HEIGHT"151 CPP="./ fixup-empty-cpp $ITERS_10M $STACK_HEIGHT"152 JAVA="java FixupEmpty $ITERS_10M $STACK_HEIGHT"153 PYTHON="./ fixup-empty.py $ITERS_10M $STACK_HEIGHT"139 raise-fixup-empty) 140 CFAT="./resume-fixup-empty-f $ITERS_10M $STACK_HEIGHT" 141 CFAR="./resume-fixup-empty-r $ITERS_10M $STACK_HEIGHT" 142 CPP="./resume-fixup-empty-cpp $ITERS_10M $STACK_HEIGHT" 143 JAVA="java ResumeFixupEmpty $ITERS_10M $STACK_HEIGHT" 144 PYTHON="./resume-fixup-empty.py $ITERS_10M $STACK_HEIGHT" 154 145 ;; 155 fixup-other)156 CFAT="./ fixup-other-f $ITERS_10M $STACK_HEIGHT"157 CFAR="./ fixup-other-r $ITERS_10M $STACK_HEIGHT"158 CPP="./ fixup-other-cpp $ITERS_10M $STACK_HEIGHT"159 JAVA="java FixupOther $ITERS_10M $STACK_HEIGHT"160 PYTHON="./ fixup-other.py $ITERS_10M $STACK_HEIGHT"146 raise-fixup-other) 147 CFAT="./resume-fixup-other-f $ITERS_10M $STACK_HEIGHT" 148 CFAR="./resume-fixup-other-r $ITERS_10M $STACK_HEIGHT" 149 CPP="./resume-fixup-other-cpp $ITERS_10M $STACK_HEIGHT" 150 JAVA="java ResumeFixupOther $ITERS_10M $STACK_HEIGHT" 151 PYTHON="./resume-fixup-other.py $ITERS_10M $STACK_HEIGHT" 161 152 ;; 162 153 *) … … 167 158 168 159 case "$TEST_LANG" in 169 cfa-t) CALL="$CFAT";;170 cfa-r) CALL="$CFAR";;171 cpp) CALL="$CPP";;172 java) CALL="$JAVA";;173 python) CALL="$PYTHON";;174 *)175 echo "No such language: $TEST_LANG" >&2176 exit 2160 cfa-t) CALL="$CFAT";; 161 cfa-r) CALL="$CFAR";; 162 cpp) CALL="$CPP";; 163 java) CALL="$JAVA";; 164 python) CALL="$PYTHON";; 165 *) 166 echo "No such language: $TEST_LANG" >&2 167 exit 2 177 168 ;; 178 169 esac … … 181 172 182 173 if [ -n "$VIEW_FILE" ]; then 183 grep -A 1 -B 0 "$CALL" "$VIEW_FILE" | sed -n -e 's!Run-Time .*: !!;T;p'174 grep -A 1 -B 0 "$CALL" "$VIEW_FILE" | sed -n -e 's!Run-Time (ns): !!;T;p' 184 175 exit 185 176 fi -
doc/theses/andrew_beach_MMath/code/throw-empty.cfa
r949339b r4e28d2e9 11 11 if (frames) { 12 12 unwind_empty(frames - 1); 13 if ( frames == -1 ) printf( "42" ); // prevent recursion optimizations14 13 } else { 15 14 throw (empty_exception){&empty_vt}; -
doc/theses/andrew_beach_MMath/code/throw-empty.cpp
r949339b r4e28d2e9 1 1 // Throw Across Empty Function 2 2 #include <chrono> 3 #include <cstdio>4 3 #include <cstdlib> 5 4 #include <exception> … … 15 14 if (frames) { 16 15 unwind_empty(frames - 1); 17 if (-1 == frames) printf("~");18 16 } else { 19 17 throw (EmptyException){}; -
doc/theses/andrew_beach_MMath/code/throw-empty.py
r949339b r4e28d2e9 33 33 34 34 end_time = thread_time_ns() 35 print('Run-Time (s) : {:.1f}'.format((end_time - start_time) / 1_000_000_000.))35 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.)) 36 36 37 37 -
doc/theses/andrew_beach_MMath/code/throw-finally.py
r949339b r4e28d2e9 36 36 37 37 end_time = thread_time_ns() 38 print('Run-Time (s) : {:.1f}'.format((end_time - start_time) / 1_000_000_000.))38 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.)) 39 39 40 40 -
doc/theses/andrew_beach_MMath/code/throw-other.py
r949339b r4e28d2e9 40 40 41 41 end_time = thread_time_ns() 42 print('Run-Time (s) : {:.1f}'.format((end_time - start_time) / 1_000_000_000.))42 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.)) 43 43 44 44 -
doc/theses/andrew_beach_MMath/code/throw-with.py
r949339b r4e28d2e9 43 43 44 44 end_time = thread_time_ns() 45 print('Run-Time (s) : {:.1f}'.format((end_time - start_time) / 1_000_000_000.))45 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.)) 46 46 47 47 -
doc/theses/andrew_beach_MMath/code/try-catch.py
r949339b r4e28d2e9 23 23 24 24 end_time = thread_time_ns() 25 print('Run-Time (s) : {:.1f}'.format((end_time - start_time) / 1_000_000_000.))25 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.)) 26 26 27 27 -
doc/theses/andrew_beach_MMath/code/try-finally.py
r949339b r4e28d2e9 22 22 23 23 end_time = thread_time_ns() 24 print('Run-Time (s) : {:.1f}'.format((end_time - start_time) / 1_000_000_000.))24 print('Run-Time (s) {:.1f}:'.format((end_time - start_time) / 1_000_000_000.)) 25 25 26 26 -
doc/theses/andrew_beach_MMath/conclusion.tex
r949339b r4e28d2e9 3 3 % Just a little knot to tie the paper together. 4 4 5 In the previous chapters ,this thesis presents the design and implementation5 In the previous chapters this thesis presents the design and implementation 6 6 of \CFA's exception handling mechanism (EHM). 7 7 Both the design and implementation are based off of tools and 8 8 techniques developed for other programming languages but they were adapted to 9 9 better fit \CFA's feature set and add a few features that do not exist in 10 other EHMs ,10 other EHMs; 11 11 including conditional matching, default handlers for unhandled exceptions 12 12 and cancellation though coroutines and threads back to the program main stack. -
doc/theses/andrew_beach_MMath/existing.tex
r949339b r4e28d2e9 6 6 compatibility with C and its programmers. \CFA is designed to have an 7 7 orthogonal feature-set based closely on the C programming paradigm 8 (non-object-oriented), and these features can be added incrementally to an 9 existing C code-base, 10 allowing programmers to learn \CFA on an as-needed basis. 8 (non-object-oriented) and these features can be added incrementally to an 9 existing C code-base allowing programmers to learn \CFA on an as-needed basis. 11 10 12 11 Only those \CFA features pertaining to this thesis are discussed. … … 46 45 \CFA adds a reference type to C as an auto-dereferencing pointer. 47 46 They work very similarly to pointers. 48 Reference-types are written the same way as pointer-types,but each47 Reference-types are written the same way as a pointer-type but each 49 48 asterisk (@*@) is replaced with a ampersand (@&@); 50 this includes cv-qualifiers (\snake{const} and \snake{volatile}) 51 and multiple levels of reference. 52 53 Generally, references act like pointers with an implicit dereferencing 49 this includes cv-qualifiers and multiple levels of reference. 50 51 Generally, references act like pointers with an implicate dereferencing 54 52 operation added to each use of the variable. 55 53 These automatic dereferences may be disabled with the address-of operator … … 85 83 Mutable references may be assigned to by converting them to a pointer 86 84 with a @&@ and then assigning a pointer to them, as in @&ri = &j;@ above. 85 % ??? 87 86 88 87 \section{Operators} … … 94 93 For example, 95 94 infixed multiplication is @?*?@, while prefix dereference is @*?@. 96 This syntax make sit easy to tell the difference between prefix operations97 (such as @++?@) and post fix operations (@?++@).95 This syntax make it easy to tell the difference between prefix operations 96 (such as @++?@) and post-fix operations (@?++@). 98 97 99 98 As an example, here are the addition and equality operators for a point type. … … 105 104 } 106 105 \end{cfa} 107 Note that this syntax works effectively as a textual transformation;106 Note that this syntax works effectively but a textual transformation, 108 107 the compiler converts all operators into functions and then resolves them 109 108 normally. This means any combination of types may be used, … … 114 113 %\subsection{Constructors and Destructors} 115 114 In \CFA, constructors and destructors are operators, which means they are 116 functions with special operator names , rather than type names as in \Cpp.115 functions with special operator names rather than type names in \Cpp. 117 116 Both constructors and destructors can be implicity called by the compiler, 118 117 however the operator names allow explicit calls. … … 138 137 @b@ because of the explicit call and @a@ implicitly. 139 138 @c@ will be initalized with the second constructor. 140 Currently, there is no general way to skip initial ization.139 Currently, there is no general way to skip initialation. 141 140 % I don't use @= anywhere in the thesis. 142 141 … … 203 202 do_twice(i); 204 203 \end{cfa} 205 Any valuewith a type fulfilling the assertion may be passed as an argument to204 Any object with a type fulfilling the assertion may be passed as an argument to 206 205 a @do_twice@ call. 207 206 … … 223 222 function. The matched assertion function is then passed as a function pointer 224 223 to @do_twice@ and called within it. 225 The global definition of @do_once@ is ignored, however if @quadruple@took a224 The global definition of @do_once@ is ignored, however if quadruple took a 226 225 @double@ argument, then the global definition would be used instead as it 227 226 would then be a better match.\cite{Moss19} 228 227 229 228 To avoid typing long lists of assertions, constraints can be collected into 230 a convenientpackage called a @trait@, which can then be used in an assertion229 convenient a package called a @trait@, which can then be used in an assertion 231 230 instead of the individual constraints. 232 231 \begin{cfa} … … 242 241 functions and variables, and are usually used to create a shorthand for, and 243 242 give descriptive names to, common groupings of assertions describing a certain 244 functionality, like @sum mable@, @listable@, \etc.243 functionality, like @sumable@, @listable@, \etc. 245 244 246 245 Polymorphic structures and unions are defined by qualifying an aggregate type 247 246 with @forall@. The type variables work the same except they are used in field 248 declarations instead of parameters, returns and local variable declarations.247 declarations instead of parameters, returns, and local variable declarations. 249 248 \begin{cfa} 250 249 forall(dtype T) … … 262 261 263 262 \section{Control Flow} 264 \CFA has a number of advanced control-flow features: @generator@, @coroutine@, 265 @monitor@, @mutex@ parameters, and @thread@. 263 \CFA has a number of advanced control-flow features: @generator@, @coroutine@, @monitor@, @mutex@ parameters, and @thread@. 266 264 The two features that interact with 267 265 the exception system are @coroutine@ and @thread@; they and their supporting … … 270 268 \subsection{Coroutine} 271 269 A coroutine is a type with associated functions, where the functions are not 272 required to finish execution when control is handed back to the caller. 273 Instead, 270 required to finish execution when control is handed back to the caller. Instead 274 271 they may suspend execution at any time and be resumed later at the point of 275 last suspension. 276 Coroutine 272 last suspension. (Generators are stackless and coroutines are stackful.) These 277 273 types are not concurrent but share some similarities along with common 278 underpinnings, so they are combined with the \CFA threading library. 279 % I had mention of generators, but they don't actually matter here. 274 underpinnings, so they are combined with the \CFA threading library. Further 275 discussion in this section only refers to the coroutine because generators are 276 similar. 280 277 281 278 In \CFA, a coroutine is created using the @coroutine@ keyword, which is an … … 325 322 \end{cfa} 326 323 327 When the main function returns ,the coroutine halts and can no longer be324 When the main function returns the coroutine halts and can no longer be 328 325 resumed. 329 326 330 327 \subsection{Monitor and Mutex Parameter} 331 Concurrency does not guarantee ordering; without ordering ,results are328 Concurrency does not guarantee ordering; without ordering results are 332 329 non-deterministic. To claw back ordering, \CFA uses monitors and @mutex@ 333 330 (mutual exclusion) parameters. A monitor is another kind of aggregate, where … … 335 332 @mutex@ parameters. 336 333 337 A function that requires deterministic (ordered) execution acquires mutual334 A function that requires deterministic (ordered) execution, acquires mutual 338 335 exclusion on a monitor object by qualifying an object reference parameter with 339 the @mutex@ qualifier.336 @mutex@. 340 337 \begin{cfa} 341 338 void example(MonitorA & mutex argA, MonitorB & mutex argB); … … 347 344 348 345 \subsection{Thread} 349 Functions, generators and coroutines are sequential,so there is only a single346 Functions, generators, and coroutines are sequential so there is only a single 350 347 (but potentially sophisticated) execution path in a program. Threads introduce 351 348 multiple execution paths that continue independently. 352 349 353 350 For threads to work safely with objects requires mutual exclusion using 354 monitors and mutex parameters. For threads to work safely with other threads 351 monitors and mutex parameters. For threads to work safely with other threads, 355 352 also requires mutual exclusion in the form of a communication rendezvous, which 356 353 also supports internal synchronization as for mutex objects. For exceptions, -
doc/theses/andrew_beach_MMath/features.tex
r949339b r4e28d2e9 5 5 and begins with a general overview of EHMs. It is not a strict 6 6 definition of all EHMs nor an exhaustive list of all possible features. 7 However ,it does cover the most common structure and features found in them.7 However it does cover the most common structure and features found in them. 8 8 9 9 \section{Overview of EHMs} … … 42 42 43 43 The @try@ statements of \Cpp, Java and Python are common examples. All three 44 also show another common feature of handlers :they are grouped by the guarded44 also show another common feature of handlers, they are grouped by the guarded 45 45 region. 46 46 … … 84 84 \paragraph{Hierarchy} 85 85 A common way to organize exceptions is in a hierarchical structure. 86 This pattern comes from object-orient ed languages where the86 This pattern comes from object-orientated languages where the 87 87 exception hierarchy is a natural extension of the object hierarchy. 88 88 … … 101 101 between different sub-hierarchies. 102 102 This design is used in \CFA even though it is not a object-orientated 103 language ,so different tools are used to create the hierarchy.103 language; so different tools are used to create the hierarchy. 104 104 105 105 % Could I cite the rational for the Python IO exception rework? … … 118 118 For effective exception handling, additional information is often passed 119 119 from the raise to the handler and back again. 120 So far, only communication of the exception 'sidentity is covered.120 So far, only communication of the exceptions' identity is covered. 121 121 A common communication method for adding information to an exception 122 122 is putting fields into the exception instance … … 129 129 \section{Virtuals} 130 130 \label{s:virtuals} 131 A common feature in many programming languages is a tool to pair code132 (behaviour) with data.133 In \CFA, this is done with the virtual system,134 which allow type information to be abstracted away, recovered and allow135 operations to be performed on the abstract objects.136 137 131 Virtual types and casts are not part of \CFA's EHM nor are they required for 138 132 an EHM. … … 158 152 % A type's descendants are its children and its children's descendants. 159 153 160 For the purposes of illustration, a proposed , but unimplemented, syntax154 For the purposes of illustration, a proposed -- but unimplemented syntax -- 161 155 will be used. Each virtual type is represented by a trait with an annotation 162 156 that makes it a virtual type. This annotation is empty for a root type, which … … 183 177 \end{minipage} 184 178 185 Every virtual type also has a list of virtual members and a unique id .186 Both are stored in a virtual table.179 Every virtual type also has a list of virtual members and a unique id, 180 both are stored in a virtual table. 187 181 Every instance of a virtual type also has a pointer to a virtual table stored 188 182 in it, although there is no per-type virtual table as in many other languages. 189 183 190 The list of virtual members is accumulated from the root type down the tree. 191 Every virtual type 184 The list of virtual members is built up down the tree. Every virtual type 192 185 inherits the list of virtual members from its parent and may add more 193 186 virtual members to the end of the list which are passed on to its children. … … 205 198 % Consider adding a diagram, but we might be good with the explanation. 206 199 207 As @child_type@ is a child of @root_type@ ,it has the virtual members of200 As @child_type@ is a child of @root_type@ it has the virtual members of 208 201 @root_type@ (@to_string@ and @size@) as well as the one it declared 209 202 (@irrelevant_function@). … … 213 206 The names ``size" and ``align" are reserved for the size and alignment of the 214 207 virtual type, and are always automatically initialized as such. 215 The other special case isuses of the trait's polymorphic argument208 The other special case are uses of the trait's polymorphic argument 216 209 (@T@ in the example), which are always updated to refer to the current 217 virtual type. This allows functions that refer to t hepolymorphic argument210 virtual type. This allows functions that refer to to polymorphic argument 218 211 to act as traditional virtual methods (@to_string@ in the example), as the 219 212 object can always be passed to a virtual method in its virtual table. 220 213 221 Up until this point ,the virtual system is similar to ones found in222 object-oriented languages ,but this is where \CFA diverges.214 Up until this point the virtual system is similar to ones found in 215 object-oriented languages but this is where \CFA diverges. 223 216 Objects encapsulate a single set of methods in each type, 224 217 universally across the entire program, … … 230 223 231 224 In \CFA, types do not encapsulate any code. 232 Whether or not a typesatisfies any given assertion, and hence any trait, is225 Whether or not satisfies any given assertion, and hence any trait, is 233 226 context sensitive. Types can begin to satisfy a trait, stop satisfying it or 234 227 satisfy the same trait at any lexical location in the program. 235 In this sense, a type's implementation in the set of functions and variables228 In this sense, an type's implementation in the set of functions and variables 236 229 that allow it to satisfy a trait is ``open" and can change 237 230 throughout the program. … … 255 248 \end{cfa} 256 249 257 Like any variable ,they may be forward declared with the @extern@ keyword.250 Like any variable they may be forward declared with the @extern@ keyword. 258 251 Forward declaring virtual tables is relatively common. 259 252 Many virtual types have an ``obvious" implementation that works in most … … 266 259 Initialization is automatic. 267 260 The type id and special virtual members ``size" and ``align" only depend on 268 the virtual type, which is fixed given the type of the virtual table ,and261 the virtual type, which is fixed given the type of the virtual table and 269 262 so the compiler fills in a fixed value. 270 The other virtual members are resolved using the best match to the member's263 The other virtual members are resolved, using the best match to the member's 271 264 name and type, in the same context as the virtual table is declared using 272 265 \CFA's normal resolution rules. 273 266 274 While much of the virtual infrastructure has been created, 275 it is currently only used 267 While much of the virtual infrastructure is created, it is currently only used 276 268 internally for exception handling. The only user-level feature is the virtual 277 269 cast, which is the same as the \Cpp \code{C++}{dynamic_cast}. … … 282 274 Note, the syntax and semantics matches a C-cast, rather than the function-like 283 275 \Cpp syntax for special casts. Both the type of @EXPRESSION@ and @TYPE@ must be 284 pointers to virtual types.276 a pointer to a virtual type. 285 277 The cast dynamically checks if the @EXPRESSION@ type is the same or a sub-type 286 278 of @TYPE@, and if true, returns a pointer to the 287 279 @EXPRESSION@ object, otherwise it returns @0p@ (null pointer). 288 This allows the expression to be used as both a cast and a type check.289 280 290 281 \section{Exceptions} 291 282 292 283 The syntax for declaring an exception is the same as declaring a structure 293 except the keyword :284 except the keyword that is swapped out: 294 285 \begin{cfa} 295 286 exception TYPE_NAME { … … 298 289 \end{cfa} 299 290 300 Fields are filled in the same way as a structure as well. However ,an extra291 Fields are filled in the same way as a structure as well. However an extra 301 292 field is added that contains the pointer to the virtual table. 302 293 It must be explicitly initialized by the user when the exception is … … 308 299 309 300 \begin{minipage}[t]{0.4\textwidth} 310 Header (.hfa):301 Header: 311 302 \begin{cfa} 312 303 exception Example { … … 319 310 \end{minipage} 320 311 \begin{minipage}[t]{0.6\textwidth} 321 Implementation (.cfa):312 Source: 322 313 \begin{cfa} 323 314 vtable(Example) example_base_vtable … … 328 319 %\subsection{Exception Details} 329 320 This is the only interface needed when raising and handling exceptions. 330 However , it is actually a shorthand for a more complex331 trait -based interface.321 However it is actually a short hand for a more complex 322 trait based interface. 332 323 333 324 The language views exceptions through a series of traits. … … 345 336 completing the virtual system). The imaginary assertions would probably come 346 337 from a trait defined by the virtual system, and state that the exception type 347 is a virtual type, 348 that that the type is a descendant of @exception_t@ (the base exception type) 338 is a virtual type, is a descendant of @exception_t@ (the base exception type) 349 339 and allow the user to find the virtual table type. 350 340 … … 365 355 }; 366 356 \end{cfa} 367 Both traits ensure a pair of types is an exception type and368 its virtual table type, 357 Both traits ensure a pair of types is an exception type, its virtual table 358 type 369 359 and defines one of the two default handlers. The default handlers are used 370 as fallbacks and are discussed in detail in \ autoref{s:ExceptionHandling}.360 as fallbacks and are discussed in detail in \vref{s:ExceptionHandling}. 371 361 372 362 However, all three of these traits can be tricky to use directly. 373 363 While there is a bit of repetition required, 374 364 the largest issue is that the virtual table type is mangled and not in a user 375 facing way. So ,these three macros are provided to wrap these traits to365 facing way. So these three macros are provided to wrap these traits to 376 366 simplify referring to the names: 377 367 @IS_EXCEPTION@, @IS_TERMINATION_EXCEPTION@ and @IS_RESUMPTION_EXCEPTION@. … … 381 371 The second (optional) argument is a parenthesized list of polymorphic 382 372 arguments. This argument is only used with polymorphic exceptions and the 383 list is passed to both types.373 list is be passed to both types. 384 374 In the current set-up, the two types always have the same polymorphic 385 arguments ,so these macros can be used without losing flexibility.386 387 For example ,consider a function that is polymorphic over types that have a375 arguments so these macros can be used without losing flexibility. 376 377 For example consider a function that is polymorphic over types that have a 388 378 defined arithmetic exception: 389 379 \begin{cfa} … … 398 388 These twin operations are the core of \CFA's exception handling mechanism. 399 389 This section covers the general patterns shared by the two operations and 400 then goes on to cover the details ofeach individual operation.390 then goes on to cover the details each individual operation. 401 391 402 392 Both operations follow the same set of steps. … … 417 407 \label{s:Termination} 418 408 Termination handling is the familiar kind of handling 419 used in most programming409 and used in most programming 420 410 languages with exception handling. 421 411 It is a dynamic, non-local goto. If the raised exception is matched and … … 493 483 Since it is so general, a more specific handler can be defined, 494 484 overriding the default behaviour for the specific exception types. 495 496 For example, consider an error reading a configuration file.497 This is most likely a problem with the configuration file (@config_error@),498 but the function could have been passed the wrong file name (@arg_error@).499 In this case the function could raise one exception and then, if it is500 unhandled, raise the other.501 This is not usual behaviour for either exception so changing the502 default handler will be done locally:503 \begin{cfa}504 {505 void defaultTerminationHandler(config_error &) {506 throw (arg_error){arg_vt};507 }508 throw (config_error){config_vt};509 }510 \end{cfa}511 485 512 486 \subsection{Resumption} … … 568 542 @EXCEPTION_TYPE@$_i$ is matched and @NAME@$_i$ is bound to the exception, 569 543 @HANDLER_BLOCK@$_i$ is executed right away without first unwinding the stack. 570 After the block has finished running ,control jumps to the raise site, where544 After the block has finished running control jumps to the raise site, where 571 545 the just handled exception came from, and continues executing after it, 572 546 not after the try statement. 573 574 For instance, a resumption used to send messages to the logger may not575 need to be handled at all. Putting the following default handler576 at the global scope can make handling that exception optional by default.577 \begin{cfa}578 void defaultResumptionHandler(log_message &) {579 // Nothing, it is fine not to handle logging.580 }581 // ... No change at raise sites. ...582 throwResume (log_message){strlit_log, "Begin event processing."}583 \end{cfa}584 547 585 548 \subsubsection{Resumption Marking} … … 588 551 not unwind the stack. A side effect is that, when a handler is matched 589 552 and run, its try block (the guarded statements) and every try statement 590 searched before it are still on the stack. The irpresence can lead to553 searched before it are still on the stack. There presence can lead to 591 554 the recursive resumption problem.\cite{Buhr00a} 592 555 % Other possible citation is MacLaren77, but the form is different. … … 622 585 \end{center} 623 586 624 There are other sets of marking rules that could be used .625 For instance, marking just the handlers that caught the exception 587 There are other sets of marking rules that could be used, 588 for instance, marking just the handlers that caught the exception, 626 589 would also prevent recursive resumption. 627 However, the rules selected mirror what happens with termination,590 However, the rules selected mirrors what happens with termination, 628 591 so this reduces the amount of rules and patterns a programmer has to know. 629 592 … … 665 628 // Handle a failure relating to f2 further down the stack. 666 629 \end{cfa} 667 In this example ,the file that experienced the IO error is used to decide630 In this example the file that experienced the IO error is used to decide 668 631 which handler should be run, if any at all. 669 632 … … 694 657 695 658 \subsection{Comparison with Reraising} 696 In languages without conditional catch -- that is,no ability to match an697 exception based on something other than its type --it can be mimicked659 In languages without conditional catch, that is no ability to match an 660 exception based on something other than its type, it can be mimicked 698 661 by matching all exceptions of the right type, checking any additional 699 662 conditions inside the handler and re-raising the exception if it does not … … 701 664 702 665 Here is a minimal example comparing both patterns, using @throw;@ 703 (no operand) to start a re-raise.666 (no argument) to start a re-raise. 704 667 \begin{center} 705 668 \begin{tabular}{l r} … … 729 692 \end{tabular} 730 693 \end{center} 731 At first glance , catch-and-reraise may appear to just be a quality-of-life694 At first glance catch-and-reraise may appear to just be a quality of life 732 695 feature, but there are some significant differences between the two 733 strat egies.696 stratagies. 734 697 735 698 A simple difference that is more important for \CFA than many other languages 736 is that the raise site changes with a re-raise,but does not with a699 is that the raise site changes, with a re-raise but does not with a 737 700 conditional catch. 738 701 This is important in \CFA because control returns to the raise site to run 739 the per-site default handler. Because of this ,only a conditional catch can702 the per-site default handler. Because of this only a conditional catch can 740 703 allow the original raise to continue. 741 704 … … 790 753 % } else throw; 791 754 % } 792 In similar simple examples ,translating from re-raise to conditional catch793 takes less code but it does not have a general ,trivial solution either.755 In similar simple examples translating from re-raise to conditional catch 756 takes less code but it does not have a general trivial solution either. 794 757 795 758 So, given that the two patterns do not trivially translate into each other, 796 759 it becomes a matter of which on should be encouraged and made the default. 797 From the premise that if a handler could handle an exception then it760 From the premise that if a handler that could handle an exception then it 798 761 should, it follows that checking as many handlers as possible is preferred. 799 So ,conditional catch and checking later handlers is a good default.762 So conditional catch and checking later handlers is a good default. 800 763 801 764 \section{Finally Clauses} 802 765 \label{s:FinallyClauses} 803 Finally clauses are used to p erform unconditional cleanup when leaving a766 Finally clauses are used to preform unconditional clean-up when leaving a 804 767 scope and are placed at the end of a try statement after any handler clauses: 805 768 \begin{cfa} … … 819 782 Execution of the finally block should always finish, meaning control runs off 820 783 the end of the block. This requirement ensures control always continues as if 821 the finally clause is not present, \ie finally is for cleanup ,not changing784 the finally clause is not present, \ie finally is for cleanup not changing 822 785 control flow. 823 786 Because of this requirement, local control flow out of the finally block 824 787 is forbidden. The compiler precludes any @break@, @continue@, @fallthru@ or 825 788 @return@ that causes control to leave the finally block. Other ways to leave 826 the finally block, such as a @longjmp@or termination are much harder to check,827 and at best requir eadditional run-time overhead, and so are only789 the finally block, such as a long jump or termination are much harder to check, 790 and at best requiring additional run-time overhead, and so are only 828 791 discouraged. 829 792 830 Not all languages with unwinding have finally clauses. Notably ,\Cpp does793 Not all languages with unwinding have finally clauses. Notably \Cpp does 831 794 without it as destructors, and the RAII design pattern, serve a similar role. 832 795 Although destructors and finally clauses can be used for the same cases, … … 835 798 Destructors take more work to create, but if there is clean-up code 836 799 that needs to be run every time a type is used, they are much easier 837 to set up for each use. % It's automatic.838 On the other hand , finally clauses capture the local context, so areeasy to839 use when the clean up is not dependent on the type of a variable or requires800 to set-up for each use. % It's automatic. 801 On the other hand finally clauses capture the local context, so is easy to 802 use when the clean-up is not dependent on the type of a variable or requires 840 803 information from multiple variables. 841 804 … … 844 807 Cancellation is a stack-level abort, which can be thought of as as an 845 808 uncatchable termination. It unwinds the entire current stack, and if 846 possible ,forwards the cancellation exception to a different stack.809 possible forwards the cancellation exception to a different stack. 847 810 848 811 Cancellation is not an exception operation like termination or resumption. 849 812 There is no special statement for starting a cancellation; instead the standard 850 library function @cancel_stack@ is called ,passing an exception. Unlike a851 raise, this exception is not used in matching ,only to pass information about813 library function @cancel_stack@ is called passing an exception. Unlike a 814 raise, this exception is not used in matching only to pass information about 852 815 the cause of the cancellation. 853 816 Finally, as no handler is provided, there is no default handler. 854 817 855 After @cancel_stack@ is called ,the exception is copied into the EHM's memory818 After @cancel_stack@ is called the exception is copied into the EHM's memory 856 819 and the current stack is unwound. 857 820 The behaviour after that depends on the kind of stack being cancelled. 858 821 859 822 \paragraph{Main Stack} 860 The main stack is the one used by 861 the program's main function at the start of execution, 823 The main stack is the one used by the program main at the start of execution, 862 824 and is the only stack in a sequential program. 863 After the main stack is unwound ,there is a program-level abort.825 After the main stack is unwound there is a program-level abort. 864 826 865 827 The first reason for this behaviour is for sequential programs where there 866 is only one stack, and hence no stack to pass information to.828 is only one stack, and hence to stack to pass information to. 867 829 Second, even in concurrent programs, the main stack has no dependency 868 830 on another stack and no reliable way to find another living stack. … … 880 842 and an implicit join (from a destructor call). The explicit join takes the 881 843 default handler (@defaultResumptionHandler@) from its calling context while 882 the implicit join provides its own ,which does a program abort if the844 the implicit join provides its own; which does a program abort if the 883 845 @ThreadCancelled@ exception cannot be handled. 884 846 … … 908 870 After a coroutine stack is unwound, control returns to the @resume@ function 909 871 that most recently resumed it. @resume@ reports a 910 @CoroutineCancelled@ exception, which contains a reference to the cancelled872 @CoroutineCancelled@ exception, which contains a references to the cancelled 911 873 coroutine and the exception used to cancel it. 912 874 The @resume@ function also takes the \defaultResumptionHandler{} from the -
doc/theses/andrew_beach_MMath/future.tex
r949339b r4e28d2e9 3 3 4 4 The following discussion covers both possible interesting research 5 that could follow from this work as wellas simple implementation5 that could follow from this work as long as simple implementation 6 6 improvements. 7 7 … … 10 10 \CFA is a developing programming language. As such, there are partially or 11 11 unimplemented features (including several broken components) 12 that I had to work around while building the EHM largely in12 that I had to workaround while building the EHM largely in 13 13 the \CFA language (some C components). Below are a few of these issues 14 14 and how implementing/fixing them would affect the EHM. 15 In addition ,there are some simple improvements that had no interesting15 In addition there are some simple improvements that had no interesting 16 16 research attached to them but would make using the language easier. 17 17 \begin{itemize} … … 28 28 Termination handlers cannot use local control-flow transfers, \eg by @break@, 29 29 @return@, \etc. The reason is that current code generation hoists a handler 30 into a nested function for convenience (versus assembl y-code generation at the30 into a nested function for convenience (versus assemble-code generation at the 31 31 try statement). Hence, when the handler runs, it can still access local 32 32 variables in the lexical scope of the try statement. Still, it does mean 33 33 that seemingly local control flow is not in fact local and crosses a function 34 34 boundary. 35 Making the termination handler 's code within the surrounding35 Making the termination handlers code within the surrounding 36 36 function would remove this limitation. 37 37 % Try blocks are much more difficult to do practically (requires our own 38 38 % assembly) and resumption handlers have some theoretical complexity. 39 39 \item 40 There is no detection of colliding unwinds. It is possible for clean up code41 run during an unwind to trigger another unwind that escapes the clean up code42 itself ,such as a termination exception caught further down the stack or a40 There is no detection of colliding unwinds. It is possible for clean-up code 41 run during an unwind to trigger another unwind that escapes the clean-up code 42 itself; such as a termination exception caught further down the stack or a 43 43 cancellation. There do exist ways to handle this case, but currently there is 44 44 no detection and the first unwind will simply be forgotten, often leaving … … 64 64 Other features of the virtual system could also remove some of the 65 65 special cases around exception virtual tables, such as the generation 66 of the @msg@ function .66 of the @msg@ function, could be removed. 67 67 68 68 The full virtual system might also include other improvement like associated … … 74 74 \section{Additional Raises} 75 75 Several other kinds of exception raises were considered beyond termination 76 (@throw@), resumption (@throwResume@), and re -raise.76 (@throw@), resumption (@throwResume@), and reraise. 77 77 78 78 The first is a non-local/concurrent raise providing asynchronous exceptions, … … 110 110 passed on. 111 111 112 Checked exceptions were never seriously considered for this project112 However checked exceptions were never seriously considered for this project 113 113 because they have significant trade-offs in usability and code reuse in 114 114 exchange for the increased safety. … … 116 116 higher-order functions from the functions the user passed into the 117 117 higher-order function. There are no well known solutions to this problem 118 that were satisfactory for \CFA (which carries some of C's 119 flexibility-over-safety design) so additional research is needed.118 that were satisfactory for \CFA (which carries some of C's flexibility 119 over safety design) so additional research is needed. 120 120 121 121 Follow-up work might add some form of checked exceptions to \CFA, … … 140 140 Zero-cost resumptions is still an open problem. First, because libunwind does 141 141 not support a successful-exiting stack-search without doing an unwind. 142 Workarounds are possible but awkward. Ideally ,an extension to libunwind could142 Workarounds are possible but awkward. Ideally an extension to libunwind could 143 143 be made, but that would either require separate maintenance or gaining enough 144 144 support to have it folded into the official library itself. 145 145 146 Also ,new techniques to skip previously searched parts of the stack need to be146 Also new techniques to skip previously searched parts of the stack need to be 147 147 developed to handle the recursive resume problem and support advanced algebraic 148 148 effects. -
doc/theses/andrew_beach_MMath/implement.tex
r949339b r4e28d2e9 14 14 \label{s:VirtualSystem} 15 15 % Virtual table rules. Virtual tables, the pointer to them and the cast. 16 While the \CFA virtual system currently has only twopublic features, virtual16 While the \CFA virtual system currently has only one public features, virtual 17 17 cast and virtual tables, 18 % ??? refs (see the virtual cast feature \vpageref{p:VirtualCast}), 18 19 substantial structure is required to support them, 19 20 and provide features for exception handling and the standard library. … … 34 35 as part of field-by-field construction. 35 36 36 \subsection{Type I D}37 Every virtual type has a unique ID.37 \subsection{Type Id} 38 Every virtual type has a unique id. 38 39 These are used in type equality, to check if the representation of two values 39 40 are the same, and to access the type's type information. … … 43 44 44 45 Our approach for program uniqueness is using a static declaration for each 45 type ID, where the run-time storage address of that variable is guaranteed to46 type id, where the run-time storage address of that variable is guaranteed to 46 47 be unique during program execution. 47 The type IDstorage can also be used for other purposes,48 The type id storage can also be used for other purposes, 48 49 and is used for type information. 49 50 50 The problem is that a type IDmay appear in multiple TUs that compose a51 program (see \autoref{ss:VirtualTable}) ,so the initial solution would seem52 to be make it external in each translation unit. Ho wever, the type IDmust51 The problem is that a type id may appear in multiple TUs that compose a 52 program (see \autoref{ss:VirtualTable}); so the initial solution would seem 53 to be make it external in each translation unit. Hovever, the type id must 53 54 have a declaration in (exactly) one of the TUs to create the storage. 54 55 No other declaration related to the virtual type has this property, so doing 55 56 this through standard C declarations would require the user to do it manually. 56 57 57 Instead ,the linker is used to handle this problem.58 Instead the linker is used to handle this problem. 58 59 % I did not base anything off of C++17; they are solving the same problem. 59 60 A new feature has been added to \CFA for this purpose, the special attribute 60 61 \snake{cfa_linkonce}, which uses the special section @.gnu.linkonce@. 61 When used as a prefix (\eg @.gnu.linkonce.example@) ,the linker does62 When used as a prefix (\eg @.gnu.linkonce.example@) the linker does 62 63 not combine these sections, but instead discards all but one with the same 63 64 full name. 64 65 65 So , each type ID must be given a unique section name with the \snake{linkonce}66 prefix. Luckily ,\CFA already has a way to get unique names, the name mangler.66 So each type id must be given a unique section name with the linkonce 67 prefix. Luckily \CFA already has a way to get unique names, the name mangler. 67 68 For example, this could be written directly in \CFA: 68 69 \begin{cfa} … … 73 74 __attribute__((section(".gnu.linkonce._X1fFv___1"))) void _X1fFv___1() {} 74 75 \end{cfa} 75 This is done internally to access the name mangler .76 This is done internally to access the name manglers. 76 77 This attribute is useful for other purposes, any other place a unique 77 78 instance required, and should eventually be made part of a public and … … 80 81 \subsection{Type Information} 81 82 82 There is data stored at the type ID's declaration, the type information.83 The type information currently is only the parent's type IDor, if the83 There is data stored at the type id's declaration, the type information. 84 The type information currently is only the parent's type id or, if the 84 85 type has no parent, the null pointer. 85 The ancestors of a virtual type are found by traversing type IDs through86 The ancestors of a virtual type are found by traversing type ids through 86 87 the type information. 87 88 An example using helper macros looks like: … … 104 105 \item 105 106 Generate a new structure definition to store the type 106 information. The layout is the same in each case, just the parent's type ID,107 information. The layout is the same in each case, just the parent's type id, 107 108 but the types used change from instance to instance. 108 109 The generated name is used for both this structure and, if relevant, the … … 114 115 \item 115 116 The definition is generated and initialized. 116 The parent IDis set to the null pointer or to the address of the parent's117 The parent id is set to the null pointer or to the address of the parent's 117 118 type information instance. Name resolution handles the rest. 118 119 \item … … 150 151 file as if it was a forward declaration, except no definition is required. 151 152 152 This technique is used for type IDinstances. A link-once definition is153 This technique is used for type-id instances. A link-once definition is 153 154 generated each time the structure is seen. This will result in multiple 154 155 copies but the link-once attribute ensures all but one are removed for a … … 167 168 \subsection{Virtual Table} 168 169 \label{ss:VirtualTable} 169 Each virtual type has a virtual table type that stores its type IDand170 Each virtual type has a virtual table type that stores its type id and 170 171 virtual members. 171 An instance of a virtual type is bound to a virtual table instance, 172 which have the values of the virtual members. 173 Both the layout of the fields (in the virtual table type) 174 and their value (in the virtual table instance) are decided by the rules given 172 Each virtual type instance is bound to a table instance that is filled with 173 the values of virtual members. 174 Both the layout of the fields and their value are decided by the rules given 175 175 below. 176 176 177 177 The layout always comes in three parts (see \autoref{f:VirtualTableLayout}). 178 The first section is just the type IDat the head of the table. It is always178 The first section is just the type id at the head of the table. It is always 179 179 there to ensure that it can be found even when the accessing code does not 180 180 know which virtual type it has. 181 The second section isall the virtual members of the parent, in the same181 The second section are all the virtual members of the parent, in the same 182 182 order as they appear in the parent's virtual table. Note that the type may 183 183 change slightly as references to the ``this" change. This is limited to … … 199 199 This, combined with the fixed offset to the virtual table pointer, means that 200 200 for any virtual type, it is always safe to access its virtual table and, 201 from there, it is safe to check the type IDto identify the exact type of the201 from there, it is safe to check the type id to identify the exact type of the 202 202 underlying object, access any of the virtual members and pass the object to 203 203 any of the method-like virtual members. … … 207 207 the context of the declaration. 208 208 209 The type ID is always fixed,with each virtual table type having210 exactly one possible type ID.209 The type id is always fixed; with each virtual table type having 210 exactly one possible type id. 211 211 The virtual members are usually filled in by type resolution. 212 212 The best match for a given name and type at the declaration site is used. 213 213 There are two exceptions to that rule: the @size@ field, the type's size, 214 is set using a @sizeof@ expression ,and the @align@ field, the214 is set using a @sizeof@ expression and the @align@ field, the 215 215 type's alignment, is set using an @alignof@ expression. 216 216 217 217 Most of these tools are already inside the compiler. Using simple 218 code transformations early on in compilation allows most of that work to be218 code transformations early on in compilation, allows most of that work to be 219 219 handed off to the existing tools. \autoref{f:VirtualTableTransformation} 220 shows an example transformation ;this example shows an exception virtual table.220 shows an example transformation, this example shows an exception virtual table. 221 221 It also shows the transformation on the full declaration. 222 222 For a forward declaration, the @extern@ keyword is preserved and the … … 312 312 struct __cfavir_type_id * const * child ); 313 313 \end{cfa} 314 The type IDfor the target type of the virtual cast is passed in as314 The type id for the target type of the virtual cast is passed in as 315 315 @parent@ and 316 316 the cast target is passed in as @child@. … … 322 322 The virtual cast either returns the original pointer or the null pointer 323 323 as the new type. 324 The function does the parent check and returns the appropriate value.325 The parent check is a simple linear search of thechild's ancestors using the324 So the function does the parent check and returns the appropriate value. 325 The parent check is a simple linear search of child's ancestors using the 326 326 type information. 327 327 … … 329 329 % The implementation of exception types. 330 330 331 Creating exceptions can be roughly divided into two parts:331 Creating exceptions can roughly divided into two parts, 332 332 the exceptions themselves and the virtual system interactions. 333 333 … … 361 361 362 362 All types associated with a virtual type, 363 the types of the virtual table and the type ID,363 the types of the virtual table and the type id, 364 364 are generated when the virtual type (the exception) is first found. 365 The type ID(the instance) is generated with the exception, if it is365 The type id (the instance) is generated with the exception, if it is 366 366 a monomorphic type. 367 However, if the exception is polymorphic, then a different type IDhas to367 However, if the exception is polymorphic, then a different type id has to 368 368 be generated for every instance. In this case, generation is delayed 369 369 until a virtual table is created. … … 372 372 When a virtual table is created and initialized, two functions are created 373 373 to fill in the list of virtual members. 374 The first is the @copy@function that adapts the exception's copy constructor374 The first is a copy function that adapts the exception's copy constructor 375 375 to work with pointers, avoiding some issues with the current copy constructor 376 376 interface. 377 Second is the @msg@function that returns a C-string with the type's name,377 Second is the msg function that returns a C-string with the type's name, 378 378 including any polymorphic parameters. 379 379 … … 402 402 403 403 % Discussing multiple frame stack unwinding: 404 Unwinding across multiple stack frames is more complex ,because that404 Unwinding across multiple stack frames is more complex because that 405 405 information is no longer contained within the current function. 406 406 With separate compilation, 407 407 a function does not know its callers nor their frame layout. 408 408 Even using the return address, that information is encoded in terms of 409 actions in code, intermixed with the actions required tofinish the function.409 actions in code, intermixed with the actions required finish the function. 410 410 Without changing the main code path it is impossible to select one of those 411 411 two groups of actions at the return site. 412 412 413 The traditional unwinding mechanism for C is implemented by saving a snap shot414 of a function's state with @setjmp@ and restoring that snap shot with413 The traditional unwinding mechanism for C is implemented by saving a snap-shot 414 of a function's state with @setjmp@ and restoring that snap-shot with 415 415 @longjmp@. This approach bypasses the need to know stack details by simply 416 resetting to a snapshot of an arbitrary but existing function frame on the 417 stack. It is up to the programmer to ensure the snapshot is valid when it is 418 reset and that all required cleanup from the unwound stacks is performed. 419 Because it does not automate or check any of this cleanup, 420 it can be easy to make mistakes and always must be handled manually. 416 reseting to a snap-shot of an arbitrary but existing function frame on the 417 stack. It is up to the programmer to ensure the snap-shot is valid when it is 418 reset and that all required clean-up from the unwound stacks is performed. 419 This approach is fragile and requires extra work in the surrounding code. 421 420 422 421 With respect to the extra work in the surrounding code, 423 many languages define clean up actions that must be taken when certain424 sections of the stack are removed , such as when the storage for a variable422 many languages define clean-up actions that must be taken when certain 423 sections of the stack are removed. Such as when the storage for a variable 425 424 is removed from the stack, possibly requiring a destructor call, 426 425 or when a try statement with a finally clause is 427 426 (conceptually) popped from the stack. 428 None of these cases should be handled by the user -- that would contradict the429 intention of these features -- so they need to be handled automatically.427 None of these cases should be handled by the user --- that would contradict the 428 intention of these features --- so they need to be handled automatically. 430 429 431 430 To safely remove sections of the stack, the language must be able to find and 432 run these clean up actions even when removing multiple functions unknown at431 run these clean-up actions even when removing multiple functions unknown at 433 432 the beginning of the unwinding. 434 433 … … 436 435 library that provides tools for stack walking, handler execution, and 437 436 unwinding. What follows is an overview of all the relevant features of 438 libunwind needed for this work. 439 Following that is the description of the \CFA code that uses libunwind 440 to implement termination. 437 libunwind needed for this work, and how \CFA uses them to implement exception 438 handling. 441 439 442 440 \subsection{libunwind Usage} … … 531 529 provided storage object. It has two public fields: the @exception_class@, 532 530 which is described above, and the @exception_cleanup@ function. 533 The clean up function is used by the EHM to clean up the exception. If it531 The clean-up function is used by the EHM to clean-up the exception, if it 534 532 should need to be freed at an unusual time, it takes an argument that says 535 533 why it had to be cleaned up. … … 553 551 of the most recent stack frame. It continues to call personality functions 554 552 traversing the stack from newest to oldest until a function finds a handler or 555 the end of the stack is reached. In the latter case, 556 @_U nwind_RaiseException@ returns @_URC_END_OF_STACK@.557 558 Second, when a handler is matched, @_Unwind_RaiseException@559 moves to the cleanupphase and walks the stack a second time.553 the end of the stack is reached. In the latter case, raise exception returns 554 @_URC_END_OF_STACK@. 555 556 Second, when a handler is matched, raise exception moves to the clean-up 557 phase and walks the stack a second time. 560 558 Once again, it calls the personality functions of each stack frame from newest 561 559 to oldest. This pass stops at the stack frame containing the matching handler. 562 If that personality function has not install eda handler, it is an error.563 564 If an error is encountered, @_Unwind_RaiseException@returns either560 If that personality function has not install a handler, it is an error. 561 562 If an error is encountered, raise exception returns either 565 563 @_URC_FATAL_PHASE1_ERROR@ or @_URC_FATAL_PHASE2_ERROR@ depending on when the 566 564 error occurred. … … 573 571 _Unwind_Stop_Fn, void *); 574 572 \end{cfa} 575 It also unwinds the stack but it does not use the search phase. Instead, 576 another 573 It also unwinds the stack but it does not use the search phase. Instead another 577 574 function, the stop function, is used to stop searching. The exception is the 578 same as the one passed to @_Unwind_RaiseException@. 579 The extra arguments are the stop 575 same as the one passed to raise exception. The extra arguments are the stop 580 576 function and the stop parameter. The stop function has a similar interface as a 581 577 personality function, except it is also passed the stop parameter. … … 725 721 one list per stack, with the 726 722 list head stored in the exception context. Within each linked list, the most 727 recently thrown exception is at the head ,followed by older thrown723 recently thrown exception is at the head followed by older thrown 728 724 exceptions. This format allows exceptions to be thrown, while a different 729 725 exception is being handled. The exception at the head of the list is currently … … 736 732 exception into managed memory. After the exception is handled, the free 737 733 function is used to clean up the exception and then the entire node is 738 passed to @free@, returning the memory back to the heap.734 passed to free, returning the memory back to the heap. 739 735 740 736 \subsection{Try Statements and Catch Clauses} … … 761 757 The three functions passed to try terminate are: 762 758 \begin{description} 763 \item[try function:] This function is the try block . It is where all the code759 \item[try function:] This function is the try block, it is where all the code 764 760 from inside the try block is placed. It takes no parameters and has no 765 761 return value. This function is called during regular execution to run the try … … 770 766 from the conditional part of each handler and runs each check, top to bottom, 771 767 in turn, to see if the exception matches this handler. 772 The match is performed in two steps : first,a virtual cast is used to check768 The match is performed in two steps, first a virtual cast is used to check 773 769 if the raised exception is an instance of the declared exception type or 774 770 one of its descendant types, and then the condition is evaluated, if 775 771 present. 776 772 The match function takes a pointer to the exception and returns 0 if the 777 exception is not handled here. Otherwise , the return value is the IDof the773 exception is not handled here. Otherwise the return value is the id of the 778 774 handler that matches the exception. 779 775 … … 786 782 \end{description} 787 783 All three functions are created with GCC nested functions. GCC nested functions 788 can be used to create closures ;784 can be used to create closures, 789 785 in other words, 790 functions that can refer to variables in their lexical scope even though786 functions that can refer to variables in their lexical scope even 791 787 those variables are part of a different function. 792 788 This approach allows the functions to refer to all the … … 873 869 At each node, the EHM checks to see if the try statement the node represents 874 870 can handle the exception. If it can, then the exception is handled and 875 the operation finishes ; otherwise,the search continues to the next node.871 the operation finishes, otherwise the search continues to the next node. 876 872 If the search reaches the end of the list without finding a try statement 877 873 with a handler clause … … 883 879 if the exception is handled and false otherwise. 884 880 The handler function checks each of its internal handlers in order, 885 top-to-bottom, until it f inds a match. If a match is found that handler is881 top-to-bottom, until it funds a match. If a match is found that handler is 886 882 run, after which the function returns true, ignoring all remaining handlers. 887 883 If no match is found the function returns false. 888 The match is performed in two steps . First a virtual cast is used to see884 The match is performed in two steps, first a virtual cast is used to see 889 885 if the raised exception is an instance of the declared exception type or one 890 of its descendant types, if so, then the second step is to see if the 891 exception passes the custom predicate 886 of its descendant types, if so then it is passed to the custom predicate 892 887 if one is defined. 893 888 % You need to make sure the type is correct before running the predicate … … 941 936 % Recursive Resumption Stuff: 942 937 \autoref{f:ResumptionMarking} shows search skipping 943 (see \ autoref{s:ResumptionMarking}), which ignores parts of938 (see \vpageref{s:ResumptionMarking}), which ignores parts of 944 939 the stack 945 940 already examined, and is accomplished by updating the front of the list as … … 956 951 This structure also supports new handlers added while the resumption is being 957 952 handled. These are added to the front of the list, pointing back along the 958 stack -- the first one points over all the checked handlers--953 stack --- the first one points over all the checked handlers --- 959 954 and the ordering is maintained. 960 955 … … 984 979 %\autoref{code:cleanup} 985 980 A finally clause is handled by converting it into a once-off destructor. 986 The code inside the clause is placed into aGCC nested-function981 The code inside the clause is placed into GCC nested-function 987 982 with a unique name, and no arguments or return values. 988 983 This nested function is 989 984 then set as the cleanup function of an empty object that is declared at the 990 985 beginning of a block placed around the context of the associated try 991 statement , as shown in \autoref{f:FinallyTransformation}.986 statement (see \autoref{f:FinallyTransformation}). 992 987 993 988 \begin{figure} … … 1029 1024 % Stack selections, the three internal unwind functions. 1030 1025 1031 Cancellation also uses libunwind to do its stack traversal and unwinding .1032 However,it uses a different primary function: @_Unwind_ForcedUnwind@. Details1033 of its interface can be found in Section~\vref{s:ForcedUnwind}.1026 Cancellation also uses libunwind to do its stack traversal and unwinding, 1027 however it uses a different primary function: @_Unwind_ForcedUnwind@. Details 1028 of its interface can be found in the Section~\vref{s:ForcedUnwind}. 1034 1029 1035 1030 The first step of cancellation is to find the cancelled stack and its type: -
doc/theses/andrew_beach_MMath/intro.tex
r949339b r4e28d2e9 25 25 All types of exception handling link a raise with a handler. 26 26 Both operations are usually language primitives, although raises can be 27 treated as a function that takes an exception argument.28 Handlers are more complex ,as they are added to and removed from the stack29 during execution, must specify what they can handle and mustgive the code to27 treated as a primitive function that takes an exception argument. 28 Handlers are more complex as they are added to and removed from the stack 29 during execution, must specify what they can handle and give the code to 30 30 handle the exception. 31 31 … … 39 39 it returns control to that function. 40 40 \begin{center} 41 %\input{termination} 42 % 43 %\medskip 44 \input{termhandle.pstex_t} 45 % I hate these diagrams, but I can't access xfig to fix them and they are 46 % better than the alternative. 41 \input{termination} 47 42 \end{center} 48 43 … … 51 46 The handler is run on top of the existing stack, often as a new function or 52 47 closure capturing the context in which the handler was defined. 53 After the handler has finished running ,it returns control to the function48 After the handler has finished running it returns control to the function 54 49 that preformed the raise, usually starting after the raise. 55 50 \begin{center} 56 %\input{resumption} 57 % 58 %\medskip 59 \input{resumhandle.pstex_t} 60 % The other one. 51 \input{resumption} 61 52 \end{center} 62 53 63 54 Although a powerful feature, exception handling tends to be complex to set up 64 and expensive to use ,55 and expensive to use 65 56 so it is often limited to unusual or ``exceptional" cases. 66 The classic example is error handling ;exceptions can be used to57 The classic example is error handling, exceptions can be used to 67 58 remove error handling logic from the main execution path, and pay 68 59 most of the cost only when the error actually occurs. … … 72 63 The \CFA EHM implements all of the common exception features (or an 73 64 equivalent) found in most other EHMs and adds some features of its own. 74 The design of all the features had to be adapted to \CFA's feature set ,as65 The design of all the features had to be adapted to \CFA's feature set as 75 66 some of the underlying tools used to implement and express exception handling 76 67 in other languages are absent in \CFA. 77 Still ,the resulting syntax resembles that of other languages:68 Still the resulting syntax resembles that of other languages: 78 69 \begin{cfa} 79 70 try { … … 97 88 covering both changes to the compiler and the run-time. 98 89 In addition, a suite of test cases and performance benchmarks were created 99 along side the implementation.90 along side the implementation. 100 91 The implementation techniques are generally applicable in other programming 101 92 languages and much of the design is as well. … … 109 100 \item Implementing stack unwinding and the \CFA EHM, including updating 110 101 the \CFA compiler and the run-time environment. 111 \item Design ing and implementinga prototype virtual system.102 \item Designed and implemented a prototype virtual system. 112 103 % I think the virtual system and per-call site default handlers are the only 113 104 % "new" features, everything else is a matter of implementation. 114 105 \item Creating tests to check the behaviour of the EHM. 115 \item Creating benchmarks to check the performance of the EHM,106 \item Creating benchmarks to check the performances of the EHM, 116 107 as compared to other languages. 117 108 \end{enumerate} … … 119 110 The rest of this thesis is organized as follows. 120 111 The current state of exceptions is covered in \autoref{s:background}. 121 The existing state of \CFA is covered in \autoref{c:existing}.112 The existing state of \CFA is also covered in \autoref{c:existing}. 122 113 New EHM features are introduced in \autoref{c:features}, 123 114 covering their usage and design. … … 138 129 message as a payload\cite{Ada12}. 139 130 140 The modern flag ship for termination exceptions -- if one exists --is \Cpp,131 The modern flag-ship for termination exceptions is \Cpp, 141 132 which added them in its first major wave of non-object-orientated features 142 133 in 1990.\cite{CppHistory} … … 146 137 inheriting from 147 138 \code{C++}{std::exception}. 148 Although there is a special catch-all syntax (@catch(...)@) ,there are no139 Although there is a special catch-all syntax (@catch(...)@) there are no 149 140 operations that can be performed on the caught value, not even type inspection. 150 Instead ,the base exception-type \code{C++}{std::exception} defines common141 Instead the base exception-type \code{C++}{std::exception} defines common 151 142 functionality (such as 152 143 the ability to describe the reason the exception was raised) and all … … 157 148 158 149 Java was the next popular language to use exceptions.\cite{Java8} 159 Its exception system largely reflects that of \Cpp, except that itrequires150 Its exception system largely reflects that of \Cpp, except that requires 160 151 you throw a child type of \code{Java}{java.lang.Throwable} 161 152 and it uses checked exceptions. 162 153 Checked exceptions are part of a function's interface, 163 154 the exception signature of the function. 164 Every exception that could be raised from a function, either directly or155 Every function that could be raised from a function, either directly or 165 156 because it is not handled from a called function, is given. 166 157 Using this information, it is possible to statically verify if any given 167 exception is handled ,and guarantee that no exception will go unhandled.158 exception is handled and guarantee that no exception will go unhandled. 168 159 Making exception information explicit improves clarity and safety, 169 160 but can slow down or restrict programming. … … 178 169 recovery or repair. In theory that could be good enough to properly handle 179 170 the exception, but more often is used to ignore an exception that the 180 programmer does not feel is worth the effort of handling , for instance if171 programmer does not feel is worth the effort of handling it, for instance if 181 172 they do not believe it will ever be raised. 182 If they are incorrect ,the exception will be silenced, while in a similar173 If they are incorrect the exception will be silenced, while in a similar 183 174 situation with unchecked exceptions the exception would at least activate 184 the language's unhandled exception code (usually , a program abort with an175 the language's unhandled exception code (usually program abort with an 185 176 error message). 186 177 187 178 %\subsection 188 179 Resumption exceptions are less popular, 189 although resumption is as old as termination; that is, few180 although resumption is as old as termination; hence, few 190 181 programming languages have implemented them. 191 182 % http://bitsavers.informatik.uni-stuttgart.de/pdf/xerox/parc/techReports/ … … 195 186 included in the \Cpp standard. 196 187 % https://en.wikipedia.org/wiki/Exception_handling 197 Since then , resumptions have been ignored in mainstream programming languages.188 Since then resumptions have been ignored in main-stream programming languages. 198 189 However, resumption is being revisited in the context of decades of other 199 190 developments in programming languages. 200 191 While rejecting resumption may have been the right decision in the past, 201 192 the situation has changed since then. 202 Some developments, such as the function alprogramming equivalent to resumptions,193 Some developments, such as the function programming equivalent to resumptions, 203 194 algebraic effects\cite{Zhang19}, are enjoying success. 204 A complete reexamination of resumption is beyond this thesis,205 but the ir reemergence is enough reasonto try them in \CFA.195 A complete reexamination of resumptions is beyond this thesis, 196 but there reemergence is enough to try them in \CFA. 206 197 % Especially considering how much easier they are to implement than 207 198 % termination exceptions and how much Peter likes them. … … 217 208 218 209 %\subsection 219 More recently ,exceptions seem to be vanishing from newer programming210 More recently exceptions seem to be vanishing from newer programming 220 211 languages, replaced by ``panic". 221 212 In Rust, a panic is just a program level abort that may be implemented by 222 213 unwinding the stack like in termination exception 223 214 handling.\cite{RustPanicMacro}\cite{RustPanicModule} 224 Go's panic th ough is very similar to a termination, except it only supports215 Go's panic through is very similar to a termination, except it only supports 225 216 a catch-all by calling \code{Go}{recover()}, simplifying the interface at 226 217 the cost of flexibility.\cite{Go:2021} 227 218 228 219 %\subsection 229 Asexception handling's most common use cases are in error handling,220 While exception handling's most common use cases are in error handling, 230 221 here are some other ways to handle errors with comparisons with exceptions. 231 222 \begin{itemize} … … 242 233 is discarded to avoid this problem. 243 234 Checking error codes also bloats the main execution path, 244 especially if the error is not handled immediately and has to be passed235 especially if the error is not handled immediately hand has to be passed 245 236 through multiple functions before it is addressed. 246 247 Here is an example of the pattern in Bash, where commands can only ``return"248 numbers and most output is done through streams of text.249 \begin{lstlisting}[language=bash,escapechar={}]250 # Immediately after running a command:251 case $? in252 0)253 # Success254 ;;255 1)256 # Error Code 1257 ;;258 2|3)259 # Error Code 2 or Error Code 3260 ;;261 # Add more cases as needed.262 asac263 \end{lstlisting}264 237 265 238 \item\emph{Special Return with Global Store}: 266 239 Similar to the error codes pattern but the function itself only returns 267 that there was an error ,268 and store sthe reason for the error in a fixed global location.269 For example ,many routines in the C standard library will only return some240 that there was an error 241 and store the reason for the error in a fixed global location. 242 For example many routines in the C standard library will only return some 270 243 error value (such as -1 or a null pointer) and the error code is written into 271 244 the standard variable @errno@. 272 245 273 246 This approach avoids the multiple results issue encountered with straight 274 error codes as only a single error value has to be returned, 275 but otherwise has the same disadvantages and more. 247 error codes but otherwise has the same disadvantages and more. 276 248 Every function that reads or writes to the global store must agree on all 277 249 possible errors and managing it becomes more complex with concurrency. 278 279 This example shows some of what has to be done to robustly handle a C280 standard library function that reports errors this way.281 \begin{lstlisting}[language=C]282 // Now a library function can set the error.283 int handle = open(path_name, flags);284 if (-1 == handle) {285 switch (errno) {286 case ENAMETOOLONG:287 // path_name is a bad argument.288 break;289 case ENFILE:290 // A system resource has been exausted.291 break;292 // And many more...293 }294 }295 \end{lstlisting}296 % cite open man page?297 250 298 251 \item\emph{Return Union}: … … 300 253 Success is one tag and the errors are another. 301 254 It is also possible to make each possible error its own tag and carry its own 302 additional information, but the two -branch format is easy to make generic255 additional information, but the two branch format is easy to make generic 303 256 so that one type can be used everywhere in error handling code. 304 257 305 258 This pattern is very popular in any functional or semi-functional language 306 259 with primitive support for tagged unions (or algebraic data types). 307 Return unions can also be expressed as monads (evaluation in a context)308 and often are in languages with special syntax for monadic evaluation,309 such as Haskell's \code{haskell}{do} blocks.310 311 The main advantage is that an arbitrary object can be used to represent an312 error, so it can include a lot more information than a simple error code.313 The disadvantages include that the it does have to be checked along the main314 execution, and if there aren't primitive tagged unions proper, usage can be315 hard to enforce.316 260 % We need listing Rust/rust to format code snippets from it. 317 261 % Rust's \code{rust}{Result<T, E>} 318 319 This is a simple example of examining the result of a failing function in 320 Haskell, using its \code{haskell}{Either} type. 321 Examining \code{haskell}{error} further would likely involve more matching, 322 but the type of \code{haskell}{error} is user defined so there are no 323 general cases. 324 \begin{lstlisting}[language=haskell] 325 case failingFunction argA argB of 326 Right value -> -- Use the successful computed value. 327 Left error -> -- Handle the produced error. 328 \end{lstlisting} 329 330 Return unions as monads will result in the same code, but can hide most 331 of the work to propagate errors in simple cases. The code to actually handle 332 the errors, or to interact with other monads (a common case in these 333 languages) still has to be written by hand. 334 335 If \code{haskell}{failingFunction} is implemented with two helpers that 336 use the same error type, then it can be implemented with a \code{haskell}{do} 337 block. 338 \begin{lstlisting}[language=haskell,literate={}] 339 failingFunction x y = do 340 z <- helperOne x 341 helperTwo y z 342 \end{lstlisting} 262 The main advantage is that an arbitrary object can be used to represent an 263 error so it can include a lot more information than a simple error code. 264 The disadvantages include that the it does have to be checked along the main 265 execution and if there aren't primitive tagged unions proper usage can be 266 hard to enforce. 343 267 344 268 \item\emph{Handler Functions}: … … 350 274 variable). 351 275 C++ uses this approach as its fallback system if exception handling fails, 352 such as \snake{std::terminate} and, for a time, 353 \snake{std::unexpected}.\footnote{\snake{std::unexpected} was part of the 354 Dynamic Exception Specification, which has been removed from the standard 355 as of C++20.\cite{CppExceptSpec}} 276 such as \snake{std::terminate_handler} and, for a time, 277 \snake{std::unexpected_handler}. 356 278 357 279 Handler functions work a lot like resumption exceptions, … … 361 283 function calls, but cheaper (constant time) to call, 362 284 they are more suited to more frequent (less exceptional) situations. 363 Although, in \Cpp and other languages that do not have checked exceptions,364 they can actually be enforced by the type system be more reliable.365 366 This is a more local example in \Cpp, using a function to provide367 a default value for a mapping.368 \begin{lstlisting}[language=C++]369 ValueT Map::key_or_default(KeyT key, ValueT(*make_default)(KeyT)) {370 ValueT * value = find_value(key);371 if (nullptr != value) {372 return *value;373 } else {374 return make_default(key);375 }376 }377 \end{lstlisting}378 285 \end{itemize} 379 286 … … 381 288 Because of their cost, exceptions are rarely used for hot paths of execution. 382 289 Hence, there is an element of self-fulfilling prophecy as implementation 383 techniques have been focused on making them cheap to set up,290 techniques have been focused on making them cheap to set-up, 384 291 happily making them expensive to use in exchange. 385 292 This difference is less important in higher-level scripting languages, 386 where using exception sfor other tasks is more common.293 where using exception for other tasks is more common. 387 294 An iconic example is Python's 388 \code{Python}{StopIteration}\cite{PythonExceptions} exception ,that295 \code{Python}{StopIteration}\cite{PythonExceptions} exception that 389 296 is thrown by an iterator to indicate that it is exhausted. 390 When paired with Python's iterator-based for-loop ,this will be thrown every297 When paired with Python's iterator-based for-loop this will be thrown every 391 298 time the end of the loop is reached.\cite{PythonForLoop} -
doc/theses/andrew_beach_MMath/performance.tex
r949339b r4e28d2e9 5 5 Instead, the focus was to get the features working. The only performance 6 6 requirement is to ensure the tests for correctness run in a reasonable 7 amount of time. Hence, onlya few basic performance tests were performed to7 amount of time. Hence, a few basic performance tests were performed to 8 8 check this requirement. 9 9 … … 13 13 one with termination and one with resumption. 14 14 15 GCCC++ is the most comparable language because both it and \CFA use the same15 C++ is the most comparable language because both it and \CFA use the same 16 16 framework, libunwind. 17 17 In fact, the comparison is almost entirely in quality of implementation. … … 37 37 resumption exceptions. Even the older programming languages with resumption 38 38 seem to be notable only for having resumption. 39 On the other hand, the functional equivalents to resumption are too new.40 There does not seem to be any standard implementations in well-known41 languages; so far, they seem confined to extensions and research languages.42 % There was some maybe interesting comparison to an OCaml extension43 % but I'm not sure how to get that working if it is interesting.44 39 Instead, resumption is compared to its simulation in other programming 45 40 languages: fixup functions that are explicitly passed into a function. … … 51 46 the number used in the timing runs is given with the results per test. 52 47 The Java tests run the main loop 1000 times before 53 beginning the actual test to ``warm up" the JVM.48 beginning the actual test to ``warm-up" the JVM. 54 49 % All other languages are precompiled or interpreted. 55 50 … … 59 54 unhandled exceptions in \Cpp and Java as that would cause the process to 60 55 terminate. 61 Luckily, performance on the ``give up and kill the process" path is not56 Luckily, performance on the ``give-up and kill the process" path is not 62 57 critical. 63 58 … … 81 76 using gcc-10 10.3.0 as a backend. 82 77 g++-10 10.3.0 is used for \Cpp. 83 Java tests are complied and run with Oracle OpenJDKversion 11.0.11.84 Python used CPythonversion 3.8.10.78 Java tests are complied and run with version 11.0.11. 79 Python used version 3.8.10. 85 80 The machines used to run the tests are: 86 81 \begin{itemize}[nosep] … … 90 85 \lstinline{@} 2.5 GHz running Linux v5.11.0-25 91 86 \end{itemize} 92 These representthe two major families of hardware architecture.87 Representing the two major families of hardware architecture. 93 88 94 89 \section{Tests} … … 98 93 99 94 \paragraph{Stack Traversal} 100 This group of tests measures the cost of traversing the stack95 This group measures the cost of traversing the stack, 101 96 (and in termination, unwinding it). 102 97 Inside the main loop is a call to a recursive function. … … 152 147 This group of tests measures the cost for setting up exception handling, 153 148 if it is 154 not used because the exceptional case did not occur.149 not used (because the exceptional case did not occur). 155 150 Tests repeatedly cross (enter, execute and leave) a try statement but never 156 151 perform a raise. … … 227 222 for that language and the result is marked N/A. 228 223 There are also cases where the feature is supported but measuring its 229 cost is impossible. This happened with Java, which uses a JIT that optimize s230 away the tests and cannot be stopped.\cite{Dice21}224 cost is impossible. This happened with Java, which uses a JIT that optimize 225 away the tests and it cannot be stopped.\cite{Dice21} 231 226 These tests are marked N/C. 232 227 To get results in a consistent range (1 second to 1 minute is ideal, … … 235 230 results and has a value in the millions. 236 231 237 An anomaly in some results came from \CFA's use of GCCnested functions.232 An anomaly in some results came from \CFA's use of gcc nested functions. 238 233 These nested functions are used to create closures that can access stack 239 234 variables in their lexical scope. 240 However, if they do so, then they can cause the benchmark's run time to235 However, if they do so, then they can cause the benchmark's run-time to 241 236 increase by an order of magnitude. 242 237 The simplest solution is to make those values global variables instead 243 of function -local variables.238 of function local variables. 244 239 % Do we know if editing a global inside nested function is a problem? 245 240 Tests that had to be modified to avoid this problem have been marked … … 260 255 \multicolumn{1}{c}{\CFA} & \multicolumn{1}{c}{\Cpp} & \multicolumn{1}{c}{Java} & \multicolumn{1}{c|}{Python} \\ 261 256 \hline 262 Empty Traversal (1M) & 23.0 & 9.6 & 17.6 & 23.4 & 30.6 & 13.6 & 15.5 & 14.7\\263 D'tor Traversal (1M) & 48. 1 & 23.5 & N/A & N/A & 64.2 & 29.2& N/A & N/A \\264 Finally Traversal (1M) & 3. 2* & N/A & 17.6 & 29.2 & 3.9* & N/A & 15.5& 19.0 \\265 Other Traversal (1M) & 3. 3* & 23.9 & 17.7 & 32.8 & 3.9* & 24.5 & 15.5 & 21.6\\266 Cross Handler (1 B) & 6.5 & 0.9 & N/C & 38.0 & 9.6 & 0.8 & N/C & 32.1\\267 Cross Finally (1 B) & 0.8 & N/A & N/C & 44.6 & 0.6& N/A & N/C & 37.3 \\268 Match All (10M) & 3 0.5 & 20.6 & 11.2 & 3.9 & 36.9 & 24.6 & 10.7& 3.1 \\269 Match None (10M) & 3 0.6 & 50.9 & 11.2 & 5.0 & 36.9 & 71.9 & 10.7 & 4.1\\257 Empty Traversal (1M) & 3.4 & 2.8 & 18.3 & 23.4 & 3.7 & 3.2 & 15.5 & 14.8 \\ 258 D'tor Traversal (1M) & 48.4 & 23.6 & N/A & N/A & 64.2 & 29.0 & N/A & N/A \\ 259 Finally Traversal (1M) & 3.4* & N/A & 17.9 & 29.0 & 4.1* & N/A & 15.6 & 19.0 \\ 260 Other Traversal (1M) & 3.6* & 23.2 & 18.2 & 32.7 & 4.0* & 24.5 & 15.5 & 21.4 \\ 261 Cross Handler (100M) & 6.0 & 0.9 & N/C & 37.4 & 10.0 & 0.8 & N/C & 32.2 \\ 262 Cross Finally (100M) & 0.9 & N/A & N/C & 44.1 & 0.8 & N/A & N/C & 37.3 \\ 263 Match All (10M) & 32.9 & 20.7 & 13.4 & 4.9 & 36.2 & 24.5 & 12.0 & 3.1 \\ 264 Match None (10M) & 32.7 & 50.3 & 11.0 & 5.1 & 36.3 & 71.9 & 12.3 & 4.2 \\ 270 265 \hline 271 266 \end{tabular} … … 281 276 & AMD & ARM \\ 282 277 \hline 283 Empty Traversal (10M) & 1.4 & 1.2\\278 Empty Traversal (10M) & 0.2 & 0.3 \\ 284 279 D'tor Traversal (10M) & 1.8 & 1.0 \\ 285 Finally Traversal (10M) & 1. 8& 1.0 \\286 Other Traversal (10M) & 22.6 & 25. 8\\287 Cross Handler (1 B) & 9.0& 11.9 \\280 Finally Traversal (10M) & 1.7 & 1.0 \\ 281 Other Traversal (10M) & 22.6 & 25.9 \\ 282 Cross Handler (100M) & 8.4 & 11.9 \\ 288 283 Match All (100M) & 2.3 & 3.2 \\ 289 Match None (100M) & 3.0 & 3.8\\284 Match None (100M) & 2.9 & 3.9 \\ 290 285 \hline 291 286 \end{tabular} … … 305 300 \multicolumn{1}{c}{Raise} & \multicolumn{1}{c}{\CFA} & \multicolumn{1}{c}{\Cpp} & \multicolumn{1}{c}{Java} & \multicolumn{1}{c|}{Python} \\ 306 301 \hline 307 Resume Empty (10M) & 1. 4 & 1.4 & 15.4 & 2.3 & 178.0 & 1.2 & 1.2 & 8.9 & 1.2 & 118.4\\302 Resume Empty (10M) & 1.5 & 1.5 & 14.7 & 2.3 & 176.1 & 1.0 & 1.4 & 8.9 & 1.2 & 119.9 \\ 308 303 \hline 309 304 \end{tabular} … … 317 312 \CFA, \Cpp and Java. 318 313 % To be exact, the Match All and Match None cases. 319 The most likely explanation is that 320 the generally faster languages have made ``common cases fast" at the expense 321 of the rarer cases. Since exceptions are considered rare, they are made 322 expensive to help speed up common actions, such as entering and leaving try 323 statements. 324 Python, on the other hand, while generally slower than the other languages, 325 uses exceptions more and has not sacrificed their performance. 314 The most likely explanation is that, since exceptions 315 are rarely considered to be the common case, the more optimized languages 316 make that case expensive to improve other cases. 326 317 In addition, languages with high-level representations have a much 327 318 easier time scanning the stack as there is less to decode. … … 355 346 Performance is similar to Empty Traversal in all languages that support finally 356 347 clauses. Only Python seems to have a larger than random noise change in 357 its run time and it is still not large.348 its run-time and it is still not large. 358 349 Despite the similarity between finally clauses and destructors, 359 finally clauses seem to avoid the spike that run time destructors have.350 finally clauses seem to avoid the spike that run-time destructors have. 360 351 Possibly some optimization removes the cost of changing contexts. 361 352 … … 365 356 This results in a significant jump. 366 357 367 Other languages experience a small increase in run time.358 Other languages experience a small increase in run-time. 368 359 The small increase likely comes from running the checks, 369 360 but they could avoid the spike by not having the same kind of overhead for … … 371 362 372 363 \item[Cross Handler] 373 Here ,\CFA falls behind \Cpp by a much more significant margin.374 This is likely due to the fact that\CFA has to insert two extra function375 calls, while \Cpp does not have to execute any other instructions.364 Here \CFA falls behind \Cpp by a much more significant margin. 365 This is likely due to the fact \CFA has to insert two extra function 366 calls, while \Cpp does not have to do execute any other instructions. 376 367 Python is much further behind. 377 368 … … 384 375 \item[Conditional Match] 385 376 Both of the conditional matching tests can be considered on their own. 386 However ,for evaluating the value of conditional matching itself, the377 However for evaluating the value of conditional matching itself, the 387 378 comparison of the two sets of results is useful. 388 Consider the massive jump in run time for \Cpp going from match all to match379 Consider the massive jump in run-time for \Cpp going from match all to match 389 380 none, which none of the other languages have. 390 Some strange interaction is causing run time to more than double for doing381 Some strange interaction is causing run-time to more than double for doing 391 382 twice as many raises. 392 Java and Python avoid this problem and have similar run time for both tests,383 Java and Python avoid this problem and have similar run-time for both tests, 393 384 possibly through resource reuse or their program representation. 394 However, \CFA is built like \Cpp, and avoids the problem as well. 395 This matches 385 However \CFA is built like \Cpp and avoids the problem as well, this matches 396 386 the pattern of the conditional match, which makes the two execution paths 397 387 very similar. … … 401 391 \subsection{Resumption \texorpdfstring{(\autoref{t:PerformanceResumption})}{}} 402 392 403 Moving on to resumption, there is one general note :393 Moving on to resumption, there is one general note, 404 394 resumption is \textit{fast}. The only test where it fell 405 395 behind termination is Cross Handler. 406 396 In every other case, the number of iterations had to be increased by a 407 factor of 10 to get the run time in an appropriate range397 factor of 10 to get the run-time in an appropriate range 408 398 and in some cases resumption still took less time. 409 399 … … 418 408 419 409 \item[D'tor Traversal] 420 Resumption does have the same spike in run time that termination has.421 The run time is actually very similar to Finally Traversal.410 Resumption does have the same spike in run-time that termination has. 411 The run-time is actually very similar to Finally Traversal. 422 412 As resumption does not unwind the stack, both destructors and finally 423 413 clauses are run while walking down the stack during the recursive returns. … … 426 416 \item[Finally Traversal] 427 417 Same as D'tor Traversal, 428 except termination did not have a spike in run time on this test case.418 except termination did not have a spike in run-time on this test case. 429 419 430 420 \item[Other Traversal] … … 437 427 The only test case where resumption could not keep up with termination, 438 428 although the difference is not as significant as many other cases. 439 It is simply a matter of where the costs come from :440 both termination and resumption have some work to set up or teardown a429 It is simply a matter of where the costs come from, 430 both termination and resumption have some work to set-up or tear-down a 441 431 handler. It just so happens that resumption's work is slightly slower. 442 432 … … 444 434 Resumption shows a slight slowdown if the exception is not matched 445 435 by the first handler, which follows from the fact the second handler now has 446 to be checked. However ,the difference is not large.436 to be checked. However the difference is not large. 447 437 448 438 \end{description} … … 458 448 More experiments could try to tease out the exact trade-offs, 459 449 but the prototype's only performance goal is to be reasonable. 460 It is already in that range, and \CFA's fixup routine simulation is450 It has already in that range, and \CFA's fixup routine simulation is 461 451 one of the faster simulations as well. 462 Plus ,exceptions add features and remove syntactic overhead,463 so even at similar performance ,resumptions have advantages452 Plus exceptions add features and remove syntactic overhead, 453 so even at similar performance resumptions have advantages 464 454 over fixup routines. -
doc/theses/andrew_beach_MMath/uw-ethesis-frontpgs.tex
r949339b r4e28d2e9 129 129 \begin{center}\textbf{Abstract}\end{center} 130 130 131 The \CFA (Cforall) programming language is an evolutionary refinement of 132 the C programming language, adding modern programming features without 133 changing the programming paradigms of C. 134 One of these modern programming features is more powerful error handling 135 through the addition of an exception handling mechanism (EHM). 136 137 This thesis covers the design and implementation of the \CFA EHM, 138 along with a review of the other required \CFA features. 139 The EHM includes common features of termination exception handling, 140 which abandons and recovers from an operation, 141 and similar support for resumption exception handling, 142 which repairs and continues with an operation. 143 The design of both has been adapted to utilize other tools \CFA provides, 144 as well as fit with the assertion based interfaces of the language. 145 146 The EHM has been implemented into the \CFA compiler and run-time environment. 147 Although it has not yet been optimized, performance testing has shown it has 148 comparable performance to other EHMs, 149 which is sufficient for use in current \CFA programs. 131 This is the abstract. 150 132 151 133 \cleardoublepage … … 156 138 \begin{center}\textbf{Acknowledgements}\end{center} 157 139 158 As is tradition and his due, I would like to begin by thanking my 159 supervisor Peter Buhr. From accepting me in a first place, 160 to helping me run performance tests, I would not be here without him. 161 Also if there was an ``artist" field here he would be listed there as well, 162 he helped me a lot with the diagrams. 163 164 I would like to thank the readers 165 Gregor Richards and Yizhou Zhang 166 for their feedback and approval. 167 The presentation of the thesis has definitely been improved with their 168 feedback. 169 170 I also thank the entire Cforall Team who built the rest of the 171 \CFA compiler. From the existing features I used in my work, to the 172 internal tooling that makes further development easier and the optimizations 173 that make running tests pass by quickly. 174 This includes: Aaron Moss, Rob Schluntz, Thierry Delisle, Michael Brooks, 175 Mubeen Zulfieqar \& Fangren Yu. 176 177 And thank-you Henry Xue, the co-op student who 178 converted my macro implementation of exception declarations into 179 the compiler features presented in this thesis. 180 181 Finally I thank my family, who are still relieved I learned how to read. 182 140 I would like to thank all the little people who made this thesis possible. 183 141 \cleardoublepage 184 142 -
doc/theses/andrew_beach_MMath/uw-ethesis.bib
r949339b r4e28d2e9 40 40 } 41 41 42 @misc{CppExceptSpec,43 author={C++ Community},44 key={Cpp Reference Exception Specification},45 howpublished={\href{https://en.cppreference.com/w/cpp/language/except_spec}{https://\-en.cppreference.com/\-w/\-cpp/\-language/\-except\_spec}},46 addendum={Accessed 2021-09-08},47 }48 49 42 @misc{RustPanicMacro, 50 43 author={The Rust Team}, 51 44 key={Rust Panic Macro}, 52 howpublished={\href{https://doc.rust-lang.org/std/ macro.panic.html}{https://\-doc.rust-lang.org/\-std/\-macro.panic.html}},45 howpublished={\href{https://doc.rust-lang.org/std/panic/index.html}{https://\-doc.rust-lang.org/\-std/\-panic/\-index.html}}, 53 46 addendum={Accessed 2021-08-31}, 54 47 } -
libcfa/src/Makefile.am
r949339b r4e28d2e9 48 48 math.hfa \ 49 49 time_t.hfa \ 50 bits/algorithm.hfa \51 50 bits/align.hfa \ 52 51 bits/containers.hfa \ … … 60 59 containers/array.hfa \ 61 60 concurrency/iofwd.hfa \ 61 concurrency/mutex_stmt.hfa \ 62 62 containers/list.hfa \ 63 63 containers/queueLockFree.hfa \ … … 78 78 memory.hfa \ 79 79 parseargs.hfa \ 80 parseconfig.hfa \81 80 rational.hfa \ 82 81 stdlib.hfa \ … … 87 86 containers/pair.hfa \ 88 87 containers/result.hfa \ 89 containers/string.hfa \90 containers/string_res.hfa \91 88 containers/vector.hfa \ 92 89 device/cpu.hfa … … 94 91 libsrc = ${inst_headers_src} ${inst_headers_src:.hfa=.cfa} \ 95 92 assert.cfa \ 93 bits/algorithm.hfa \ 96 94 bits/debug.cfa \ 97 95 exception.c \ … … 109 107 concurrency/invoke.h \ 110 108 concurrency/future.hfa \ 111 concurrency/kernel/fwd.hfa \ 112 concurrency/mutex_stmt.hfa 109 concurrency/kernel/fwd.hfa 113 110 114 111 inst_thread_headers_src = \ … … 196 193 $(CFACOMPILE) -quiet -XCFA,-l ${<} -c -o ${@} 197 194 198 concurrency/io/call.cfa: $(srcdir)/concurrency/io/call.cfa.in199 ${AM_V_GEN}python3 $< > $@200 201 195 #---------------------------------------------------------------------------------------------------------------- 202 196 libcfa_la_SOURCES = ${libsrc} -
libcfa/src/concurrency/clib/cfathread.cfa
r949339b r4e28d2e9 13 13 // Update Count : 14 14 // 15 16 // #define EPOLL_FOR_SOCKETS17 15 18 16 #include "fstream.hfa" … … 25 23 #include "cfathread.h" 26 24 27 extern "C" {28 #include <string.h>29 #include <errno.h>30 }31 32 25 extern void ?{}(processor &, const char[], cluster &, thread$ *); 33 26 extern "C" { 34 27 extern void __cfactx_invoke_thread(void (*main)(void *), void * this); 35 extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags);36 28 } 37 29 38 30 extern Time __kernel_get_time(); 39 extern unsigned register_proc_id( void );40 31 41 32 //================================================================================ 42 // Epoll support for sockets 43 44 #if defined(EPOLL_FOR_SOCKETS) 45 extern "C" { 46 #include <sys/epoll.h> 47 #include <sys/resource.h> 48 } 49 50 static pthread_t master_poller; 51 static int master_epollfd = 0; 52 static size_t poller_cnt = 0; 53 static int * poller_fds = 0p; 54 static struct leaf_poller * pollers = 0p; 55 56 struct __attribute__((aligned)) fd_info_t { 57 int pollid; 58 size_t rearms; 59 }; 60 rlim_t fd_limit = 0; 61 static fd_info_t * volatile * fd_map = 0p; 62 63 void * master_epoll( __attribute__((unused)) void * args ) { 64 unsigned id = register_proc_id(); 65 66 enum { MAX_EVENTS = 5 }; 67 struct epoll_event events[MAX_EVENTS]; 68 for() { 69 int ret = epoll_wait(master_epollfd, events, MAX_EVENTS, -1); 70 if ( ret < 0 ) { 71 abort | "Master epoll error: " | strerror(errno); 72 } 73 74 for(i; ret) { 75 thread$ * thrd = (thread$ *)events[i].data.u64; 76 unpark( thrd ); 77 } 78 } 79 80 return 0p; 81 } 82 83 static inline int epoll_rearm(int epollfd, int fd, uint32_t event) { 84 struct epoll_event eevent; 85 eevent.events = event | EPOLLET | EPOLLONESHOT; 86 eevent.data.u64 = (uint64_t)active_thread(); 87 88 if(0 != epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &eevent)) 89 { 90 if(errno == ENOENT) return -1; 91 abort | acquire | "epoll" | epollfd | "ctl rearm" | fd | "error: " | errno | strerror(errno); 92 } 93 94 park(); 95 return 0; 96 } 97 98 thread leaf_poller { 99 int epollfd; 100 }; 101 102 void ?{}(leaf_poller & this, int fd) { this.epollfd = fd; } 103 104 void main(leaf_poller & this) { 105 enum { MAX_EVENTS = 1024 }; 106 struct epoll_event events[MAX_EVENTS]; 107 const int max_retries = 5; 108 int retries = max_retries; 109 110 struct epoll_event event; 111 event.events = EPOLLIN | EPOLLET | EPOLLONESHOT; 112 event.data.u64 = (uint64_t)&(thread&)this; 113 114 if(0 != epoll_ctl(master_epollfd, EPOLL_CTL_ADD, this.epollfd, &event)) 115 { 116 abort | "master epoll ctl add leaf: " | errno | strerror(errno); 117 } 118 119 park(); 120 121 for() { 122 yield(); 123 int ret = epoll_wait(this.epollfd, events, MAX_EVENTS, 0); 124 if ( ret < 0 ) { 125 abort | "Leaf epoll error: " | errno | strerror(errno); 126 } 127 128 if(ret) { 129 for(i; ret) { 130 thread$ * thrd = (thread$ *)events[i].data.u64; 131 unpark( thrd, UNPARK_REMOTE ); 132 } 133 } 134 else if(0 >= --retries) { 135 epoll_rearm(master_epollfd, this.epollfd, EPOLLIN); 136 } 137 } 138 } 139 140 void setup_epoll( void ) __attribute__(( constructor )); 141 void setup_epoll( void ) { 142 if(master_epollfd) abort | "Master epoll already setup"; 143 144 master_epollfd = epoll_create1(0); 145 if(master_epollfd == -1) { 146 abort | "failed to create master epoll: " | errno | strerror(errno); 147 } 148 149 struct rlimit rlim; 150 if(int ret = getrlimit(RLIMIT_NOFILE, &rlim); 0 != ret) { 151 abort | "failed to get nofile limit: " | errno | strerror(errno); 152 } 153 154 fd_limit = rlim.rlim_cur; 155 fd_map = alloc(fd_limit); 156 for(i;fd_limit) { 157 fd_map[i] = 0p; 158 } 159 160 poller_cnt = 2; 161 poller_fds = alloc(poller_cnt); 162 pollers = alloc(poller_cnt); 163 for(i; poller_cnt) { 164 poller_fds[i] = epoll_create1(0); 165 if(poller_fds[i] == -1) { 166 abort | "failed to create leaf epoll [" | i | "]: " | errno | strerror(errno); 167 } 168 169 (pollers[i]){ poller_fds[i] }; 170 } 171 172 pthread_attr_t attr; 173 if (int ret = pthread_attr_init(&attr); 0 != ret) { 174 abort | "failed to create master epoll thread attr: " | ret | strerror(ret); 175 } 176 177 if (int ret = pthread_create(&master_poller, &attr, master_epoll, 0p); 0 != ret) { 178 abort | "failed to create master epoll thread: " | ret | strerror(ret); 179 } 180 } 181 182 static inline int epoll_wait(int fd, uint32_t event) { 183 if(fd_map[fd] >= 1p) { 184 fd_map[fd]->rearms++; 185 epoll_rearm(poller_fds[fd_map[fd]->pollid], fd, event); 186 return 0; 187 } 188 189 for() { 190 fd_info_t * expected = 0p; 191 fd_info_t * sentinel = 1p; 192 if(__atomic_compare_exchange_n( &(fd_map[fd]), &expected, sentinel, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED)) { 193 struct epoll_event eevent; 194 eevent.events = event | EPOLLET | EPOLLONESHOT; 195 eevent.data.u64 = (uint64_t)active_thread(); 196 197 int id = thread_rand() % poller_cnt; 198 if(0 != epoll_ctl(poller_fds[id], EPOLL_CTL_ADD, fd, &eevent)) 199 { 200 abort | "epoll ctl add" | poller_fds[id] | fd | fd_map[fd] | expected | "error: " | errno | strerror(errno); 201 } 202 203 fd_info_t * ninfo = alloc(); 204 ninfo->pollid = id; 205 ninfo->rearms = 0; 206 __atomic_store_n( &fd_map[fd], ninfo, __ATOMIC_SEQ_CST); 207 208 park(); 209 return 0; 210 } 211 212 if(expected >= 0) { 213 fd_map[fd]->rearms++; 214 epoll_rearm(poller_fds[fd_map[fd]->pollid], fd, event); 215 return 0; 216 } 217 218 Pause(); 219 } 220 } 221 #endif 222 223 //================================================================================ 224 // Thread run by the C Interface 33 // Thread run y the C Interface 225 34 226 35 struct cfathread_object { … … 436 245 // Mutex 437 246 struct cfathread_mutex { 438 linear_backoff_then_block_lock impl;247 fast_lock impl; 439 248 }; 440 249 int cfathread_mutex_init(cfathread_mutex_t *restrict mut, const cfathread_mutexattr_t *restrict) __attribute__((nonnull (1))) { *mut = new(); return 0; } … … 451 260 // Condition 452 261 struct cfathread_condition { 453 condition_variable( linear_backoff_then_block_lock) impl;262 condition_variable(fast_lock) impl; 454 263 }; 455 264 int cfathread_cond_init(cfathread_cond_t *restrict cond, const cfathread_condattr_t *restrict) __attribute__((nonnull (1))) { *cond = new(); return 0; } … … 479 288 // IO operations 480 289 int cfathread_socket(int domain, int type, int protocol) { 481 return socket(domain, type 482 #if defined(EPOLL_FOR_SOCKETS) 483 | SOCK_NONBLOCK 484 #endif 485 , protocol); 290 return socket(domain, type, protocol); 486 291 } 487 292 int cfathread_bind(int socket, const struct sockaddr *address, socklen_t address_len) { … … 494 299 495 300 int cfathread_accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) { 496 #if defined(EPOLL_FOR_SOCKETS) 497 int ret; 498 for() { 499 yield(); 500 ret = accept4(socket, address, address_len, SOCK_NONBLOCK); 501 if(ret >= 0) break; 502 if(errno != EAGAIN && errno != EWOULDBLOCK) break; 503 504 epoll_wait(socket, EPOLLIN); 505 } 506 return ret; 507 #else 508 return cfa_accept4(socket, address, address_len, 0, CFA_IO_LAZY); 509 #endif 301 return cfa_accept4(socket, address, address_len, 0, CFA_IO_LAZY); 510 302 } 511 303 512 304 int cfathread_connect(int socket, const struct sockaddr *address, socklen_t address_len) { 513 #if defined(EPOLL_FOR_SOCKETS) 514 int ret; 515 for() { 516 ret = connect(socket, address, address_len); 517 if(ret >= 0) break; 518 if(errno != EAGAIN && errno != EWOULDBLOCK) break; 519 520 epoll_wait(socket, EPOLLIN); 521 } 522 return ret; 523 #else 524 return cfa_connect(socket, address, address_len, CFA_IO_LAZY); 525 #endif 305 return cfa_connect(socket, address, address_len, CFA_IO_LAZY); 526 306 } 527 307 … … 535 315 536 316 ssize_t cfathread_sendmsg(int socket, const struct msghdr *message, int flags) { 537 #if defined(EPOLL_FOR_SOCKETS) 538 ssize_t ret; 539 __STATS__( false, io.ops.sockwrite++; ) 540 for() { 541 ret = sendmsg(socket, message, flags); 542 if(ret >= 0) break; 543 if(errno != EAGAIN && errno != EWOULDBLOCK) break; 544 545 __STATS__( false, io.ops.epllwrite++; ) 546 epoll_wait(socket, EPOLLOUT); 547 } 548 #else 549 ssize_t ret = cfa_sendmsg(socket, message, flags, CFA_IO_LAZY); 550 #endif 551 return ret; 317 return cfa_sendmsg(socket, message, flags, CFA_IO_LAZY); 552 318 } 553 319 554 320 ssize_t cfathread_write(int fildes, const void *buf, size_t nbyte) { 555 321 // Use send rather then write for socket since it's faster 556 #if defined(EPOLL_FOR_SOCKETS) 557 ssize_t ret; 558 // __STATS__( false, io.ops.sockwrite++; ) 559 for() { 560 ret = send(fildes, buf, nbyte, 0); 561 if(ret >= 0) break; 562 if(errno != EAGAIN && errno != EWOULDBLOCK) break; 563 564 // __STATS__( false, io.ops.epllwrite++; ) 565 epoll_wait(fildes, EPOLLOUT); 566 } 567 #else 568 ssize_t ret = cfa_send(fildes, buf, nbyte, 0, CFA_IO_LAZY); 569 #endif 570 return ret; 322 return cfa_send(fildes, buf, nbyte, 0, CFA_IO_LAZY); 571 323 } 572 324 … … 584 336 msg.msg_controllen = 0; 585 337 586 #if defined(EPOLL_FOR_SOCKETS) 587 ssize_t ret; 588 yield(); 589 for() { 590 ret = recvmsg(socket, &msg, flags); 591 if(ret >= 0) break; 592 if(errno != EAGAIN && errno != EWOULDBLOCK) break; 593 594 epoll_wait(socket, EPOLLIN); 595 } 596 #else 597 ssize_t ret = cfa_recvmsg(socket, &msg, flags, CFA_IO_LAZY); 598 #endif 338 ssize_t ret = cfa_recvmsg(socket, &msg, flags, CFA_IO_LAZY); 599 339 600 340 if(address_len) *address_len = msg.msg_namelen; … … 604 344 ssize_t cfathread_read(int fildes, void *buf, size_t nbyte) { 605 345 // Use recv rather then read for socket since it's faster 606 #if defined(EPOLL_FOR_SOCKETS) 607 ssize_t ret; 608 __STATS__( false, io.ops.sockread++; ) 609 yield(); 610 for() { 611 ret = recv(fildes, buf, nbyte, 0); 612 if(ret >= 0) break; 613 if(errno != EAGAIN && errno != EWOULDBLOCK) break; 614 615 __STATS__( false, io.ops.epllread++; ) 616 epoll_wait(fildes, EPOLLIN); 617 } 618 #else 619 ssize_t ret = cfa_recv(fildes, buf, nbyte, 0, CFA_IO_LAZY); 620 #endif 621 return ret; 622 } 623 624 } 346 return cfa_recv(fildes, buf, nbyte, 0, CFA_IO_LAZY); 347 } 348 349 } -
libcfa/src/concurrency/invoke.h
r949339b r4e28d2e9 170 170 bool corctx_flag; 171 171 172 int last_cpu; 173 172 174 //SKULLDUGGERY errno is not save in the thread data structure because returnToKernel appears to be the only function to require saving and restoring it 173 175 … … 175 177 struct cluster * curr_cluster; 176 178 177 // preferred ready-queue or CPU179 // preferred ready-queue 178 180 unsigned preferred; 179 181 -
libcfa/src/concurrency/io.cfa
r949339b r4e28d2e9 90 90 static inline unsigned __flush( struct $io_context & ); 91 91 static inline __u32 __release_sqes( struct $io_context & ); 92 extern void __kernel_unpark( thread$ * thrd , unpark_hint);92 extern void __kernel_unpark( thread$ * thrd ); 93 93 94 94 bool __cfa_io_drain( processor * proc ) { … … 118 118 __cfadbg_print_safe( io, "Kernel I/O : Syscall completed : cqe %p, result %d for %p\n", &cqe, cqe.res, future ); 119 119 120 __kernel_unpark( fulfil( *future, cqe.res, false ) , UNPARK_LOCAL);120 __kernel_unpark( fulfil( *future, cqe.res, false ) ); 121 121 } 122 122 -
libcfa/src/concurrency/kernel.cfa
r949339b r4e28d2e9 22 22 #include <errno.h> 23 23 #include <stdio.h> 24 #include <string.h>25 24 #include <signal.h> 26 25 #include <unistd.h> … … 32 31 #include "kernel_private.hfa" 33 32 #include "preemption.hfa" 34 #include "strstream.hfa"35 #include "device/cpu.hfa"36 33 37 34 //Private includes … … 234 231 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle); 235 232 236 { 237 eventfd_t val; 238 ssize_t ret = read( this->idle, &val, sizeof(val) ); 239 if(ret < 0) { 240 switch((int)errno) { 241 case EAGAIN: 242 #if EAGAIN != EWOULDBLOCK 243 case EWOULDBLOCK: 244 #endif 245 case EINTR: 246 // No need to do anything special here, just assume it's a legitimate wake-up 247 break; 248 default: 249 abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) ); 250 } 251 } 252 } 233 __disable_interrupts_hard(); 234 eventfd_t val; 235 eventfd_read( this->idle, &val ); 236 __enable_interrupts_hard(); 253 237 254 238 #if !defined(__CFA_NO_STATISTICS__) … … 341 325 } 342 326 343 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); )327 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->unique_id, rdtscl()); ) 344 328 __cfadbg_print_safe(runtime_core, "Kernel : core %p waiting on eventfd %d\n", this, this->idle); 345 329 346 { 347 eventfd_t val; 348 ssize_t ret = read( this->idle, &val, sizeof(val) ); 349 if(ret < 0) { 350 switch((int)errno) { 351 case EAGAIN: 352 #if EAGAIN != EWOULDBLOCK 353 case EWOULDBLOCK: 354 #endif 355 case EINTR: 356 // No need to do anything special here, just assume it's a legitimate wake-up 357 break; 358 default: 359 abort( "KERNEL : internal error, read failure on idle eventfd, error(%d) %s.", (int)errno, strerror( (int)errno ) ); 360 } 361 } 362 } 330 // __disable_interrupts_hard(); 331 eventfd_t val; 332 eventfd_read( this->idle, &val ); 333 // __enable_interrupts_hard(); 363 334 364 335 __STATS( if(this->print_halts) __cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->unique_id, rdtscl()); ) … … 422 393 /* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next ); 423 394 __builtin_prefetch( thrd_dst->context.SP ); 395 396 int curr = __kernel_getcpu(); 397 if(thrd_dst->last_cpu != curr) { 398 int64_t l = thrd_dst->last_cpu; 399 int64_t c = curr; 400 int64_t v = (l << 32) | c; 401 __push_stat( __tls_stats(), v, false, "Processor", this ); 402 } 403 404 thrd_dst->last_cpu = curr; 424 405 425 406 __cfadbg_print_safe(runtime_core, "Kernel : core %p running thread %p (%s)\n", this, thrd_dst, thrd_dst->self_cor.name); … … 476 457 if(unlikely(thrd_dst->preempted != __NO_PREEMPTION)) { 477 458 // The thread was preempted, reschedule it and reset the flag 478 schedule_thread$( thrd_dst , UNPARK_LOCAL);459 schedule_thread$( thrd_dst ); 479 460 break RUNNING; 480 461 } … … 560 541 // Scheduler routines 561 542 // KERNEL ONLY 562 static void __schedule_thread( thread$ * thrd , unpark_hint hint) {543 static void __schedule_thread( thread$ * thrd ) { 563 544 /* paranoid */ verify( ! __preemption_enabled() ); 564 545 /* paranoid */ verify( ready_schedule_islocked()); … … 580 561 // Dereference the thread now because once we push it, there is not guaranteed it's still valid. 581 562 struct cluster * cl = thrd->curr_cluster; 582 __STATS(bool outside = hint == UNPARK_LOCAL &&thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; )563 __STATS(bool outside = thrd->last_proc && thrd->last_proc != kernelTLS().this_processor; ) 583 564 584 565 // push the thread to the cluster ready-queue 585 push( cl, thrd, hint);566 push( cl, thrd, local ); 586 567 587 568 // variable thrd is no longer safe to use … … 608 589 } 609 590 610 void schedule_thread$( thread$ * thrd , unpark_hint hint) {591 void schedule_thread$( thread$ * thrd ) { 611 592 ready_schedule_lock(); 612 __schedule_thread( thrd , hint);593 __schedule_thread( thrd ); 613 594 ready_schedule_unlock(); 614 595 } … … 661 642 } 662 643 663 void __kernel_unpark( thread$ * thrd , unpark_hint hint) {644 void __kernel_unpark( thread$ * thrd ) { 664 645 /* paranoid */ verify( ! __preemption_enabled() ); 665 646 /* paranoid */ verify( ready_schedule_islocked()); … … 669 650 if(__must_unpark(thrd)) { 670 651 // Wake lost the race, 671 __schedule_thread( thrd , hint);652 __schedule_thread( thrd ); 672 653 } 673 654 … … 676 657 } 677 658 678 void unpark( thread$ * thrd , unpark_hint hint) {659 void unpark( thread$ * thrd ) { 679 660 if( !thrd ) return; 680 661 … … 682 663 disable_interrupts(); 683 664 // Wake lost the race, 684 schedule_thread$( thrd , hint);665 schedule_thread$( thrd ); 685 666 enable_interrupts(false); 686 667 } -
libcfa/src/concurrency/kernel.hfa
r949339b r4e28d2e9 151 151 struct __attribute__((aligned(128))) __timestamp_t { 152 152 volatile unsigned long long tv; 153 volatile unsigned long long ma; 154 }; 155 156 // Aligned timestamps which are used by the relaxed ready queue 157 struct __attribute__((aligned(128))) __help_cnts_t { 158 volatile unsigned long long src; 159 volatile unsigned long long dst; 160 volatile unsigned long long tri; 161 }; 162 163 static inline void ?{}(__timestamp_t & this) { this.tv = 0; this.ma = 0; } 153 }; 154 155 static inline void ?{}(__timestamp_t & this) { this.tv = 0; } 164 156 static inline void ^?{}(__timestamp_t & this) {} 165 157 … … 177 169 // Array of times 178 170 __timestamp_t * volatile tscs; 179 180 // Array of stats181 __help_cnts_t * volatile help;182 171 183 172 // Number of lanes (empty or not) -
libcfa/src/concurrency/kernel/fwd.hfa
r949339b r4e28d2e9 119 119 120 120 extern "Cforall" { 121 enum unpark_hint { UNPARK_LOCAL, UNPARK_REMOTE };122 123 121 extern void park( void ); 124 extern void unpark( struct thread$ *, unpark_hint ); 125 static inline void unpark( struct thread$ * thrd ) { unpark(thrd, UNPARK_LOCAL); } 122 extern void unpark( struct thread$ * this ); 126 123 static inline struct thread$ * active_thread () { 127 124 struct thread$ * t = publicTLS_get( this_thread ); -
libcfa/src/concurrency/kernel/startup.cfa
r949339b r4e28d2e9 200 200 __cfadbg_print_safe(runtime_core, "Kernel : Main cluster ready\n"); 201 201 202 // Construct the processor context of the main processor203 void ?{}(processorCtx_t & this, processor * proc) {204 (this.__cor){ "Processor" };205 this.__cor.starter = 0p;206 this.proc = proc;207 }208 209 void ?{}(processor & this) with( this ) {210 ( this.terminated ){};211 ( this.runner ){};212 init( this, "Main Processor", *mainCluster, 0p );213 kernel_thread = pthread_self();214 215 runner{ &this };216 __cfadbg_print_safe(runtime_core, "Kernel : constructed main processor context %p\n", &runner);217 }218 219 // Initialize the main processor and the main processor ctx220 // (the coroutine that contains the processing control flow)221 mainProcessor = (processor *)&storage_mainProcessor;222 (*mainProcessor){};223 224 register_tls( mainProcessor );225 226 202 // Start by initializing the main thread 227 203 // SKULLDUGGERY: the mainThread steals the process main thread … … 234 210 __cfadbg_print_safe(runtime_core, "Kernel : Main thread ready\n"); 235 211 212 213 214 // Construct the processor context of the main processor 215 void ?{}(processorCtx_t & this, processor * proc) { 216 (this.__cor){ "Processor" }; 217 this.__cor.starter = 0p; 218 this.proc = proc; 219 } 220 221 void ?{}(processor & this) with( this ) { 222 ( this.terminated ){}; 223 ( this.runner ){}; 224 init( this, "Main Processor", *mainCluster, 0p ); 225 kernel_thread = pthread_self(); 226 227 runner{ &this }; 228 __cfadbg_print_safe(runtime_core, "Kernel : constructed main processor context %p\n", &runner); 229 } 230 231 // Initialize the main processor and the main processor ctx 232 // (the coroutine that contains the processing control flow) 233 mainProcessor = (processor *)&storage_mainProcessor; 234 (*mainProcessor){}; 235 236 register_tls( mainProcessor ); 237 mainThread->last_cpu = __kernel_getcpu(); 238 236 239 //initialize the global state variables 237 240 __cfaabi_tls.this_processor = mainProcessor; … … 249 252 // Add the main thread to the ready queue 250 253 // once resume is called on mainProcessor->runner the mainThread needs to be scheduled like any normal thread 251 schedule_thread$(mainThread , UNPARK_LOCAL);254 schedule_thread$(mainThread); 252 255 253 256 // SKULLDUGGERY: Force a context switch to the main processor to set the main thread's context to the current UNIX … … 483 486 link.next = 0p; 484 487 link.ts = -1llu; 485 preferred = ready_queue_new_preferred();488 preferred = -1u; 486 489 last_proc = 0p; 487 490 #if defined( __CFA_WITH_VERIFY__ ) -
libcfa/src/concurrency/kernel_private.hfa
r949339b r4e28d2e9 46 46 } 47 47 48 void schedule_thread$( thread$ * , unpark_hint hint) __attribute__((nonnull (1)));48 void schedule_thread$( thread$ * ) __attribute__((nonnull (1))); 49 49 50 50 extern bool __preemption_enabled(); … … 300 300 // push thread onto a ready queue for a cluster 301 301 // returns true if the list was previously empty, false otherwise 302 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint);302 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, bool local); 303 303 304 304 //----------------------------------------------------------------------- … … 321 321 322 322 //----------------------------------------------------------------------- 323 // get preferred ready for new thread324 unsigned ready_queue_new_preferred();325 326 //-----------------------------------------------------------------------327 323 // Increase the width of the ready queue (number of lanes) by 4 328 324 void ready_queue_grow (struct cluster * cltr); -
libcfa/src/concurrency/locks.hfa
r949339b r4e28d2e9 324 324 } 325 325 326 // linear backoff bounded by spin_count 327 spin = spin_start; 328 int spin_counter = 0; 329 int yield_counter = 0; 330 for ( ;; ) { 331 if(try_lock_contention(this)) return true; 332 if(spin_counter < spin_count) { 333 for (int i = 0; i < spin; i++) Pause(); 334 if (spin < spin_end) spin += spin; 335 else spin_counter++; 336 } else if (yield_counter < yield_count) { 337 // after linear backoff yield yield_count times 338 yield_counter++; 339 yield(); 340 } else { break; } 341 } 342 343 // block until signalled 344 while (block(this)) if(try_lock_contention(this)) return true; 345 346 // this should never be reached as block(this) always returns true 347 return false; 348 } 349 350 static inline bool lock_improved(linear_backoff_then_block_lock & this) with(this) { 351 // if owner just return 352 if (active_thread() == owner) return true; 353 size_t compare_val = 0; 354 int spin = spin_start; 355 // linear backoff 356 for( ;; ) { 357 compare_val = 0; 358 if (internal_try_lock(this, compare_val)) return true; 359 if (2 == compare_val) break; 360 for (int i = 0; i < spin; i++) Pause(); 361 if (spin >= spin_end) break; 362 spin += spin; 363 } 364 365 // linear backoff bounded by spin_count 366 spin = spin_start; 367 int spin_counter = 0; 368 int yield_counter = 0; 369 for ( ;; ) { 370 compare_val = 0; 371 if(internal_try_lock(this, compare_val)) return true; 372 if (2 == compare_val) break; 373 if(spin_counter < spin_count) { 374 for (int i = 0; i < spin; i++) Pause(); 375 if (spin < spin_end) spin += spin; 376 else spin_counter++; 377 } else if (yield_counter < yield_count) { 378 // after linear backoff yield yield_count times 379 yield_counter++; 380 yield(); 381 } else { break; } 382 } 383 326 384 if(2 != compare_val && try_lock_contention(this)) return true; 327 385 // block until signalled … … 344 402 static inline void on_notify(linear_backoff_then_block_lock & this, struct thread$ * t ) { unpark(t); } 345 403 static inline size_t on_wait(linear_backoff_then_block_lock & this) { unlock(this); return 0; } 346 static inline void on_wakeup(linear_backoff_then_block_lock & this, size_t recursion ) { lock (this); }404 static inline void on_wakeup(linear_backoff_then_block_lock & this, size_t recursion ) { lock_improved(this); } 347 405 348 406 //----------------------------------------------------------------------------- -
libcfa/src/concurrency/mutex_stmt.hfa
r949339b r4e28d2e9 41 41 } 42 42 43 static inline L * __get_p tr( L & this) {44 return & this;43 static inline L * __get_pointer( L & lock ) { 44 return &lock; 45 45 } 46 47 static inline L __get_type( L & this );48 49 static inline L __get_type( L * this );50 46 } -
libcfa/src/concurrency/ready_queue.cfa
r949339b r4e28d2e9 100 100 #define __kernel_rseq_unregister rseq_unregister_current_thread 101 101 #elif defined(CFA_HAVE_LINUX_RSEQ_H) 102 staticvoid __kernel_raw_rseq_register (void);103 staticvoid __kernel_raw_rseq_unregister(void);102 void __kernel_raw_rseq_register (void); 103 void __kernel_raw_rseq_unregister(void); 104 104 105 105 #define __kernel_rseq_register __kernel_raw_rseq_register … … 246 246 // Cforall Ready Queue used for scheduling 247 247 //======================================================================= 248 unsigned long long moving_average(unsigned long long nval, unsigned long long oval) {249 const unsigned long long tw = 16;250 const unsigned long long nw = 4;251 const unsigned long long ow = tw - nw;252 return ((nw * nval) + (ow * oval)) / tw;253 }254 255 248 void ?{}(__ready_queue_t & this) with (this) { 256 249 #if defined(USE_CPU_WORK_STEALING) … … 258 251 lanes.data = alloc( lanes.count ); 259 252 lanes.tscs = alloc( lanes.count ); 260 lanes.help = alloc( cpu_info.hthrd_count );261 253 262 254 for( idx; (size_t)lanes.count ) { 263 255 (lanes.data[idx]){}; 264 256 lanes.tscs[idx].tv = rdtscl(); 265 lanes.tscs[idx].ma = rdtscl();266 }267 for( idx; (size_t)cpu_info.hthrd_count ) {268 lanes.help[idx].src = 0;269 lanes.help[idx].dst = 0;270 lanes.help[idx].tri = 0;271 257 } 272 258 #else 273 259 lanes.data = 0p; 274 260 lanes.tscs = 0p; 275 lanes.help = 0p;276 261 lanes.count = 0; 277 262 #endif … … 285 270 free(lanes.data); 286 271 free(lanes.tscs); 287 free(lanes.help);288 272 } 289 273 290 274 //----------------------------------------------------------------------- 291 275 #if defined(USE_CPU_WORK_STEALING) 292 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->ready_queue) {276 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, bool push_local) with (cltr->ready_queue) { 293 277 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 294 278 295 279 processor * const proc = kernelTLS().this_processor; 296 const bool external = (!proc) || (cltr != proc->cltr); 297 298 // Figure out the current cpu and make sure it is valid 280 const bool external = !push_local || (!proc) || (cltr != proc->cltr); 281 299 282 const int cpu = __kernel_getcpu(); 300 283 /* paranoid */ verify(cpu >= 0); … … 302 285 /* paranoid */ verify(cpu * READYQ_SHARD_FACTOR < lanes.count); 303 286 304 // Figure out where thread was last time and make sure it's 305 /* paranoid */ verify(thrd->preferred >= 0); 306 /* paranoid */ verify(thrd->preferred < cpu_info.hthrd_count); 307 /* paranoid */ verify(thrd->preferred * READYQ_SHARD_FACTOR < lanes.count); 308 const int prf = thrd->preferred * READYQ_SHARD_FACTOR; 309 310 const cpu_map_entry_t & map; 311 choose(hint) { 312 case UNPARK_LOCAL : &map = &cpu_info.llc_map[cpu]; 313 case UNPARK_REMOTE: &map = &cpu_info.llc_map[prf]; 314 } 287 const cpu_map_entry_t & map = cpu_info.llc_map[cpu]; 315 288 /* paranoid */ verify(map.start * READYQ_SHARD_FACTOR < lanes.count); 316 289 /* paranoid */ verify(map.self * READYQ_SHARD_FACTOR < lanes.count); … … 323 296 if(unlikely(external)) { r = __tls_rand(); } 324 297 else { r = proc->rdq.its++; } 325 choose(hint) { 326 case UNPARK_LOCAL : i = start + (r % READYQ_SHARD_FACTOR); 327 case UNPARK_REMOTE: i = prf + (r % READYQ_SHARD_FACTOR); 328 } 298 i = start + (r % READYQ_SHARD_FACTOR); 329 299 // If we can't lock it retry 330 300 } while( !__atomic_try_acquire( &lanes.data[i].lock ) ); … … 362 332 processor * const proc = kernelTLS().this_processor; 363 333 const int start = map.self * READYQ_SHARD_FACTOR; 364 const unsigned long long ctsc = rdtscl();365 334 366 335 // Did we already have a help target 367 336 if(proc->rdq.target == -1u) { 368 unsigned long long max = 0; 337 // if We don't have a 338 unsigned long long min = ts(lanes.data[start]); 369 339 for(i; READYQ_SHARD_FACTOR) { 370 unsigned long long tsc = moving_average(ctsc - ts(lanes.data[start + i]), lanes.tscs[start + i].ma); 371 if(tsc > max) max = tsc; 372 } 373 proc->rdq.cutoff = (max + 2 * max) / 2; 340 unsigned long long tsc = ts(lanes.data[start + i]); 341 if(tsc < min) min = tsc; 342 } 343 proc->rdq.cutoff = min; 344 374 345 /* paranoid */ verify(lanes.count < 65536); // The following code assumes max 65536 cores. 375 346 /* paranoid */ verify(map.count < 65536); // The following code assumes max 65536 cores. 376 347 377 if(0 == (__tls_rand() % 10 0)) {348 if(0 == (__tls_rand() % 10_000)) { 378 349 proc->rdq.target = __tls_rand() % lanes.count; 379 350 } else { … … 387 358 } 388 359 else { 389 unsigned long long max = 0; 390 for(i; READYQ_SHARD_FACTOR) { 391 unsigned long long tsc = moving_average(ctsc - ts(lanes.data[start + i]), lanes.tscs[start + i].ma); 392 if(tsc > max) max = tsc; 393 } 394 const unsigned long long cutoff = (max + 2 * max) / 2; 360 const unsigned long long bias = 0; //2_500_000_000; 361 const unsigned long long cutoff = proc->rdq.cutoff > bias ? proc->rdq.cutoff - bias : proc->rdq.cutoff; 395 362 { 396 363 unsigned target = proc->rdq.target; 397 364 proc->rdq.target = -1u; 398 lanes.help[target / READYQ_SHARD_FACTOR].tri++; 399 if(moving_average(ctsc - lanes.tscs[target].tv, lanes.tscs[target].ma) > cutoff) { 365 if(lanes.tscs[target].tv < cutoff && ts(lanes.data[target]) < cutoff) { 400 366 thread$ * t = try_pop(cltr, target __STATS(, __tls_stats()->ready.pop.help)); 401 367 proc->rdq.last = target; 402 368 if(t) return t; 403 else proc->rdq.target = -1u;404 369 } 405 else proc->rdq.target = -1u;406 370 } 407 371 … … 464 428 } 465 429 466 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->ready_queue) {430 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, bool push_local) with (cltr->ready_queue) { 467 431 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 468 432 469 const bool external = (hint != UNPARK_LOCAL)|| (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);433 const bool external = !push_local || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 470 434 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count ); 471 435 … … 551 515 #endif 552 516 #if defined(USE_WORK_STEALING) 553 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, unpark_hint hint) with (cltr->ready_queue) {517 __attribute__((hot)) void push(struct cluster * cltr, struct thread$ * thrd, bool push_local) with (cltr->ready_queue) { 554 518 __cfadbg_print_safe(ready_queue, "Kernel : Pushing %p on cluster %p\n", thrd, cltr); 555 519 556 520 // #define USE_PREFERRED 557 521 #if !defined(USE_PREFERRED) 558 const bool external = (hint != UNPARK_LOCAL)|| (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr);522 const bool external = !push_local || (!kernelTLS().this_processor) || (cltr != kernelTLS().this_processor->cltr); 559 523 /* paranoid */ verify(external || kernelTLS().this_processor->rdq.id < lanes.count ); 560 524 #else 561 525 unsigned preferred = thrd->preferred; 562 const bool external = (hint != UNPARK_LOCAL)|| (!kernelTLS().this_processor) || preferred == -1u || thrd->curr_cluster != cltr;526 const bool external = push_local || (!kernelTLS().this_processor) || preferred == -1u || thrd->curr_cluster != cltr; 563 527 /* paranoid */ verifyf(external || preferred < lanes.count, "Invalid preferred queue %u for %u lanes", preferred, lanes.count ); 564 528 … … 681 645 // Actually pop the list 682 646 struct thread$ * thrd; 683 unsigned long long tsc_before = ts(lane);684 647 unsigned long long tsv; 685 648 [thrd, tsv] = pop(lane); … … 695 658 __STATS( stats.success++; ) 696 659 697 #if defined(USE_WORK_STEALING) || defined(USE_CPU_WORK_STEALING) 698 unsigned long long now = rdtscl(); 660 #if defined(USE_WORK_STEALING) 699 661 lanes.tscs[w].tv = tsv; 700 lanes.tscs[w].ma = moving_average(now > tsc_before ? now - tsc_before : 0, lanes.tscs[w].ma);701 662 #endif 702 663 703 #if defined(USE_CPU_WORK_STEALING) 704 thrd->preferred = w / READYQ_SHARD_FACTOR; 705 #else 706 thrd->preferred = w; 707 #endif 664 thrd->preferred = w; 708 665 709 666 // return the popped thread … … 731 688 732 689 //----------------------------------------------------------------------- 733 // get preferred ready for new thread734 unsigned ready_queue_new_preferred() {735 unsigned pref = 0;736 if(struct thread$ * thrd = publicTLS_get( this_thread )) {737 pref = thrd->preferred;738 }739 else {740 #if defined(USE_CPU_WORK_STEALING)741 pref = __kernel_getcpu();742 #endif743 }744 745 #if defined(USE_CPU_WORK_STEALING)746 /* paranoid */ verify(pref >= 0);747 /* paranoid */ verify(pref < cpu_info.hthrd_count);748 #endif749 750 return pref;751 }752 753 //-----------------------------------------------------------------------754 690 // Check that all the intrusive queues in the data structure are still consistent 755 691 static void check( __ready_queue_t & q ) with (q) { … … 979 915 extern void __enable_interrupts_hard(); 980 916 981 staticvoid __kernel_raw_rseq_register (void) {917 void __kernel_raw_rseq_register (void) { 982 918 /* paranoid */ verify( __cfaabi_rseq.cpu_id == RSEQ_CPU_ID_UNINITIALIZED ); 983 919 … … 997 933 } 998 934 999 staticvoid __kernel_raw_rseq_unregister(void) {935 void __kernel_raw_rseq_unregister(void) { 1000 936 /* paranoid */ verify( __cfaabi_rseq.cpu_id >= 0 ); 1001 937 -
libcfa/src/concurrency/ready_subqueue.hfa
r949339b r4e28d2e9 98 98 99 99 // Get the relevant nodes locally 100 unsigned long long ts = this.anchor.ts; 100 101 thread$ * node = this.anchor.next; 101 102 this.anchor.next = node->link.next; … … 115 116 /* paranoid */ verify( node->link.ts != 0 ); 116 117 /* paranoid */ verify( this.anchor.ts != 0 ); 117 return [node, t his.anchor.ts];118 return [node, ts]; 118 119 } 119 120 -
libcfa/src/concurrency/stats.cfa
r949339b r4e28d2e9 48 48 stats->io.calls.completed = 0; 49 49 stats->io.calls.errors.busy = 0; 50 stats->io.ops.sockread = 0;51 stats->io.ops.epllread = 0;52 stats->io.ops.sockwrite = 0;53 stats->io.ops.epllwrite = 0;54 50 #endif 55 51 … … 108 104 tally_one( &cltr->io.calls.completed , &proc->io.calls.completed ); 109 105 tally_one( &cltr->io.calls.errors.busy, &proc->io.calls.errors.busy ); 110 tally_one( &cltr->io.ops.sockread , &proc->io.ops.sockread );111 tally_one( &cltr->io.ops.epllread , &proc->io.ops.epllread );112 tally_one( &cltr->io.ops.sockwrite , &proc->io.ops.sockwrite );113 tally_one( &cltr->io.ops.epllwrite , &proc->io.ops.epllwrite );114 106 #endif 115 107 } … … 187 179 | " - cmp " | eng3(io.calls.drain) | "/" | eng3(io.calls.completed) | "(" | ws(3, 3, avgcomp) | "/drain)" 188 180 | " - " | eng3(io.calls.errors.busy) | " EBUSY"; 189 sstr | "- ops blk: "190 | " sk rd: " | eng3(io.ops.sockread) | "epll: " | eng3(io.ops.epllread)191 | " sk wr: " | eng3(io.ops.sockwrite) | "epll: " | eng3(io.ops.epllwrite);192 181 sstr | nl; 193 182 } -
libcfa/src/concurrency/stats.hfa
r949339b r4e28d2e9 102 102 volatile uint64_t sleeps; 103 103 } poller; 104 struct {105 volatile uint64_t sockread;106 volatile uint64_t epllread;107 volatile uint64_t sockwrite;108 volatile uint64_t epllwrite;109 } ops;110 104 }; 111 105 #endif -
libcfa/src/concurrency/thread.cfa
r949339b r4e28d2e9 25 25 #include "invoke.h" 26 26 27 uint64_t thread_rand();28 29 27 //----------------------------------------------------------------------------- 30 28 // Thread ctors and dtors … … 36 34 preempted = __NO_PREEMPTION; 37 35 corctx_flag = false; 36 disable_interrupts(); 37 last_cpu = __kernel_getcpu(); 38 enable_interrupts(); 38 39 curr_cor = &self_cor; 39 40 self_mon.owner = &this; … … 43 44 link.next = 0p; 44 45 link.ts = -1llu; 45 preferred = ready_queue_new_preferred();46 preferred = -1u; 46 47 last_proc = 0p; 47 48 #if defined( __CFA_WITH_VERIFY__ ) … … 140 141 /* paranoid */ verify( this_thrd->context.SP ); 141 142 142 schedule_thread$( this_thrd , UNPARK_LOCAL);143 schedule_thread$( this_thrd ); 143 144 enable_interrupts(); 144 145 } -
libcfa/src/device/cpu.cfa
r949339b r4e28d2e9 422 422 } 423 423 } 424 425 cpu_info_t cpu_info; -
libcfa/src/device/cpu.hfa
r949339b r4e28d2e9 30 30 }; 31 31 32 externcpu_info_t cpu_info;32 cpu_info_t cpu_info; -
libcfa/src/fstream.cfa
r949339b r4e28d2e9 10 10 // Created On : Wed May 27 17:56:53 2015 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : T ue Sep 21 21:51:38202113 // Update Count : 4 6012 // Last Modified On : Thu Jul 29 22:34:10 2021 13 // Update Count : 454 14 14 // 15 15 … … 28 28 #define IO_MSG "I/O error: " 29 29 30 void ?{}( ofstream & os, void * file ) with(os){31 file$ = file;32 sepDefault$ = true;33 sepOnOff$ = false;34 nlOnOff$ = true;35 prt$ = false;36 sawNL$ = false;37 acquired$ = false;30 void ?{}( ofstream & os, void * file ) { 31 os.file$ = file; 32 os.sepDefault$ = true; 33 os.sepOnOff$ = false; 34 os.nlOnOff$ = true; 35 os.prt$ = false; 36 os.sawNL$ = false; 37 os.acquired$ = false; 38 38 sepSetCur$( os, sepGet( os ) ); 39 39 sepSet( os, " " ); … … 124 124 void open( ofstream & os, const char name[], const char mode[] ) { 125 125 FILE * file = fopen( name, mode ); 126 #ifdef __CFA_DEBUG__ 126 127 if ( file == 0p ) { 127 128 throw (Open_Failure){ os }; 128 129 // abort | IO_MSG "open output file \"" | name | "\"" | nl | strerror( errno ); 129 130 } // if 130 (os){ file }; // initialize 131 #endif // __CFA_DEBUG__ 132 (os){ file }; 131 133 } // open 132 134 … … 135 137 } // open 136 138 137 void close( ofstream & os ) with(os){138 if ( (FILE *)( file$) == 0p ) return;139 if ( (FILE *)( file$) == (FILE *)stdout || (FILE *)(file$) == (FILE *)stderr ) return;140 141 if ( fclose( (FILE *)( file$) ) == EOF ) {139 void close( ofstream & os ) { 140 if ( (FILE *)(os.file$) == 0p ) return; 141 if ( (FILE *)(os.file$) == (FILE *)stdout || (FILE *)(os.file$) == (FILE *)stderr ) return; 142 143 if ( fclose( (FILE *)(os.file$) ) == EOF ) { 142 144 throw (Close_Failure){ os }; 143 145 // abort | IO_MSG "close output" | nl | strerror( errno ); 144 146 } // if 145 file$ = 0p;147 os.file$ = 0p; 146 148 } // close 147 149 … … 175 177 } // fmt 176 178 177 inline void acquire( ofstream & os ) with(os){178 lock( lock$ ); // may increase recursive lock179 if ( ! acquired$ ) acquired$ = true; // not locked ?180 else unlock( lock$ ); // unwind recursive lock at start179 inline void acquire( ofstream & os ) { 180 lock( os.lock$ ); 181 if ( ! os.acquired$ ) os.acquired$ = true; 182 else unlock( os.lock$ ); 181 183 } // acquire 182 184 … … 185 187 } // release 186 188 187 void ?{}( osacquire & acq, ofstream & os ) { lock( os.lock$ ); &acq.os = &os; }189 void ?{}( osacquire & acq, ofstream & os ) { &acq.os = &os; lock( os.lock$ ); } 188 190 void ^?{}( osacquire & acq ) { release( acq.os ); } 189 191 … … 217 219 218 220 // private 219 void ?{}( ifstream & is, void * file ) with(is){220 file$ = file;221 nlOnOff$ = false;222 acquired$ = false;221 void ?{}( ifstream & is, void * file ) { 222 is.file$ = file; 223 is.nlOnOff$ = false; 224 is.acquired$ = false; 223 225 } // ?{} 224 226 … … 260 262 void open( ifstream & is, const char name[], const char mode[] ) { 261 263 FILE * file = fopen( name, mode ); 264 #ifdef __CFA_DEBUG__ 262 265 if ( file == 0p ) { 263 266 throw (Open_Failure){ is }; 264 267 // abort | IO_MSG "open input file \"" | name | "\"" | nl | strerror( errno ); 265 268 } // if 266 (is){ file }; // initialize 269 #endif // __CFA_DEBUG__ 270 is.file$ = file; 267 271 } // open 268 272 … … 271 275 } // open 272 276 273 void close( ifstream & is ) with(is){274 if ( (FILE *)( file$) == 0p ) return;275 if ( (FILE *)( file$) == (FILE *)stdin ) return;276 277 if ( fclose( (FILE *)( file$) ) == EOF ) {277 void close( ifstream & is ) { 278 if ( (FILE *)(is.file$) == 0p ) return; 279 if ( (FILE *)(is.file$) == (FILE *)stdin ) return; 280 281 if ( fclose( (FILE *)(is.file$) ) == EOF ) { 278 282 throw (Close_Failure){ is }; 279 283 // abort | IO_MSG "close input" | nl | strerror( errno ); 280 284 } // if 281 file$ = 0p;285 is.file$ = 0p; 282 286 } // close 283 287 … … 320 324 } // fmt 321 325 322 inline void acquire( ifstream & is ) with(is){323 lock( lock$ ); // may increase recursive lock324 if ( ! acquired$ ) acquired$ = true; // not locked ?325 else unlock( lock$ ); // unwind recursive lock at start326 inline void acquire( ifstream & is ) { 327 lock( is.lock$ ); 328 if ( ! is.acquired$ ) is.acquired$ = true; 329 else unlock( is.lock$ ); 326 330 } // acquire 327 331 … … 330 334 } // release 331 335 332 void ?{}( isacquire & acq, ifstream & is ) { lock( is.lock$ ); &acq.is = &is; }336 void ?{}( isacquire & acq, ifstream & is ) { &acq.is = &is; lock( is.lock$ ); } 333 337 void ^?{}( isacquire & acq ) { release( acq.is ); } 334 338 … … 343 347 344 348 // exception I/O constructors 345 void ?{}( Open_Failure & ex, ofstream & ostream ) with(ex) {346 virtual_table = &Open_Failure_vt;347 ostream = &ostream;348 t ag = 1;349 } // ?{} 350 351 void ?{}( Open_Failure & ex, ifstream & istream ) with(ex) {352 virtual_table = &Open_Failure_vt;353 istream = &istream;354 t ag = 0;349 void ?{}( Open_Failure & this, ofstream & ostream ) { 350 this.virtual_table = &Open_Failure_vt; 351 this.ostream = &ostream; 352 this.tag = 1; 353 } // ?{} 354 355 void ?{}( Open_Failure & this, ifstream & istream ) { 356 this.virtual_table = &Open_Failure_vt; 357 this.istream = &istream; 358 this.tag = 0; 355 359 } // ?{} 356 360 … … 359 363 360 364 // exception I/O constructors 361 void ?{}( Close_Failure & ex, ofstream & ostream ) with(ex) {362 virtual_table = &Close_Failure_vt;363 ostream = &ostream;364 t ag = 1;365 } // ?{} 366 367 void ?{}( Close_Failure & ex, ifstream & istream ) with(ex) {368 virtual_table = &Close_Failure_vt;369 istream = &istream;370 t ag = 0;365 void ?{}( Close_Failure & this, ofstream & ostream ) { 366 this.virtual_table = &Close_Failure_vt; 367 this.ostream = &ostream; 368 this.tag = 1; 369 } // ?{} 370 371 void ?{}( Close_Failure & this, ifstream & istream ) { 372 this.virtual_table = &Close_Failure_vt; 373 this.istream = &istream; 374 this.tag = 0; 371 375 } // ?{} 372 376 … … 375 379 376 380 // exception I/O constructors 377 void ?{}( Write_Failure & ex, ofstream & ostream ) with(ex) {378 virtual_table = &Write_Failure_vt;379 ostream = &ostream;380 t ag = 1;381 } // ?{} 382 383 void ?{}( Write_Failure & ex, ifstream & istream ) with(ex) {384 virtual_table = &Write_Failure_vt;385 istream = &istream;386 t ag = 0;381 void ?{}( Write_Failure & this, ofstream & ostream ) { 382 this.virtual_table = &Write_Failure_vt; 383 this.ostream = &ostream; 384 this.tag = 1; 385 } // ?{} 386 387 void ?{}( Write_Failure & this, ifstream & istream ) { 388 this.virtual_table = &Write_Failure_vt; 389 this.istream = &istream; 390 this.tag = 0; 387 391 } // ?{} 388 392 … … 391 395 392 396 // exception I/O constructors 393 void ?{}( Read_Failure & ex, ofstream & ostream ) with(ex) {394 virtual_table = &Read_Failure_vt;395 ostream = &ostream;396 t ag = 1;397 } // ?{} 398 399 void ?{}( Read_Failure & ex, ifstream & istream ) with(ex) {400 virtual_table = &Read_Failure_vt;401 istream = &istream;402 t ag = 0;397 void ?{}( Read_Failure & this, ofstream & ostream ) { 398 this.virtual_table = &Read_Failure_vt; 399 this.ostream = &ostream; 400 this.tag = 1; 401 } // ?{} 402 403 void ?{}( Read_Failure & this, ifstream & istream ) { 404 this.virtual_table = &Read_Failure_vt; 405 this.istream = &istream; 406 this.tag = 0; 403 407 } // ?{} 404 408 -
libcfa/src/fstream.hfa
r949339b r4e28d2e9 80 80 void release( ofstream & ); 81 81 82 void lock( ofstream & );83 void unlock( ofstream & );84 85 82 struct osacquire { 86 83 ofstream & os; -
libcfa/src/memory.cfa
r949339b r4e28d2e9 155 155 156 156 forall(T &) 157 T * release(unique_ptr(T) & this) {158 T * data = this.data;159 this.data = 0p;160 return data;161 }162 163 forall(T &)164 157 int ?==?(unique_ptr(T) const & this, unique_ptr(T) const & that) { 165 158 return this.data == that.data; -
libcfa/src/memory.hfa
r949339b r4e28d2e9 94 94 95 95 forall(T &) 96 T * release(unique_ptr(T) & this);97 98 forall(T &)99 96 int ?==?(unique_ptr(T) const & this, unique_ptr(T) const & that); 100 97 forall(T &) -
src/Concurrency/Keywords.cc
r949339b r4e28d2e9 1200 1200 new PointerType( 1201 1201 noQualifiers, 1202 //new TypeofType( noQualifiers, args.front()->clone() ) 1203 new TypeofType( noQualifiers, new UntypedExpr( 1204 new NameExpr( "__get_type" ), 1205 { args.front()->clone() } 1206 ) 1207 ) 1202 new TypeofType( noQualifiers, args.front()->clone() ) 1208 1203 ), 1209 1204 new ConstantExpr( Constant::from_ulong( args.size() ) ), … … 1214 1209 map_range < std::list<Initializer*> > ( args, [](Expression * var ){ 1215 1210 return new SingleInit( new UntypedExpr( 1216 new NameExpr( "__get_ptr" ),1217 { var }1211 new NameExpr( "__get_pointer" ), 1212 { var } 1218 1213 ) ); 1219 //return new SingleInit( new AddressExpr( var ) );1220 1214 }) 1221 1215 ) … … 1223 1217 1224 1218 StructInstType * lock_guard_struct = new StructInstType( noQualifiers, lock_guard_decl ); 1225 TypeExpr * lock_type_expr = new TypeExpr( 1226 new TypeofType( noQualifiers, new UntypedExpr( 1227 new NameExpr( "__get_type" ), 1228 { args.front()->clone() } 1229 ) 1230 ) 1231 ); 1219 TypeExpr * lock_type_expr = new TypeExpr( new TypeofType( noQualifiers, args.front()->clone() ) ); 1232 1220 1233 1221 lock_guard_struct->parameters.push_back( lock_type_expr ) ; -
src/Parser/parser.yy
r949339b r4e28d2e9 10 10 // Created On : Sat Sep 1 20:22:55 2001 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : S at Sep 11 08:20:44 202113 // Update Count : 50 4012 // Last Modified On : Sun Aug 8 09:14:44 2021 13 // Update Count : 5038 14 14 // 15 15 … … 2446 2446 | simple_assignment_operator initializer { $$ = $1 == OperKinds::Assign ? $2 : $2->set_maybeConstructed( false ); } 2447 2447 | '=' VOID { $$ = new InitializerNode( true ); } 2448 | '{' initializer_list_opt comma_opt '}' { $$ = new InitializerNode( $2, true ); }2449 2448 ; 2450 2449 … … 2460 2459 | designation initializer { $$ = $2->set_designators( $1 ); } 2461 2460 | initializer_list_opt ',' initializer { $$ = (InitializerNode *)( $1->set_last( $3 ) ); } 2462 | initializer_list_opt ',' designation initializer { $$ = (InitializerNode *)($1->set_last( $4->set_designators( $3 ) )); } 2461 | initializer_list_opt ',' designation initializer 2462 { $$ = (InitializerNode *)($1->set_last( $4->set_designators( $3 ) )); } 2463 2463 ; 2464 2464 -
tests/Makefile.am
r949339b r4e28d2e9 75 75 pybin/tools.py \ 76 76 long_tests.hfa \ 77 .in/parseconfig-all.txt \78 .in/parseconfig-errors.txt \79 .in/parseconfig-missing.txt \80 77 io/.in/io.data \ 81 78 io/.in/many_read.data \ … … 85 82 concurrent/clib_tls.c \ 86 83 exceptions/with-threads.hfa \ 87 exceptions/except-io.hfa \ 88 unified_locking/mutex_test.hfa 84 exceptions/except-io.hfa 89 85 90 86 dist-hook: -
tests/concurrent/mutexstmt/locks.cfa
r949339b r4e28d2e9 4 4 const unsigned int num_times = 10000; 5 5 6 single_acquisition_lock m1, m2, m3, m4, m5;6 owner_lock m1, m2, m3, m4, m5; 7 7 8 8 thread T_Mutex {}; … … 65 65 printf("Start Test: single lock mutual exclusion\n"); 66 66 { 67 T_Mutex t[1 0];67 T_Mutex t[1]; 68 68 } 69 69 printf("End Test: single lock mutual exclusion\n"); -
tools/perf/process_stat_array.py
r949339b r4e28d2e9 1 1 #!/usr/bin/python3 2 2 3 import argparse, json, math, os, sys, re 4 from PIL import Image 5 import numpy as np 3 import argparse, os, sys, re 6 4 7 5 def dir_path(string): … … 13 11 parser = argparse.ArgumentParser() 14 12 parser.add_argument('--path', type=dir_path, default=".cfadata", help= 'paste path to biog.txt file') 15 parser.add_argument('--out', type=argparse.FileType('w'), default=sys.stdout)16 13 17 14 try : … … 26 23 counters = {} 27 24 28 max_cpu = 029 min_cpu = 100000030 max_tsc = 031 min_tsc = 1844674407370955161532 33 25 #open the files 34 26 for filename in filenames: … … 39 31 with open(os.path.join(root, filename), 'r') as file: 40 32 for line in file: 41 raw = [int(x.strip()) for x in line.split(',')] 42 43 ## from/to 44 high = (raw[1] >> 32) 45 low = (raw[1] & 0xffffffff) 46 data = [me, raw[0], high, low] 47 max_cpu = max(max_cpu, high, low) 48 min_cpu = min(min_cpu, high, low) 49 50 ## number 51 # high = (raw[1] >> 8) 52 # low = (raw[1] & 0xff) 53 # data = [me, raw[0], high, low] 54 # max_cpu = max(max_cpu, low) 55 # min_cpu = min(min_cpu, low) 56 57 58 max_tsc = max(max_tsc, raw[0]) 59 min_tsc = min(min_tsc, raw[0]) 33 # data = [int(x.strip()) for x in line.split(',')] 34 data = [int(line.strip())] 35 data = [me, *data] 60 36 merged.append(data) 61 37 62 except Exception as e: 63 print(e) 38 except: 64 39 pass 65 40 66 67 print({"max-cpu": max_cpu, "min-cpu": min_cpu, "max-tsc": max_tsc, "min-tsc": min_tsc})68 41 69 42 # Sort by timestamp (the second element) … … 74 47 merged.sort(key=takeSecond) 75 48 76 json.dump({"values":merged, "max-cpu": max_cpu, "min-cpu": min_cpu, "max-tsc": max_tsc, "min-tsc": min_tsc}, args.out) 49 # for m in merged: 50 # print(m) 77 51 78 # vmin = merged[ 0][1] 79 # vmax = float(merged[-1][1] - vmin) / 2500000000.0 80 # # print(vmax) 52 single = [] 53 curr = 0 81 54 82 # bins = [] 83 # for _ in range(0, int(math.ceil(vmax * 10))): 84 # bins.append([0] * (32 * 32)) 55 # merge the data 56 # for (me, time, value) in merged: 57 for (me, value) in merged: 58 # check now much this changes 59 old = counters[me] 60 change = value - old 61 counters[me] = value 85 62 86 # # print(len(bins)) 87 # bins = np.array(bins) 63 # add change to the current 64 curr = curr + change 65 single.append( value ) 88 66 89 # rejected = 0 90 # highest = 0 67 pass 91 68 92 # for x in merged: 93 # b = int(float(x[1] - vmin) / 250000000.0) 94 # from_ = x[2] 95 # if from_ < 0 or from_ > 32: 96 # rejected += 1 97 # continue; 98 # to_ = x[3] 99 # if to_ < 0 or to_ > 32: 100 # rejected += 1 101 # continue; 102 # idx = (to_ * 32) + from_ 103 # bins[b][idx] = bins[b][idx] + 1 104 # highest = max(highest, bins[b][idx]) 105 106 # bins = np.array(map(lambda x: np.int8(x * 255.0 / float(highest)), bins)) 107 108 # print([highest, rejected]) 109 # print(bins.shape) 110 111 # im = Image.fromarray(bins) 112 # im.save('test.png') 113 114 # vmax = merged[-1][1] 115 116 # diff = float(vmax - vmin) / 2500000000.0 117 # print([vmin, vmax]) 118 # print([vmax - vmin, diff]) 119 120 # print(len(merged)) 121 122 # for b in bins: 123 # print(b) 124 125 # single = [] 126 # curr = 0 127 128 # # merge the data 129 # # for (me, time, value) in merged: 130 # for (me, value) in merged: 131 # # check now much this changes 132 # old = counters[me] 133 # change = value - old 134 # counters[me] = value 135 136 # # add change to the current 137 # curr = curr + change 138 # single.append( value ) 139 140 # pass 141 142 # print(single) 69 print(single) 143 70 144 71 # single = sorted(single)[:len(single)-100]
Note:
See TracChangeset
for help on using the changeset viewer.