用于功能语言的简单时序分析器

时间:2012-08-14 18:59:47

标签: profiling ocaml

我需要一个简单的时序分析器来估计我的程序的某些部分的运行时(用OCaml编写,但我相信这可能适用于其他函数式语言),我找不到一个非常简单的解决方案,类似于什么我们可以使用timer.start / timer.stop等函数以命令式语言编写代码。所以我尝试了一个使用延迟评估的方法,它对我需要的东西很有效,但是我没有找到任何对这个方法的引用,所以我想知道这个方法是有缺陷的还是有一个更简单的解决方案。

所以,问题是:您是否了解功能语言(尤其是OCaml)的类似实现?如果是这样,请向我们表明,我想借用他们的一些想法来改善我的“穷人的探究者”(我见过this question但它对我帮助不大)。从我看到的情况来看,GHC已经有了收集时间信息的方法,因此对Haskell来说可能不是问题。

顺便说一句,我尝试按照OCaml手册(17.4)中的说明进行时序分析,但它对于我需要的东西来说太“低级”了:它在C函数级别提供了大量信息,这使得它成为可能更难以准确评估OCaml代码的哪一部分是罪魁祸首。

下面是我在OCaml中的实现(请注意,每次我想测量时间时都需要添加“lazy”表达式,但同时我可以精确控制我需要的信息量。)

open Unix (* for the timers *)

(** 'timers' associates keys (strings) to time counters, 
   to allow for multiple simultaneous measurements. *)
let timers : (string, (float * float)) Hashtbl.t = Hashtbl.create 1

(** starts the timer associated with key <name> *)
let timer_start (name : string) : unit =
  let now = Unix.times () in
  Hashtbl.replace timers name (now.tms_utime, now.tms_stime)

(** Returns time elapsed between the corresponding call to 
   timer_start and this call *)
let timer_stop (name : string) : float =
  try
    let now = Unix.times () in
    let t = Hashtbl.find timers name in
    (now.tms_utime -. fst t) +. (now.tms_stime -. snd t)
  with
    Not_found -> 0.0

(** Wrapper for the timer function using lazy evaluation *)
let time (s : string) (e : 'a Lazy.t) : 'a =
  timer_start s;
  let a = Lazy.force e in
  let t2 = timer_stop s in
  (* outputs timing information *)
  Printf.printf "TIMER,%s,%f\n" s t2; a


(** Example *)
let rec fibo n = 
  match n with
    | 0 -> 1
    | 1 -> 1
    | n' -> fibo (n - 1) + fibo (n - 2)

let main =
  let f = time "fibo" (lazy (fibo 42)) in
  Printf.printf "f = %d\n" f

2 个答案:

答案 0 :(得分:2)

Unix.times测量CPU时间,而不是挂钟时间。因此,这仅适用于将所有时间都花在CPU上的计算代码。并且不需要BTW hashtbl,即使对于多个同时测量,也只需在timer_start中返回开始时间并在timer_stop中将其减去。

答案 1 :(得分:1)

合并来自@Jeffrey_Scofield和@ygrek的想法,“最穷人的时间分析器”确实如此简单,根本不需要提及,这可以解释为什么我没有找到它。所以我合并了他们的答案并制作了一个更简单的版本:

open Unix (* for the timers *)

(* Wrapper for the timer function using a "unit -> 'a" thunk *)
let time (s : string) (e : unit -> 'a) : 'a =
  let tstart = Unix.times () in
  let a = e () in
  let tend = Unix.times () in
  let delta = (tend.tms_utime -. tstart.tms_utime) +. 
              (tend.tms_stime -. tstart.tms_stime) in
  (* outputs timing information *)
  Printf.printf "TIMER,%s,%f\n" s delta; a

(* Example *)
let rec fibo n = 
  match n with
    | 0 -> 1
    | 1 -> 1
    | n' -> fibo (n - 1) + fibo (n - 2)

let main =
  let f = time "fibo" (fun () -> fibo 42) in
  Printf.printf "f = %d\n" f