求支持向流输出结果的Common Lisp计时功能实现方案
Common Lisp
time宏输出写入文件的实现方案 Common Lisp标准中time宏的输出默认绑定到动态变量*trace-output*,不需要额外引入第三方库,通过临时重绑定该变量即可完成输出落盘,具体可按需求选择以下两种方案:
方案1:直接捕获原生time输出
如果需要保留time宏的原生输出格式,只需要在执行测试代码前把*trace-output*绑定到目标文件流即可,示例如下:
;; 将time输出追加写入time-results.txt (with-open-file (*trace-output* "time-results.txt" :direction :output :if-exists :append :if-does-not-exist :create) ;; 替换为你要测试的代码 (time (loop for i from 1 to 1000000 sum i)))
如果需要同时在终端看到计时输出、同时写入文件,可以绑定广播流实现:
(with-open-file (file-stream "time-results.txt" :direction :output :if-exists :append :if-does-not-exist :create) (let ((*trace-output* (make-broadcast-stream *standard-output* file-stream))) (time (loop for i from 1 to 1000000 sum i))))
方案2:自定义结构化计时输出(更适合统计分析)
如果需要后续对计时结果做批量统计、筛选,建议自定义计时宏输出结构化的CSV格式数据,避免解析原生time的非结构化文本,SBCL环境下的示例实现如下:
(defmacro time-to-csv (csv-path test-form &optional case-desc) "执行test-form,将计时结果按CSV格式追加写入csv-path,case-desc为测试用例说明" (let ((start-real (gensym)) (start-run (gensym)) (start-gc-time (gensym)) (start-gc-count (gensym))) `(let ((,start-real (get-internal-real-time)) (,start-run (get-internal-run-time)) (,start-gc-time sb-ext:*gc-run-time*) (,start-gc-count sb-ext:*gc-count*)) (multiple-value-prog1 (,test-form) (let* ((real-sec (/ (- (get-internal-real-time) ,start-real) internal-time-units-per-second)) (run-sec (/ (- (get-internal-run-time) ,start-run) internal-time-units-per-second)) (gc-sec (/ (- sb-ext:*gc-run-time* ,start-gc-time) internal-time-units-per-second)) (gc-count (- sb-ext:*gc-count* ,start-gc-count))) (with-open-file (f ,csv-path :direction :output :if-exists :append :if-does-not-exist :create) ;; 输出格式:用例描述, 实时时间(秒), CPU时间(秒), GC时间(秒), GC次数 (format f "~S,~,4F,~,4F,~,4F,~D~%" (or ,case-desc (prin1-to-string ',test-form)) real-sec run-sec gc-sec gc-count))))))) ;; 使用示例 (time-to-csv "benchmark-results.csv" (loop for i from 1 to 1000000 sum i) "百万序列求和测试")
生成的CSV文件可以直接用Excel、Python pandas等工具导入做聚合统计、排序筛选。
注意事项
- 绝大多数主流Common Lisp实现(SBCL、CCL、ABCL等)的
time宏输出都绑定*trace-output*,小众实现如果不生效,可以查询对应实现的文档确认time的输出目标流变量。 - 自定义计时宏中的GC相关接口是SBCL专属,其他实现可以替换为对应实现提供的GC统计接口即可。
内容的提问来源于stack exchange,提问作者Dr Rama Lakshmanan
相关产品推荐
相关产品推荐

