diff --git a/manifest/product_octez.ml b/manifest/product_octez.ml index d1d286db12aee934d16cdd01c3fbe8c346c5093f..cff4e1dfa733580943fce7f7d32371288dbc8803 100644 --- a/manifest/product_octez.ml +++ b/manifest/product_octez.ml @@ -5343,11 +5343,14 @@ let _octez_scoru_wasm_fast_tests = ~preprocess:(staged_pps [ppx_import; ppx_deriving_show]) let octez_experimental_agnostic_baker_lib = + let (PPX {preprocess; preprocessor_deps}) = ppx_profiler in public_lib "octez-experimental-agnostic-baker-lib" ~path:"src/lib_agnostic_baker" ~internal_name:"octez_experimental_agnostic_baker" ~synopsis:"Octez: library for Agnostic Baker" + ~preprocess + ~preprocessor_deps ~deps: [ octez_rustzcash_deps; @@ -5358,6 +5361,7 @@ let octez_experimental_agnostic_baker_lib = octez_client_base_unix |> open_; octez_node_config; octez_client_commands |> open_; + octez_profiler |> open_; ] (* PROTOCOL PACKAGES *) @@ -8280,6 +8284,7 @@ let _octez_node = ] let _octez_experimental_agnostic_baker = + let (PPX {preprocess; preprocessor_deps}) = ppx_profiler in let protocol_deps = let deps_for_protocol protocol = let is_optional = @@ -8297,6 +8302,8 @@ let _octez_experimental_agnostic_baker = ~path:"src/bin_agnostic_baker" ~internal_name:"main_agnostic_baker" ~synopsis:"Tezos: `octez-experimental-agnostic-baker` binary for baking" + ~preprocess + ~preprocessor_deps ~release_status:Released ~with_macos_security_framework:true ~deps: @@ -8306,6 +8313,7 @@ let _octez_experimental_agnostic_baker = octez_base |> open_ ~m:"TzPervasives" |> open_; octez_base_unix |> open_; octez_experimental_agnostic_baker_lib |> open_; + octez_profiler |> open_; ] @ protocol_deps) ~linkall:true diff --git a/opam/octez-experimental-agnostic-baker-lib.opam b/opam/octez-experimental-agnostic-baker-lib.opam index ee8a3184911cfc10bfe52a14b2d92e2bddd7e23d..5ecb396d33b34d4ebb7c885a2fd508f9b26b3a01 100644 --- a/opam/octez-experimental-agnostic-baker-lib.opam +++ b/opam/octez-experimental-agnostic-baker-lib.opam @@ -10,9 +10,9 @@ license: "MIT" depends: [ "dune" { >= "3.11.1" } "ocaml" { >= "4.14" } + "octez-libs" { = version } "octez-rustzcash-deps" { = version } "bls12-381" { = version } - "octez-libs" { = version } "octez-shell-libs" { = version } "octez-node-config" { = version } ] diff --git a/opam/octez-experimental-agnostic-baker.opam b/opam/octez-experimental-agnostic-baker.opam index bc418220acd15ced0dc7aeaf182d5f7e068ce0bf..eab07475ebd54426345d1c13b2bf634f00b4cdf8 100644 --- a/opam/octez-experimental-agnostic-baker.opam +++ b/opam/octez-experimental-agnostic-baker.opam @@ -10,9 +10,9 @@ license: "MIT" depends: [ "dune" { >= "3.11.1" } "ocaml" { >= "4.14" } + "octez-libs" { = version } "octez-rust-deps" { = version } "bls12-381" { = version } - "octez-libs" { = version } "octez-experimental-agnostic-baker-lib" { = version } "octez-protocol-021-PsQuebec-libs" { = version } "octez-protocol-022-PsRiotum-libs" { = version } diff --git a/src/bin_agnostic_baker/dune b/src/bin_agnostic_baker/dune index d836df1c327ce14c22a47aa2af4a6c640c20d4b6..d184c7a2c707fddea5970943a0d616b44d85402d 100644 --- a/src/bin_agnostic_baker/dune +++ b/src/bin_agnostic_baker/dune @@ -12,11 +12,14 @@ octez-libs.base octez-libs.base.unix octez-experimental-agnostic-baker-lib + octez-libs.octez-profiler octez-protocol-021-PsQuebec-libs.agnostic-baker octez-protocol-022-PsRiotum-libs.agnostic-baker (select void_for_linking-octez-protocol-alpha-libs-agnostic-baker from (octez-protocol-alpha-libs.agnostic-baker -> void_for_linking-octez-protocol-alpha-libs-agnostic-baker.empty) (-> void_for_linking-octez-protocol-alpha-libs-agnostic-baker.empty))) + (preprocess (pps octez-libs.ppx_profiler)) + (preprocessor_deps (env_var TEZOS_PPX_PROFILER)) (link_flags (:standard) (:include %{workspace_root}/static-link-flags.sexp) @@ -27,7 +30,8 @@ -open Tezos_base.TzPervasives -open Tezos_base -open Tezos_base_unix - -open Octez_experimental_agnostic_baker)) + -open Octez_experimental_agnostic_baker + -open Tezos_profiler)) (rule (action diff --git a/src/bin_agnostic_baker/main_agnostic_baker.ml b/src/bin_agnostic_baker/main_agnostic_baker.ml index a1c5132671f86849762de99af4812bbabb2d77ab..5dbaafca021b8bd12d26187dfc348f2cd5882d79 100644 --- a/src/bin_agnostic_baker/main_agnostic_baker.ml +++ b/src/bin_agnostic_baker/main_agnostic_baker.ml @@ -6,16 +6,29 @@ (* *) (*****************************************************************************) +let[@warning "-32"] may_start_profiler baking_dir = + match Tezos_profiler_unix.Profiler_instance.selected_backend () with + | Some {instance_maker; _} -> + let profiler_maker = instance_maker ~directory:baking_dir in + Agnostic_baker_profiler.init profiler_maker + | None -> () + let run () = let open Lwt_result_syntax in let Run_args.{node_endpoint; base_dir; baker_args} = Run_args.parse_args Sys.argv in + let base_dir = + Option.value + ~default:Tezos_client_base_unix.Client_config.Cfg_file.default.base_dir + base_dir + in let*! () = Tezos_base_unix.Internal_event_unix.init ~config:(Parameters.log_config ~base_dir) () in + () [@profiler.overwrite may_start_profiler base_dir] ; let daemon = Daemon.create ~node_endpoint ~baker_args in let* (_ : unit) = Daemon.run daemon in let*! () = Lwt_utils.never_ending () in diff --git a/src/lib_agnostic_baker/agnostic_baker_events.ml b/src/lib_agnostic_baker/agnostic_baker_events.ml index 4a591d8ffb79728468358dc44a061a038340637f..ce6a651baadc0269f83f0f0cbb7e746ba24d1af3 100644 --- a/src/lib_agnostic_baker/agnostic_baker_events.ml +++ b/src/lib_agnostic_baker/agnostic_baker_events.ml @@ -22,6 +22,7 @@ let starting_baker = ("proto", Protocol_hash.encoding) ("args", string) ~pp1:Protocol_hash.pp_short + ~pp2:Format.pp_print_string let baker_running = declare_1 @@ -92,12 +93,15 @@ let waiting_for_active_protocol = () let period_status = - declare_2 + declare_3 ~section ~alternative_color ~level:Notice ~name:"period_status" - ~msg:"new block on {period} period (remaining period duration {remaining})" + ~msg: + "new block ({block}) on {period} period (remaining period duration \ + {remaining})" + ("block", Block_hash.encoding) ("period", string) ("remaining", int31) diff --git a/src/lib_agnostic_baker/agnostic_baker_profiler.ml b/src/lib_agnostic_baker/agnostic_baker_profiler.ml new file mode 100644 index 0000000000000000000000000000000000000000..9b93ffd25beffacfd751a402166c6e20debeaaec --- /dev/null +++ b/src/lib_agnostic_baker/agnostic_baker_profiler.ml @@ -0,0 +1,17 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Trilitech *) +(* *) +(*****************************************************************************) +open Profiler + +let agnostic_baker_profiler = unplugged () + +let init profiler_maker = + match profiler_maker ~name:"agnostic_baker" with + | Some instance -> plug agnostic_baker_profiler instance + | None -> () + +let create_reset_block_section = + section_maker Block_hash.equal Block_hash.to_b58check diff --git a/src/lib_agnostic_baker/agnostic_baker_profiler.mli b/src/lib_agnostic_baker/agnostic_baker_profiler.mli new file mode 100644 index 0000000000000000000000000000000000000000..3e9e56176b2bccf20d645f4a1f71832f8dc5387e --- /dev/null +++ b/src/lib_agnostic_baker/agnostic_baker_profiler.mli @@ -0,0 +1,16 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Trilitech *) +(* *) +(*****************************************************************************) + +(** Unplugged agnostic baker profiler. *) +val agnostic_baker_profiler : Profiler.profiler + +(** Plug the agnostic baker profiler given its name and Profiler instance option. *) +val init : (name:string -> Profiler.instance option) -> unit + +(** Creates a function to reset the block section *) +val create_reset_block_section : + Profiler.profiler -> Block_hash.t * Profiler.metadata -> unit diff --git a/src/lib_agnostic_baker/daemon.ml b/src/lib_agnostic_baker/daemon.ml index f396b39727e8a7d577ea8538d2db7346c6ea0784..0dfe075731dce0c875b33a501ab1ca3b0997e3ac 100644 --- a/src/lib_agnostic_baker/daemon.ml +++ b/src/lib_agnostic_baker/daemon.ml @@ -6,6 +6,14 @@ (* *) (*****************************************************************************) +module Profiler = struct + include (val Profiler.wrap Agnostic_baker_profiler.agnostic_baker_profiler) + + let[@warning "-32"] reset_block_section = + Agnostic_baker_profiler.create_reset_block_section + Agnostic_baker_profiler.agnostic_baker_profiler +end + open Agnostic_baker_errors (* Number of extra levels to keep the old baker alive before shutting it down. @@ -77,7 +85,11 @@ let spawn_baker protocol_hash ~baker_args = let baker_args = "./mock-binary" :: baker_args in let cancel_promise, canceller = Lwt.wait () in let* thread = - let*? plugin = Protocol_plugins.proto_plugin_for_protocol protocol_hash in + let*? plugin = + (Protocol_plugins.proto_plugin_for_protocol + protocol_hash + [@profiler.record_f {verbosity = Notice} "proto_plugin_for_protocol"]) + in let baker_commands = Commands.baker_commands plugin in return @@ run_thread @@ -157,26 +169,25 @@ let hot_swap_baker ~state ~current_protocol_hash ~next_protocol_hash state.current_baker <- Some new_baker ; return_unit -(** [parse_level head_info] retrieves the ["level"] field information from the - json information of the chain from [head_info]. *) -let parse_level head_info = - let json = Ezjsonm.from_string head_info in - Ezjsonm.find json ["level"] |> Ezjsonm.get_int - -(** [maybe_kill_old_baker state head_info] checks whether the [old_baker] process +(** [maybe_kill_old_baker state node_addr] checks whether the [old_baker] process from the [state] of the agnostic baker has surpassed its lifetime and it stops it if that is the case. *) -let maybe_kill_old_baker state head_info = - let open Lwt_syntax in +let maybe_kill_old_baker state node_addr = + let open Lwt_result_syntax in match state.old_baker with | None -> return_unit | Some {baker; level_to_kill} -> - let head_level = parse_level head_info in + let* head_level = + (Rpc_services.get_level + ~node_addr [@profiler.record_s {verbosity = Notice} "get_level"]) + in if head_level >= level_to_kill then ( - let* () = + let*! () = Agnostic_baker_events.(emit stopping_baker) baker.protocol_hash in - Lwt.wakeup baker.process.canceller 0 ; + Lwt.wakeup + baker.process.canceller + 0 [@profiler.record_f {verbosity = Notice} "kill old baker"] ; state.old_baker <- None ; return_unit) else return_unit @@ -184,24 +195,42 @@ let maybe_kill_old_baker state head_info = (** [monitor_voting_periods ~state head_stream] continuously monitors [heads_stream] to detect protocol changes. It will: - Shut down an old baker it its time has come; - - Spawn and "hot-swap" to a new baker if the next protocol hash is different. *) + - Spawn and "hot-swap" to a new baker if the next protocol hash is different. + The voting period information is used for logging purposes. *) let monitor_voting_periods ~state head_stream = let open Lwt_result_syntax in let node_addr = state.node_endpoint in let rec loop () = - let*! head_info_opt = Lwt_stream.get head_stream in - match head_info_opt with + let*! v = Lwt_stream.get head_stream in + match v with | None -> tzfail Lost_node_connection - | Some head_info -> + | Some _tick -> + let* block_hash = + (Rpc_services.get_block_hash + ~node_addr + [@profiler.record_s {verbosity = Notice} "get_block_hash"]) + in + () + [@profiler.reset_block_section {profiler_module = Profiler} block_hash] ; let* period_kind, remaining = - Rpc_services.get_current_period ~node_addr + (Rpc_services.get_current_period + ~node_addr + [@profiler.record_s {verbosity = Notice} "get_current_period"]) in let*! () = - Agnostic_baker_events.(emit period_status) (period_kind, remaining) + Agnostic_baker_events.(emit period_status) + (block_hash, period_kind, remaining) + in + let* () = + (maybe_kill_old_baker + state + node_addr + [@profiler.record_s {verbosity = Notice} "maybe_kill_old_baker"]) in - let*! () = maybe_kill_old_baker state head_info in let* next_protocol_hash = - Rpc_services.get_next_protocol_hash ~node_addr + (Rpc_services.get_next_protocol_hash + ~node_addr + [@profiler.record_s {verbosity = Notice} "get_next_protocol_hash"]) in let* current_protocol_hash = match state.current_baker with @@ -211,12 +240,17 @@ let monitor_voting_periods ~state head_stream = let* () = if not (Protocol_hash.equal current_protocol_hash next_protocol_hash) then - hot_swap_baker - ~state - ~current_protocol_hash - ~next_protocol_hash - ~level_to_kill_old_baker: - (parse_level head_info + extra_levels_for_old_baker) + let* head_level = + (Rpc_services.get_level + ~node_addr + [@profiler.record_s {verbosity = Notice} "get_level"]) + in + (hot_swap_baker + ~state + ~current_protocol_hash + ~next_protocol_hash + ~level_to_kill_old_baker:(head_level + extra_levels_for_old_baker) + [@profiler.record_s {verbosity = Notice} "hot_swap_baker"]) else return_unit in loop () diff --git a/src/lib_agnostic_baker/dune b/src/lib_agnostic_baker/dune index ba71b4b59caba9b155a450638a774b774602dc90..266070c8d71eee41716df6b22473bb042c9acbb2 100644 --- a/src/lib_agnostic_baker/dune +++ b/src/lib_agnostic_baker/dune @@ -13,7 +13,10 @@ octez-libs.base.unix octez-shell-libs.client-base-unix octez-node-config - octez-shell-libs.client-commands) + octez-shell-libs.client-commands + octez-libs.octez-profiler) + (preprocess (pps octez-libs.ppx_profiler)) + (preprocessor_deps (env_var TEZOS_PPX_PROFILER)) (flags (:standard) -open Data_encoding @@ -21,4 +24,5 @@ -open Tezos_base -open Tezos_base_unix -open Tezos_client_base_unix - -open Tezos_client_commands)) + -open Tezos_client_commands + -open Tezos_profiler)) diff --git a/src/lib_agnostic_baker/parameters.ml b/src/lib_agnostic_baker/parameters.ml index e273beaa109b79c761b6e53d4827ea757b76c0ef..7e67520deb12099891ed01bc0b3d712f8f64af1d 100644 --- a/src/lib_agnostic_baker/parameters.ml +++ b/src/lib_agnostic_baker/parameters.ml @@ -14,11 +14,6 @@ let default_node_endpoint = let default_daily_logs_path = Some "octez-experimental-agnostic-baker" let log_config ~base_dir = - let base_dir : string = - match base_dir with - | Some p -> p - | None -> Tezos_client_base_unix.Client_config.Cfg_file.default.base_dir - in let daily_logs_path = default_daily_logs_path |> Option.map Filename.Infix.(fun logdir -> base_dir // "logs" // logdir) diff --git a/src/lib_agnostic_baker/parameters.mli b/src/lib_agnostic_baker/parameters.mli index df009a953ce5c48539be61c21b50d56a1d5244c0..79f7c870b15427fbc491dc6ba16bd0b3c17686ec 100644 --- a/src/lib_agnostic_baker/parameters.mli +++ b/src/lib_agnostic_baker/parameters.mli @@ -13,7 +13,7 @@ val default_node_endpoint : string (** Default logs path for the agnostic baker. *) val default_daily_logs_path : string option -val log_config : base_dir:string option -> Tezos_base.Internal_event_config.t +val log_config : base_dir:string -> Tezos_base.Internal_event_config.t (** Status of a protocol, based on Manifest/Product_octez/Protocol. A protocol is considered as [Active] while it is running on a network, diff --git a/src/lib_agnostic_baker/rpc_services.ml b/src/lib_agnostic_baker/rpc_services.ml index bde5622bb7787374406ca2fe6ff1a03ded597edd..c2415fc5cbc18fd4e3d38a13f3f3d0fb7233b248 100644 --- a/src/lib_agnostic_baker/rpc_services.ml +++ b/src/lib_agnostic_baker/rpc_services.ml @@ -64,6 +64,25 @@ let get_level ~node_addr = in call_and_wrap_rpc ~node_addr ~uri ~f +let get_block_hash ~node_addr = + let open Lwt_result_syntax in + let f json = + (* Hash field in the RPC result *) + let name = "hash" in + let* v = + match json with + | `O fields -> ( + match List.assoc_opt ~equal:( = ) name fields with + | None -> tzfail (Cannot_decode_node_data ("missing field " ^ name)) + | Some node -> return node) + | _ -> tzfail (Cannot_decode_node_data "not an object") + in + let block_hash = Block_hash.of_b58check_exn @@ Ezjsonm.get_string v in + return block_hash + in + let uri = Format.sprintf "%s/chains/main/blocks/head/header" node_addr in + call_and_wrap_rpc ~node_addr ~uri ~f + let get_next_protocol_hash ~node_addr = let open Lwt_result_syntax in let f json = diff --git a/src/lib_agnostic_baker/rpc_services.mli b/src/lib_agnostic_baker/rpc_services.mli index 063adf0e11f00b4e1b428c9ed24b1882b7bb3dd1..904ac48456d98d3bd02bef10fedc3b96ab3eb2bc 100644 --- a/src/lib_agnostic_baker/rpc_services.mli +++ b/src/lib_agnostic_baker/rpc_services.mli @@ -16,6 +16,10 @@ val request_uri : (** [get_level ~node_addr] returns the level of the block. *) val get_level : node_addr:string -> (int, error trace) result Lwt.t +(** [get_level ~node_addr] returns the hash of the block. *) +val get_block_hash : + node_addr:string -> (Block_hash.t, error trace) result Lwt.t + (** [get_next_protocol_hash ~node_addr] returns the protocol hash contained in the [next_protocol] field of the metadata of a block. *)