Skip to content

Commit

Permalink
Fix slow compilation due to always_inline on large function. Add benc…
Browse files Browse the repository at this point in the history
…hmark check. (#9)

* removing always inilne on long function helped a LOT

* use custom split function to remove raising quality

* start adding benchmarks

* start adding in benchmarks

* rm test files

* fix alignment test
  • Loading branch information
thatstoasty authored Jun 9, 2024
1 parent 0764d07 commit 90e77a1
Show file tree
Hide file tree
Showing 37 changed files with 6,064 additions and 293 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 20,6 @@ jobs:
run: |
export MODULAR_HOME="/home/runner/.modular"
export PATH="/home/runner/.modular/pkg/packages.modular.com_mojo/bin:$PATH"
pytest
pytest tests/unit
pytest tests/integration
bash run_examples.sh
Empty file added benchmarks/__init__.mojo
Empty file.
31 changes: 31 additions & 0 deletions benchmarks/basic_styling.mojo
Original file line number Diff line number Diff line change
@@ -0,0 1,31 @@
import mog
from benchmark.compiler import keep


fn basic_styling():
var style = (
mog.new_style()
.bold(True)
.foreground(mog.Color("#FAFAFA"))
.background(mog.Color("#7D56F4"))
.padding_top(2)
.padding_left(4)
.width(22)
)

var output = style.render("Hello, kitty")
keep(output)


fn basic_styling_big_file():
var content: String = ""
try:
with open("./benchmarks/data/big.txt", "r") as file:
content = file.read()
var style = mog.new_style().bold(True).foreground(mog.Color("#FAFAFA")).background(
mog.Color("#7D56F4")
).width(100)
var output = style.render(content)
keep(output)
except e:
print(e)
5,474 changes: 5,474 additions & 0 deletions benchmarks/data/big.txt

Large diffs are not rendered by default.

249 changes: 249 additions & 0 deletions benchmarks/layout.mojo
Original file line number Diff line number Diff line change
@@ -0,0 1,249 @@
from benchmark.compiler import keep
from external.gojo.strings import StringBuilder
from external.weave.ansi import printable_rune_width
from mog.join import join_vertical, join_horizontal
from mog.border import hidden_border, normal_border, rounded_border, Border
from mog.style import Style
from mog.size import get_width
from mog import position
from mog.whitespace import (
place,
with_whitespace_chars,
with_whitespace_foreground,
)
import mog


alias width = 96
alias column_width = 30
alias subtle = mog.AdaptiveColor(light="#D9DCCF", dark="#383838")
alias highlight = mog.AdaptiveColor(light="#874BFD", dark="#7D56F4")
alias special = mog.AdaptiveColor(light="#43BF6D", dark="#73F59F")


fn build_tabs() -> String:
alias active_tab_border = Border(
top="",
bottom=" ",
left="",
right="",
top_left="",
top_right="",
bottom_left="",
bottom_right="",
)

alias tab_border = Border(
top="",
bottom="",
left="",
right="",
top_left="",
top_right="",
bottom_left="",
bottom_right="",
)

var tab_style = Style.new().border(tab_border).border_foreground(highlight).padding(0, 1)

var active_tab = tab_style.copy().border(active_tab_border, True)

var tab_gap = tab_style.copy().border_top(False).border_left(False).border_right(False)

var row = join_horizontal(
position.top,
active_tab.render("Mog"),
tab_style.render("Gojo"),
tab_style.render("Lightbug"),
tab_style.render("Basalt"),
tab_style.render("Prism"),
)
var gap = tab_gap.render(String(" ") * max(0, width - get_width(row) - 2))
return join_horizontal(position.bottom, row, gap)


fn build_description() -> String:
var divider = Style.new().padding(0, 1).foreground(subtle).render("")

var url = Style.new().foreground(special)
var desc_style = Style.new().margin_top(1)
var info_style = Style.new().border(normal_border(), True, False, False, False).border_foreground(subtle)

return join_vertical(
position.left,
desc_style.render("Style Definitions for Nice Terminal Layouts.\nInspired by charmbracelet/lipgloss"),
info_style.render("From Mikhail" divider url.render("https://github.com/thatstoasty/mog")),
)


fn build_dialog_box() -> String:
var dialog_box_style = Style.new().alignment(position.center).border(rounded_border()).border_foreground(
mog.Color("#874BFD")
).padding(1, 0)

var button_style = Style.new().foreground(mog.Color("#FFF7DB")).background(mog.Color("#888B7E")).padding(
0, 3
).margin_top(1)

var active_button_style = button_style.copy().foreground(mog.Color("#FFF7DB")).background(
mog.Color("#F25D94")
).margin_right(2).underline()

var ok_button = active_button_style.render("Yes")
var cancel_button = button_style.render("Maybe")

var question = Style.new().width(50).alignment(position.center).render("Are you sure you want to eat marmalade?")

var buttons = join_horizontal(position.top, ok_button, cancel_button)
var ui = join_vertical(position.center, question, buttons)

# TODO: Cannot handle unicode characters with a length greater than 1. For example: east asian characters like Kanji.
return place(
width,
9,
position.center,
position.center,
dialog_box_style.render(ui),
with_whitespace_chars["⣾⣽⣻⢿⡿⣟⣯⣷"](),
with_whitespace_foreground[subtle](),
)


fn build_lists() -> String:
var list_style = Style.new().border(normal_border(), False, True, False, False).border_foreground(
subtle
).margin_right(2).height(8).width(column_width 1)

var list_header = Style.new().border(normal_border(), False, False, True, False).border_foreground(
subtle
).margin_right(2)

var list_item = Style.new().padding_left(2)

var check_mark = Style.new().foreground(special).padding_right(1).render("")

var list_done = Style.new().crossout().foreground(mog.AdaptiveColor(light="#969B86", dark="#696969"))

var lists = join_horizontal(
position.top,
list_style.render(
join_vertical(
position.left,
list_header.render("Citrus Fruits to Try"),
check_mark list_done.render("Grapefruit"),
check_mark list_done.render("Yuzu"),
list_item.render("Citron"),
list_item.render("Kumquat"),
list_item.render("Pomelo"),
),
),
list_style.copy()
.width(column_width)
.render(
join_vertical(
position.left,
list_header.render("Actual Lip Gloss Vendors"),
list_item.render("Glossier"),
list_item.render("Claire's Boutique"),
check_mark list_done.render("Nyx"),
list_item.render("Mac"),
check_mark list_done.render("Milk"),
),
),
list_style.copy()
.width(column_width - 1)
.render(
join_vertical(
position.left,
list_header.render("Programming Languages"),
list_item.render("Mojo"),
list_item.render("Rust"),
check_mark list_done.render("Python"),
list_item.render("Gleam"),
check_mark list_done.render("Go"),
),
),
)

return join_horizontal(position.top, lists)


fn build_history() -> String:
var history_style = Style.new().height(20).width(column_width).padding(1, 2).margin(1, 3, 0, 0).alignment(
position.left
).foreground(mog.Color("#FFFDF5")).background(highlight)

alias history_a = "The Romans learned from the Greeks that quinces slowly cooked with honey would “set” when cool. The Apicius gives a recipe for preserving whole quinces, stems and leaves attached, in a bath of honey diluted with defrutum: Roman marmalade. Preserves of quince and lemon appear (along with rose, apple, plum and pear) in the Book of ceremonies of the Byzantine Emperor Constantine VII Porphyrogennetos."
alias history_b = "Medieval quince preserves, which went by the French name cotignac, produced in a clear version and a fruit pulp version, began to lose their medieval seasoning of spices in the 16th century. In the 17th century, La Varenne provided recipes for both thick and clear cotignac."
alias history_c = "In 1524, Henry VIII, King of England, received a “box of marmalade” from Mr. Hull of Exeter. This was probably marmelada, a solid quince paste from Portugal, still made and sold in southern Europe today. It became a favourite treat of Anne Boleyn and her ladies in waiting."

return join_horizontal(
position.top,
history_style.copy().alignment(position.right).render(history_a),
history_style.copy().alignment(position.center).render(history_b),
history_style.copy().margin_right(0).render(history_c),
)


fn build_status_bar() -> String:
var status_nugget_style = Style.new().foreground(mog.Color("#FFFDF5")).padding(0, 1)

var status_bar_style = Style.new().foreground(mog.Color("#C1C6B2")).background(mog.Color("#353533"))

var status_style = Style.new().foreground(mog.Color("#FFFDF5")).background(mog.Color("#FF5F87")).padding(0, 1)
# .margin_right(1)

var encoding_style = status_nugget_style.copy().background(mog.Color("#A550DF")).horizontal_alignment(
position.right
)

var status_text_style = status_bar_style.copy().padding_left(1)
var fish_cake_style = status_nugget_style.copy().background(mog.Color("#6124DF"))

var status_key = status_style.render("STATUS")
var encoding = encoding_style.render("UTF-8")
var fish_cake = fish_cake_style.render("Fish Cake")
var status_val = status_text_style.copy().width(
width - get_width(status_key) - get_width(encoding) - get_width(fish_cake)
).render("Ravishing")

var bar = join_horizontal(
position.top,
status_key,
status_val,
encoding,
fish_cake,
)

return status_bar_style.width(width).render(bar)


fn render_layout():
# The page style
var builder = StringBuilder()
var doc_style = Style.new().padding(1, 2, 1, 2).border(rounded_border()).border_foreground(subtle)

# Tabs.
_ = builder.write_string(build_tabs())
_ = builder.write_string("\n\n")

# Title
_ = builder.write_string(build_description())
_ = builder.write_string("\n\n")

# Dialog box
_ = builder.write_string(build_dialog_box())
_ = builder.write_string("\n\n")

# List
_ = builder.write_string(build_lists())
_ = builder.write_string("\n")

# History
_ = builder.write_string(build_history())
_ = builder.write_string("\n\n")

# Status bar
_ = builder.write_string(build_status_bar())
var output = doc_style.render(builder.render())
keep(output)
51 changes: 51 additions & 0 deletions benchmarks/run.mojo
Original file line number Diff line number Diff line change
@@ -0,0 1,51 @@
import benchmark
from benchmarks.layout import render_layout
from benchmarks.basic_styling import basic_styling, basic_styling_big_file
import mog


fn table_styling(row: Int, col: Int) -> mog.Style:
var style = mog.new_style().horizontal_alignment(mog.center).vertical_alignment(mog.center).padding(0, 1)
var header_style = style.copy().foreground(mog.Color("#39E506"))
if row == 0:
return header_style
else:
return style


fn main():
var results = mog.new_table()
results.style_function = table_styling
results.set_headers("Name", "Mean (ms)", "Total (ms)", "Iterations", "Warmup Total", "Warmup Iterations")

var report = benchmark.run[render_layout](max_iters=10)
results.row(
"Render layout",
str(report.mean(benchmark.Unit.ms)),
str(report.duration(benchmark.Unit.ms)),
str(report.iters()),
str(report.warmup_duration / 1e6),
str(report.warmup_iters),
)

var bs_report = benchmark.run[basic_styling](max_iters=10)
results.row(
"Basic styling",
str(bs_report.mean(benchmark.Unit.ms)),
str(bs_report.duration(benchmark.Unit.ms)),
str(bs_report.iters()),
str(bs_report.warmup_duration / 1e6),
str(bs_report.warmup_iters),
)

var bs_big_report = benchmark.run[basic_styling_big_file](max_iters=10)
results.row(
"Large file test",
str(bs_big_report.mean(benchmark.Unit.ms)),
str(bs_big_report.duration(benchmark.Unit.ms)),
str(bs_big_report.iters()),
str(bs_big_report.warmup_duration / 1e6),
str(bs_big_report.warmup_iters),
)

print(results.render())
Loading

0 comments on commit 90e77a1

Please sign in to comment.