diff --git a/Makefile b/Makefile index d0587d790..6cb5816f0 100644 --- a/Makefile +++ b/Makefile @@ -45,8 +45,8 @@ web-docs: bench: COALTON_ENV=release sbcl --noinform \ --non-interactive \ - --eval "(ql:quickload :coalton/benchmarks :silent t)" \ - --eval "(sb-ext::without-gcing (coalton-benchmarks:run-benchmarks))" + --eval "(ql:quickload :coalton/benchmarks :silent t)" \ + --eval "(coalton-benchmarks:run-coalton-benchmarks)" .PHONY: parser-coverage parser-coverage: diff --git a/benchmarks/README.md b/benchmarking/README.md similarity index 84% rename from benchmarks/README.md rename to benchmarking/README.md index 2feb099e6..00b0bece1 100644 --- a/benchmarks/README.md +++ b/benchmarking/README.md @@ -4,4 +4,4 @@ `(in-package #:coalton-benchmarks)` -`(run-benchmarks)` \ No newline at end of file +`(run-coalton-benchmarks)` diff --git a/benchmarks/benchmarking.lisp b/benchmarking/benchmarking.lisp similarity index 51% rename from benchmarks/benchmarking.lisp rename to benchmarking/benchmarking.lisp index 20a3c8fcd..73b54abeb 100644 --- a/benchmarks/benchmarking.lisp +++ b/benchmarking/benchmarking.lisp @@ -1,7 +1,8 @@ -(defpackage #:coalton-benchmarking +(defpackage #:coalton-benchmarking/benchmarking (:use #:coalton - #:coalton-prelude) + #:coalton-prelude + #:coalton-benchmarking/printing) (:local-nicknames (#:vec #:coalton-library/vector) (#:hash #:coalton-library/hashtable) @@ -22,7 +23,14 @@ #:import-benchmarks #:reexport-benchmarks)) -(in-package #:coalton-benchmarking) +(in-package #:coalton-benchmarking/benchmarking) + +(cl:defvar *coalton-verbose-benchmarking* cl:t) + +(cl:defvar *coalton-benchmark-width* 90) + +(cl:defvar *coalton-benchmark-sci-notation* cl:t + "Coalton benchmarks should use scientific notation for times (or not).") (coalton-toplevel @@ -33,10 +41,14 @@ (code (Unit -> Unit)) (packages (Vector String))) - (declare *verbose-benchmarking* Boolean) - (define *verbose-benchmarking* + (declare verbose-benchmarking (Unit -> Boolean)) + (define (verbose-benchmarking) "This variable indicates whether benchmarks should print to the repl or just return a BenchmarkResult object." - True) + (lisp Boolean () *coalton-verbose-benchmarking*)) + + (define (benchmark-width) + "The width of the benchmark table output. Ideally should be divisible by 5." + (lisp UFix () *coalton-benchmark-width*)) (declare *benchmark-environment* (hash:Hashtable String Benchmark)) (define *benchmark-environment* @@ -47,58 +59,59 @@ (define-struct BenchmarkResults "Results from a Benchmark run." - (name String) - (iterations UFix) - (real-time Integer)) - ;; TODO: this should have cpu-time, space/bytes consed, etc. + (name String) + (iterations UFix) + (run-time UFix) + (real-time UFix) + #+sbcl + (bytes-consed UFix)) + + (declare format-time (UFix -> String)) + (define (format-time rtime) + "Converts time from microseconds to seconds then prunes down to a 10 characters." + (lisp String (rtime) + (cl:let ((control-string (cl:if *coalton-benchmark-sci-notation* + "~,4e s" + "~,7f s"))) + (cl:format cl:nil control-string (cl:/ rtime 1e6))))) - (define-instance (Into BenchmarkResults String) - (define (into (BenchmarkResults name iterations real-time)) - (lisp String (name iterations real-time) - (cl:format cl:nil "~%Benchmark Results:~%Name: ~a~%Iterations: ~a~%Real-Time: ~a ms~%" - name - iterations - real-time)))) + (define-instance (Into BenchmarkResults TableRow) + (define (into (BenchmarkResults name iterations run-time real-time #+sbcl bytes-consed)) + (TableRow (benchmark-width) (vec:make name + (format-time run-time) + (format-time real-time) + #+sbcl + (into bytes-consed) + (into iterations))))) (define-struct BenchmarkSystem (architecture String) (OS String) (lisp-impl String) - (lisp-version String)) - - (define-instance (Into BenchmarkSystem String) - (define (into (BenchmarkSystem architecture os lisp-impl lisp-version)) - (lisp String (architecture os lisp-impl lisp-version) - (cl:format cl:nil "~a, ~a, ~a ~a" - architecture - os - lisp-impl - lisp-version)))) + (lisp-version String) + (release? Boolean) + (inlining? Boolean)) (declare benchmark-system-info (Unit -> BenchmarkSystem)) (define (benchmark-system-info) - "This gathers information about your the system the benchmark is run on." + "This gathers information about the system the benchmark is run on." (BenchmarkSystem (sys:architecture) (sys:os) (sys:implementation) - (sys:lisp-version))) + (sys:lisp-version) + (lisp Boolean () + (cl:if (cl:member 'coalton-release cl:*features*) + cl:t + cl:nil)) + (lisp Boolean () + coalton-impl/settings:*coalton-heuristic-inlining*))) (define-struct PackageBenchmarkResults "This is information about a run of package benchmarks." (package-name String) (system BenchmarkSystem) - (Results (vector BenchmarkResults))) - - (define-instance (Into PackageBenchmarkResults String) - (define (into (PackageBenchmarkResults package-name system results)) - (let system-info = (as String system)) - (let result-strings = (map (fn (r) (the String (into r))) results)) - (lisp String (package-name system-info result-strings) - (cl:format cl:nil "Package Benchmark Results:~%Package: ~a~%System: ~a~%~%~%~a" - package-name - system-info - result-strings))))) + (Results (vector BenchmarkResults)))) (coalton-toplevel @@ -136,13 +149,17 @@ (declare %run-benchmark (Benchmark -> BenchmarkResults)) (define (%run-benchmark (Benchmark name iterations func _package)) + (let profile = (sys:make-profile (fn () + (for i in (iter:up-to iterations) + (func) + Unit)))) (BenchmarkResults name iterations - (snd (time (fn () - (for i in (iter:up-to iterations) - (func) - Unit)))))) + (.run-time profile) + (.real-time profile) + #+sbcl + (.bytes-consed profile))) (declare run-benchmark (String -> BenchmarkResults)) (define (run-benchmark name) @@ -151,31 +168,70 @@ (fn () (error (lisp String (name) (cl:format cl:nil "No benchmark defined by this name: ~a" name)))) (find-benchmark name)))) - (if *verbose-benchmarking* - (progn (print results) - results) - results))) + results)) + + (define (system-header-text (BenchmarkSystem architecture os lisp-impl lisp-version release inlining)) + (Tuple (lisp String (architecture os lisp-impl lisp-version) + (cl:format cl:nil "System: ~a ~a ~a~a" + architecture + os + lisp-impl + lisp-version)) + (lisp String (release inlining) + (cl:format cl:nil "Coalton ~a mode ~a heuristic inlining" + (cl:if release + "release" + "development") + (cl:if inlining + "with" + "without"))))) + + (define (column-names) + (render (TopTableRow (benchmark-width) (vec:make "Benchmark" + "Run time" + "Real time" + #+sbcl + "Bytes consed" + "# Iterations")))) + + (define (package-header name system) + (let sys = (system-header-text system)) + (let out = (vec:new)) + (vec:push! (render (TableHeader (benchmark-width) (lisp String (name) + (cl:format cl:nil "Package '~a'" + name)))) + out) + (vec:push! (render (TableHeader (benchmark-width) (fst sys))) out) + (vec:push! (render (TableHeader (benchmark-width) (snd sys))) out) + (vec:push! (column-names) out) + (as String out)) (define (run-package-benchmarks name) "Runs all benchmarks for a package" (let system = (benchmark-system-info)) - (let sys-str = (as String system)) - (when *verbose-benchmarking* - (print - (lisp String (name sys-str) - (cl:format cl:nil "Package '~a' Benchmark Results~%System:~a" - name - sys-str)))) + (when (verbose-benchmarking) + (print (package-header name system))) (let results = (vec:new)) (for b in (find-package-benchmarks name) (let res = (%run-benchmark b)) - (when *verbose-benchmarking* - (print res)) + (when (verbose-benchmarking) + (print (render (as TableRow res)))) (vec:push! (%run-benchmark b) results)) + (when (verbose-benchmarking) + (print (render (BottomEdge (benchmark-width) #+sbcl 5 #-sbcl 4)))) (PackageBenchmarkResults name system - results))) + results)) + + (define-instance (Into PackageBenchmarkResults String) + (define (into (PackageBenchmarkResults package-name system results)) + (let out = (vec:new)) + (vec:push! (package-header package-name system) out) + (for res in results + (vec:push! (render (as TableRow res)) out)) + (vec:push! (render (BottomEdge (benchmark-width) #+sbcl 5 #-sbcl 4)) out) + (as String out)))) (cl:defmacro define-benchmark (name iterations func) "Defines a Coalton benchmark" diff --git a/benchmarks/big-float.lisp b/benchmarking/benchmarks/big-float.lisp similarity index 94% rename from benchmarks/big-float.lisp rename to benchmarking/benchmarks/big-float.lisp index 8a4eef650..8bfa20f09 100644 --- a/benchmarks/big-float.lisp +++ b/benchmarking/benchmarks/big-float.lisp @@ -73,7 +73,7 @@ (let x = (into x)) (sqrt x)))) - (define (big-mult-constants n x) + (define (big-mult-const n x) (with-precision n (fn () (let x = (into x)) @@ -85,7 +85,7 @@ ;(iterations '*big-float-bench-iterations*) ;(precision (coalton (big-float-bench-precision))) (rand (cl:* (cl:- (cl:random 2)) (cl:random 100.0d0)))) - `(coalton (coalton-benchmarking::%define-benchmark ,name 1000 + `(coalton (coalton-benchmarking/benchmarking::%define-benchmark ,name 1000 (fn () (,func 10000 ,rand) @@ -100,4 +100,4 @@ (define-big-float-benchmark big-sqrt) -(define-big-float-benchmark big-mult-constants) +(define-big-float-benchmark big-mult-const) diff --git a/benchmarks/fibonacci.lisp b/benchmarking/benchmarks/fibonacci.lisp similarity index 91% rename from benchmarks/fibonacci.lisp rename to benchmarking/benchmarks/fibonacci.lisp index 764103fad..af7edd378 100644 --- a/benchmarks/fibonacci.lisp +++ b/benchmarking/benchmarks/fibonacci.lisp @@ -42,8 +42,8 @@ (coalton-toplevel - (declare fib (Integer -> Integer)) - (define (fib n) + (declare fib (Integer -> Integer)) + (define (fib n) (when (== n 0) (return 0)) @@ -84,23 +84,23 @@ ;;; Benchmarks ;;; -(define-benchmark recursive-fib 1000 +(define-benchmark rec-fib 1000 (fn () (fib 20) Unit)) -(define-benchmark recursive-fib-generic 1000 +(define-benchmark rec-fib-generic 1000 (fn () (fib-generic-wrapped 20) Unit)) -(define-benchmark recursive-fib-lisp 1000 +(define-benchmark rec-fib-lisp 1000 (fn () (lisp Unit () (lisp-fib 20) Unit))) -(define-benchmark recursive-fib-monomorphized 1000 +(define-benchmark rec-fib-mono 1000 (fn () (lisp Unit () (fib-monomorphized 20) diff --git a/benchmarks/gabriel-benchmarks/gabriel.lisp b/benchmarking/benchmarks/gabriel-benchmarks/gabriel.lisp similarity index 100% rename from benchmarks/gabriel-benchmarks/gabriel.lisp rename to benchmarking/benchmarks/gabriel-benchmarks/gabriel.lisp diff --git a/benchmarks/gabriel-benchmarks/package.lisp b/benchmarking/benchmarks/gabriel-benchmarks/package.lisp similarity index 100% rename from benchmarks/gabriel-benchmarks/package.lisp rename to benchmarking/benchmarks/gabriel-benchmarks/package.lisp diff --git a/benchmarks/gabriel-benchmarks/stak.lisp b/benchmarking/benchmarks/gabriel-benchmarks/stak.lisp similarity index 100% rename from benchmarks/gabriel-benchmarks/stak.lisp rename to benchmarking/benchmarks/gabriel-benchmarks/stak.lisp diff --git a/benchmarks/gabriel-benchmarks/tak.lisp b/benchmarking/benchmarks/gabriel-benchmarks/tak.lisp similarity index 100% rename from benchmarks/gabriel-benchmarks/tak.lisp rename to benchmarking/benchmarks/gabriel-benchmarks/tak.lisp diff --git a/benchmarks/gabriel-benchmarks/takl.lisp b/benchmarking/benchmarks/gabriel-benchmarks/takl.lisp similarity index 100% rename from benchmarks/gabriel-benchmarks/takl.lisp rename to benchmarking/benchmarks/gabriel-benchmarks/takl.lisp diff --git a/benchmarks/gabriel-benchmarks/takr.lisp b/benchmarking/benchmarks/gabriel-benchmarks/takr.lisp similarity index 100% rename from benchmarks/gabriel-benchmarks/takr.lisp rename to benchmarking/benchmarks/gabriel-benchmarks/takr.lisp diff --git a/benchmarks/package.lisp b/benchmarking/benchmarks/package.lisp similarity index 100% rename from benchmarks/package.lisp rename to benchmarking/benchmarks/package.lisp diff --git a/benchmarking/package.lisp b/benchmarking/package.lisp new file mode 100644 index 000000000..6cb037fc1 --- /dev/null +++ b/benchmarking/package.lisp @@ -0,0 +1,6 @@ +(uiop:define-package #:coalton-benchmarking + (:use #:coalton + #:coalton-prelude) + (:mix-reexport + #:coalton-benchmarking/printing + #:coalton-benchmarking/benchmarking)) diff --git a/benchmarking/printing.lisp b/benchmarking/printing.lisp new file mode 100644 index 000000000..b2d451593 --- /dev/null +++ b/benchmarking/printing.lisp @@ -0,0 +1,314 @@ +(defpackage #:coalton-benchmarking/printing + (:use + #:coalton + #:coalton-prelude) + (:local-nicknames + (#:iter #:coalton-library/iterator) + (#:vec #:coalton-library/vector) + (#:math #:coalton-library/math) + (#:str #:coalton-library/string) + (#:list #:coalton-library/list)) + (:export + #:render + + #:TopEdge + #:TopInternalEdge + #:InternalEdge + #:BottomEdge + #:TCell + + #:TableHeader + #:TableRow + #:TopTableRow + #:Table)) + +(in-package #:coalton-benchmarking/printing) + +(coalton-toplevel + + (define-class (Render :a) + (render (:a -> String)))) + +(coalton-toplevel + + (define-type BoxChar + Horizontal + Vertical + TopLeft + TopRight + TopDown + BottomLeft + BottomRight + BottomUp + LeftCross + RightCross + Cross + Newline + ;; (Whitespace UFix) + ) + + (define-type TableComponent + (TopEdge UFix) + (TopInternalEdge UFix UFix) + (InternalEdge UFix UFix) + (BottomEdge UFix UFix) + (TCell String UFix)) + + (declare %column-spacing (UFix -> UFix -> (Tuple UFix UFix))) + (define (%column-spacing width columns) + "Evenly divides the width by the number of columns. Returns the size for each column plus a leftovers for the last column." + (let ((size (math:floor/ (into width) (into columns))) + (remainder (- (into width) (* size (into columns))))) + (Tuple (math:1- (fromint size)) (fromint remainder)))) + + (declare %whitespace (UFix -> String)) + (define (%whitespace width) + "Generates whitespace with a given width." + (let space = (vec:new)) + (for i in (iter:up-to width) + (vec:push! " " space)) + (into space)) + + (declare %write-cell (String -> UFix -> String)) + (define (%write-cell text width) + ;; TODO this needs to take care of strings too long for their cell + (let ((blank (- width (str:length text))) + (offsets (Tuple (%whitespace (fromint (math:floor/ (into blank) 2))) + (%whitespace (fromint (math:ceiling/ (into blank) 2))))) + (out (vec:new))) + (vec:push! (fst offsets) out) + (vec:push! text out) + (vec:push! (snd offsets) out) + (into (the (vec:Vector String) out)))) + + + + (declare %horizontal (UFix -> String)) + (define (%horizontal width) + "Generates whitespace with a given width." + (let line = (vec:new)) + (for i in (iter:up-to width) + (vec:push! Horizontal line)) + (render line)) + + (declare %top-edge (UFix -> String)) + (define (%top-edge width) + "Generates the top-edge of a box of width `width`." + (let out = (vec:new)) + (vec:push! TopLeft out) + (for i in (iter:up-to width) + (vec:push! Horizontal out)) + (vec:push! TopRight out) + (vec:push! NewLine out) + (render out)) + + (declare %top-internal-edge (UFix -> UFix -> String)) + (define (%top-internal-edge width columns) + "Generates the top-edge of a row of width `width` divided evenly into `columns` columns" + (let ((spacing (%column-spacing width columns)) + (out (vec:new))) + (vec:push! LeftCross out) + (for j in (iter:up-to (math:1- columns)) + (for i in (iter:up-to (fst spacing)) + (vec:push! Horizontal out)) + (vec:push! TopDown out)) + (for i in (iter:up-to (+ (fst spacing) (snd spacing))) + (vec:push! Horizontal out)) + (vec:push! RightCross out) + (vec:push! NewLine out) + (render (the (vec:Vector BoxChar) out)))) + + (declare %internal-edge (UFix -> UFix -> String)) + (define (%internal-edge width columns) + "Generates the top-edge of a row of width `width` divided evenly into `columns` columns" + (let ((spacing (%column-spacing width columns)) + (out (vec:new))) + (vec:push! LeftCross out) + (for j in (iter:up-to (math:1- columns)) + (for i in (iter:up-to (fst spacing)) + (vec:push! Horizontal out)) + (vec:push! Cross out)) + (for i in (iter:up-to (+ (fst spacing) (snd spacing))) + (vec:push! Horizontal out)) + (vec:push! RightCross out) + (vec:push! NewLine out) + (render (the (vec:Vector BoxChar) out)))) + + (declare %bottom-edge (UFix -> UFix -> String)) + (define (%bottom-edge width columns) + "Generates the top-edge of a row of width `width` divided evenly into `columns` columns" + (let ((spacing (%column-spacing width columns)) + (out (vec:new))) + (vec:push! BottomLeft out) + (for j in (iter:up-to (math:1- columns)) + (for i in (iter:up-to (fst spacing)) + (vec:push! Horizontal out)) + (vec:push! BottomUp out)) + (for i in (iter:up-to (+ (fst spacing) (snd spacing))) + (vec:push! Horizontal out)) + (vec:push! BottomRight out) + (vec:push! NewLine out) + (render (the (vec:Vector BoxChar) out)))) + + (declare %write-row (UFix -> (vec:Vector String) -> String)) + (define (%write-row width column-texts) + (let ((columns (vec:length column-texts)) + (spacing (%column-spacing width columns)) + (out (the (vec:Vector String) (vec:new)))) + (vec:push! (render (InternalEdge width columns)) out) + (vec:push! (render Vertical) out) + (for txt in column-texts + (vec:push! (%write-cell txt (fst spacing)) out) + (vec:push! (render Vertical) out)) + (vec:push! (render NewLine) out) + (into out))) + + (declare %write-top-row (UFix -> (vec:Vector String) -> String)) + (define (%write-top-row width column-texts) + (let ((columns (vec:length column-texts)) + (spacing (%column-spacing width columns)) + (out (the (vec:Vector String) (vec:new)))) + (vec:push! (render (TopInternalEdge width columns)) out) + (vec:push! (render Vertical) out) + (for txt in column-texts + (vec:push! (%write-cell txt (fst spacing)) out) + (vec:push! (render Vertical) out)) + (vec:push! (render NewLine) out) + (into out))) + + (define-instance (Render TableComponent) + (define (render tc) + (match tc + ((TopEdge width) + (%top-edge width)) + ((TopInternalEdge width columns) + (%top-internal-edge width columns)) + ((InternalEdge width columns) + (%internal-edge width columns)) + ((BottomEdge width columns) + (%bottom-edge width columns)) + ((TCell text width) + (%write-cell text width))))) + + (define-instance (Render BoxChar) + (define (render bc) + (match bc + ((Horizontal) "─") + ((Vertical) "│") + ((TopLeft) "┌") + ((TopRight) "┐") + ((TopDown) "┬") + ((BottomLeft) "└") + ((BottomRight) "┘") + ((BottomUp) "┴") + ((Cross) "┼") + ((LeftCross) "├") + ((RightCross) "┤") + ((Newline) " +")))) + + (define-instance (Render (List BoxChar)) + (define (render bcs) + (into (map render bcs)))) + + (define-instance (Render (vec:Vector BoxChar)) + (define (render bcs) + (into (map render bcs))))) + + + +(coalton-toplevel + + (define-struct TableHeader + (Width "The width of the TableHeader" UFix) + (text "The text of the tableHeader" String)) + + (define-struct TableRow + (width UFix) + (column-contents (vec:Vector String))) + + (define-struct TopTableRow + (width UFix) + (column-contents (vec:Vector String))) + + (define-instance (Render TableRow) + (define (render (TableRow width contents)) + (%write-row width contents))) + + (define-instance (Render TopTableRow) + (define (render (TopTableRow width contents)) + (%write-top-row width contents))) + + (define-instance (Render TableHeader) + (define (render (TableHeader width text)) + (let ((blank (the Integer (into (- width (str:length text))))) + (offsets (Tuple (%whitespace (fromint (math:floor/ blank 2))) + (%whitespace (fromint (math:ceiling/ blank 2))))) + (out (the (vec:Vector String) (vec:new)))) + (vec:push! (%top-edge (math:1- width)) out) + (vec:push! (render Vertical) out) + (vec:push! (render (TCell text (math:1- width))) out) + (vec:push! (render Vertical) out) + (vec:push! (render NewLine) out) + (into out)))) + + (define (test-explicit-table) + (print (render (TableHeader 75 "Rick Astley Lyrics"))) + (print (render (TopTableRow 75 (vec:make "Never" "Gonna" "Give" "You" "Up")))) + (print (render (TableRow 75 (vec:make "Never" "Gonna" "Let" "You" "Down")))) + (print (render (TableRow 75 (vec:make "" "" "" "" "")))) + (print (render (BottomEdge 75 5)))) + + + (define-struct Table + (width UFix) + (columns UFix) + (header (Optional String)) + (column-names (vec:Vector String)) + (row-data (vec:Vector (vec:Vector String)))) + + (define-instance (Render Table) + (define (render (Table width columns header cnames rows)) + (let out = (vec:new)) + (unwrap-or-else + (fn (h) + (vec:push! (render (TableHeader width h)) out)) + (fn () + (vec:push! (%top-edge width) out)) + header) + (vec:push! (render (TopTableRow width cnames)) out) + ;; (vec:push! (%internal-edge width columns) out) + (for r in rows + (vec:push! (render (TableRow width r)) out)) + (vec:push! (%bottom-edge width columns) out) + (into out))) + + + (define (test-table) + (print (render + (Table + 80 + 5 + (Some "Rick Astley Lyrics") + (vec:make "" "Each" "Lyric" "is" "Here") + (vec:make (vec:make "Never" "Gonna" "Give" "You" "Up") + (vec:make "" "" "" "" "") + (vec:make "Never" "Gonna" "Let" "You" "Down")))))) + + ;; truncate string- make sure string is less than the possible width + + + + + #+ig(define-struct Table + (header (Optional TableHeader)) + (rows (Vector TableRow)) + ;(columns "The number of columns." UFix) + ;(column-names "The names of each column" (List String)) + ) + + + + + ) + diff --git a/coalton.asd b/coalton.asd index 0a912be14..0730e00c8 100644 --- a/coalton.asd +++ b/coalton.asd @@ -138,9 +138,11 @@ :license "MIT" :version (:read-file-form "VERSION.txt") :depends-on (#:coalton) - :pathname "benchmarks" + :pathname "benchmarking" :serial t - :components ((:file "benchmarking"))) + :components ((:file "printing") + (:file "benchmarking") + (:file "package"))) (asdf:defsystem #:coalton/benchmarks :author "Coalton contributors (https://github.com/coalton-lang/coalton)" @@ -153,7 +155,7 @@ :depends-on (#:coalton #:coalton/library/big-float #:coalton/benchmarking) - :pathname "benchmarks" + :pathname "benchmarking/benchmarks" :serial t :components ((:file "fibonacci") (:file "big-float") diff --git a/library/string.lisp b/library/string.lisp index e2e7fb6ca..7c22aa3a7 100644 --- a/library/string.lisp +++ b/library/string.lisp @@ -195,6 +195,16 @@ does not have that suffix." (lisp String (lst) (cl:coerce lst 'cl:string)))) + (define-instance (Into (List String) String) + (define (into strs) + (lisp String (strs) + (cl:format cl:nil "~{~a~}" strs)))) + + (define-instance (Into (Vector String) String) + (define (into strs) + (lisp String (strs) + (cl:format cl:nil "~{~a~}" (cl:coerce strs 'cl:list))))) + (define-instance (Iso (List Char) String))) (define-instance-into-integral-string Integer) diff --git a/library/system.lisp b/library/system.lisp index e817d5898..0351263e1 100644 --- a/library/system.lisp +++ b/library/system.lisp @@ -8,6 +8,12 @@ #:time #:sleep) (:export + #:get-real-time + #:get-run-time + #+sbcl #:get-bytes-consed + #:Profile + #:make-profile) + (:export #:LispCondition @@ -33,6 +39,7 @@ (cl:declaim #.coalton-impl/settings:*coalton-optimize-library*) (coalton-toplevel + (declare gc (Unit -> Unit)) (define (gc _) "Perform a full garbage collection." @@ -63,6 +70,53 @@ While the result will always contain microseconds, some implementations may retu Unit))) ;;; +;;; Pofiling +;;; + +(coalton-toplevel + + (declare get-run-time (Unit -> UFix)) + (define (get-run-time) + (lisp UFix () + (cl:get-internal-run-time))) + + (declare get-real-time (Unit -> UFix)) + (define (get-real-time) + (lisp UFix () + (cl:get-internal-real-time))) + + #+sbcl + (declare get-bytes-consed (Unit -> UFix)) + #+sbcl + (define (get-bytes-consed) + (lisp UFix () + (sb-ext:get-bytes-consed))) + + (define-struct (Profile :a) + (output :a) + (run-time UFix) + (real-time UFix) + #+sbcl + (bytes-consed UFix)) + + (declare make-profile ((Unit -> :a) -> (Profile :a))) + (define (make-profile f) + (gc) + (let (#+sbcl + (start-bytes-consed (get-bytes-consed)) + (start-run-time (get-run-time)) + (start-real-time (get-real-time)) + (value (f)) + #+sbcl (end-bytes-consed (get-bytes-consed)) + (end-run-time (get-run-time)) + (end-real-time (get-real-time))) + (Profile + value + (- end-run-time start-run-time) + (- end-real-time start-real-time) + #+sbcl + (- end-bytes-consed start-bytes-consed))))) +;;; ;;; Gathering System information ;;;