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

Melds benchmarking #91

Draft
wants to merge 3 commits into
base: melds
Choose a base branch
from
Draft
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
7 changes: 7 additions & 0 deletions src/core/editor/Zipper.re
Original file line number Diff line number Diff line change
Expand Up @@ -303,3 +303,10 @@ let selection_str = (cur: Cursor.Base.t('tok)): option(string) =>
|> String.concat("")
|> Option.some
};

let to_string = (z: t): string => {
zip(z)
|> Cell.flatten
|> List.map((x: Token.t) => x.text)
|> String.concat("");
};
145 changes: 145 additions & 0 deletions src/web/Benchmark.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
open Tylr_core;

/* given base program string, figure out how many copies to concatenate
to get a program of the provided number of lines, do that concat, and then trim to the exact line count.
*/
let get_program_string_of_length = (program_str, num_lines: int): string => {
let base_lines = program_str |> String.split_on_char('\n');
let base_num_lines = base_lines |> List.length;
let num_copies = num_lines / base_num_lines;
let remainder = num_lines mod base_num_lines + 1;
let program = String.concat("\n", List.init(num_copies, _ => program_str));
let program =
program
++ String.concat("\n", fst(Stds.Lists.split_n(base_lines, remainder)));
program;
};

let benchmark = progam_str =>
Util.TimeUtil.get_time(() => progam_str |> Store.parse |> ignore);

let time_per_line = (lines: int, time: int): float => {
float_of_int(time) /. float_of_int(lines);
};

let benchmark_parsing = () => {
let program_str = Data.longlong;
print_endline(
"BENCHMARK: parsing (prefix of) complete program with no internal obligations",
);
let num_tokens = Labeler.label(program_str) |> List.length;
let num_chars = program_str |> String.length;
let num_lines = program_str |> String.split_on_char('\n') |> List.length;
print_endline(
"BENCHMARK: base program consists of "
++ string_of_int(num_lines)
++ " lines, "
++ string_of_int(num_chars)
++ " chars, and "
++ string_of_int(num_tokens)
++ " tokens",
);
print_endline(
"BENCHMARK: Average tokens per line: "
++ string_of_float(float_of_int(num_tokens) /. float_of_int(num_lines)),
);
print_endline(
"BENCHMARK: Average chars per line: "
++ string_of_float(float_of_int(num_chars) /. float_of_int(num_lines)),
);
let a = benchmark(program_str);
print_endline("BENCHMARK: warmup parse: " ++ string_of_int(a) ++ "ms");
let b = benchmark(program_str);
print_endline(
"BENCHMARK: same parse after warmup: " ++ string_of_int(b) ++ "ms",
);
for (i in 1 to 20) {
let num_lines = 30 * i;
let program_str = get_program_string_of_length(program_str, num_lines);
let c = benchmark(program_str);
print_endline(
"ITERATION "
++ string_of_int(i)
++ " :"
++ string_of_int(num_lines)
++ " lines. parsed in "
++ string_of_int(c)
++ "ms",
);
// print_endline(
// "time per line: "
// ++ string_of_float(time_per_line(num_lines, c))
// ++ "ms",
// );
};
};

let cursor_depth = (z: Zipper.t): int => {
let cell = Zipper.zip(~save_cursor=true, z);
switch (cell.marks.cursor) {
| Some(Point(cursor)) => cursor.path |> List.length
| _ => failwith("benchmark: no cursor")
};
};

let pre_plus_suf_length = (z: Zipper.t): int => {
let ((pre, suf), _tl) = Ctx.uncons(z.ctx);
List.length(pre) + List.length(suf);
};

let benchmark_hole_fills = () => {
let program_str = Data.holey;
//let program_str = List.fold_left((++), "", List.init(40, _ => Data.base1));
let num_holes = 20; //40
let reps_per_action = 200;
let zipper_action = Modify.insert("X");

print_endline("BENCHMARK: filling hole edits at different depths");
print_endline("init program, parsed and then stringed:");
print_endline(program_str |> Store.parse |> Zipper.to_string);
// let a = benchmark(program_str);
// print_endline("BENCHMARK: warmup parse: " ++ string_of_int(a) ++ "ms");
// let b = benchmark(program_str);
// print_endline(
// "BENCHMARK: same parse after warmup: " ++ string_of_int(b) ++ "ms",
// );
let z =
List.fold_left(
(z_acc, _x) => {
// perform insertion action repeatedly
let t =
Util.TimeUtil.get_time(() => {
for (_ in 1 to reps_per_action) {
let _ = zipper_action(z_acc);
();
}
});
print_endline(
"presuf: "
++ string_of_int(pre_plus_suf_length(z_acc))
++ ", depth: "
++ string_of_int(cursor_depth(z_acc))
++ ", "
++ "time for "
++ string_of_int(reps_per_action)
++ " insertions:"
++ string_of_int(t)
++ "ms",
);
// fill hole and return zipper with caret moved to previous hole
let z2 = Modify.insert("X", z_acc);
switch (Tab.perform(L, z2)) {
| None => z2
| Some(z3) => z3
};
},
// starts at bottom of holey program
Store.parse(program_str),
List.init(num_holes, _ => ()),
);
();
print_endline("program after actions:");
print_endline(z |> Zipper.to_string);
};

//benchmark_parsing();
214 changes: 214 additions & 0 deletions src/web/Data.re
Original file line number Diff line number Diff line change
Expand Up @@ -381,3 +381,217 @@ update(init, StampEmoji)


|};

let longlong = {|let x = 1 in
let y = 2 in

let x = 1 + 1 in
let y = 2 * 1 + 3 < 56 * 3455 - 345442 in
type Emoji = Smile + Frown + Smirk in
type Cell = Empty + Stamped(Emoji) in
type Model = ([[Cell]], Emoji) in
type Action =
StampEmoji(Int, Int)
+ ClearCell(Int, Int)
+ SelectEmoji(Emoji)
in
let init: Model = (
[[None, None, None],
[None, None, None],
[None, None, None]],
Smile)
in
let update_grid: (Int, Int, Cell, [[Cell]]) -> [[Cell]] =
fun (row, col, cell, grid) ->
update_nth(row, update_nth(col, cell, List.nth(row, grid)), grid)
in
let update: (Model, Action) -> Model =
fun ((cells, selected), action) ->
case action
| StampEmoji(row, col) =>
(update_grid(row, col, Stamped(Smile), cells), selected)
| ClearCell(row, col) =>
(update_grid(row, col, Empty, cells), selected)
| SelectEmoji(new) => (cells, new)
end
in

type Point = (Int, Int) in
type Rect = (Point, Int, Int) in
type Circ = (Point, Int) in
type Shape = R(Rect) + C(Circ) in
let contains = fun (s: Shape, p: Point) ->
let (x, y) = p in
case s
| R(((x_min, y_min), x_len, y_len)) =>
x_min <= x && x <= x_min + x_len
&& y_min <= y && y <= y_min + y_len
| C((center, r)) => dist(center, p) <= r
end
in

type Point = (Int, Int) in
type Rect = (Point, Int, Int) in
let contains = fun (r: Rect, p: Point) ->
let (x, y) = p in
let ((x_min, y_min), x_len, y_len) = r in
x_min <= x && x <= x_min + x_len
&& y_min <= y && y <= y_min + y_len
in

let blah = shapes
|> filter(fun shape -> area(shape) < 50)
|> map(dilate(5))
|> map(rotate(pi / 4))
|> map(translate(6, 7)) in

let blah = shapes
|> map(rotate(pi / 4))
|> map(translate(6, 7))
|> filter(fun shape -> area(shape) < 50)
|> map(dilate(5)) in

let f = fun (square, p1, p2) ->
let mark =
fun center ->
if square then
let (x, y) = center in
rect(x - 2, y - 2, 4, 4)
else
let r = 4 in
circle(center, r)
in
[mark(p1), line(p1, p2), mark(p2)] in

let f = fun (p1, p2) ->
let mark =
fun center ->
let r = 4 in
circle(center, r)
in
[mark(p1), line(p1, p2), mark(p2)] in

let dist =
fun (p1, p2) ->
let (x1, y1) = p1 in
let (x2, y2) = p2 in
sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2))
in
let f = fun (center, p) ->
let r = dist(center, p) in
circle(center, r) in

|};

let holey = {|let x = + 1 in
let y = 2 in

let x = 1 + 1 in
let y = 2 * 1 + 3 < 56 * + 345442 in
type Emoji = Smile + Frown + Smirk in
type Cell = Empty + Stamped(Emoji) in
type Model = ([[ ]], Emoji) in
type Action =
StampEmoji(Int, Int)
+ ClearCell(Int, Int)
+ SelectEmoji(Emoji)
in
let init: Model = (
[[None, None, None],
[None, None, None],
[None, None, ]],
Smile)
in
let update_grid: (Int, Int, Cell, [[Cell]]) -> [[Cell]] =
fun (row, col, cell, grid) ->
update_nth(row, update_nth(col, cell, List.nth(row, grid)), grid)
in
let update: (Model, Action) -> Model =
fun ((cells, selected), action) ->
case action
| StampEmoji(row, col) =>
(update_grid(row, , Stamped(Smile), cells), selected)
| ClearCell(row, col) =>
(update_grid(row, col, Empty, cells), selected)
| SelectEmoji( ) => (cells, new)
end
in

type Point = (Int, Int) in
type Rect = (Point, Int, Int) in
type Circ = (Point, Int) in
type Shape = R(Rect) + C(Circ) in
let contains = fun ( , p: Point) ->
let (x, y) = p in
case s
| R(((x_min, y_min), x_len, y_len)) =>
<= x && x <= x_min + x_len
&& y_min <= y && y <= y_min +
| C((center, r)) => dist(center, p) <= r
end
in

type Point = (Int, Int) in
type Rect = (Point, Int, Int) in
let contains = fun (r: Rect, p: Point) ->
let (x, y) = p in
let ((x_min, y_min), x_len, y_len) = r in
x_min <= x && x <= x_min + x_len
&& y_min <= y && y <= y_min + y_len
in

let blah = shapes
|> filter(fun shape -> area(shape) < 50)
|> map(dilate(5))
|> map(rotate( / 4))
|> map(translate(6, 7)) in

let blah = shapes
|> map(rotate(pi / 4))
|> map(translate(, 7))
|> filter(fun shape -> area( ) < 50)
|> map(dilate(5)) in

let f = fun (square, p1, p2) ->
let =
fun center ->
if square then
let (x, y) = center in
rect(x - 2, y - 2, 4, )
else
let r = 4 in
circle(center, )
in
[mark(p1), line(p1, p2), mark(p2)] in

let f = fun (p1, p2) ->
let mark =
fun center ->
let r = 4 in
circle(center, )
in
[mark(p1), line(p1, p2), mark(p2)] in

let dist =
fun (p1, p2) ->
let (x1, ) = p1 in
let (x2, y2) = p2 in
sqrt(pow(x1 - x2, 2) + pow(y1 - y2, ))
in
let f = fun (center, p) ->
let r = dist(center, p) in
circle( , r) in

|};

let base1 = {|let = 1 in
|};

let base1' = base1 ++ base1 ++ base1 ++ base1 ++ base1;

let base2 = {|let x = + 2 in
let x = + 2 * 3 in
let x = + 2 / 3 + 4 in
let x = 1 + 2 + + 4 + 5 in
let x = 1 + 2 * 3 + + 5 + 6 in
|};
2 changes: 2 additions & 0 deletions src/web/Main.re
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,5 @@ Incr_dom.Start_app.start(
~bind_to_element_with_id="container",
~initial_model=Model.init_from_store(),
);

Benchmark.benchmark_hole_fills();
Loading
Loading