1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
type stats =
  { solver_sat_time :
      Mtime.Span.t Atomic.t (* time taken by the solver to answer SAT queries *)
  ; solver_final_model_time : Mtime.Span.t Atomic.t
      (* time taken by the solver to answer final model queries at the end of execution when a bug is found *)
  ; solver_intermediate_model_time : Mtime.Span.t Atomic.t
      (* time taken by the solver to answer model queries during the execution, for instance when concretizing through `select_i32` *)
  ; path_count : int Atomic.t
  }

let empty_stats () =
  { solver_sat_time = Atomic.make Mtime.Span.min_span
  ; solver_final_model_time = Atomic.make Mtime.Span.min_span
  ; solver_intermediate_model_time = Atomic.make Mtime.Span.min_span
  ; path_count = Atomic.make 1
  }

let handle_time_span atomic_span f =
  if Log.is_bench_enabled () then
    let counter = Mtime_clock.counter () in
    (* f is supposed to take a long time! *)
    let res = f () in
    let span = Mtime_clock.count counter in
    let rec atomic_set () =
      let curr = Atomic.get atomic_span in
      let success =
        Atomic.compare_and_set atomic_span curr (Mtime.Span.add curr span)
      in
      if success then res else atomic_set ()
    in
    atomic_set ()
  else f ()

let with_utime f =
  if Log.is_bench_enabled () then
    let before = (Unix.times ()).tms_utime in
    let r = f () in
    let after = (Unix.times ()).tms_utime in
    (r, Some (after -. before))
  else (f (), None)

let percentage ~whole ~self =
  let whole = Mtime.Span.to_float_ns whole in
  let self = Mtime.Span.to_float_ns self in
  self /. whole *. 100.

let print_final ~bench_stats ~execution_time_a ~execution_time_b
  ~wait_for_all_domains =
  let execution_time =
    (* execution time shouldn't be none in bench mode *)
    let execution_time_a =
      match execution_time_a with None -> assert false | Some t -> t
    in
    (* they were both in seconds, we need to convert them to ns. *)
    let sum_ns = (execution_time_a +. execution_time_b) *. 1_000_000_000. in
    match Mtime.Span.of_float_ns sum_ns with
    | Some s -> s
    | None ->
      Log.warn (fun m -> m "Invalid time benchmarked!");
      Mtime.Span.zero
  in
  let solver_sat_time = Atomic.get bench_stats.solver_sat_time in
  let solver_final_model_time =
    Atomic.get bench_stats.solver_final_model_time
  in
  let solver_intermediate_model_time =
    Atomic.get bench_stats.solver_intermediate_model_time
  in
  let solver_model_time =
    Mtime.Span.add solver_intermediate_model_time solver_final_model_time
  in
  let solver_time = Mtime.Span.add solver_sat_time solver_model_time in
  let interpreter_time = Mtime.Span.abs_diff execution_time solver_time in

  Log.bench (fun m ->
    m "whole execution time          : %a" Mtime.Span.pp execution_time );

  Log.bench (fun m ->
    let percentage = percentage ~whole:execution_time ~self:solver_time in
    m "solver time                   : %a (%.2G%%)" Mtime.Span.pp solver_time
      percentage );
  Log.bench (fun m ->
    let percentage = percentage ~whole:execution_time ~self:solver_sat_time in
    m "solver SAT time               : %a (%.2G%%)" Mtime.Span.pp
      solver_sat_time percentage );
  Log.bench (fun m ->
    let percentage = percentage ~whole:execution_time ~self:solver_model_time in
    m "solver model time             : %a (%.2G%%)" Mtime.Span.pp
      solver_model_time percentage );
  Log.bench (fun m ->
    let percentage =
      percentage ~whole:execution_time ~self:solver_final_model_time
    in
    m "solver final model time       : %a (%.2G%%)" Mtime.Span.pp
      solver_final_model_time percentage );
  Log.bench (fun m ->
    let percentage =
      percentage ~whole:execution_time ~self:solver_intermediate_model_time
    in
    m "solver intermediate model time: %a (%.2G%%)" Mtime.Span.pp
      solver_intermediate_model_time percentage );

  Log.bench (fun m ->
    let percentage = percentage ~whole:execution_time ~self:interpreter_time in
    m "interpreter loop time         : %a (%.2G%%)" Mtime.Span.pp
      interpreter_time percentage );
  Log.bench (fun m -> m "path count: %d" (Atomic.get bench_stats.path_count));

  let solver_stats = Solver.get_all_stats ~wait_for_all_domains in
  Log.bench (fun m -> m "solver stats: %a" Solver.pp_stats solver_stats)