Skip to content

Commit 8c9bf5e

Browse files
authored
Semaphore without probes: dummy notes (#142)
* Allow [%probe_is_enabled name] without a [%probe name ..] in the same compilation unit * Refactor probes type in emit.mlp (amd64) * Emit dummy probes * Update version of probe notes * Address review comments * Make probe handler optional to handle dummy probes nicely.
1 parent e5b3bdd commit 8c9bf5e

File tree

3 files changed

+99
-55
lines changed

3 files changed

+99
-55
lines changed

backend/amd64/emit.mlp

Lines changed: 99 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -528,18 +528,29 @@ let function_name = ref ""
528528
let tailrec_entry_point = ref None
529529

530530
(* Emit tracing probes *)
531+
type probe_handler =
532+
{
533+
probe_stack_offset: int;
534+
probe_num_stack_slots: int array;
535+
(* Record frame info held in the corresponding mutable variables. *)
536+
probe_handler_code_sym: string;
537+
(* Probe handler function symbol. *)
538+
probe_arg: Reg.t array;
539+
probe_live: Reg.Set.t;
540+
(* Information about Iprobe instruction,
541+
recorded at probe site and used for emitting the notes and
542+
the wrapper code at the end of the compilation unit. *)
543+
}
531544

532545
type probe =
533546
{
534-
stack_offset: int;
535-
num_stack_slots: int array;
536-
(* Record frame info held in the corresponding mutable variables. *)
537547
probe_label: label;
538548
(* Probe site, recorded in .note.stapsdt section
539549
for enabling and disabling the probes *)
540-
probe_insn: Linear.instruction;
541-
(* Iprobe instruction, recorded at probe site and used for emitting
542-
the notes and the wrapper code at the end of the compilation unit. *)
550+
probe_name: string;
551+
(* User-defined name of the probe. *)
552+
probe_handler: probe_handler option;
553+
(* User-defined handler or None for dummy probes. *)
543554
}
544555

545556
let probe_handler_wrapper_name probe_label =
@@ -935,13 +946,20 @@ let emit_instr fallthrough i =
935946
in
936947
I.prefetch is_write locality (addressing addr QWORD i 0)
937948
| Lop (Iname_for_debugger _) -> ()
938-
| Lop (Iprobe _) ->
949+
| Lop (Iprobe { name; handler_code_sym }) ->
939950
let probe_label = new_label () in
951+
let h =
952+
{ probe_handler_code_sym = handler_code_sym;
953+
probe_arg = Array.copy i.arg;
954+
probe_live = i.live;
955+
probe_stack_offset = !stack_offset;
956+
probe_num_stack_slots = Array.copy num_stack_slots;
957+
}
958+
in
940959
let probe =
941960
{ probe_label;
942-
probe_insn = i;
943-
stack_offset = !stack_offset;
944-
num_stack_slots = Array.copy num_stack_slots;
961+
probe_name = name;
962+
probe_handler = Some h;
945963
}
946964
in
947965
probes := probe :: !probes;
@@ -1283,23 +1301,20 @@ let make_stack_loc ~offset i (r : Reg.t) =
12831301

12841302
let emit_probe_handler_wrapper p =
12851303
let wrap_label = probe_handler_wrapper_name p.probe_label in
1286-
let probe_name, handler_code_sym =
1287-
match p.probe_insn.desc with
1288-
| Lop (Iprobe { name; handler_code_sym; }) -> name, handler_code_sym
1289-
| _ -> assert false
1290-
in
1304+
let h = Option.get p.probe_handler in
12911305
(* Restore stack frame info as it was at the probe site, so we can easily
12921306
refer to slots in the corresponding frame. (As per the comment above,
12931307
recall that the wrapper does however have its own frame.) *)
12941308
frame_required := true;
1295-
stack_offset := p.stack_offset;
1309+
stack_offset := h.probe_stack_offset;
12961310
for i = 0 to Proc.num_register_classes - 1 do
1297-
num_stack_slots.(i) <- p.num_stack_slots.(i);
1311+
num_stack_slots.(i) <- h.probe_num_stack_slots.(i);
12981312
done;
12991313
(* Account for the return address that is now pushed on the stack. *)
13001314
stack_offset := !stack_offset + 8;
13011315
(* Emit function entry code *)
1302-
D.comment (Printf.sprintf "probe %s %s" probe_name handler_code_sym);
1316+
D.comment (Printf.sprintf "probe %s %s" p.probe_name
1317+
h.probe_handler_code_sym);
13031318
emit_named_text_section wrap_label;
13041319
D.align 16;
13051320
_label wrap_label;
@@ -1313,15 +1328,15 @@ let emit_probe_handler_wrapper p =
13131328
assert (size_addr = 8 && size_int = 8 && size_float = 8);
13141329
(* Compute the size of stack slots for all live hard registers. *)
13151330
let live =
1316-
Reg.Set.elements p.probe_insn.live
1331+
Reg.Set.elements h.probe_live
13171332
|> List.filter Reg.is_reg
13181333
|> Array.of_list
13191334
in
13201335
let live_offset = 8 * (Array.length live) in
13211336
(* Compute the size of stack slots for spilling all arguments of the probe. *)
13221337
let aux_offset = 8 (* for saving r15 *) in
1323-
let tmp_offset = 8 * (Array.length p.probe_insn.arg) in
1324-
let loc_args, loc_offset = Proc.loc_arguments (Reg.typv p.probe_insn.arg) in
1338+
let tmp_offset = 8 * (Array.length h.probe_arg) in
1339+
let loc_args, loc_offset = Proc.loc_arguments (Reg.typv h.probe_arg) in
13251340
(* Ensure the stack is aligned.
13261341
Assuming that the stack at the probe site is 16-byte aligned,
13271342
[loc_arguments] ensures that [loc_offset] is 16-byte aligned.
@@ -1345,16 +1360,16 @@ let emit_probe_handler_wrapper p =
13451360
I.mov r15 (reg saved_r15);
13461361
(* Spill all arguments of the probe. Some of these may already be on the
13471362
stack, in which case a temporary is used for the move. *)
1348-
let tmp = Array.mapi (make_stack_loc ~offset:loc_offset) p.probe_insn.arg in
1363+
let tmp = Array.mapi (make_stack_loc ~offset:loc_offset) h.probe_arg in
13491364
Array.iteri (fun i reg -> move_allowing_stack_to_stack reg (tmp.(i)))
1350-
p.probe_insn.arg;
1365+
h.probe_arg;
13511366
(* Load probe arguments to correct locations for the handler *)
13521367
Array.iteri (fun i reg -> move_allowing_stack_to_stack tmp.(i) reg) loc_args;
13531368
(* Reload spilled registers used as temporaries *)
13541369
I.mov (reg saved_r15) r15;
13551370
(* Emit call to handler *)
1356-
add_used_symbol handler_code_sym;
1357-
emit_call handler_code_sym;
1371+
add_used_symbol h.probe_handler_code_sym;
1372+
emit_call h.probe_handler_code_sym;
13581373
(* Record a frame description for the wrapper *)
13591374
let label = new_label () in
13601375
let live_offset =
@@ -1383,7 +1398,7 @@ let emit_probe_handler_wrapper p =
13831398
cfi_endproc ();
13841399
emit_function_type_and_size wrap_label
13851400

1386-
let emit_probe_notes0 () =
1401+
let emit_probe_notes0 probes =
13871402
begin match system with
13881403
| S_gnu | S_cygwin | S_solaris | S_win32 | S_linux_elf | S_bsd_elf
13891404
| S_beos | S_mingw | S_win64 | S_linux | S_mingw64 | S_unknown ->
@@ -1403,18 +1418,16 @@ let emit_probe_notes0 () =
14031418
Printf.sprintf "%d@%s" (Reg.size_of_contents_in_bytes arg) arg_name
14041419
in
14051420
let describe_one_probe p =
1406-
let probe_name =
1407-
match p.probe_insn.desc with
1408-
| Lop (Iprobe { name; _; }) -> name
1409-
| _ -> assert false
1410-
in
14111421
let args =
1412-
Array.fold_right (fun arg acc -> (stap_arg arg)::acc)
1413-
p.probe_insn.arg
1414-
[]
1415-
|> String.concat " "
1422+
match p.probe_handler with
1423+
| None -> ""
1424+
| Some h ->
1425+
Array.fold_right (fun arg acc -> (stap_arg arg)::acc)
1426+
h.probe_arg
1427+
[]
1428+
|> String.concat " "
14161429
in
1417-
let semaphore_label = emit_symbol (find_or_add_semaphore probe_name) in
1430+
let semaphore_label = emit_symbol (find_or_add_semaphore p.probe_name) in
14181431
D.align 4;
14191432
let a = new_label() in
14201433
let b = new_label() in
@@ -1440,13 +1453,13 @@ let emit_probe_notes0 () =
14401453
D.qword (const 0)
14411454
end;
14421455
D.qword (ConstLabel semaphore_label);
1443-
D.bytes "ocaml.1\000";
1444-
D.bytes (probe_name ^ "\000");
1456+
D.bytes "ocaml.2\000";
1457+
D.bytes (p.probe_name ^ "\000");
14451458
D.bytes (args ^ "\000");
14461459
def_label d;
14471460
D.align 4;
14481461
in
1449-
List.iter describe_one_probe !probes;
1462+
List.iter describe_one_probe probes;
14501463
begin match system with
14511464
| S_gnu | S_cygwin | S_solaris | S_win32 | S_linux_elf | S_bsd_elf
14521465
| S_beos | S_mingw | S_win64 | S_linux | S_mingw64 | S_unknown ->
@@ -1475,10 +1488,49 @@ let emit_probe_notes0 () =
14751488
add_def_symbol label)
14761489
!probe_semaphores
14771490

1478-
let emit_probe_notes () =
1479-
match !probes with
1480-
| [] -> ()
1481-
| _ -> emit_probe_notes0 ()
1491+
let emit_probe_notes probes =
1492+
match probes, String.Map.is_empty !probe_semaphores with
1493+
| [], true -> ()
1494+
| _ -> emit_probe_notes0 probes
1495+
1496+
let emit_dummy_probe_sites () =
1497+
let semaphores_without_probes =
1498+
List.fold_left (fun acc probe ->
1499+
String.Map.remove probe.probe_name acc)
1500+
!probe_semaphores !probes in
1501+
if (String.Map.is_empty semaphores_without_probes) then []
1502+
else begin
1503+
let fun_name = Compilenv.make_symbol (Some "___dummy_probes") in
1504+
1505+
(* start the function (as in fundecl) *)
1506+
emit_named_text_section fun_name;
1507+
D.align 16;
1508+
add_def_symbol fun_name;
1509+
D.global (emit_symbol fun_name);
1510+
D.label (emit_symbol fun_name);
1511+
cfi_startproc ();
1512+
1513+
(* emit dummy probe sites: labeled NOP only for stapsdt probes to work,
1514+
but no calls to probe wrapper because there is no ocaml probe handler. *)
1515+
let dummy_probes =
1516+
String.Map.fold (fun probe_name _label acc ->
1517+
let probe_label = new_label () in
1518+
def_label probe_label;
1519+
I.nop (); (* for uprobes and usdt probes as well *)
1520+
let probe = { probe_name;
1521+
probe_label;
1522+
probe_handler = None;
1523+
}
1524+
in
1525+
probe :: acc)
1526+
semaphores_without_probes []
1527+
in
1528+
I.ret ();
1529+
(* end the function (as in fundecl) *)
1530+
cfi_endproc ();
1531+
emit_function_type_and_size fun_name;
1532+
dummy_probes
1533+
end
14821534

14831535
let end_assembly() =
14841536
if !float_constants <> [] then begin
@@ -1495,6 +1547,9 @@ let end_assembly() =
14951547
(* Emit probe handler wrappers *)
14961548
List.iter emit_probe_handler_wrapper !probes;
14971549

1550+
(* Emit dummy probes for semaphores without probes in this compilation unit. *)
1551+
let dummy_probes = emit_dummy_probe_sites () in
1552+
14981553
emit_named_text_section (Compilenv.make_symbol (Some "code_end"));
14991554
if system = S_macosx then I.nop ();
15001555
(* suppress "ld warning: atom sorting error" *)
@@ -1544,7 +1599,7 @@ let end_assembly() =
15441599
D.size frametable (ConstSub (ConstThis, ConstLabel frametable))
15451600
end;
15461601

1547-
emit_probe_notes ();
1602+
emit_probe_notes (dummy_probes @ !probes);
15481603

15491604
if system = S_linux then
15501605
(* Mark stack as non-executable, PR#4564 *)

ocaml/typing/typecore.ml

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ type error =
124124
| Probe_format
125125
| Probe_name_too_long of string
126126
| Probe_name_format of string
127-
| Probe_name_undefined of string
128127
| Probe_is_enabled_format
129128
| Literal_overflow of string
130129
| Unknown_literal of string * char
@@ -3753,10 +3752,6 @@ and type_expect_
37533752
_ } ,
37543753
_)}]) ->
37553754
check_probe_name name name_loc env;
3756-
add_delayed_check
3757-
(fun () ->
3758-
if not (Env.has_probe name) then
3759-
raise(Error(name_loc, env, (Probe_name_undefined name))));
37603755
rue {
37613756
exp_desc = Texp_probe_is_enabled {name};
37623757
exp_loc = loc; exp_extra = [];
@@ -5606,11 +5601,6 @@ let report_error ~loc env = function
56065601
Probe names may only contain alphanumeric characters or \
56075602
underscores."
56085603
name
5609-
| Probe_name_undefined name ->
5610-
Location.errorf ~loc
5611-
"Undefined probe name `%s' used in %%probe_is_enabled. \
5612-
Not found [%%probe \"%s\" ...] in the same compilation unit."
5613-
name name
56145604
| Probe_format ->
56155605
Location.errorf ~loc
56165606
"Probe points must consist of a name, as a string \

ocaml/typing/typecore.mli

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,6 @@ type error =
181181
| Probe_format
182182
| Probe_name_too_long of string
183183
| Probe_name_format of string
184-
| Probe_name_undefined of string
185184
(* CR-soon mshinwell: Use an inlined record *)
186185
| Probe_is_enabled_format
187186
| Literal_overflow of string

0 commit comments

Comments
 (0)