https://gitlab.com/tezos/tezos
Raw File
Tip revision: 5d2b54869adbb19d8ef2ef6ef351d18f45f86070 authored by Frej Soya on 06 September 2022, 13:03:36 UTC
fixup! Snoop: quick tmp fix for early crash.
Tip revision: 5d2b548
translator_benchmarks.ml
(*****************************************************************************)
(*                                                                           *)
(* Open Source License                                                       *)
(* Copyright (c) 2021-2022 Nomadic Labs, <contact@nomadic-labs.com>          *)
(*                                                                           *)
(* Permission is hereby granted, free of charge, to any person obtaining a   *)
(* copy of this software and associated documentation files (the "Software"),*)
(* to deal in the Software without restriction, including without limitation *)
(* the rights to use, copy, modify, merge, publish, distribute, sublicense,  *)
(* and/or sell copies of the Software, and to permit persons to whom the     *)
(* Software is furnished to do so, subject to the following conditions:      *)
(*                                                                           *)
(* The above copyright notice and this permission notice shall be included   *)
(* in all copies or substantial portions of the Software.                    *)
(*                                                                           *)
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  *)
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL   *)
(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING   *)
(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER       *)
(* DEALINGS IN THE SOFTWARE.                                                 *)
(*                                                                           *)
(*****************************************************************************)

open Protocol
module Size = Gas_input_size

(** {2 [Script_ir_translator] benchmarks} *)

module Config = struct
  type config = {
    generator_config : Michelson_generation.generator_config;
    michelson_terms_file : string option;
  }

  let default_config =
    {
      generator_config = Michelson_generation.default_generator_config;
      michelson_terms_file = None;
    }

  let config_encoding =
    let open Data_encoding in
    conv
      (fun {generator_config; michelson_terms_file} ->
        (generator_config, michelson_terms_file))
      (fun (generator_config, michelson_terms_file) ->
        {generator_config; michelson_terms_file})
      (obj2
         (req "generator_config" Michelson_generation.generator_config_encoding)
         (opt "michelson_terms_file" string))
end

module Default_boilerplate = struct
  type workload = Translator_workload.t

  let workload_encoding = Translator_workload.encoding

  let workload_to_vector = Translator_workload.workload_to_sparse_vec

  let tags = [Tags.translator]

  let make_models t_kind code_or_data =
    [
      ( "gas_translator_model",
        Translator_model.gas_based_model t_kind code_or_data );
      ( "size_translator_model",
        Translator_model.size_based_model t_kind code_or_data );
    ]
end

(* ----------------------------------------------------------------------- *)
(* Error handling *)

type phase = Workload_production | In_protocol | Global

type error_kind =
  | Global_error of {
      benchmark_name : string;
      workload : Tezos_base.TzPervasives.tztrace;
    }
  | Bad_data of {
      benchmark_name : string;
      micheline : Alpha_context.Script.expr;
      expected_type : Alpha_context.Script.expr;
      phase : phase;
    }
  | Bad_code of {
      benchmark_name : string;
      micheline : Alpha_context.Script.expr;
      expected_stack_type : Alpha_context.Script.expr list;
      phase : phase;
    }

let pp_phase fmtr (phase : phase) =
  match phase with
  | Workload_production -> Format.fprintf fmtr "workload production"
  | In_protocol -> Format.fprintf fmtr "in protocol"
  | Global -> Format.fprintf fmtr "global"

let report_michelson_errors fmtr errs =
  Michelson_v1_error_reporter.report_errors
    ~details:true
    ~show_source:true
    fmtr
    errs

let make_printable node =
  Micheline_printer.printable Michelson_v1_primitives.string_of_prim node

let pp_error_kind fmtr (error_kind : error_kind) =
  match error_kind with
  | Global_error {benchmark_name; workload} ->
      Format.open_vbox 1 ;
      Format.fprintf fmtr "Global error:@," ;
      Format.fprintf fmtr "benchmark = %s@," benchmark_name ;
      Format.fprintf fmtr "workload:@," ;
      report_michelson_errors fmtr workload ;
      Format.close_box ()
  | Bad_data {benchmark_name; micheline; expected_type; phase} ->
      Format.open_vbox 1 ;
      Format.fprintf fmtr "Bad data:@," ;
      Format.fprintf fmtr "benchmark = %s@," benchmark_name ;
      Format.fprintf
        fmtr
        "expression = @[<v 1>%a@]@,"
        Micheline_printer.print_expr
        (make_printable micheline) ;
      Format.fprintf
        fmtr
        "expected type = @[<v 1>%a@]@,"
        Micheline_printer.print_expr
        (make_printable expected_type) ;
      Format.fprintf fmtr "phase = %a@," pp_phase phase ;
      Format.close_box ()
  | Bad_code {benchmark_name; micheline; expected_stack_type; phase} ->
      Format.open_vbox 1 ;
      Format.fprintf fmtr "Bad code:@," ;
      Format.fprintf fmtr "benchmark = %s@," benchmark_name ;
      Format.fprintf
        fmtr
        "expression = @[<v 1>%a@]@,"
        Micheline_printer.print_expr
        (make_printable micheline) ;
      Format.fprintf
        fmtr
        "expected stack = @[<v 1>%a@]@,"
        (Format.pp_print_list
           ~pp_sep:(fun fmtr () -> Format.fprintf fmtr "::")
           (fun fmtr node ->
             let printable = make_printable node in
             Format.fprintf fmtr "%a" Micheline_printer.print_expr printable))
        expected_stack_type ;
      Format.fprintf fmtr "phase = %a@," pp_phase phase ;
      Format.close_box ()

exception Translator_benchmark_error of error_kind

let () =
  Printexc.register_printer (function
      | Translator_benchmark_error err ->
          Some (Format.asprintf "%a" pp_error_kind err)
      | _ -> None)

let global_error benchmark_name workload =
  raise (Translator_benchmark_error (Global_error {benchmark_name; workload}))

let bad_data benchmark_name micheline expected_type phase =
  raise
    (Translator_benchmark_error
       (Bad_data {benchmark_name; micheline; expected_type; phase}))

let bad_code benchmark_name micheline expected_stack_type phase =
  raise
    (Translator_benchmark_error
       (Bad_code {benchmark_name; micheline; expected_stack_type; phase}))

(* ----------------------------------------------------------------------- *)
(* Typechecking data (Micheline data -> typed data) *)

let strict = Script_ir_translator_config.make ~legacy:false ()

module Typechecking_data : Benchmark.S = struct
  include Config
  include Default_boilerplate

  let models = make_models Translator_workload.Parsing Translator_workload.Data

  let name = "TYPECHECKING_DATA"

  let info = "Benchmarking typechecking of data"

  let typechecking_data_benchmark rng_state (node : Protocol.Script_repr.expr)
      (michelson_type : Script_repr.expr) =
    Lwt_main.run
      ( Execution_context.make ~rng_state >>=? fun (ctxt, _) ->
        let ex_ty = Type_helpers.michelson_type_to_ex_ty michelson_type ctxt in
        let workload =
          match
            Translator_workload.data_typechecker_workload
              ctxt
              Translator_workload.Parsing
              (Micheline.root node)
              ex_ty
          with
          | None -> bad_data name node michelson_type Workload_production
          | Some workload -> workload
        in
        match ex_ty with
        | Script_typed_ir.Ex_ty ty ->
            let closure () =
              match
                Lwt_main.run
                  (Script_ir_translator.parse_data
                     ctxt
                     ~elab_conf:strict
                     ~allow_forged:false
                     ty
                     (Micheline.root node))
              with
              | Error _ | (exception _) ->
                  bad_data name node michelson_type In_protocol
              | Ok _ -> ()
            in
            return (Generator.Plain {workload; closure}) )
    |> function
    | Ok closure -> closure
    | Error errs -> global_error name errs

  let make_bench rng_state cfg () =
    let Michelson_mcmc_samplers.{term; typ} =
      Michelson_generation.make_data_sampler rng_state cfg.generator_config
    in
    typechecking_data_benchmark rng_state term typ

  let create_benchmarks ~rng_state ~bench_num config =
    match config.michelson_terms_file with
    | Some file ->
        Format.eprintf "Loading terms from %s@." file ;
        let terms = Michelson_mcmc_samplers.load ~filename:file in
        List.filter_map
          (function
            | Michelson_mcmc_samplers.Data {term; typ} ->
                Some (fun () -> typechecking_data_benchmark rng_state term typ)
            | _ -> None)
          terms
    | None ->
        Format.eprintf "No michelson_terms_file given, generating on-the-fly@." ;
        List.repeat bench_num (make_bench rng_state config)
end

let () = Registration_helpers.register (module Typechecking_data)

module Unparsing_data : Benchmark.S = struct
  include Config
  include Default_boilerplate

  let models =
    make_models Translator_workload.Unparsing Translator_workload.Data

  let name = "UNPARSING_DATA"

  let info = "Benchmarking unparsing of data"

  let unparsing_data_benchmark rng_state (node : Protocol.Script_repr.expr)
      (michelson_type : Protocol.Script_repr.expr) =
    Lwt_main.run
      ( Execution_context.make ~rng_state >>=? fun (ctxt, _) ->
        let ex_ty = Type_helpers.michelson_type_to_ex_ty michelson_type ctxt in
        let workload =
          match
            Translator_workload.data_typechecker_workload
              ctxt
              Translator_workload.Unparsing
              (Micheline.root node)
              ex_ty
          with
          | None -> bad_data name node michelson_type Workload_production
          | Some workload -> workload
        in
        match ex_ty with
        | Script_typed_ir.Ex_ty ty ->
            Script_ir_translator.parse_data
              ctxt
              ~elab_conf:strict
              ~allow_forged:false
              ty
              (Micheline.root node)
            >|= Environment.wrap_tzresult
            >>=? fun (typed, ctxt) ->
            let closure () =
              match
                Lwt_main.run
                  (Script_ir_translator.unparse_data
                     ctxt
                     Script_ir_unparser.Optimized
                     ty
                     typed)
              with
              | Error _ | (exception _) ->
                  bad_data name node michelson_type In_protocol
              | Ok _ -> ()
            in
            return (Generator.Plain {workload; closure}) )
    |> function
    | Ok closure -> closure
    | Error errs -> global_error name errs

  let make_bench rng_state cfg () =
    let Michelson_mcmc_samplers.{term; typ} =
      Michelson_generation.make_data_sampler rng_state cfg.generator_config
    in
    unparsing_data_benchmark rng_state term typ

  let create_benchmarks ~rng_state ~bench_num config =
    match config.michelson_terms_file with
    | Some file ->
        Format.eprintf "Loading terms from %s@." file ;
        let terms = Michelson_mcmc_samplers.load ~filename:file in
        List.filter_map
          (function
            | Michelson_mcmc_samplers.Data {term; typ} ->
                Some (fun () -> unparsing_data_benchmark rng_state term typ)
            | _ -> None)
          terms
    | None ->
        Format.eprintf "No michelson_terms_file given, generating on-the-fly@." ;
        List.repeat bench_num (make_bench rng_state config)
end

let () = Registration_helpers.register (module Unparsing_data)

module Typechecking_code : Benchmark.S = struct
  include Config
  include Default_boilerplate

  let models = make_models Translator_workload.Parsing Translator_workload.Code

  let name = "TYPECHECKING_CODE"

  let info = "Benchmarking typechecking of code"

  let typechecking_code_benchmark rng_state (node : Protocol.Script_repr.expr)
      (stack : Script_repr.expr list) =
    Lwt_main.run
      ( Execution_context.make ~rng_state >>=? fun (ctxt, _) ->
        let ex_stack_ty =
          Type_helpers.michelson_type_list_to_ex_stack_ty stack ctxt
        in
        let workload =
          match
            Translator_workload.code_typechecker_workload
              ctxt
              Translator_workload.Parsing
              (Micheline.root node)
              ex_stack_ty
          with
          | None -> bad_code name node stack Workload_production
          | Some workload -> workload
        in
        let (Script_ir_translator.Ex_stack_ty bef) = ex_stack_ty in
        let closure () =
          let result =
            Lwt_main.run
              (Script_ir_translator.parse_instr
                 Script_tc_context.data
                 ctxt
                 ~elab_conf:strict
                 (Micheline.root node)
                 bef)
          in
          match Environment.wrap_tzresult result with
          | Error errs ->
              Format.eprintf "%a@." Error_monad.pp_print_trace errs ;
              bad_code name node stack In_protocol
          | Ok _ -> ()
        in
        return (Generator.Plain {workload; closure}) )
    |> function
    | Ok closure -> closure
    | Error errs -> global_error name errs

  let make_bench rng_state (cfg : Config.config) () =
    let open Michelson_generation in
    let Michelson_mcmc_samplers.{term; bef; aft = _} =
      make_code_sampler rng_state cfg.generator_config
    in
    typechecking_code_benchmark rng_state term bef

  let create_benchmarks ~rng_state ~bench_num config =
    match config.michelson_terms_file with
    | Some file ->
        Format.eprintf "Loading terms from %s@." file ;
        let terms = Michelson_mcmc_samplers.load ~filename:file in
        List.filter_map
          (function
            | Michelson_mcmc_samplers.Code {term; bef; aft = _} ->
                Some (fun () -> typechecking_code_benchmark rng_state term bef)
            | _ -> None)
          terms
    | None ->
        Format.eprintf "No michelson_terms_file given, generating on-the-fly@." ;
        List.repeat bench_num (make_bench rng_state config)
end

let () = Registration_helpers.register (module Typechecking_code)

module Unparsing_code : Benchmark.S = struct
  include Config
  include Default_boilerplate

  let models =
    make_models Translator_workload.Unparsing Translator_workload.Code

  let name = "UNPARSING_CODE"

  let info = "Benchmarking unparsing of code"

  let unparsing_code_benchmark rng_state (node : Protocol.Script_repr.expr)
      (stack : Script_repr.expr list) =
    Lwt_main.run
      ( Execution_context.make ~rng_state >>=? fun (ctxt, _) ->
        let ex_stack_ty =
          Type_helpers.michelson_type_list_to_ex_stack_ty stack ctxt
        in
        let workload =
          match
            Translator_workload.code_typechecker_workload
              ctxt
              Translator_workload.Unparsing
              (Micheline.root node)
              ex_stack_ty
          with
          | None -> bad_code name node stack Workload_production
          | Some workload -> workload
        in
        let (Script_ir_translator.Ex_stack_ty bef) = ex_stack_ty in
        (* We parse the code just to check it is well-typed. *)
        Script_ir_translator.parse_instr
          Script_tc_context.data
          ctxt
          ~elab_conf:strict
          (Micheline.root node)
          bef
        >|= Environment.wrap_tzresult
        >>=? fun (_typed, ctxt) ->
        let closure () =
          let result =
            Lwt_main.run
              (Script_ir_translator.unparse_code
                 ctxt
                 Optimized
                 (Micheline.root node))
          in
          match Environment.wrap_tzresult result with
          | Error errs ->
              Format.eprintf "%a@." Error_monad.pp_print_trace errs ;
              bad_code name node stack In_protocol
          | Ok _ -> ()
        in
        return (Generator.Plain {workload; closure}) )
    |> function
    | Ok closure -> closure
    | Error errs -> global_error name errs

  let make_bench rng_state (cfg : Config.config) () =
    let open Michelson_generation in
    let Michelson_mcmc_samplers.{term; bef; aft = _} =
      make_code_sampler rng_state cfg.generator_config
    in
    unparsing_code_benchmark rng_state term bef

  let create_benchmarks ~rng_state ~bench_num config =
    match config.michelson_terms_file with
    | Some file ->
        Format.eprintf "Loading terms from %s@." file ;
        let terms = Michelson_mcmc_samplers.load ~filename:file in
        List.filter_map
          (function
            | Michelson_mcmc_samplers.Code {term; bef; aft = _} ->
                Some (fun () -> unparsing_code_benchmark rng_state term bef)
            | _ -> None)
          terms
    | None -> List.repeat bench_num (make_bench rng_state config)
end

let () = Registration_helpers.register (module Unparsing_code)

let rec check_printable_ascii v i =
  if Compare.Int.(i < 0) then true
  else
    match v.[i] with
    | '\n' | '\x20' .. '\x7E' -> check_printable_ascii v (i - 1)
    | _ -> false

let check_printable_benchmark =
  let open Tezos_shell_benchmarks.Encoding_benchmarks_helpers in
  linear_shared
    ~name:"CHECK_PRINTABLE"
    ~generator:(fun rng_state ->
      let open Base_samplers in
      let string =
        readable_ascii_string rng_state ~size:{min = 1; max = 1024}
      in
      (string, {Shared_linear.bytes = String.length string}))
    ~make_bench:(fun generator () ->
      let generated, workload = generator () in
      let closure () =
        ignore (check_printable_ascii generated (String.length generated - 1))
      in
      Generator.Plain {workload; closure})
    ()

let () = Registration_helpers.register check_printable_benchmark

module Ty_eq : Benchmark.S = struct
  type config = {max_size : int}

  let config_encoding =
    let open Data_encoding in
    conv
      (fun {max_size} -> max_size)
      (fun max_size -> {max_size})
      (obj1 (req "max_size" int31))

  let default_config = {max_size = 64}

  type workload = Ty_eq_workload of {nodes : int; consumed : Size.t}

  let workload_encoding =
    let open Data_encoding in
    conv
      (function Ty_eq_workload {nodes; consumed} -> (nodes, consumed))
      (fun (nodes, consumed) -> Ty_eq_workload {nodes; consumed})
      (obj2 (req "nodes" int31) (req "consumed" int31))

  let workload_to_vector = function
    | Ty_eq_workload {nodes; consumed} ->
        Sparse_vec.String.of_list
          [("nodes", float_of_int nodes); ("consumed", float_of_int consumed)]

  let name = "TY_EQ"

  let info = "Benchmarking equating types"

  let tags = [Tags.translator]

  let intercept_var = Free_variable.of_string (Format.asprintf "%s_const" name)

  let coeff_var = Free_variable.of_string (Format.asprintf "%s_coeff" name)

  let size_model =
    Model.make
      ~conv:(function Ty_eq_workload {nodes; _} -> (nodes, ()))
      ~model:
        (Model.affine_split_const
           ~intercept1:Builtin_benchmarks.timer_variable
           ~intercept2:intercept_var
           ~coeff:coeff_var)

  let codegen_model =
    Model.make
      ~conv:(function Ty_eq_workload {nodes; _} -> (nodes, ()))
      ~model:(Model.affine ~intercept:intercept_var ~coeff:coeff_var)

  let () =
    Registration_helpers.register_for_codegen
      name
      (Model.For_codegen codegen_model)

  let models =
    [("size_translator_model", size_model); ("codegen", codegen_model)]

  let ty_eq_benchmark rng_state nodes (ty : Script_typed_ir.ex_ty) =
    Lwt_main.run
      ( Execution_context.make ~rng_state >>=? fun (ctxt, _) ->
        let ctxt = Gas_helpers.set_limit ctxt in
        match ty with
        | Ex_ty ty ->
            let dummy_loc = 0 in
            Lwt.return
              (Gas_monad.run ctxt
              @@ Script_ir_translator.ty_eq
                   ~error_details:(Informative dummy_loc)
                   ty
                   ty)
            >|= Environment.wrap_tzresult
            >>=? fun (_, ctxt') ->
            let consumed =
              Alpha_context.Gas.consumed ~since:ctxt ~until:ctxt'
            in
            let workload =
              Ty_eq_workload
                {nodes; consumed = Z.to_int (Gas_helpers.fp_to_z consumed)}
            in
            let closure () =
              ignore
                (Gas_monad.run ctxt
                @@ Script_ir_translator.ty_eq
                     ~error_details:(Informative dummy_loc)
                     ty
                     ty)
            in
            return (Generator.Plain {workload; closure}) )
    |> function
    | Ok closure -> closure
    | Error errs -> global_error name errs

  let make_bench rng_state (cfg : config) () =
    let nodes =
      Base_samplers.(
        sample_in_interval ~range:{min = 1; max = cfg.max_size} rng_state)
    in
    let ty =
      Michelson_generation.Samplers.Random_type.m_type ~size:nodes rng_state
    in
    ty_eq_benchmark rng_state nodes ty

  let create_benchmarks ~rng_state ~bench_num config =
    List.repeat bench_num (make_bench rng_state config)
end

let () = Registration_helpers.register (module Ty_eq)

(* A dummy type generator, sampling linear terms of a given size.
   The generator always returns types of the shape:

   [pair unit (pair unit (pair unit ...))]

   This structure is the worse-case of the unparsing function for types because
   an extra test is performed to determine if the comb type needs to be folded.
*)
let rec dummy_type_generator size =
  let open Script_typed_ir in
  if size <= 1 then Ex_ty unit_t
  else
    match dummy_type_generator (size - 2) with
    | Ex_ty r -> (
        let l = unit_t in
        match pair_t (-1) l r with
        | Error _ -> assert false
        | Ok (Ty_ex_c t) -> Ex_ty t)

(* A dummy comparable type generator, sampling linear terms of a given size. *)
let rec dummy_comparable_type_generator size =
  let open Script_ir_translator in
  let open Script_typed_ir in
  if size <= 0 then Ex_comparable_ty unit_t
  else
    match dummy_comparable_type_generator (size - 2) with
    | Ex_comparable_ty r ->
        let l = unit_t in
        Ex_comparable_ty
          (match comparable_pair_t (-1) l r with
          | Error _ -> assert false
          | Ok t -> t)

module Parse_type_shared = struct
  type config = {max_size : int}

  let default_config = {max_size = Constants_repr.michelson_maximum_type_size}

  let config_encoding =
    let open Data_encoding in
    conv
      (fun {max_size} -> max_size)
      (fun max_size -> {max_size})
      (obj1 (req "max_size" int31))

  type workload = Type_workload of {nodes : int; consumed : Size.t}

  let workload_encoding =
    let open Data_encoding in
    conv
      (function Type_workload {nodes; consumed} -> (nodes, consumed))
      (fun (nodes, consumed) -> Type_workload {nodes; consumed})
      (obj2 (req "nodes" int31) (req "consumed" int31))

  let workload_to_vector = function
    | Type_workload {nodes; consumed} ->
        Sparse_vec.String.of_list
          [("nodes", float_of_int nodes); ("consumed", float_of_int consumed)]

  let tags = [Tags.translator]
end

let parse_ty ctxt node =
  Script_ir_translator.parse_ty
    ctxt
    ~legacy:true
    ~allow_lazy_storage:true
    ~allow_operation:true
    ~allow_contract:true
    ~allow_ticket:true
    node

let unparse_ty ctxt ty = Script_ir_unparser.unparse_ty ~loc:(-1) ctxt ty

module Parse_type_benchmark : Benchmark.S = struct
  include Parse_type_shared

  let name = "PARSE_TYPE"

  let info = "Benchmarking parse_ty"

  let make_bench rng_state config () =
    ( Lwt_main.run (Execution_context.make ~rng_state) >>? fun (ctxt, _) ->
      let ctxt = Gas_helpers.set_limit ctxt in
      let size = Random.State.int rng_state config.max_size in
      let ty = dummy_type_generator size in
      match ty with
      | Ex_ty ty ->
          Environment.wrap_tzresult @@ unparse_ty ctxt ty
          >>? fun (unparsed, _) ->
          Environment.wrap_tzresult @@ parse_ty ctxt unparsed
          >>? fun (_, ctxt') ->
          let consumed =
            Z.to_int
              (Gas_helpers.fp_to_z
                 (Alpha_context.Gas.consumed ~since:ctxt ~until:ctxt'))
          in
          let nodes =
            let x = Script_typed_ir.ty_size ty in
            Saturation_repr.to_int @@ Script_typed_ir.Type_size.to_int x
          in
          let workload = Type_workload {nodes; consumed} in
          let closure () = ignore (parse_ty ctxt unparsed) in
          ok (Generator.Plain {workload; closure}) )
    |> function
    | Ok closure -> closure
    | Error errs -> global_error name errs

  let size_model =
    Model.make
      ~conv:(function Type_workload {nodes; consumed = _} -> (nodes, ()))
      ~model:
        (Model.affine
           ~intercept:
             (Free_variable.of_string (Format.asprintf "%s_const" name))
           ~coeff:(Free_variable.of_string (Format.asprintf "%s_coeff" name)))

  let models = [("size_translator_model", size_model)]

  let create_benchmarks ~rng_state ~bench_num config =
    List.repeat bench_num (make_bench rng_state config)
end

let () = Registration_helpers.register (module Parse_type_benchmark)

module Unparse_type_benchmark : Benchmark.S = struct
  include Parse_type_shared

  let name = "UNPARSE_TYPE"

  let info = "Benchmarking unparse_ty"

  let make_bench rng_state config () =
    ( Lwt_main.run (Execution_context.make ~rng_state) >>? fun (ctxt, _) ->
      let ctxt = Gas_helpers.set_limit ctxt in
      let size = Random.State.int rng_state config.max_size in
      let ty = dummy_type_generator size in
      match ty with
      | Ex_ty ty ->
          Environment.wrap_tzresult @@ unparse_ty ctxt ty >>? fun (_, ctxt') ->
          let consumed =
            Z.to_int
              (Gas_helpers.fp_to_z
                 (Alpha_context.Gas.consumed ~since:ctxt ~until:ctxt'))
          in
          let nodes =
            let x = Script_typed_ir.ty_size ty in
            Saturation_repr.to_int @@ Script_typed_ir.Type_size.to_int x
          in
          let workload = Type_workload {nodes; consumed} in
          let closure () = ignore (unparse_ty ctxt ty) in
          ok (Generator.Plain {workload; closure}) )
    |> function
    | Ok closure -> closure
    | Error errs -> global_error name errs

  let size_model =
    Model.make
      ~conv:(function Type_workload {nodes; consumed = _} -> (nodes, ()))
      ~model:
        (Model.affine
           ~intercept:
             (Free_variable.of_string (Format.asprintf "%s_const" name))
           ~coeff:(Free_variable.of_string (Format.asprintf "%s_coeff" name)))

  let models = [("size_translator_model", size_model)]

  let create_benchmarks ~rng_state ~bench_num config =
    List.repeat bench_num (make_bench rng_state config)

  let () =
    Registration_helpers.register_for_codegen
      name
      (Model.For_codegen size_model)
end

let () = Registration_helpers.register (module Unparse_type_benchmark)
back to top