# HG changeset patch # User Steve Losh # Date 1545796044 18000 # Node ID b9239b4fe503554f30e89960d20eefa3513fa7dc # Parent f668996c206c64c8a80cd6338bad63bb5c55c1e3 Move benchmark file diff -r f668996c206c -r b9239b4fe503 src/bench.lisp --- a/src/bench.lisp Tue Dec 25 22:43:26 2018 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,165 +0,0 @@ -(in-package :conserve) - -(defparameter *field-length* 50) -(defparameter *row-length* 50) -(defparameter *data-rows* 10000) -(defparameter *data-repetitions* 10) - -(defun random-char (string) - (aref string (random (length string)))) - -(defun random-field () - (with-output-to-string (s) - (dotimes (i (random *field-length*)) - (write-char (random-char (concatenate 'string (string #\newline) - " abcdefghijklmnop,\"")) - s)))) - -(defun random-row () - (loop :repeat (1+ (random *row-length*)) :collect (random-field))) - -(defun random-data () - (loop :repeat *data-rows* :collect (random-row))) - -(defun bench-this (data) - (let* ((str (make-string-input-stream - (with-output-to-string (s) - (time (write-rows data s))))) - (result (time (read-rows str)))) - (equal data result))) - -(defun bench-cl-csv (data) - (let* ((str (make-string-input-stream - (with-output-to-string (s) - (time (cl-csv:write-csv data :stream s))))) - (result (time (cl-csv:read-csv str)))) - (equal data result))) - -(defun bench () - (let ((data (random-data))) - (write-line "MINE") - (bench-this data) - (write-line "cl-csv") - (bench-cl-csv data)) - ) - - -(defvar *data* nil) - -(defun generate-large-data () - (setf *data* (random-data))) - -(defun write-file-this () - (with-open-file (s "test/large-this.csv" - :direction :output - :if-exists :supersede) - (time - (loop :repeat *data-repetitions* :do - (write-rows *data* s))))) - -(defun write-file-cl-csv () - (with-open-file (s "test/large-cl-csv.csv" - :direction :output - :if-exists :supersede) - (time (loop :repeat *data-repetitions* :do - (cl-csv:write-csv *data* - :stream s - :newline (string #\newline)))))) -(defun write-file-fare () - (with-open-file (s "test/large-fare.csv" - :direction :output - :if-exists :supersede) - (fare-csv:with-rfc4180-csv-syntax () - (time (loop :repeat *data-repetitions* :do - (fare-csv:write-csv-lines *data* s)))))) - -(defun bench-write-file () - (write-line "Generating data.") - (time (generate-large-data)) - - (write-line "Benchmarking this (writing).") - #+sbcl (sb-ext:gc :full t) - (write-file-this) - - (write-line "Benchmarking cl-csv (writing).") - #+sbcl (sb-ext:gc :full t) - (write-file-cl-csv) - - (write-line "Benchmarking fare-csv (writing).") - #+sbcl (sb-ext:gc :full t) - (write-file-fare)) - - -(defun read-file-this () - (with-open-file (s "test/large-this.csv") - (time (loop - :with data = *data* - :for row = (read-row s nil :eof) - :for expected-row = (progn (when (null data) - (setf data *data*)) - (pop data)) - :until (eql :eof row) - :summing 1 - :do (assert (equal expected-row row)))))) - -(defun read-file-cl-csv () - (with-open-file (s "test/large-cl-csv.csv") - (let ((result 0)) - (time (handler-case - (loop - :with data = *data* - :for row = (cl-csv:read-csv-row s - :newline (string #\newline) - :trim-outer-whitespace nil) - :for expected-row = (progn (when (null data) - (setf data *data*)) - (pop data)) - :do (incf result) (assert (equal expected-row row))) - (end-of-file () result)))))) - -;; There are a couple of problems with fare-csv that make it annoying to work -;; with: -;; -;; fare-csv:read-csv-line can't tell you the difference between '("") and eof so -;; we have to check for it manually to know when we're done. This is only -;; a problem when we're reading line by line. -;; -;; fare-csv also can't roundtrip '(""). CSV itself is incapable of -;; differentiating '() and '("") unless you force quoting, but fare-csv chooses -;; '() over '(""). Why would you sell out the marginally-useful case (a 1-col -;; CSV) in favor of the utterly useless case (a 0-col CSV)? -(defun read-file-fare () - (with-open-file (s "test/large-fare.csv") - (fare-csv:with-rfc4180-csv-syntax () - (time (loop - :with data = *data* - :for eof = (peek-char nil s nil :eof) - :for row = (fare-csv:read-csv-line s) - :for expected-row = (progn (when (null data) - (setf data *data*)) - (pop data)) - :until (eql :eof eof) - :summing 1 - :do (if (equal expected-row '("")) - (assert (equal nil row)) - (assert (equal expected-row row)))))))) - -(defun bench-read-file () - (write-line "Benchmarking this (reading).") - #+sbcl (sb-ext:gc :full t) - (format t "Read ~D rows.~2%" (read-file-this)) - - (write-line "Benchmarking cl-csv (reading).") - #+sbcl (sb-ext:gc :full t) - (format t "Read ~D rows.~2%" (read-file-cl-csv)) - - (write-line "Benchmarking fare-csv (reading).") - #+sbcl (sb-ext:gc :full t) - (format t "Read ~D rows.~2%" (read-file-fare)) - - (values)) - -(defun bench-file () - (bench-write-file) - (bench-read-file)) - diff -r f668996c206c -r b9239b4fe503 test/bench.lisp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/bench.lisp Tue Dec 25 22:47:24 2018 -0500 @@ -0,0 +1,165 @@ +(in-package :conserve) + +(defparameter *field-length* 50) +(defparameter *row-length* 50) +(defparameter *data-rows* 10000) +(defparameter *data-repetitions* 10) + +(defun random-char (string) + (aref string (random (length string)))) + +(defun random-field () + (with-output-to-string (s) + (dotimes (i (random *field-length*)) + (write-char (random-char (concatenate 'string (string #\newline) + " abcdefghijklmnop,\"")) + s)))) + +(defun random-row () + (loop :repeat (1+ (random *row-length*)) :collect (random-field))) + +(defun random-data () + (loop :repeat *data-rows* :collect (random-row))) + +(defun bench-this (data) + (let* ((str (make-string-input-stream + (with-output-to-string (s) + (time (write-rows data s))))) + (result (time (read-rows str)))) + (equal data result))) + +(defun bench-cl-csv (data) + (let* ((str (make-string-input-stream + (with-output-to-string (s) + (time (cl-csv:write-csv data :stream s))))) + (result (time (cl-csv:read-csv str)))) + (equal data result))) + +(defun bench () + (let ((data (random-data))) + (write-line "MINE") + (bench-this data) + (write-line "cl-csv") + (bench-cl-csv data)) + ) + + +(defvar *data* nil) + +(defun generate-large-data () + (setf *data* (random-data))) + +(defun write-file-this () + (with-open-file (s "test/large-this.csv" + :direction :output + :if-exists :supersede) + (time + (loop :repeat *data-repetitions* :do + (write-rows *data* s))))) + +(defun write-file-cl-csv () + (with-open-file (s "test/large-cl-csv.csv" + :direction :output + :if-exists :supersede) + (time (loop :repeat *data-repetitions* :do + (cl-csv:write-csv *data* + :stream s + :newline (string #\newline)))))) +(defun write-file-fare () + (with-open-file (s "test/large-fare.csv" + :direction :output + :if-exists :supersede) + (fare-csv:with-rfc4180-csv-syntax () + (time (loop :repeat *data-repetitions* :do + (fare-csv:write-csv-lines *data* s)))))) + +(defun bench-write-file () + (write-line "Generating data.") + (time (generate-large-data)) + + (write-line "Benchmarking this (writing).") + #+sbcl (sb-ext:gc :full t) + (write-file-this) + + (write-line "Benchmarking cl-csv (writing).") + #+sbcl (sb-ext:gc :full t) + (write-file-cl-csv) + + (write-line "Benchmarking fare-csv (writing).") + #+sbcl (sb-ext:gc :full t) + (write-file-fare)) + + +(defun read-file-this () + (with-open-file (s "test/large-this.csv") + (time (loop + :with data = *data* + :for row = (read-row s nil :eof) + :for expected-row = (progn (when (null data) + (setf data *data*)) + (pop data)) + :until (eql :eof row) + :summing 1 + :do (assert (equal expected-row row)))))) + +(defun read-file-cl-csv () + (with-open-file (s "test/large-cl-csv.csv") + (let ((result 0)) + (time (handler-case + (loop + :with data = *data* + :for row = (cl-csv:read-csv-row s + :newline (string #\newline) + :trim-outer-whitespace nil) + :for expected-row = (progn (when (null data) + (setf data *data*)) + (pop data)) + :do (incf result) (assert (equal expected-row row))) + (end-of-file () result)))))) + +;; There are a couple of problems with fare-csv that make it annoying to work +;; with: +;; +;; fare-csv:read-csv-line can't tell you the difference between '("") and eof so +;; we have to check for it manually to know when we're done. This is only +;; a problem when we're reading line by line. +;; +;; fare-csv also can't roundtrip '(""). CSV itself is incapable of +;; differentiating '() and '("") unless you force quoting, but fare-csv chooses +;; '() over '(""). Why would you sell out the marginally-useful case (a 1-col +;; CSV) in favor of the utterly useless case (a 0-col CSV)? +(defun read-file-fare () + (with-open-file (s "test/large-fare.csv") + (fare-csv:with-rfc4180-csv-syntax () + (time (loop + :with data = *data* + :for eof = (peek-char nil s nil :eof) + :for row = (fare-csv:read-csv-line s) + :for expected-row = (progn (when (null data) + (setf data *data*)) + (pop data)) + :until (eql :eof eof) + :summing 1 + :do (if (equal expected-row '("")) + (assert (equal nil row)) + (assert (equal expected-row row)))))))) + +(defun bench-read-file () + (write-line "Benchmarking this (reading).") + #+sbcl (sb-ext:gc :full t) + (format t "Read ~D rows.~2%" (read-file-this)) + + (write-line "Benchmarking cl-csv (reading).") + #+sbcl (sb-ext:gc :full t) + (format t "Read ~D rows.~2%" (read-file-cl-csv)) + + (write-line "Benchmarking fare-csv (reading).") + #+sbcl (sb-ext:gc :full t) + (format t "Read ~D rows.~2%" (read-file-fare)) + + (values)) + +(defun bench-file () + (bench-write-file) + (bench-read-file)) +