Example #1
0
def test_chess(test_env):
    slide = test_env.slide
    board = slide.box(width=500, height=500)
    board.new_style("black", color="black", size=50)

    colors = ["#e0e0ff", "#A0A0ff"]
    tiles = {}
    for i in range(8):
        row = board.box(height="fill", width="100%", horizontal=True)
        for j in range(8):
            b = row.box(width="fill", height="100%")
            b.rect(bg_color=colors[(i + j) % 2])
            tiles[(j, i)] = b.overlay(z_level=1)
    board.rect(color="black")

    points = [
        tiles[(3, 4)].mid_point(), tiles[(3, 2)].mid_point(),
        tiles[(4, 2)].mid_point()
    ]

    arrow = Arrow(30)
    slide.box(show="1-3").line(points,
                               color="green",
                               stroke_width=15,
                               end_arrow=arrow)

    tiles[(3, 4)].box(show="1").text("♞", "black")
    tiles[(3, 3)].box(show="2").text("♞", "black")
    tiles[(3, 2)].box(show="3").text("♞", "black")
    tiles[(4, 2)].box(show="4").text("♞", "black")
    test_env.check("chess", 4)
Example #2
0
def intro_slide(slides: Slides):
    slide = slides.new_slide()
    slide.set_style("text", s(size=60, bold=True))
    slide.set_style("orange",
                    slide.get_style("text").compose(s(color="orange")))

    safe = slide.box()
    safe.text("Fast & ~orange{Safe}", style="text")

    slide.box(height=100)

    line = slide.box(width="fill", horizontal=True)
    development = line.box(width="50%", y=0)
    development.overlay(show="2-3").text("Memory safety")
    development.overlay(show="4").text("Memory safety",
                                       style=s(color="orange"))
    performance = line.box(width="50%", y=0, show="3+")
    performance.text("Fearless concurrency")

    arrow = Arrow(20)
    slide.box(show="2+").line(
        [safe.p("80%", "100%"), development.p("50%", 0)],
        stroke_width=5,
        color="orange",
        end_arrow=arrow)
    slide.box(show="3+").line(
        [safe.p("80%", "100%"), performance.p("50%", 0)],
        stroke_width=5,
        color="orange",
        end_arrow=arrow)
Example #3
0
def intro_slide(slides: Slides):
    slide = slides.new_slide()
    slide.set_style("text", s(size=60, bold=True))
    slide.set_style("orange", slide.get_style("text"), s(color="orange"))

    fast = slide.box()
    fast.text("~orange{Fast} & Safe", style="text")

    slide.box(height=100)

    line = slide.box(width="fill", horizontal=True)
    development = line.box(width="50%", y=0)
    development.overlay().text("Quick development")
    performance = line.box(width="50%", y=0)
    performance.text("High performance", style=s(color="orange"))

    arrow = Arrow(20)
    slide.box().line(
        [fast.p("15%", "100%"), development.p("50%", 0)],
        stroke_width=5,
        color="orange",
        end_arrow=arrow)
    slide.box().line(
        [fast.p("15%", "100%"), performance.p("50%", 0)],
        stroke_width=5,
        color="orange",
        end_arrow=arrow)
Example #4
0
    def line(start,
             end,
             start_x,
             end_x,
             right_x,
             offset_x,
             color,
             show,
             y="65%"):
        line_start = code_box.line_box(start, width="fill")
        line_end = code_box.line_box(end, width="fill")
        arrow = Arrow(20)

        start = line_start.p(start_x, y)
        end = line_end.p(end_x, y)

        content.box(show=show).line([
            start,
            line_start.p(right_x, y).add(offset_x, 0),
            line_end.p(right_x, y).add(offset_x, 0), end
        ],
                                    start_arrow=arrow,
                                    end_arrow=arrow,
                                    stroke_width=5,
                                    color=color)
Example #5
0
def pointer_to_line(content,
                    code_box,
                    line,
                    x,
                    y,
                    show,
                    textbox_pos=("0", "0"),
                    code_pos=("0", "0")):
    arrow = Arrow(20)
    line = code_box.line_box(line, show=show)
    text_box = content.box(x=x, y=y, show=show)
    content.box(show=show).line([
        text_box.p(textbox_pos[0], textbox_pos[1]),
        line.p(code_pos[0], code_pos[1])
    ],
                                end_arrow=arrow,
                                stroke_width=5,
                                color="orange")
    return text_box
Example #6
0
def llvm_iterator(slides: Slides):
    slide = slides.new_slide()
    content = slide_header(slide, "Compiles to LLVM")
    content.box(height=600, x=350).image("imgs/llvm-flow.svg")

    slide = slides.new_slide()
    content = slide_header(slide, "Compiles to LLVM")
    src = content.box(width=700, height=100)
    src.image("imgs/godbolt-dot-product.svg")

    content.box(height=60)
    assembly = content.box(width="fill", height=400, show="2+")
    assembly.image("imgs/godbolt-dot-product-assembly.svg")

    arrow = Arrow(20)
    content.box(show="2+").line(
        [src.p("50%", "100%"),
         assembly.p("50%", "0%").add(0, -10)],
        stroke_width=5,
        color="orange",
        end_arrow=arrow)
Example #7
0
def test_line_highlight_no_fragments(test_env):
    slide = test_env.slide

    slide.box(100, 100, 200, 200).rect(color="green")
    slide.box(120, 120, 160, 160).rect(bg_color="green")

    slide.box(320, 100, 200, 200).rect(color="blue", rx=20, ry=20)
    slide.box(340, 120, 160, 160).rect(bg_color="blue", rx=20, ry=20)

    slide.polygon([(540, 300), (740, 300), (640, 100)], color="red")
    slide.polygon([(570, 280), (710, 280), (640, 140)], bg_color="red")

    slide.line([(760, 100), (940, 100), (760, 300), (960, 300)],
               color="orange",
               stroke_width=5)

    slide.line([(100, 500), (200, 500)], color="black", stroke_width=1)
    slide.line([(100, 550), (200, 550)], color="black", stroke_width=5)
    slide.line([(100, 600), (200, 600)], color="black", stroke_width=10)

    arrow1 = Arrow(10, stroke_width=1)
    slide.line([(300, 500), (400, 500)],
               color="black",
               stroke_width=1,
               start_arrow=arrow1,
               end_arrow=arrow1)
    arrow2 = Arrow(20, stroke_width=5)
    slide.line([(300, 550), (400, 550)],
               color="black",
               stroke_width=5,
               start_arrow=arrow2,
               end_arrow=arrow2)
    arrow3 = Arrow(30, stroke_width=10)
    slide.line([(300, 600), (400, 600)],
               color="black",
               stroke_width=10,
               start_arrow=arrow3,
               end_arrow=arrow3)

    arrow1 = Arrow(10)
    slide.line([(500, 500), (600, 500)],
               color="black",
               stroke_width=1,
               start_arrow=arrow1,
               end_arrow=arrow1)
    arrow2 = Arrow(20)
    slide.line([(500, 550), (600, 550)],
               color="black",
               stroke_width=5,
               start_arrow=arrow2,
               end_arrow=arrow2)
    arrow3 = Arrow(30)
    slide.line([(500, 600), (600, 600)],
               color="black",
               stroke_width=10,
               start_arrow=arrow3,
               end_arrow=arrow3)

    arrow1 = Arrow(10, inner=0.5)
    slide.line([(700, 500), (800, 500)],
               color="black",
               stroke_width=1,
               start_arrow=arrow1,
               end_arrow=arrow1)
    arrow2 = Arrow(20, inner=0.5)
    slide.line([(700, 550), (800, 550)],
               color="black",
               stroke_width=5,
               start_arrow=arrow2,
               end_arrow=arrow2)
    arrow3 = Arrow(30, inner=0.5)
    slide.line([(700, 600), (800, 600)],
               color="black",
               stroke_width=10,
               start_arrow=arrow3,
               end_arrow=arrow3)

    arrow1 = Arrow(10, inner=2.0)
    slide.line([(900, 500), (1000, 500)],
               color="black",
               stroke_width=1,
               start_arrow=arrow1,
               end_arrow=arrow1)
    arrow2 = Arrow(20, inner=2.0)
    slide.line([(900, 550), (1000, 550)],
               color="black",
               stroke_width=5,
               start_arrow=arrow2,
               end_arrow=arrow2)
    arrow3 = Arrow(30, inner=2.0)
    slide.line([(900, 600), (1000, 600)],
               color="black",
               stroke_width=10,
               start_arrow=arrow3,
               end_arrow=arrow3)

    test_env.check("shapes")
Example #8
0
def test_shapes(test_env):
    slide = test_env.slide

    slide.box(x=650, y=350, width=50, height=50).ellipse(bg_color="green")
    slide.box(x=720, y=350, width=150, height=50).ellipse(
        bg_color="purple", color="yellow", stroke_width=10
    )
    slide.box(x=900, y=350, width=50, height=100).ellipse(bg_color="blue")

    slide.box(x=100, y=100, width=200, height=200).rect(color="green")
    slide.box(x=120, y=120, width=160, height=160).rect(bg_color="green")

    slide.box(x=320, y=100, width=200, height=200).rect(color="blue", rx=20, ry=20)
    slide.box(x=340, y=120, width=160, height=160).rect(bg_color="blue", rx=20, ry=20)

    slide.polygon([(540, 300), (740, 300), (640, 100)], color="red")
    slide.polygon([(570, 280), (710, 280), (640, 140)], bg_color="red")

    slide.line(
        [(760, 100), (940, 100), (760, 300), (960, 300)], color="orange", stroke_width=5
    )

    slide.line([(100, 500), (200, 500)], color="black", stroke_width=1)
    slide.line([(100, 550), (200, 550)], color="black", stroke_width=5)
    slide.line([(100, 600), (200, 600)], color="black", stroke_width=10)

    arrow1 = Arrow(10, stroke_width=1)
    slide.line(
        [(300, 500), (400, 500)],
        color="black",
        stroke_width=1,
        start_arrow=arrow1,
        end_arrow=arrow1,
    )
    arrow2 = Arrow(20, stroke_width=5)
    slide.line(
        [(300, 550), (400, 550)],
        color="black",
        stroke_width=5,
        start_arrow=arrow2,
        end_arrow=arrow2,
    )
    arrow3 = Arrow(30, stroke_width=10)
    slide.line(
        [(300, 600), (400, 600)],
        color="black",
        stroke_width=10,
        start_arrow=arrow3,
        end_arrow=arrow3,
    )

    arrow1 = Arrow(10)
    slide.line(
        [(500, 500), (600, 500)],
        color="black",
        stroke_width=1,
        start_arrow=arrow1,
        end_arrow=arrow1,
    )
    arrow2 = Arrow(20)
    slide.line(
        [(500, 550), (600, 550)],
        color="black",
        stroke_width=5,
        start_arrow=arrow2,
        end_arrow=arrow2,
    )
    arrow3 = Arrow(30)
    slide.line(
        [(500, 600), (600, 600)],
        color="black",
        stroke_width=10,
        start_arrow=arrow3,
        end_arrow=arrow3,
    )

    arrow1 = Arrow(10, inner=0.5)
    slide.line(
        [(700, 500), (800, 500)],
        color="black",
        stroke_width=1,
        start_arrow=arrow1,
        end_arrow=arrow1,
    )
    arrow2 = Arrow(20, inner=0.5)
    slide.line(
        [(700, 550), (800, 550)],
        color="black",
        stroke_width=5,
        start_arrow=arrow2,
        end_arrow=arrow2,
    )
    arrow3 = Arrow(30, inner=0.5)
    slide.line(
        [(700, 600), (800, 600)],
        color="black",
        stroke_width=10,
        start_arrow=arrow3,
        end_arrow=arrow3,
    )

    arrow1 = Arrow(10, inner=2.0)
    slide.line(
        [(900, 500), (1000, 500)],
        color="black",
        stroke_width=1,
        start_arrow=arrow1,
        end_arrow=arrow1,
    )
    arrow2 = Arrow(20, inner=2.0)
    slide.line(
        [(900, 550), (1000, 550)],
        color="black",
        stroke_width=5,
        start_arrow=arrow2,
        end_arrow=arrow2,
    )
    arrow3 = Arrow(30, inner=2.0)
    slide.line(
        [(900, 600), (1000, 600)],
        color="black",
        stroke_width=10,
        start_arrow=arrow3,
        end_arrow=arrow3,
    )

    # Dashes

    # dash(10) space(10) ...
    slide.line([(100, 350), (500, 350)], stroke_width=10, stroke_dasharray="10")

    # dash(10) space(20) ...
    slide.line([(100, 380), (500, 380)], stroke_width=10, stroke_dasharray="10 20")

    # dash(20) space(10) dash(2) space(10) ...
    slide.line([(100, 410), (500, 410)], stroke_width=10, stroke_dasharray="20 10 2 10")

    # dashed rectangle
    slide.box(x=550, y=350, width=50, height=50).rect(
        stroke_width=5, stroke_dasharray="2", color="black", rx=5, ry=5
    )
Example #9
0
def test_path(test_env):
    COLOR1 = "blue"

    slide = test_env.slide
    box = slide.box(height="80%", width="80%").rect(color="black")

    arrow1 = Arrow(10)
    box.path(
        [("M", box.p(0, 0)), ("L", (300, 400)), ("Q", (400, 400), (300, 500))],
        end_arrow=arrow1,
    )

    box.path(
        [
            ("M", box.p(0, 0)),
            ("C", box.p(0, -40), box.p("100%", -40), box.p("100%", 0)),
        ],
        color="red",
        stroke_width=4,
        bg_color="blue",
    )

    root = (
        slide.box(x=250, y="[50%]", width=100, height=50)
        .rect(color=COLOR1, bg_color="#EEE", rx=5, ry=5)
        .text("Root")
    )
    child1 = (
        slide.box(x=650, y="[20%]", width=100, height=50)
        .rect(color=COLOR1, bg_color="#EEE", rx=5, ry=5)
        .text("Child1")
    )
    child2 = (
        slide.box(x=650, y="[80%]", width=100, height=50)
        .rect(color=COLOR1, bg_color="#EEE", rx=5, ry=5)
        .text("Child2")
    )

    arrow = Arrow(10)

    # Path root -> child1
    r1 = root.p("100%", "50%")
    c1 = child1.p("0%", "50%")

    # See SVG <path> documentation for commands explanation
    # In short: M = move to, L = line to, C/S = bezier curve, Q/T = quadratic
    slide.path(
        [("M", r1), ("C", r1.add(300, 0), c1.add(-300, 0), c1)],
        end_arrow=arrow,
        stroke_width=2,
        color=COLOR1,
    )

    # Path root -> child2
    c2 = child2.p("0%", "50%")
    slide.path(
        [("M", r1), ("Q", c2.add(-100, 0), c2)],
        end_arrow=arrow,
        stroke_width=2,
        color=COLOR1,
        stroke_dasharray="10",
    )

    # Path chiled1 -> child1
    c1t = child1.p("50%", "0%")
    c1r = child1.p("100%", "50%")
    slide.path(
        [("M", c1t), ("C", c1t.add(0, -100), c1r.add(100, 0), c1r)],
        end_arrow=arrow,
        stroke_width=2,
        color=COLOR1,
    )

    slide.path([("M", (650, 350)), ("L", (750, 350))], stroke_width=4, color="green")
    slide.path(
        [("M", (600, 450)), ("L", (700, 250)), ("L", (800, 450))],
        stroke_width=4,
        color="red",
    )
    slide.path(
        [("M", (600, 450)), ("Q", (700, 250), (800, 450))], bg_color="blue", color=None
    )
Example #10
0
label = slide.box(100, 400, 200, 130, show="5")
label.update_style("default", color="white")
label.rect(bg_color="green", rx=10, ry=10)
label.text("Comment for\na line")

# Here we creates the triangle heading to a line,
# method 'p' returns a position relatively to the box
label.polygon([
    label.p("99%", "40%"),
    label.p("99%", "60%"),
    code_box.line_box(4).p(0, "50%")
],
              bg_color="green")

# Now we are creating an arrow head for the orange line
arrow = Arrow(10)
p1 = code_box.line_box(0).p("100%", "50%")
p2 = code_box.line_box(5).p("100%", "50%")
slide.box(show="6").line(
    [p1, p1.add(40, 0), p2.add(40, 0), p2],
    stroke_width=3,
    color="orange",
    end_arrow=arrow)

# Console demo ############################################

slide = slides.new_slide()

slide.derive_style("code", "shell", color="white")
slide.new_style("prompt", color="#aaaaff")
slide.new_style("cmd", color="yellow")
Example #11
0
def cache_conflicts(slides: SlideDeck, backup: bool):
    if backup:
        slide = new_slide(slides)
        content = slide_header(slide, "Code (backup)")
        code(
            content.box(),
            """// Addresses of N integers, each `offset` bytes apart
std::vector<int*> data = ...;
for (auto ptr: data)
{
    *ptr += 1;
}
// Offsets: 4, 64, 4000, 4096, 4128""")
        slide = new_slide(slides)
        content = slide_header(slide, "Result (backup)")
        content.box(height=600).image("images/example1-time.png")

    slide = new_slide(slides)
    content = slide_header(slide, "Cache memory")
    content.box(height=600).image("images/haswell-diagram.png")
    content.box(width=230, height=40, x=816, y=530).rect(color=COLOR_BACKEND,
                                                         stroke_width=3)

    slide = new_slide(slides)
    content = slide_header(slide, "How are (L1) caches implemented")
    list_wrapper = content.box()
    list_item(list_wrapper).text("N-way set associative table")
    list_item(list_wrapper, level=1, show="last+").text("Hardware hash table")
    list_item(list_wrapper, show="next+").text("Key = address (8B)")
    list_item(list_wrapper, show="next+").text("Entry = cache line (64B)")

    slide = new_slide(slides)
    content = slide_header(slide, "N-way set associative cache")
    hash_size = 8
    hash_dimension = 60

    def table(wrapper: Box,
              size,
              dimension,
              buckets=None,
              bucket_indices=True):
        htable = wrapper.box(horizontal=True)
        items = []
        for i in range(size):
            cell = htable.box(width=dimension,
                              height=dimension,
                              horizontal=True).rect("black", stroke_width=2)
            items.append(cell)

        if buckets:
            bucket_width = int((size / buckets) * dimension)
            for i in range(buckets):
                pos = i * bucket_width
                htable.box(x=pos, y=0, width=bucket_width,
                           height=dimension).rect("black", stroke_width=6)
                if bucket_indices:
                    htable.box(x=pos, y=dimension - 5,
                               width=bucket_width).text(str(i))

        return (htable, items)

    content.box().text("Size = {} cache lines".format(hash_size),
                       style="notice")
    (htable, hitems) = table(content.box(p_top=20), hash_size, hash_dimension)
    arrow_wrapper = content.box()
    arrow = Arrow(20)
    arrow_wrapper.box().line([
        hitems[0].p("50%", 0).add(0, -20),
        hitems[-1].p("50%", 0).add(0, -20),
    ],
                             start_arrow=arrow,
                             end_arrow=arrow,
                             stroke_width=5,
                             color=COLOR_NOTE)

    content.box(
        p_top=20,
        show="next+").text("Associativity (N) - # of cache lines per bucket")
    content.box(p_top=10, show="next+").text("# of buckets = Size / N")

    row = content.box(horizontal=True, p_top=20)
    lcol = row.box(y=0)
    rcol = row.box(y=0, p_left=20)

    def htable_row(text, block_count):
        padding = 20
        height = 110
        lcol.box(show="next+", p_top=padding, height=height).text(text)
        return table(rcol.box(show="last+", p_top=padding, height=height),
                     hash_size, hash_dimension, block_count)

    htable_row("N = 1 (direct mapped)", hash_size)
    htable_row("N = {} (fully associative)".format(hash_size), 1)
    htable_row("N = 2", hash_size // 2)

    slide = new_slide(slides)
    content = slide_header(slide, "How are addresses hashed?")

    content.box().text("64-bit address:")
    row = content.box(horizontal=True, width=800)
    widths = ["60%", "25%", "15%"]
    address_colors = ["#B22222", "#007944", "#0018AE"]
    labels = ["Tag", "Index", "Offset"]

    for i in range(3):
        wrapper = row.box(width=widths[i]).rect(color=address_colors[i],
                                                stroke_width=4)
        wrapper.box(padding=4).text(labels[i])
    labelrow = content.box(horizontal=True, x=220)
    labelrow.box().text("63")
    labelrow.box(p_left=770).text("0")

    list_wrapper = content.box(p_top=20)
    list_item(list_wrapper, show="next+").text("Offset", "bold")
    list_item(list_wrapper, level=1,
              show="last+").text("Selects byte within a cache line")
    list_item(list_wrapper, level=1,
              show="last+").text("log2(cache line size) bits")
    list_item(list_wrapper, show="next+").text("Index", "bold")
    list_item(list_wrapper, level=1,
              show="last+").text("Selects bucket within the cache")
    list_item(list_wrapper, level=1,
              show="last+").text("log2(bucket count) bits")
    list_item(list_wrapper, show="next+").text("Tag", "bold")
    list_item(list_wrapper, level=1, show="last+").text("Used for matching")

    slide = new_slide(slides)
    content = slide_header(slide, "N-way set associative cache")

    queue = content.box(x="55%", y=40, horizontal=True)
    queue.box(p_right=40).text("Cache lines:")
    colors = ("#F0134D", "#FF6F5E", "#F0134D")
    cacheline_labels = ("A", "B", "C")
    for i in range(3):
        queue.box(width=hash_dimension,
                  height=hash_dimension).rect(color="black",
                                              bg_color=colors[i],
                                              stroke_width=5).text(
                                                  cacheline_labels[i],
                                                  style=s(bold=True,
                                                          color="white"))

    index = content.box(x="55%", y=90, horizontal=True)
    index.box(p_right=75).text("Index bits:")
    index_bits = (0, 1, 0)
    for i in range(3):
        index.box(width=hash_dimension,
                  height=hash_dimension).text(str(index_bits[i]))

    def insert(slot, show, item):
        wrapper = slot.overlay(show=show)
        wrapper.rect(bg_color=colors[item])
        wrapper.text(cacheline_labels[item], style=s(bold=True, color="white"))

    row = content.box(horizontal=True, p_top=20)
    lcol = row.box(y=0)
    rcol = row.box(y=0, p_left=20)

    def htable_row(text, block_count):
        padding = 20
        height = 140
        lcol.box(show="next+", p_top=padding, height=height).text(text)
        return table(rcol.box(show="last+", p_top=padding, height=height),
                     hash_size, hash_dimension, block_count)

    (_, hitems) = htable_row("N = 1", hash_size)
    insert(hitems[0], "next+", 0)
    insert(hitems[1], "next+", 1)
    insert(hitems[0], "next+", 2)

    (_, hitems) = htable_row("N = {}".format(hash_size), 1)
    insert(hitems[0], "next+", 0)
    insert(hitems[1], "next+", 1)
    insert(hitems[2], "next+", 2)

    (_, hitems) = htable_row("N = 2", hash_size // 2)
    insert(hitems[0], "next+", 0)
    insert(hitems[2], "next+", 1)
    insert(hitems[1], "next+", 2)

    slide = new_slide(slides)
    slide.update_style("default", s(size=46))
    slide.update_style("bold", s(size=46))
    content = slide_header(slide, "Intel L1 cache")
    bash(content.box(),
         """$ getconf -a | grep LEVEL1_DCACHE
LEVEL1_DCACHE_SIZE      32768
LEVEL1_DCACHE_ASSOC     8
LEVEL1_DCACHE_LINESIZE  64""",
         text_style=s(align="left"))
    list_wrapper = content.box(p_top=20)
    list_item(
        list_wrapper,
        show="next+").text("~bold{Cache line size} - 64 B (6 offset bits)")
    list_item(list_wrapper, show="next+").text("~bold{Associativity} (N) - 8")
    list_item(list_wrapper, show="next+").text("~bold{Size} - 32768 B")
    list_item(list_wrapper, show="next+").text("32768 / 64 => 512 cache lines")
    list_item(list_wrapper,
              show="next+").text("512 / 8 => 64 buckets (6 index bits)")

    slides.set_style("tag", s(color=address_colors[0]))
    tag = slides.get_style("tag")
    slides.set_style("index", tag.compose(s(color=address_colors[1])))
    slides.set_style("offset", tag.compose(s(color=address_colors[2])))

    styles = ["tag", "index", "offset"]
    colors = ["#F0134D", "#FF6F5E", "#1F6650", "#40BFC1"]

    def address(cols, content, next=True, use_style=True, row=0):
        for i, col in enumerate(cols):
            show = "1+"
            if next:
                show = "next+" if i == 0 else "last+"

            style = "default"
            if use_style:
                if i == 0:
                    style = s(color=colors[row])
                else:
                    style = styles[i - 1]
            col.box(show=show).text(content[i], style=style)

    slide = new_slide(slides)
    content = slide_header(slide, "Offset = 4B")

    width = 700
    columns = 4
    row = content.box(horizontal=True)
    cols = [row.box(width=width // columns) for _ in range(columns)]

    address(cols, ("Number", "Tag", "Index", "Offset"),
            next=False,
            use_style=False)
    address(cols, ("A", "..100000", "000000", "000000"), next=False)
    address(cols, ("B", "..100000", "000000", "000100"), row=1)
    address(cols, ("C", "..100000", "000000", "001000"), row=2)
    address(cols, ("D", "..100000", "000000", "001100"), row=3)

    hash_dimension = 80
    (htable, hitems) = table(content.box(p_top=20), hash_size, hash_dimension,
                             hash_size // 2)
    for i in range(4):
        hitems[0].box(show="{}+".format(i + 1),
                      width=hash_dimension // 4,
                      height=hash_dimension).rect(bg_color=colors[i])

    list_wrapper = content.box(p_top=40)
    list_item(
        list_wrapper,
        show="next+").text("Same bucket, same cache line for each number")
    list_item(list_wrapper,
              show="next+").text("Most efficient, no space is wasted")

    slide = new_slide(slides)
    content = slide_header(slide, "Offset = 64B")

    row = content.box(horizontal=True)
    cols = [row.box(width=width // columns) for _ in range(columns)]

    address(cols, ("Number", "Tag", "Index", "Offset"),
            next=False,
            use_style=False)
    address(cols, ("A", "..100000", "000000", "000000"), next=False)
    address(cols, ("B", "..100000", "000001", "000000"), row=1)
    address(cols, ("C", "..100000", "000010", "000000"), row=2)
    address(cols, ("D", "..100000", "000011", "000000"), row=3)

    (htable, hitems) = table(content.box(p_top=20), hash_size, hash_dimension,
                             hash_size // 2)
    for i in range(4):
        hitems[i * 2].box(show="{}+".format(i + 1),
                          width=hash_dimension // 4,
                          height=hash_dimension,
                          x=0).rect(bg_color=colors[i])

    list_wrapper = content.box(p_top=40)
    list_item(list_wrapper,
              show="next+").text("Different bucket for each number")
    list_item(list_wrapper, show="next+").text("Wastes 60B in each cache line")
    list_item(list_wrapper,
              show="next+").text("Equally distributed among buckets")

    slide = new_slide(slides)
    content = slide_header(slide, "Offset = 4096B")

    row = content.box(horizontal=True)
    cols = [row.box(width=width // columns) for _ in range(columns)]

    address(cols, ("Number", "Tag", "Index", "Offset"),
            next=False,
            use_style=False)
    address(cols, ("A", "..100000", "000000", "000000"), next=False)
    address(cols, ("B", "..100001", "000000", "000000"), row=1)
    address(cols, ("C", "..100010", "000000", "000000"), row=2)
    address(cols, ("D", "..100011", "000000", "000000"), row=3)

    (htable, hitems) = table(content.box(p_top=20), hash_size, hash_dimension,
                             hash_size // 2)
    for i in range(4):
        hitems[i % 2].box(show="{}+".format(i + 1),
                          width=hash_dimension // 4,
                          height=hash_dimension,
                          x=0).rect(bg_color=colors[i])

    list_wrapper = content.box(p_top=40)
    list_item(list_wrapper, show="next+").text(
        "Same bucket, but different cache lines for each number!")
    list_item(list_wrapper,
              show="next+").text("Bucket full => evictions necessary")

    slide = new_slide(slides)
    content = slide_header(slide, "How to measure?")
    content.box().text("~tt{l1d.replacement}", style=s(size=48))
    content.box(
        p_top=20).text("How many times was a cache line loaded into L1?")

    if backup:
        bash(content.box(p_top=40, show="next+"),
             """$ perf stat -e l1d.replacement ./example1
4B    offset ->     149 558
4096B offset -> 426 218 383""",
             text_style=s(align="left"))
Example #12
0
def project(slides: Slides):
    slide = slides.new_slide()
    content = slide_header(slide, "Project management (Cargo)")
    content.box(height=400).image("imgs/cargo.png")

    slide = slides.new_slide()
    slide.update_style("code", s(size=30))

    content = slide_header(slide, "Using libraries")

    line = content.box(width="fill", horizontal=True)

    cargo = line.box(width="50%", p_right=50)
    cargo.box().text("Cargo.toml")
    cargo_code = code(
        cargo.box(), """
[package]
name = "hello_world"
version = "0.1.0"

[dependencies]
ibverbs = "0.4"
json = "1.0"
protobuf = "2.0"
""", "toml")

    main = line.box(width="50%", show="2+", y=0)
    main.box().text("main.rs")
    main_code = code(
        main.box(), """
use json::parse;

fn main() {
    parse("data.json");
}""")

    arrow = Arrow(20)
    p1 = cargo_code.line_box(5).p("100%", "50%")
    p2 = main_code.line_box(0).p(0, "50%")
    slide.box(show="2+").line(
        [p1.add(-40, 0), p1, p2.add(-10, 0)],
        stroke_width=5,
        color="orange",
        end_arrow=arrow)

    content.box(height=10)
    content.box(show="3+").text("More than 26k libraries available")

    slide = slides.new_slide()
    content = slide_header(slide, "Unified documentation")
    content.box(width=900).image("imgs/rust-docs.png")

    slide = slides.new_slide()
    content = slide_header(slide, "Integrated tooling")

    def cargo_line(parent, text, code, show="1+", **text_args):
        wrapper = parent.box(width="fill", horizontal=True, show=show)
        textbox = wrapper.box(width="50%")
        textbox = textbox.text(text, **text_args)

        codebox = wrapper.box(width="40%")
        bash(codebox, code, x=0, width="fill")
        return textbox

    wrapper = content.box(width="fill")
    cargo_line(wrapper, "Build", "$ cargo build", "1+")
    cargo_line(wrapper, "Run", "$ cargo run", "2+")

    slide = slides.new_slide()
    slide.update_style("code", s(size=40))
    content = slide_header(slide, "Integrated tooling (tests)")

    code(content.box(), """
#[test]
fn test_add() {
    assert_eq!(add(1, 2), 3);
}
""")

    content.box(height=20)
    bash(content.box(show="2+"), "$ cargo test")

    slide = slides.new_slide()
    slide.update_style("code", s(size=40))
    content = slide_header(slide, "Integrated tooling (benchmarks)")

    code(
        content.box(), """
#[bench]
fn bench_add_two(b: &mut Bencher) {
    b.iter(|| add_two(2));
}
""")

    content.box(height=20)
    bash(content.box(show="2+"), "$ cargo bench")

    slide = slides.new_slide()
    content = slide_header(slide, "Integrated tooling")
    wrapper = content.box(width="fill")
    cargo_line(wrapper, "Format", "$ cargo fmt")
    cargo_line(wrapper, "Lint", "$ cargo clippy", "next+")
    box = cargo_line(wrapper, "Publish to SC", "$ cargo publish", "next+")
    box = box.line_box(0)
    box.line([box.p("53%", "55%"), box.p("73%", "55%")], stroke_width=3)

    slide = slides.new_slide()
    slide.update_style("code", s(size=24))
    content = slide_header(slide, "Build scripts")
    content.box().text("build.rs")

    code_width = 940
    code_step(content.box(width=code_width, height=400),
              """
fn main() {
    // generate Protobuf objects
    protoc_rust::run("protobuf/message.proto", "src/protos");

    // generate C headers
    cbindgen::Builder::new()
      .generate()
      .write_to_file("bindings.h");
}
""",
              "1", ((0, 1, 2, 3, None, None, None, None, 8),
                    (0, 1, 2, 3, 4, 5, 6, 7, 8)),
              width=code_width)

    slide = slides.new_slide()
    content = slide_header(slide, "(interlude)")
    content.box(height=600).image("imgs/meme-cargo.jpg")