Module Mavryk_time_measurement_ppx.Time_ppx

Ppx for embedded time measurement tooling generation

This PPX is used to handle the rewriting of Ocaml expressions annotated with the following attributes: [@time.duration], [@time.duration_lwt], [@time.timestamp_pre] and [@time.flush].

If one of these annotations is detected on an expression, this last one will be wrapped in a thunk that will be given respectively to duration, duration_lwt, timestamp_pre or flush functions from Mavryk_time_measurement_runtime.Default.Time_measurement module along with the label extracted from the attribute payload if needed.

Example:

let x = 40 + 2 [@time.duration label42] in x

(* ==> *)

let x =
  Mavryk_time_measurement_runtime.Default.Time_measurement.duration
    "label42"
    (fun () -> 40 + 2)

Expressions recursivity

The PPX handles cases where sub-expressions are annotated.

For example, the following program will be valid and both @time.duration attributes will be effective:

(let x =
   "Hi there!" [@time.duration sub_expr]
 in x) [@time.duration expr]

It however needs to be handled with care: When tagging nested expressions, the outer time measurement will include the time spent to measure the sub-expression.

Validity

All dedicated attributes must follow the following rules in order to be semantically correct:

type measurement_key = {
  1. label : string;
  2. metadata : Ppxlib.expression Stdlib.Option.t;
}
type rewriter =
  1. | Duration of measurement_key * Ppxlib.location
  2. | Duration_lwt of measurement_key * Ppxlib.location
  3. | Timestamp_pre of measurement_key * Ppxlib.location
  4. | Flush of Ppxlib.location
type rewriter_constants = {
  1. fn_name : string;
  2. attribute_name : string;
}
val duration : measurement_key -> Ppxlib.location -> rewriter
val duration_lwt : measurement_key -> Ppxlib.location -> rewriter
val timestamp_pre : measurement_key -> Ppxlib.location -> rewriter
val flush : Ppxlib.location -> rewriter
val create_rewriter_constants : string -> rewriter_constants
val duration_constants : rewriter_constants
val duration_lwt_constants : rewriter_constants
val timestamp_pre_constants : rewriter_constants
val flush_constants : rewriter_constants
val attribute_names : string list
val constants_of_rewriter : rewriter -> rewriter_constants
val labeled_rewriter_of_attr_name : string -> (measurement_key -> Ppxlib.location -> rewriter) option
val locaction_of_rewriter : rewriter -> Ppxlib.location
val error : Ppxlib.Location.t -> [< `Invalid_payload | `Non_empty_payload | `Too_many_Detection of string ] -> 'a
val get_attribute_name : Ppxlib.attribute -> string
val has_attribute_name : Ppxlib.attribute -> string -> bool

has_attribute_name attribute name evaluates if the name of the given attribute is equal to the given name.

val filter_attribute_with_name : string -> Ppxlib.attribute list -> Ppxlib.attribute list

filter_attribute_with_name name attributes evaluates in the list of attributes whose elements having the given name have been filtered out.

val filter_attribute_with_names : string list -> Ppxlib.attribute list -> Ppxlib.attribute list

filter_attribute_with_names names attributes evaluates in the list of attributes whose elements having one of the given names have been filtered out.

val fresh_identifier : string -> string

fresh_identifier prefix evaluates in a new identifier prefixed by prefix at each call. The function guarantees that it never returns the same identifier twice.

val key_of_payload : Ppxlib.Location.t -> Ppxlib.payload -> measurement_key

key_of_payload location payload extracts a measurement_key from the given payload if possible. The payload can be:

  • An ocaml identifier as described here: https://ocaml.org/manual/lex.html. In this case, this identifier will be used as key label.
  • An apply of expression where the first element should be an ocaml identifier an the second one an expression that should evaluate in a list of string. In this case, the first element will be used as key label and the second one as key metadata. Note that this preprocessing step will not enforce this expression to evaluate to a list of string. It will rather accept every expression and let the compilation check the typing during typing analysis afterward.
val check_empty_payload : Ppxlib.Location.t -> Ppxlib.payload -> unit
val rewriter_of_attribute : Ppxlib.attribute -> rewriter option

rewriter_of_attribute attribute inspects the given attribute name and tries to recognise if it is related to this PPX. In this case, it will evaluate in the corresponding rewriter.

val extract_rewriters : Ppxlib.attribute list -> rewriter list

extract_rewriters attributes inspects the given list of attributes and evaluates in the list of rewriters that have been identified with it.

val validate_rewriters : rewriter list -> unit

validate_rewriters rewriters inspects the given list of rewriters and ensures that it is semantically correct.

val argument_of_key : measurement_key -> Ppxlib.location -> Ppxlib_ast.Ast.expression

argument_of_key key loc transforms the given measurement key into a labeled argument that intends be used in an expression application at the given location.

val ldot_of_non_empty_list : (string * string list) -> Ppxlib.longident
val time_measurement_longident : string -> Ppxlib.longident
val wrap_with_labelled_call : Ppxlib_ast.Ast.expression -> Ppxlib.location -> measurement_key -> string -> Astlib.Ast_500.Parsetree.expression

wrap_with_labelled_call expr loc key fn wraps the given expression into a thunk and gives it as an argument to a call of the function fn of module Time_measurement. It will use the given measurement key to compute subsidiary arguments.

val bind_with_flush_call : Ppxlib_ast.Ast.expression -> Ppxlib.location -> Ppxlib_ast.Ast.expression

bind_with_flush_call expr loc binds the given expression with a Lwt promise that memoizes the results of expr and then call Time_measurement.flush. It then binds to a new Lwt promise that returns the memoized result of expr.

val rewrite : rewriter list -> Ppxlib.expression -> Ppxlib_ast.Ast.expression

rewrite rewriters initial_expr sequentially interpretes the given rewriters in order to rewrite the given expression initial_expr.

val remove_attributes : Ppxlib.expression -> Ppxlib.expression

remove_attributes expr removes the attributes of the given expression if they match attributes handled by this PPX.

val mapper : Ppxlib.Ast_traverse.map