Skip to content

Fix stack switching on OpenCilk's runtime#363

Open
kennyzzhang wants to merge 5 commits into
janestreet:masterfrom
kennyzzhang:fix_cilk
Open

Fix stack switching on OpenCilk's runtime#363
kennyzzhang wants to merge 5 commits into
janestreet:masterfrom
kennyzzhang:fix_cilk

Conversation

@kennyzzhang

Copy link
Copy Markdown

OpenCilk's work stealing scheduler cheetah uses longjmp to switch between user and runtime code. This causes the stackframes to stairstep downwards, as expected from the FAQ.

image

So, I've "added some explicit code in magic-trace for [OpenCilk]".

In particular, upon jumping to user code, the runtime's stack is put into an inactive stack, which is then restored when jumping back to the user code.

The main two functions in cheetah that call longjmp are longjmp_to_runtime and sysdep_longjmp_to_sf.
sysdep_longjmp_to_sf is called from two different places, longjmp_to_user_code or __cilkrts_sync.
This means an extra frame needs to be popped when sysdep_longjmp_to_sf is called, and we should only put the runtime stack into an inactive stack when we see longjmp_to_user_code.

This is my first time writing OCaml, and honestly I was fumbling around copying and adapting other parts of the codebase to coerce things to work. But it seems like things work well enough that it's now much easier to tell if Cilk workers are failing to find work.

image

Signed-off-by: kennyzzhang <kennyzzhang@gmail.com>
longjmp_to_user_code pushes to inactive stacks, longjmp_to_runtime pops from inactive stacks

Signed-off-by: kennyzzhang <kennyzzhang@gmail.com>
Signed-off-by: kennyzzhang <kennyzzhang@gmail.com>
Signed-off-by: kennyzzhang <kennyzzhang@gmail.com>
Signed-off-by: kennyzzhang <kennyzzhang@gmail.com>

@Xyene Xyene left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks, looks mostly good! A couple of nits/suggestions.

Comment thread src/trace_writer.ml
let ret = ret_without_checking_for_go_hacks

let switch_to_user_code t (thread_info : _ Thread_info.t) ~time =
(* Pop the sysdep_longjmp_to_sf frame *)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
(* Pop the sysdep_longjmp_to_sf frame *)
(* Pop the [sysdep_longjmp_to_sf] frame. *)

Comment thread src/trace_writer.ml
between user and runtime stacks.

To deal with this stack switching, when jumping into the runtime, we need to clear the
user's stack frames. The inactive_callstacks mechanism is perfect for keeping track of

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
user's stack frames. The inactive_callstacks mechanism is perfect for keeping track of
user's stack frames. The [inactive_callstacks] mechanism is perfect for keeping track of

Comment thread src/trace_writer.ml
let switch_to_user_code t (thread_info : _ Thread_info.t) ~time =
(* Pop the sysdep_longjmp_to_sf frame *)
ret t thread_info ~time;
(* The next stack frame is either __cilkrts_sync or longjmp_to_user_code. In either

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
(* The next stack frame is either __cilkrts_sync or longjmp_to_user_code. In either
(* The next stack frame is either [__cilkrts_sync] or [longjmp_to_user_code]. In either

Comment thread src/trace_writer.ml
thread_info.callstack <- Callstack.create ~create_time:time
| "__cilkrts_sync" -> ret t thread_info ~time
| _ -> Printf.printf "OpenCilk_hacks: Unexpected symbol %s\n" symbol)
| _ -> Printf.printf "OpenCilk_hacks: Unexpected symbol [unknown]"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: these are not just [unknown] symbols. Writing the match exhaustively would make that a little more clear.

Comment thread src/trace_writer.ml
Stack.push thread_info.inactive_callstacks thread_info.callstack;
thread_info.callstack <- Callstack.create ~create_time:time
| "__cilkrts_sync" -> ret t thread_info ~time
| _ -> Printf.printf "OpenCilk_hacks: Unexpected symbol %s\n" symbol)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: let's use eprintf here, and use the %! syntax to force a flush. For example, see

https://github.com/kennyzzhang/magic-trace/blob/c31a2f752fbdf41f786b87b3c0fd5ff4869b05eb/src/trace_writer.ml#L1027-L1034

Comment thread src/trace_writer.ml
Thread_info.set_callstack thread_info ~is_kernel_address ~time
;;

(* OpenCilk's runtime cheetah (https://github.com/OpenCilk/cheetah) uses longjmp to switch

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: let's move all of this code up, so that let call ... = ... is close in the file with let ret ... = ....

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.

2 participants