#!/usr/bin/clisp (defun component-present-p (value) (and value (not (eql value :unspecific)))) (defun directory-pathname-p (p) (and (not (component-present-p (pathname-name p))) (not (component-present-p (pathname-type p))) p)) (defun pathname-as-directory (name) (let ((pathname (pathname name))) (when (wild-pathname-p pathname) (error "Can't reliably convert wild pathnames.")) (if (not (directory-pathname-p name)) (make-pathname :directory (append (or (pathname-directory pathname) (list :relative)) (list (file-namestring pathname))) :name nil :type nil :defaults pathname) pathname))) (defun directory-wildcard (dirname) (make-pathname :name :wild :type #-clisp :wild #+clisp nil :defaults (pathname-as-directory dirname))) #+clisp (defun clisp-subdirectories-wildcard (wildcard) (make-pathname :directory (append (pathname-directory wildcard) (list :wild)) :name nil :type nil :defaults wildcard)) (defun list-directory (dirname) (when (wild-pathname-p dirname) (error "Can only list concrete directory names.")) (let ((wildcard (directory-wildcard dirname))) #+(or sbcl cmu lispworks) (directory wildcard) #+openmcl (directory wildcard :directories t) #+allegro (directory wildcard :directories-are-files nil) #+clisp (nconc (directory wildcard) (directory (clisp-subdirectories-wildcard wildcard))) #-(or sbcl cmu lispworks openmcl allegro clisp) (error "list-directory not implemented"))) (defun walk-directory (dirname fn &key recursive directories (test (constantly t))) (let ((name (pathname-as-directory dirname))) (dolist (x (list-directory name)) (cond ((directory-pathname-p x) (when (and directories (funcall test x)) (funcall fn x) (when recursive (walk-directory x fn :recursive recursive :directories directories :test test)))) ((funcall test x) (funcall fn x)))))) (defparameter *check-type* (list "out")) (defun process_func (dir) (unless (directory-pathname-p dir) (dolist (x *check-type*) (when (equal (pathname-type dir) x) (format t "Processing: ~a ... " dir) (parse_file dir) (format t "done~%") (return))))) (defun to_number (sym) (let ((sym (char-upcase sym))) (cond ((and (char>= sym #\0) (char<= sym #\9)) (values (- (char-int sym) (char-int #\0)) t)) ((and (char>= sym #\A) (char<= sym #\F)) (values (+ (- (char-int sym) (char-int #\A)) 10) t)) (t (values 0 nil))))) (defun string_to_list (str) (let ((num 0) (ret ()) (string_len (length str))) (dotimes (i string_len) (let ((sym (elt str i))) (multiple-value-bind (n is_num) (to_number sym) (labels ((add_element () (push num ret))) (cond (is_num (setf num (+ (* num 10) n)) (when (eql i (- string_len 1)) (add_element))) (t (unless (eql num 0) (add_element) (setf num 0)))))))) (nreverse ret))) (defun make-output-name (file) (concatenate 'string (namestring file) ".data")) (defun process_string (file str numbers) (cond ((string/= str "") (let* ((check_string " KB reclen") (strlen (length check_string)) (res (STRING< check_string str))) (cond (numbers (let ((nums (string_to_list str))) (with-open-file (out (make-output-name file) :direction :output :if-exists :append) (dolist (item nums) (format out "~a " item)) (format out "~%")))) (res (when (= res strlen) (setf numbers t))) (t)))) (t (setf numbers nil))) numbers) (defparameter *first-file-p* t) (defparameter *iozone-tests* (list "filesize" "reclen" "write" "rewrite" "read" "reread" "random-read" "random-write" "bkwd-read" "record-rewrite" "stride-read" "fwrite" "frewrite" "fread" "freread")) (defmacro with-output-dir ((out pos operation dir flags) &body form) `(let ((,pos 2)) (dolist (operation (nthcdr 2 *iozone-tests*)) (let* ((dir (pathname-as-directory ,dir)) (output-file (make-pathname :directory (pathname-directory ,dir) :name operation :type "gnuplot"))) (with-open-file (,out (ENSURE-DIRECTORIES-EXIST output-file) :direction :output :if-exists ,flags) ,@form)) (incf pos)))) (defun write-gnuplot-headers (dir) (with-output-dir (out pos operation dir :supersede) (format out "set title \"Iozone performance: ~a, KB/s\"~%" operation) (format out "set terminal png small size 450 350~%") ;(format out "set logscale x~%") ;(format out "set logscale y~%") (format out "set xlabel \"Record size in KBytes\"~%") (format out "set ylabel \"Kbytes/sec\"~%") (format out "set output \"~a.png\"~%" operation) (format out "plot "))) (defun update-gnuplot-headers (dir file) (with-output-dir (out pos operation dir :append) (unless *first-file-p* (format out ", ")) (let* ((fstype (pathname-name file)) (name (make-output-name file))) (format out "\"~a\" using 2:~d title \"~a\" with lines" name (1+ pos) fstype)))) (defun write-gnuplot-footers (dir) (with-output-dir (out pos operation dir :append) (format out "~%"))) (defun parse_file (file) (with-open-file (out (make-output-name file) :direction :output :if-exists :supersede) (format out "")) (let ((numbers nil)) (with-open-file (in file :direction :input) (loop for str = (read-line in nil) while str do (setf numbers (process_string file str numbers))))) (update-gnuplot-headers *iozone-result-output-dir* file) (setf *first-file-p* nil)) (defparameter *iozone-result-dir* "/tmp/") #+clisp (when (not (null ext:*args*)) (setf *iozone-result-dir* (first ext:*args*))) (defparameter *iozone-result-output-dir* (concatenate 'string *iozone-result-dir* "/out")) (write-gnuplot-headers *iozone-result-output-dir*) (walk-directory *iozone-result-dir* 'process_func) (write-gnuplot-footers *iozone-result-output-dir*)