Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filter trace to range #222

Merged
merged 1 commit into from
Jun 29, 2022
Merged

Filter trace to range #222

merged 1 commit into from
Jun 29, 2022

Conversation

pbaumbacher
Copy link
Contributor

Adds a new flag -filter "(<start> <stop>)" to magic trace. With this flag, the trace is trimmed to only include events that occur between start (inclusive) and stop (exclusive) (#81). If either symbol doesn't appear in the trace, no output is produced. In multi-snapshot mode, the trace only includes regions between consecutive start and stop calls. The -filter flag is compatible with the same modes as the -trigger flag.

When producing a .sexp output, only events that occur in the filtered region are emitted. When producing a fuchsia .fxt output, the full available callstack around the filtered region is reconstructed. Active stack frames at the beginning of the filtered region have the time start was called as their inferred start time.

Copy link
Member

@Xyene Xyene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work! Could you also please interactive rebase over current master, and squash commits into logical groupings? Seems like a few commits unrelated to your work snuck in.

open! Core

module Range = struct
type t = string * string [@@deriving sexp]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this a record? Accepting it as a (start stop) sexp and then manually expanding it into named record fields in the arg type parser sounds reasonable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, if we do this, we don't need the extra Range module, and could call of_command_string for both left/right of the tuple here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need two modules to express the difference between a the filter we get from the command line (range of Symbol_selection.ts) and a filter that's been evaluated (turned into strings) by fzf.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turned it into a record and changed things around a bit so [Unevaluated] is the inner module. I think it reads a bit better, but let me know if I'm missing something obvious and can get rid of the extra module altogether.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess what I'm unclear on is why not have:

module Symbol_range = struct
  type t =
    { start_symbol : Symbol_selection.t
    ; stop_symbol : Symbol_selection.t
    }

  (* Accepts '(foo bar)', returns { start_symbol = User_selected "foo"; stop_symbol = User_selected = "bar" } *)
  let arg_type = ...
end

and not have the Option.map call.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This lets you get rid of String_pair I think.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that makes sense, wasn't thinking through what I was doing with the Option.map

core/trace_filter.mli Outdated Show resolved Hide resolved
test/test.ml Outdated Show resolved Hide resolved
test/test.ml Outdated Show resolved Hide resolved
rewrite_callstack t ~callstack:thread_info.callstack ~thread_info ~time
;;

let maybe_start_hot_section t ~should_write ~time =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe_start_trimmed_region?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filtered_region?

Hashtbl.iter t.thread_info ~f:(fun thread_info ->
flush t ~to_time:time thread_info;
Deque.clear thread_info.start_events);
t.in_hot_section <- true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`in_trimmed_range?

@@ -9,6 +9,8 @@ type t =
| Syscall
[@@deriving sexp, compare]

let equal t1 t2 = compare t1 t2 = 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does [@@deriving equal] work here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, because Int64.Hex (used by Perf_map_location) doesn't derive equal.

open! Core

module Range = struct
type t = string * string [@@deriving sexp]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess what I'm unclear on is why not have:

module Symbol_range = struct
  type t =
    { start_symbol : Symbol_selection.t
    ; stop_symbol : Symbol_selection.t
    }

  (* Accepts '(foo bar)', returns { start_symbol = User_selected "foo"; stop_symbol = User_selected = "bar" } *)
  let arg_type = ...
end

and not have the Option.map call.

src/perf_tool_backend.ml Outdated Show resolved Hide resolved
[@@deriving fields]
end

type t =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this type used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's returned by evaluate_trace_filter in trace.ml and gets passed around until the filter is actually applied.

src/for_range.ml Outdated Show resolved Hide resolved
src/trace.ml Outdated Show resolved Hide resolved
src/for_range.ml Outdated
| Error _ | Ok (Power _) -> hits, in_filtered_region
| Ok (Trace ok) ->
(match
( Time_ns_unix.Span.(ok.time = hd.time)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about something like

let hits, in_filtered_region =
  match hits with
  | [] -> hits, in_filtered_region
  | hd :: tl ->
    (match event with
    | Ok (Trace { kind = Some Call; time; dst; _ })
      when Time_ns_unix.Span.(time = hd.time) &&
           Symbol.equal dst.symbol hd.symbol -> tl, not in_filtered_region
    | _ -> hits, in_filtered_region)
in

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to something close to this

Copy link
Member

@Xyene Xyene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise LGTM. I think if you rebased/squashed we could be good to merge.

@pbaumbacher pbaumbacher force-pushed the range-trace branch 2 times, most recently from 1d7693e to d792775 Compare June 24, 2022 20:57
@pbaumbacher
Copy link
Contributor Author

Otherwise LGTM. I think if you rebased/squashed we could be good to merge.

I had to update the range logic a bit to handle Sample events. The most straightforward way to do this was just to treat any stack containing a range symbol as a Symbol_hit, but a consequence is that in sampling mode the filtered region begins at the end of the range start function, instead of at the beginning in tracing mode.

Making the behavior identical would require a bit more work: the control flow would have to be fairly different depending on if we're receiving sampling events or perf events. I think using sampling with the filter isn't likely to be a super common use-case, but let me know what you think.

…put to include only

events between consecutive occurences of <start> and <stop>.

Signed-off-by: Peter Baumbacher <pbaumbacher@gmail.com>
Copy link
Member

@Xyene Xyene left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@Xyene Xyene merged commit ed4fb49 into janestreet:master Jun 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants