summaryrefslogtreecommitdiff
path: root/otherlibs
diff options
context:
space:
mode:
authorNicolás Ojeda Bär <n.oje.bar@gmail.com>2017-12-07 10:42:12 +0100
committerMark Shinwell <mshinwell@gmail.com>2017-12-07 09:42:12 +0000
commitcaf391ff2ebe90967198d5f2b30a47e7d1f67216 (patch)
treee76a653db349c95707c7f835476116154efd22f4 /otherlibs
parent148e6a2947991495dc6e2f811d794aecf185e6b0 (diff)
downloadocaml-caf391ff2ebe90967198d5f2b30a47e7d1f67216.tar.gz
raw_spacetime_lib refactor + related fixes (#1477)
Diffstat (limited to 'otherlibs')
-rw-r--r--otherlibs/raw_spacetime_lib/Makefile66
-rw-r--r--otherlibs/raw_spacetime_lib/raw_spacetime_lib.ml91
-rw-r--r--otherlibs/raw_spacetime_lib/raw_spacetime_lib.mli1
-rw-r--r--otherlibs/raw_spacetime_lib/spacetime_offline.c251
4 files changed, 291 insertions, 118 deletions
diff --git a/otherlibs/raw_spacetime_lib/Makefile b/otherlibs/raw_spacetime_lib/Makefile
index 4b40cabb68..5ba21859b6 100644
--- a/otherlibs/raw_spacetime_lib/Makefile
+++ b/otherlibs/raw_spacetime_lib/Makefile
@@ -15,67 +15,19 @@
# Makefile for Raw_spacetime_lib
-ROOTDIR=../..
-include $(ROOTDIR)/config/Makefile
-
-CAMLRUN ?= $(ROOTDIR)/boot/ocamlrun
-CAMLC=$(CAMLRUN) $(ROOTDIR)/ocamlc -nostdlib -I $(ROOTDIR)/stdlib
-CAMLOPT=$(CAMLRUN) $(ROOTDIR)/ocamlopt -nostdlib \
- -I $(ROOTDIR)/stdlib
-
-# The remainder of this file could probably be simplified by including
-# ../Makefile.
-
LIBNAME=raw_spacetime_lib
+COBJS=spacetime_offline.$(O)
CAMLOBJS=raw_spacetime_lib.cmo
-COMPFLAGS=-w +33..39 -warn-error A -bin-annot -g -safe-string $(EXTRACAMLFLAGS)
-
-CMIFILES=$(CAMLOBJS:.cmo=.cmi)
-CAMLOBJS_NAT=$(CAMLOBJS:.cmo=.cmx)
-
-all: $(LIBNAME).cma $(CMIFILES)
-
-allopt: $(LIBNAME).cmxa $(LIBNAME).$(CMXS) $(CMIFILES)
-
-$(LIBNAME).cma: $(CAMLOBJS)
- $(CAMLC) -a -o $(LIBNAME).cma -linkall $(CAMLOBJS)
-
-$(LIBNAME).cmxa: $(CAMLOBJS_NAT)
- $(CAMLOPT) -a -o $(LIBNAME).cmxa -linkall $(CAMLOBJS_NAT)
-
-$(LIBNAME).cmxs: $(LIBNAME).cmxa
- $(CAMLOPT) -shared -o $(LIBNAME).cmxs -I . $(LIBNAME).cmxa
-
-INSTALL_LIBDIR=$(DESTDIR)$(LIBDIR)
-
-install::
- cp $(LIBNAME).cma $(CMIFILES) $(CMIFILES:.cmi=.mli) $(INSTALL_LIBDIR)
-
-installopt:
- cp $(CAMLOBJS_NAT) $(LIBNAME).cmxa $(LIBNAME).$(A) $(INSTALL_LIBDIR)/
- if test -f $(LIBNAME).cmxs; then \
- cp $(LIBNAME).cmxs $(INSTALL_LIBDIR)/; \
- fi
-
-partialclean:
- rm -f *.cm*
-
-clean:: partialclean
- rm -f *.a *.o
-
-.SUFFIXES: .ml .mli .cmi .cmo .cmx
-
-.mli.cmi:
- $(CAMLC) -c $(COMPFLAGS) $<
-
-.ml.cmo:
- $(CAMLC) -c $(COMPFLAGS) $<
-
-.ml.cmx:
- $(CAMLOPT) -c $(COMPFLAGS) $<
+include ../Makefile
+.PHONY: depend
depend:
- $(CAMLRUN) $(ROOTDIR)/tools/ocamldep *.mli *.ml > .depend
+ifeq "$(TOOLCHAIN)" "msvc"
+ $(error Dependencies cannot be regenerated using the MSVC ports)
+else
+ $(CC) -MM $(CPPFLAGS) *.c | sed -e 's/\.o/.$$(O)/g' > .depend
+ $(CAMLRUN) $(ROOTDIR)/tools/ocamldep -slash *.mli *.ml >> .depend
+endif
include .depend
diff --git a/otherlibs/raw_spacetime_lib/raw_spacetime_lib.ml b/otherlibs/raw_spacetime_lib/raw_spacetime_lib.ml
index 2592d39329..98edc53545 100644
--- a/otherlibs/raw_spacetime_lib/raw_spacetime_lib.ml
+++ b/otherlibs/raw_spacetime_lib/raw_spacetime_lib.ml
@@ -146,8 +146,7 @@ module Trace = struct
(* This function unmarshals into malloc blocks, which mean that we
obtain a straightforward means of writing [compare] on [node]s. *)
external unmarshal : in_channel -> 'a
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_unmarshal_trie"
+ = "caml_spacetime_unmarshal_trie"
let unmarshal in_channel =
let trace = unmarshal in_channel in
@@ -156,15 +155,11 @@ module Trace = struct
else
Some ((Obj.magic trace) : node)
- let node_is_null (node : node) =
- ((Obj.magic node) : unit) == ()
-
let foreign_node_is_null (node : foreign_node) =
((Obj.magic node) : unit) == ()
external node_num_header_words : unit -> int
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_node_num_header_words" "noalloc"
+ = "caml_spacetime_node_num_header_words" [@@noalloc]
let num_header_words = lazy (node_num_header_words ())
@@ -186,16 +181,14 @@ module Trace = struct
| _ -> assert false
external annotation : ocaml_node -> int -> Annotation.t
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_ocaml_allocation_point_annotation"
- "noalloc"
+ = "caml_spacetime_ocaml_allocation_point_annotation"
+ [@@noalloc]
let annotation t = annotation t.node t.offset
external count : ocaml_node -> int -> int
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_ocaml_allocation_point_count"
- "noalloc"
+ = "caml_spacetime_ocaml_allocation_point_count"
+ [@@noalloc]
let num_words_including_headers t = count t.node t.offset
end
@@ -214,15 +207,13 @@ module Trace = struct
| _ -> assert false
external callee_node : ocaml_node -> int -> 'target
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_ocaml_direct_call_point_callee_node"
+ = "caml_spacetime_ocaml_direct_call_point_callee_node"
let callee_node (type target) (t : target t) : target =
callee_node t.node t.offset
external call_count : ocaml_node -> int -> int
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_ocaml_direct_call_point_call_count"
+ = "caml_spacetime_ocaml_direct_call_point_call_count"
let call_count t =
if Shape_table.call_counts t.shape_table then
@@ -252,30 +243,26 @@ module Trace = struct
(* CR-soon mshinwell: maybe rename ...c_node_call_site -> c_node_pc,
since it isn't a call site in this case. *)
external callee : foreign_node -> Function_entry_point.t
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_c_node_call_site"
+ = "caml_spacetime_c_node_call_site"
let callee t = callee t.node
(* This can return a node satisfying "is_null" in the case of an
uninitialised tail call point. See the comment in the C code. *)
external callee_node : foreign_node -> node
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_c_node_callee_node" "noalloc"
+ = "caml_spacetime_c_node_callee_node" [@@noalloc]
let callee_node t = callee_node t.node
external call_count : foreign_node -> int
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_c_node_call_count"
+ = "caml_spacetime_c_node_call_count"
let call_count t =
if t.call_counts then Some (call_count t.node)
else None
external next : foreign_node -> foreign_node
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_c_node_next" "noalloc"
+ = "caml_spacetime_c_node_next" [@@noalloc]
let next t =
let next = { t with node = next t.node; } in
@@ -284,9 +271,8 @@ module Trace = struct
end
external callees : ocaml_node -> int -> foreign_node
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_ocaml_indirect_call_point_callees"
- "noalloc"
+ = "caml_spacetime_ocaml_indirect_call_point_callees"
+ [@@noalloc]
let callees t =
let callees =
@@ -314,13 +300,12 @@ module Trace = struct
| Indirect_call of Indirect_call_point.t
external classify_direct_call_point : ocaml_node -> int -> int
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_classify_direct_call_point"
- "noalloc"
+ = "caml_spacetime_classify_direct_call_point"
+ [@@noalloc]
let classify t =
match t.part_of_shape with
- | Shape_table.Direct_call callee ->
+ | Shape_table.Direct_call _callee ->
let direct_call_point =
match classify_direct_call_point t.node t.offset with
| 0 ->
@@ -381,16 +366,13 @@ module Trace = struct
type t = ocaml_node
external function_identifier : t -> Function_identifier.t
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_ocaml_function_identifier"
+ = "caml_spacetime_ocaml_function_identifier"
external next_in_tail_call_chain : t -> t
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_ocaml_tail_chain" "noalloc"
+ = "caml_spacetime_ocaml_tail_chain" [@@noalloc]
external compare : t -> t -> int
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_compare_node" "noalloc"
+ = "caml_spacetime_compare_node" [@@noalloc]
let fields t ~shape_table =
let id = function_identifier t in
@@ -415,8 +397,7 @@ module Trace = struct
type t = foreign_node
external compare : t -> t -> int
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_compare_node" "noalloc"
+ = "caml_spacetime_compare_node" [@@noalloc]
let fields t =
if foreign_node_is_null t then None
@@ -428,29 +409,24 @@ module Trace = struct
external program_counter : t -> Program_counter.Foreign.t
(* This is not a mistake; the same C function works. *)
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_c_node_call_site"
+ = "caml_spacetime_c_node_call_site"
external annotation : t -> Annotation.t
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_c_node_profinfo" "noalloc"
+ = "caml_spacetime_c_node_profinfo" [@@noalloc]
external num_words_including_headers : t -> int
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_c_node_allocation_count" "noalloc"
+ = "caml_spacetime_c_node_allocation_count" [@@noalloc]
end
module Call_point = struct
type t = foreign_node
external call_site : t -> Program_counter.Foreign.t
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_c_node_call_site"
+ = "caml_spacetime_c_node_call_site"
(* May return a null node. See comment above and the C code. *)
external callee_node : t -> node
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_c_node_callee_node" "noalloc"
+ = "caml_spacetime_c_node_callee_node" [@@noalloc]
end
module Field = struct
@@ -461,16 +437,14 @@ module Trace = struct
| Call of Call_point.t
external is_call : t -> bool
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_c_node_is_call" "noalloc"
+ = "caml_spacetime_c_node_is_call" [@@noalloc]
let classify t =
if is_call t then Call t
else Allocation t
external next : t -> t
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_c_node_next" "noalloc"
+ = "caml_spacetime_c_node_next" [@@noalloc]
let next t =
let next = next t in
@@ -484,8 +458,7 @@ module Trace = struct
type t = node
external compare : t -> t -> int
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_compare_node" "noalloc"
+ = "caml_spacetime_compare_node" [@@noalloc]
end
include T
@@ -494,10 +467,8 @@ module Trace = struct
| OCaml of OCaml.Node.t
| Foreign of Foreign.Node.t
- (* CR-soon lwhite: These functions should work in bytecode *)
external is_ocaml_node : t -> bool
- = "caml_spacetime_only_works_for_native_code"
- "caml_spacetime_is_ocaml_node" "noalloc"
+ = "caml_spacetime_is_ocaml_node" [@@noalloc]
let classify t =
if is_ocaml_node t then OCaml ((Obj.magic t) : ocaml_node)
@@ -601,8 +572,6 @@ module Heap_snapshot = struct
call_counts : bool;
}
- let pathname_suffix_trace = "trace"
-
(* The order of these constructors must match the C code. *)
type what_comes_next =
| Snapshot
diff --git a/otherlibs/raw_spacetime_lib/raw_spacetime_lib.mli b/otherlibs/raw_spacetime_lib/raw_spacetime_lib.mli
index 051057dde4..6bdffffe96 100644
--- a/otherlibs/raw_spacetime_lib/raw_spacetime_lib.mli
+++ b/otherlibs/raw_spacetime_lib/raw_spacetime_lib.mli
@@ -324,6 +324,7 @@ module Heap_snapshot : sig
val num_words_including_headers : t -> int
val next : t -> t option
end
+
(** Total allocations across *all threads*. *)
(* CR-someday mshinwell: change the relevant variables to be thread-local *)
val total_allocations : t -> Total_allocation.t option
diff --git a/otherlibs/raw_spacetime_lib/spacetime_offline.c b/otherlibs/raw_spacetime_lib/spacetime_offline.c
new file mode 100644
index 0000000000..fa93e5da99
--- /dev/null
+++ b/otherlibs/raw_spacetime_lib/spacetime_offline.c
@@ -0,0 +1,251 @@
+/**************************************************************************/
+/* */
+/* OCaml */
+/* */
+/* Mark Shinwell and Leo White, Jane Street Europe */
+/* */
+/* Copyright 2013--2016, Jane Street Group, LLC */
+/* */
+/* All rights reserved. This file is distributed under the terms of */
+/* the GNU Lesser General Public License version 2.1, with the */
+/* special exception on linking described in the file LICENSE. */
+/* */
+/**************************************************************************/
+
+#define CAML_INTERNALS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+
+#include "caml/alloc.h"
+#include "caml/config.h"
+#include "caml/fail.h"
+#include "caml/gc.h"
+#include "caml/intext.h"
+#include "caml/major_gc.h"
+#include "caml/memory.h"
+#include "caml/minor_gc.h"
+#include "caml/misc.h"
+#include "caml/mlvalues.h"
+#include "caml/roots.h"
+#include "caml/signals.h"
+#include "caml/stack.h"
+#include "caml/sys.h"
+#include "caml/spacetime.h"
+
+#include "caml/s.h"
+
+#define SPACETIME_PROFINFO_WIDTH 26
+#define Spacetime_profinfo_hd(hd) \
+ (Gen_profinfo_hd(SPACETIME_PROFINFO_WIDTH, hd))
+
+#ifdef ARCH_SIXTYFOUR
+
+/* CR-someday lwhite: The following two definitions are copied from spacetime.c
+ because they are needed here, but must be inlined in spacetime.c
+ for performance. Perhaps a macro or "static inline" would be
+ more appropriate. */
+
+c_node* caml_spacetime_offline_c_node_of_stored_pointer_not_null
+ (value node_stored)
+{
+ CAMLassert(Is_c_node(node_stored));
+ return (c_node*) Hp_val(node_stored);
+}
+
+c_node_type caml_spacetime_offline_classify_c_node(c_node* node)
+{
+ return (node->pc & 2) ? CALL : ALLOCATION;
+}
+
+CAMLprim value caml_spacetime_compare_node(
+ value node1, value node2)
+{
+ CAMLassert(!Is_in_value_area(node1));
+ CAMLassert(!Is_in_value_area(node2));
+
+ if (node1 == node2) {
+ return Val_long(0);
+ }
+ if (node1 < node2) {
+ return Val_long(-1);
+ }
+ return Val_long(1);
+}
+
+CAMLprim value caml_spacetime_unmarshal_trie (value v_channel)
+{
+ return caml_input_value_to_outside_heap(v_channel);
+}
+
+CAMLprim value caml_spacetime_node_num_header_words(value unit)
+{
+ unit = Val_unit;
+ return Val_long(Node_num_header_words);
+}
+
+CAMLprim value caml_spacetime_is_ocaml_node(value node)
+{
+ CAMLassert(Is_ocaml_node(node) || Is_c_node(node));
+ return Val_bool(Is_ocaml_node(node));
+}
+
+CAMLprim value caml_spacetime_ocaml_function_identifier(value node)
+{
+ CAMLassert(Is_ocaml_node(node));
+ return caml_copy_int64((uint64_t) Decode_node_pc(Node_pc(node)));
+}
+
+CAMLprim value caml_spacetime_ocaml_tail_chain(value node)
+{
+ CAMLassert(Is_ocaml_node(node));
+ return Tail_link(node);
+}
+
+CAMLprim value caml_spacetime_classify_direct_call_point
+ (value node, value offset)
+{
+ uintnat field;
+ value callee_node;
+
+ CAMLassert(Is_ocaml_node(node));
+
+ field = Long_val(offset);
+
+ callee_node = Direct_callee_node(node, field);
+ if (!Is_block(callee_node)) {
+ /* An unused call point (may be a tail call point). */
+ return Val_long(0);
+ } else if (Is_ocaml_node(callee_node)) {
+ return Val_long(1); /* direct call point to OCaml code */
+ } else {
+ return Val_long(2); /* direct call point to non-OCaml code */
+ }
+}
+
+CAMLprim value caml_spacetime_ocaml_allocation_point_annotation
+ (value node, value offset)
+{
+ uintnat profinfo_shifted;
+ profinfo_shifted = (uintnat) Alloc_point_profinfo(node, Long_val(offset));
+ return Val_long(Spacetime_profinfo_hd(profinfo_shifted));
+}
+
+CAMLprim value caml_spacetime_ocaml_allocation_point_count
+ (value node, value offset)
+{
+ value count = Alloc_point_count(node, Long_val(offset));
+ CAMLassert(!Is_block(count));
+ return count;
+}
+
+CAMLprim value caml_spacetime_ocaml_direct_call_point_callee_node
+ (value node, value offset)
+{
+ return Direct_callee_node(node, Long_val(offset));
+}
+
+CAMLprim value caml_spacetime_ocaml_direct_call_point_call_count
+(value node, value offset)
+{
+ return Direct_call_count(node, Long_val(offset));
+}
+
+CAMLprim value caml_spacetime_ocaml_indirect_call_point_callees
+ (value node, value offset)
+{
+ value callees = Indirect_pc_linked_list(node, Long_val(offset));
+ CAMLassert(Is_block(callees));
+ CAMLassert(Is_c_node(callees));
+ return callees;
+}
+
+CAMLprim value caml_spacetime_c_node_is_call(value node)
+{
+ c_node* c_node;
+ CAMLassert(node != (value) NULL);
+ CAMLassert(Is_c_node(node));
+ c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
+ switch (caml_spacetime_offline_classify_c_node(c_node)) {
+ case CALL: return Val_true;
+ case ALLOCATION: return Val_false;
+ }
+ CAMLassert(0);
+ return Val_unit; /* silence compiler warning */
+}
+
+CAMLprim value caml_spacetime_c_node_next(value node)
+{
+ c_node* c_node;
+
+ CAMLassert(node != (value) NULL);
+ CAMLassert(Is_c_node(node));
+ c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
+ CAMLassert(c_node->next == Val_unit || Is_c_node(c_node->next));
+ return c_node->next;
+}
+
+CAMLprim value caml_spacetime_c_node_call_site(value node)
+{
+ c_node* c_node;
+ CAMLassert(node != (value) NULL);
+ CAMLassert(Is_c_node(node));
+ c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
+ return caml_copy_int64((uint64_t) Decode_c_node_pc(c_node->pc));
+}
+
+CAMLprim value caml_spacetime_c_node_callee_node(value node)
+{
+ c_node* c_node;
+ CAMLassert(node != (value) NULL);
+ CAMLassert(Is_c_node(node));
+ c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
+ CAMLassert(caml_spacetime_offline_classify_c_node(c_node) == CALL);
+ /* This might be an uninitialised tail call point: for example if an OCaml
+ callee was indirectly called but the callee wasn't instrumented (e.g. a
+ leaf function that doesn't allocate). */
+ if (Is_tail_caller_node_encoded(c_node->data.call.callee_node)) {
+ return Val_unit;
+ }
+ return c_node->data.call.callee_node;
+}
+
+CAMLprim value caml_spacetime_c_node_call_count(value node)
+{
+ c_node* c_node;
+ CAMLassert(node != (value) NULL);
+ CAMLassert(Is_c_node(node));
+ c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
+ CAMLassert(caml_spacetime_offline_classify_c_node(c_node) == CALL);
+ if (Is_tail_caller_node_encoded(c_node->data.call.callee_node)) {
+ return Val_long(0);
+ }
+ return c_node->data.call.call_count;
+}
+
+CAMLprim value caml_spacetime_c_node_profinfo(value node)
+{
+ c_node* c_node;
+ CAMLassert(node != (value) NULL);
+ CAMLassert(Is_c_node(node));
+ c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
+ CAMLassert(caml_spacetime_offline_classify_c_node(c_node) == ALLOCATION);
+ CAMLassert(!Is_block(c_node->data.allocation.profinfo));
+ return Val_long(Spacetime_profinfo_hd(c_node->data.allocation.profinfo));
+}
+
+CAMLprim value caml_spacetime_c_node_allocation_count(value node)
+{
+ c_node* c_node;
+ CAMLassert(node != (value) NULL);
+ CAMLassert(Is_c_node(node));
+ c_node = caml_spacetime_offline_c_node_of_stored_pointer_not_null(node);
+ CAMLassert(caml_spacetime_offline_classify_c_node(c_node) == ALLOCATION);
+ CAMLassert(!Is_block(c_node->data.allocation.count));
+ return c_node->data.allocation.count;
+}
+
+#endif