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

Lambda-lifting: ensure that functions are move to a more appropriate place #1360

Merged
merged 2 commits into from
Dec 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 43 additions & 4 deletions benchmarks/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ GRAPHSNOPR = time.pdf time-optim.pdf nativejs.pdf
GRAPHSPR = size.pdf size-optim.pdf compiletime.pdf

# graphs showing the impact of supporting effects
GRAPHSEFF = time-effects.pdf size-effects.pdf
GRAPHSEFF = time-effects.pdf size-effects.pdf size-bzip2-effects.pdf

# For full benchs:
all: _perf graphsnopr graphspr graphseff _noperf
Expand All @@ -14,7 +14,7 @@ graphsnopr: _noprecomp $(GRAPHSNOPR)

graphspr: __precomp $(GRAPHSPR)

graphseff: $(GRAPHSEFF)
graphseff: __precomp $(GRAPHSEFF)

# For fast benchs:
test: _perf fastrun $(GRAPHS) _noperf
Expand Down Expand Up @@ -48,7 +48,6 @@ __run:
touch __run

__run_effects:
make _noprecomp
$(RUN) -fast -nobyteopt -effects
touch __run_effects

Expand Down Expand Up @@ -165,7 +164,47 @@ size-effects.svg: __run_effects
-omit boyer_no_exc \
-omit kb_no_exc \
-omit loop \
-max 2.5 -svg 7 650 150 -edgecaption -ylabel Size \
-append boulderdash \
-append cubes \
-append minesweeper \
-append planet \
-append js_of_ocaml \
-append ocamlc \
-max 2 -svg 7 650 150 -edgecaption -ylabel Size \
> $@

size-gzipped-effects.svg: __run_effects
$(REPORT) -config report-size-gzipped-effects.config \
-omit binary_trees \
-omit fannkuch_redux \
-omit fannkuch_redux_2 \
-omit boyer_no_exc \
-omit kb_no_exc \
-omit loop \
-append boulderdash \
-append cubes \
-append minesweeper \
-append planet \
-append js_of_ocaml \
-append ocamlc \
-max 1.2 -min 0.8 -svg 7 650 150 -edgecaption -ylabel Size \
> $@

size-bzip2-effects.svg: __run_effects
$(REPORT) -config report-size-bzip2-effects.config \
-omit binary_trees \
-omit fannkuch_redux \
-omit fannkuch_redux_2 \
-omit boyer_no_exc \
-omit kb_no_exc \
-omit loop \
-append boulderdash \
-append cubes \
-append minesweeper \
-append planet \
-append js_of_ocaml \
-append ocamlc \
-max 1.1 -min 0.95 -svg 7 650 150 -edgecaption -ylabel Size \
> $@

compiletime.svg: __run __precomp __missingcompiletimes
Expand Down
2 changes: 2 additions & 0 deletions benchmarks/report-size-bzip2-effects.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
histogramref sizes "" js_of_ocaml/bzip2 #fbaf4f direct (bzip2)
histogram sizes "" effects/bzip2 #fb4f4f effects (bzip2)
2 changes: 2 additions & 0 deletions benchmarks/report-size-gzipped-effects.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
histogramref sizes "" js_of_ocaml/gzipped #fbaf4f direct (gzip)
histogram sizes "" effects/gzipped #fb4f4f effects (gzip)
5 changes: 4 additions & 1 deletion benchmarks/report.ml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ let nreference = ref (-1)

let maximum = ref (-1.)

let minimum = ref 0.

let table = ref false

let omitted = ref []
Expand Down Expand Up @@ -201,7 +203,7 @@ let gnuplot_output ch no_header (h, t) =
(if !errors then " lw 1" else "");
if !ylabel <> "" then Printf.fprintf ch "set ylabel \"%s\"\n" !ylabel;
if !maximum > 0.
then Printf.fprintf ch "set yrange [0:%f]\n" !maximum
then Printf.fprintf ch "set yrange [%f:%f]\n" !minimum !maximum
else Printf.fprintf ch "set yrange [0:]\n");
(* labels *)
for i = 0 to n - 1 do
Expand Down Expand Up @@ -360,6 +362,7 @@ let _ =
let options =
[ "-ref", Arg.Set_int nreference, "<col> use column <col> as the baseline"
; "-max", Arg.Set_float maximum, "<m> truncate graph at level <max>"
; "-min", Arg.Set_float minimum, "<m> truncate graph below level <min>"
; "-table", Arg.Set table, " output a text table"
; ( "-omit"
, Arg.String (fun s -> omitted := split_on_char s ~sep:',' @ !omitted)
Expand Down
22 changes: 22 additions & 0 deletions benchmarks/run.ml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ let compr_file_size param =
compile_no_ext param ~comptime:false (fun ~src ~dst ->
Format.sprintf "sed 's/^ *//g' %s | gzip -c | wc -c > %s" src dst)

let bzip2_file_size param =
compile_no_ext param ~comptime:false (fun ~src ~dst ->
Format.sprintf "sed 's/^ *//g' %s | bzip2 -c | wc -c > %s" src dst)

let runtime_size param =
compile_no_ext param ~comptime:false (fun ~src ~dst ->
Format.sprintf
Expand Down Expand Up @@ -270,6 +274,24 @@ let _ =
Spec.js_of_ocaml
sizes
(Spec.sub_spec Spec.js_of_ocaml "gzipped");
compr_file_size
param
code
Spec.js_of_ocaml_effects
sizes
(Spec.sub_spec Spec.js_of_ocaml_effects "gzipped");
bzip2_file_size
param
code
Spec.js_of_ocaml_effects
sizes
(Spec.sub_spec Spec.js_of_ocaml_effects "bzip2");
bzip2_file_size
param
code
Spec.js_of_ocaml
sizes
(Spec.sub_spec Spec.js_of_ocaml "bzip2");
runtime_size
param
code
Expand Down
19 changes: 13 additions & 6 deletions compiler/lib/code.ml
Original file line number Diff line number Diff line change
Expand Up @@ -524,12 +524,19 @@ let fold_closures p f accu =
let prepend ({ start; blocks; free_pc } as p) body =
match body with
| [] -> p
| _ ->
let new_start = free_pc in
let branch = if Addr.Map.mem start blocks then Branch (start, []) else Stop in
let blocks = Addr.Map.add new_start { params = []; body; branch } blocks in
let free_pc = free_pc + 1 in
{ start = new_start; blocks; free_pc }
| _ -> (
match Addr.Map.find start blocks with
| block ->
{ p with
blocks = Addr.Map.add start { block with body = body @ block.body } blocks
}
| exception Not_found ->
let new_start = free_pc in
let blocks =
Addr.Map.add new_start { params = []; body; branch = Stop } blocks
in
let free_pc = free_pc + 1 in
{ start = new_start; blocks; free_pc })

let empty_block = { params = []; body = []; branch = Stop }

Expand Down
6 changes: 3 additions & 3 deletions compiler/tests-compiler/gh1354.ml
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ with Exit ->
global_data=runtime.caml_get_global_data(),
Stdlib=global_data.Stdlib,
Stdlib_Printf=global_data.Stdlib__Printf,
_c_=[0,[4,0,0,0,[12,10,0]],runtime.caml_string_of_jsbytes("%d\n")],
_b_=0,
_c_=[0,[4,0,0,0,[12,10,0]],runtime.caml_string_of_jsbytes("%d\n")],
_a_=0;
try
{0;_b_ = _a_ + 1 | 0;throw Stdlib[3]}
Expand Down Expand Up @@ -113,6 +113,7 @@ with Exit ->
global_data=runtime.caml_get_global_data(),
Stdlib=global_data.Stdlib,
Stdlib_Printf=global_data.Stdlib__Printf,
_c_=0,
_g_=
[0,
[4,0,0,0,[12,32,[4,0,0,0,[12,10,0]]]],
Expand All @@ -121,7 +122,6 @@ with Exit ->
[0,
[4,0,0,0,[12,32,[4,0,0,0,[12,10,0]]]],
caml_string_of_jsbytes("%d %d\n")],
_c_=0,
_a_=0,
_b_=0;
try
Expand Down Expand Up @@ -184,9 +184,9 @@ with Exit ->
global_data=runtime.caml_get_global_data(),
Stdlib=global_data.Stdlib,
Stdlib_Printf=global_data.Stdlib__Printf,
_b_=0,
_e_=[0,[4,0,0,0,[12,10,0]],caml_string_of_jsbytes("%d\n")],
_c_=[0,[4,0,0,0,[12,10,0]],caml_string_of_jsbytes("%d\n")],
_b_=0,
_a_=0;
try
{var _d_=_a_;
Expand Down
24 changes: 11 additions & 13 deletions compiler/tests-compiler/lambda_lifting.ml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ Printf.printf "%d\n" (f 3)
[0,
[4,0,0,0,[12,10,0]],
runtime.caml_string_of_jsbytes("%d\n")];
function _b_(){return caml_cps_exact_call0(_i_())}
function _b_()
{var f$0=f();return caml_cps_exact_call0(_h_(f$0,3))}
function h(x,y)
{function h(z,cont)
{return caml_cps_exact_call1(cont,(x + y | 0) + z | 0)}
Expand All @@ -60,24 +61,21 @@ Printf.printf "%d\n" (f 3)
{var g$0=g(x);return caml_cps_exact_call2(g$0,5,cont)}
return f}
function _c_()
{return function(_p_)
{return function(_o_)
{var Test=[0];
runtime.caml_register_global(2,Test,"Test");
return}}
function _d_()
{return function(_o_){return caml_cps_exact_call1(_c_(),_o_)}}
function _e_(_m_,_n_)
{return function(){return caml_cps_call3(_m_,_a_,_n_,_d_())}}
{return function(_n_){return caml_cps_exact_call1(_c_(),_n_)}}
function _e_(_l_,_m_)
{return function(){return caml_cps_call3(_l_,_a_,_m_,_d_())}}
function _f_()
{return function(_l_)
{return caml_cps_exact_call0(_e_(Stdlib_Printf[2],_l_))}}
{return function(_k_)
{return caml_cps_exact_call0(_e_(Stdlib_Printf[2],_k_))}}
function _g_()
{return function(_k_){return caml_cps_exact_call1(_f_(),_k_)}}
function _h_(f,_j_)
{return function(){return caml_cps_exact_call2(f,_j_,_g_())}}
function _i_()
{return function()
{var f$0=f();return caml_cps_exact_call0(_h_(f$0,3))}}
{return function(_j_){return caml_cps_exact_call1(_f_(),_j_)}}
function _h_(f,_i_)
{return function(){return caml_cps_exact_call2(f,_i_,_g_())}}
return caml_cps_exact_call0(_b_)},
[])}
(globalThis));
Expand Down
Binary file added manual/files/performances/size-bzip2-effects.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified manual/files/performances/size-effects.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 10 additions & 8 deletions manual/performances.wiki
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ See how various js_of_ocaml options affect the generated size and execution time
<<a_img src="performances/time-optim.png" | Relative execution times >>

We show the performance impact of supporting effect handlers. The code
is about 20% to 50% larger. The impact on compressed code is actually
lower since we are adding a lot of function definitions, which are
rather verbose in JavaScript but compress well. Code that involves a
lot of function calls without allocation, such as {{{fib}}}, becomes
much slower. The overhead is more reasonable for code that performs a
lot of allocations ({{{hamming}}}) or that performs some numeric
computations ({{{almabench}}}, {{{fft}}}). Exception handling is
faster ({{{boyer}}}).
is about 50% larger. The impact on compressed code is actually much lower
since we are adding a lot of function definitions, which are rather
verbose in JavaScript but compress well: the compressed code size
increase by about only 5% for large files compressed with {{{bzip2}}}.
Code that involves a lot of function calls without allocation, such as
{{{fib}}}, becomes much slower. The overhead is more reasonable for
code that performs a lot of allocations ({{{hamming}}}) or that
performs some numeric computations ({{{almabench}}}, {{{fft}}}).
Exception handling is faster ({{{boyer}}}).

<<a_img src="performances/size-effects.png" | Relative size >>
<<a_img src="performances/size-bzip2-effects.png" | Relative size (compressed with bzip2) >>
<<a_img src="performances/time-effects.png" | Relative execution times >>