示例#1
0
def design(slides: Slides):
    slide = slides.new_slide()
    content = slide_header(slide, "Design by community")

    list = content.box()
    list_item(list).text("Open source")
    list_item(list).text("RFC")
    list.box(width=700, height=200, p_top=40).image("imgs/rust-rfc.png")

    slide = slides.new_slide()
    content = slide_header(slide, "Backwards compatibility")

    small = s(size=28)

    list = content.box()
    list_item(list).text("Strong BC guarantees")
    list_item(list, show="2+").text("New version every 6 weeks")
    list_item(list, show="2+", level=1).text(
        "Thousands of libraries tested to spot regressions", style=small)
    list_item(list, show="3+").text("Big changes => new edition")
    list_item(list, show="3+", level=1).text("Rust 2015 vs Rust 2018",
                                             style=small)

    slide = slides.new_slide()
    slide.update_style("code", s(size=38))
    content = slide_header(slide, "Unstable features")

    code(content.box(), """
#![feature(async_await)]
async fn foo() {
    ...
}""")

    content.box(height=20)
    bash(content.box(show="2+"), "$ cargo +nightly build")
示例#2
0
def intro(slides: SlideDeck):
    slide = new_slide(slides)
    slide.box().text(
        """CPU design effects
that can degrade performance of your programs""", s(bold=True, size=40))

    slide.box(p_top=40).text("""Jakub Beránek
[email protected]""", s(bold=False, size=30))

    slide = new_slide(slides)
    content = slide_header(slide, "~tt{whoami}")
    list_wrapper = content.box()
    list_item(list_wrapper).text(
        "PhD student @ VSB-TUO, Ostrava, Czech Republic")
    list_item(list_wrapper).text(
        "Research assistant @ IT4Innovations (HPC center)")
    list_item(list_wrapper).text(
        "HPC, distributed systems, program optimization")

    slide = new_slide(slides)
    content = slide_header(slide, "How do we get maximum performance?")
    list_wrapper = content.box()
    list_item(list_wrapper).text("Select the right algorithm")
    list_item(list_wrapper, show="next+").text("Use a low-overhead language")
    list_item(list_wrapper, show="next+").text("Compile properly")
    list_item(list_wrapper,
              show="next+").text("~bold{Tune to the underlying hardware}")
示例#3
0
def parallelization(slides: Slides):
    slide = slides.new_slide()
    content = slide_header(slide, "Concurrency primitives")

    list = content.box()
    list_item(list).text("Mutexes")
    list_item(list, show="next+").text("Condition variables")
    list_item(list, show="next+").text("Atomics")
    list_item(list, show="next+").text("Synchronized queues")

    slide = slides.new_slide()
    slide.update_style("code", s(size=30))
    content = slide_header(slide, "Shared-memory parallelism")
    content.box().text("No OpenMP ☹")

    code_width = 800

    content.box(height=40)
    rayon = content.box(show="2+")
    rayon_box = rayon.box(horizontal=True)
    rayon_box.box().text("Rayon (+ Rayon adaptive")
    rayon_box.box(width=20)
    rayon_box.box(width=60).image("imgs/saurabh.png")
    rayon_box.box().text(" )")
    rayon.box(height=30)
    code_box = code(rayon.box(),
                    """
fn sum_of_squares(input: &[i32]) -> i32 {
    input.par_iter()
         .map(|&i| i * i)
         .sum()
}""",
                    width=code_width)
    code_box.line_box(1, z_level=99, x=165, width=165,
                      show="3+").rect(bg_color=CODE_HIGHLIGHT_COLOR)

    code(rayon.box(show="4+"),
         """
#[parallel]
for x in 0..10 {
    println!("{}", x);
}""",
         width=code_width)

    slide = slides.new_slide()
    slide.update_style("code", s(size=26))
    content = slide_header(slide, "Message-passing")
    code(
        content, """
let universe = mpi::initialize();
let world = universe.world();
let size = world.size();
let rank = world.rank();

if rank == 0 {
    let (msg, status) = world.any_process().receive_vec();
}
""")
示例#4
0
def intrinsics(slides: Slides):
    slide = slides.new_slide()
    slide.update_style("code", s(size=38))

    content = slide_header(slide, "Branch prediction")

    code(
        content.box(), """
if core::intrinsic::likely(condition) {
    ...
} else #[cold] {
    ...
}""")

    slide = slides.new_slide()
    slide.update_style("code", s(size=34))
    content = slide_header(slide, "SIMD")

    code_width = 900
    code(content.box(),
         """
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::_mm256_add_epi64;

_mm256_add_epi64(...);""",
         width=code_width)

    content.box(height=50)
    code(content.box(show="2+"),
         """
data.simd_iter()
    .simd_map(|v| {
        f32s(9.0) * v.abs().sqrt().ceil() -
        f32s(4.0) - f32s(2.0)
    })
    .scalar_collect();""",
         width=code_width)

    slide = slides.new_slide()
    slide.update_style("code", s(size=38))
    content = slide_header(slide, "Inline assembly")

    code(
        content.box(), """
fn add(a: i32, b: i32) -> i32 {
    let c: i32;
    unsafe {
        asm!("add $2, $0"
             : "=r"(c)
             : "0"(a), "r"(b));
    }
    c
}""")
示例#5
0
def rust_safety(slides: Slides):
    slide = slides.new_slide()
    slide.set_style("text", s(size=60, bold=True))

    slide.box().text("Rust is safe...", style="text")
    slide.box(show="2+").text("...but from what?", style="text")

    slide = slides.new_slide()
    content = slide_header(slide, "Undefined behaviour")
    content.box(width=800).image("imgs/cpp-undefined.png")

    slide = slides.new_slide()
    content = slide_header(slide, "UB in Java")
    content.box().text("Java::Iterator::remove")
    with_bg(content.box()).text(
        """“The behavior of an iterator is ~emph{unspecified} if the underlying
collection is modified while the iteration is in progress in any way
other than by calling this method, unless an overriding class has specified
a concurrent modification policy.”
""",
        style=s(size=28, align="left"))

    slide = slides.new_slide()
    content = slide_header(slide, "UB in Python")
    content.box().text("~tt{for} statement")
    with_bg(content.box()).text(
        """“There is a subtlety when the sequence is being modified by the loop (this can only
occur for mutable sequences, e.g. lists). An internal counter is used to keep track
of which item ... ~emph{This can lead to nasty bugs} that can be avoided by making a
temporary copy using a slice of the whole sequence ...”
""",
        style=s(size=24, align="left"))

    slide = slides.new_slide()
    content = slide_header(slide, "Sources of UB")
    list = content.box()
    items = [
        "Null pointer dereference", "Double-free", "Use-after-free",
        "Out-of-bounds access", "Integer conversion", "Integer overflow",
        "Iterator invalidation", "Invalid alignment", "…"
    ]
    for item in items:
        list_item(list, show="next+").text(item)

    content.box(height=20)
    content.box(show="next+").text(
        "Rust tries very hard to avoid all of the above",
        style=s(size=44, bold=True))
示例#6
0
def adt(slides: Slides):
    slide = slides.new_slide()
    slide.update_style("code", s(size=26))
    content = slide_header(
        slide, """Algebraic data types/tagged unions/sum types/
discriminated unions/variants""")

    code_width = 960
    code(content.box(),
         """
enum Packet {
    Header { source: u32, tag: u32, data: Vec<u8> },
    Payload { data: Vec<u8> },
    Ack { seq: u64 }
}""",
         width=code_width)

    content.box(height=10)
    content.box(show="next+").text("Pattern matching",
                                   style=s(bold=True, size=40))

    code(content.box(show="last+"),
         """
match socket.get_packet() {
    Header {data, ..} | Payload {data, ..} => { },
    _ => { println!("Packet without data"); }
}
""",
         width=code_width)

    content.box(height=10)
    content.box(
        show="next+").text("The compiler forces you to handle all variants")
示例#7
0
def structures(slides: Slides):
    slide = slides.new_slide()
    slide.update_style("code", s(size=26))
    content = slide_header(slide, "Structures")

    code_width = 920
    code(content.box(),
         """
struct Person {
    pub age: u32,
    name: String
}
""",
         width=code_width)

    code(content.box(show="next+"),
         """
impl Person {
    pub fn new(age: u32, name: String) -> Person {
        Person { age, name }
    }
    pub fn is_adult(&self) -> bool {
        self.age >= 18
    }
}    
""",
         width=code_width)
示例#8
0
def zero_cost(slides: Slides):
    slide = slides.new_slide()
    content = slide_header(slide, "Zero-cost abstractions")
    content.box().text("Bjarne Stroustrup:", s(size=60))

    with_bg(content.box()).text("""What you don’t use, you don’t pay for.
What you do use, you couldn’t hand code any better.""")
示例#9
0
def benchmark_game(slides: Slides):
    slide = slides.new_slide()
    content = slide_header(slide, "Benchmark game")
    content.box(width=900).image("imgs/benchmark-game.png")
    content.box().text(
        "https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/gpp"
        "-rust.html",
        style=s(size=20))
示例#10
0
    def unsafe_slide(header, code_body, content_show="1", code_size=36):
        slide = slides.new_slide()
        slide.update_style("code", s(size=code_size))
        content = slide_header(slide, "Unsafe Rust")
        content.box(y=0).text("Unsafe Rust allows:")

        content.box(height=20)
        content.box(show=content_show).text(header)
        content.box(height=10)
        code(content.box(show=content_show), code_body)
示例#11
0
    def person_slide(end=""):
        slide = slides.new_slide()
        slide.update_style("code", s(size=50))
        content = slide_header(slide, "Ownership")
        return (slide,
                code(content,
                     """
fn foo(bitmap: Bitmap) {{
    ...
}}{}""".format(end),
                     width=840))
示例#12
0
def runtime(slides: Slides):
    slide = slides.new_slide()
    slide.update_style("default", s(size=40))
    content = slide_header(slide, "Minimal runtime")

    list = content.box()
    list_item(list, show="next+").text("No GC")
    list.box(width=600, height=400, show="last+",
             padding=0).image("imgs/gc.svg")
    list_item(list, show="next+").text("No exceptions")
    list_item(list, show="next+").text("Tight data layout")
    list_item(list, show="next+").text("Supports embedded platforms")
示例#13
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)
示例#14
0
def multiphase_compiler(slides: Slides):
    slide = slides.new_slide()
    slide.update_style("code", s(size=34))
    content = slide_header(slide, "Multi-phase compiler")

    code(
        content.box(), """
fn main() {
    look_ma_no_forward_declaration();
}

fn look_ma_no_forward_declaration() { }
""")
示例#15
0
def concurrency_issues(slides: Slides):
    slide = slides.new_slide()
    content = slide_header(slide, "Concurrency issues")

    content.box().text("Rust doesn't prevent:")
    list = content.box()
    list_item(list, show="next+").text("Deadlocks")
    list_item(list, show="next+").text("General race conditions")

    content.box(height=20)
    content.box(show="next+").text("Rust prevents (at compile time):")
    list = content.box()
    list_item(list, show="next+").text("Data races")

    slide = slides.new_slide()
    content = slide_header(slide, "What causes data races?")

    text_style = s(size=50)
    content.box(show="next+").text("Concurrent aliasing and mutability...", style=text_style)
    content.box(show="next+").text("...but Rust already disables that!", style=text_style)

    content.box(height=20)
    content.box(show="next+").text("So how do we get any concurrency at all...?", style=text_style)
示例#16
0
def caveats(slides: Slides):
    slide = slides.new_slide()
    content = slide_header(slide, "Performance caveats")

    l1_style = s(size=26)

    list = content.box()
    list_item(list).text("Out-of-bounds checks")
    list_item(list, level=1,
              show="2+").text("Can be optimized away (iterators)",
                              style=l1_style)
    list_item(list, show="3+").text("Integer overflow is not undefined")
    list_item(list, level=1,
              show="4+").text("Runtime checks only in debug mode",
                              style=l1_style)
示例#17
0
def constexpr(slides: Slides):
    slide = slides.new_slide()
    slide.update_style("code", s(size=38))

    content = slide_header(slide, "Constexpr functions")

    code(
        content.box(), """
const fn double(x: i32) -> i32 {
    x * 2
}

const FIVE: i32 = 5;
const TEN: i32 = double(FIVE);
""")
示例#18
0
    def cpp_lifetime(comment=""):
        slide = slides.new_slide()
        slide.update_style("code", s(size=38))
        content = slide_header(slide, "Lifetimes (C++)")
        code(content,
             """
int* p;
{{
    int value = 5;
    p = &value;
}}{comment}
std::cout << *p << std::endl;
""".format(comment=comment),
             "cpp",
             width=800)
示例#19
0
def generics(slides: Slides):
    slide = slides.new_slide()
    slide.update_style("code", s(size=30))
    content = slide_header(slide, "Generics")

    code_width = 900

    code(content.box(),
         """
struct KeyValue<K, V> {
    key: K,
    value: V
}""",
         width=code_width)
    code(content.box(show="next+"),
         """
trait Buffer<T> {
    fn read(&self) -> T;    
}""",
         width=code_width)

    content.box(height=10)
    code(content.box(show="next+"),
         """
fn print_buffer<B: Buffer<T>, T: Display>(buffer: B) {
    println!("{}", buffer.read());
}""",
         width=code_width)
    code(content.box(show="next+"),
         """
fn print_bigger<T: PartialEq + Display>(a: T, b: T) {
    if (a > b) { println!("{}", a); }
}
""",
         width=code_width)

    content.box(height=10)
    code(content.box(show="next+"),
         """
impl <T: Display> Serialize for T {
    ...
}
""",
         width=code_width)
示例#20
0
def message_passing(slides: Slides):
    slide = slides.new_slide()
    slide.update_style("code", s(size=38))
    content = slide_header(slide, "Message passing")

    code_width = 900
    code_step(content.box(width=code_width, height=300), """
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
    tx.send(5);
});
let received = rx.recv();
""", "1", (
        ("               mpsc::channel();", None, None, None, None),
        (0, None, None, None, None),
        (0, 1, 2, 3, None),
        (0, 1, 2, 3, 4)
    ), width=code_width)

    content.box(height=20)
    content.box(show="next+").text("""Splitting a channel into a receiver + sender removes aliasing
    and allows moving the sender independently of the receiver.""", s(size=34))
示例#21
0
def false_sharing(slides: SlideDeck, backup: bool):
    if backup:
        slide = new_slide(slides)
        content = slide_header(slide, "Code (backup)")
        code(
            content.box(), """// tid - [0, NO_OF_THREADS)
void thread_fn(int tid, double* data)
{
    size_t repetitions = 1024 * 1024 * 1024UL;
    for (size_t i = 0; i < repetitions; i++)
    {
        data[tid] *= i;
    }
}""")
        slide = new_slide(slides)
        content = slide_header(slide, "Result (backup)")
        content.box(height=600).image("images/example3-time.png")

    slide = new_slide(slides)
    content = slide_header(slide, "Cache system")
    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)
    content.box(width=226, height=40, x=240, y=570).rect(color=COLOR_BACKEND,
                                                         stroke_width=3)

    slide = new_slide(slides)
    content = slide_header(slide, "Cache coherency")
    content.box(height=600).image("images/false-sharing.svg")

    slide = new_slide(slides)
    content = slide_header(slide, "False sharing")
    content.box(width="90%").image("images/false-sharing-array.svg")

    slide = new_slide(slides)
    content = slide_header(slide, "How to measure?")
    content.box().text("~tt{l2_rqsts.all_rfo}", s(size=48))
    content.box(p_top=20).text(
        "How many times some core invalidated data in other cores?")

    if backup:
        bash(content.box(p_top=40, show="next+"),
             """$ perf stat -e l2_rqsts.all_rfo ./example3
1 thread   ->        59 711
2 threads  -> 1 112 258 710""",
             text_style=s(align="left"))
示例#22
0
def modules(slides: Slides):
    slide = slides.new_slide()
    slide.update_style("code", s(size=24))
    slide.set_style("bold", s(bold=True))
    content = slide_header(slide, "Proper module system")

    line = content.box(width="fill", horizontal=True)
    lib = line.box(width="50%", y=0)
    text_box = lib.box()
    text_box.box(show="1").text("foo.rs")
    text_box.overlay(show="next+").text("~bold{foo}.rs")
    code(
        lib.box(), """
pub fn fun1() {
    println!("fun1");
}
fn fun2() {
    println!("fun2");
}
""")

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

fn main() {
    foo::fun1();
    // foo::fun2(); private
}""")

    content.box(height=60)
    advantages = content.box(show="3+")
    advantages.update_style("default", s(size=40))
    list_item(advantages).text("visibility control")
    list_item(advantages).text("self-contained")
示例#23
0
def intro(slides: Slides):
    slide = slides.new_slide()
    slide.set_style("title", s(size=60, bold=True))
    slide.set_style("name", s(size=30))

    slide.sbox(height="30%").image("imgs/logo.svg")
    slide.box(height=80)
    slide.box().text("Rust: Fast & Safe", "title")
    slide.box(height=20)
    slide.box().text("Jakub Beránek, Mathieu Fehr, Saurabh Raje", "name")

    slide = slides.new_slide()
    slide.box(width=500).image("imgs/meme-rust-meeting.jpg")

    slide = slides.new_slide()
    content = slide_header(slide, "What is Rust?")
    content.box().text("""
System programming language for building
reliable and efficient software.""")

    content.box(height=20)
    content.box(width="fill", height=150, show="2+").image("imgs/history.svg")
    content.box(height=20)
    content.box(width="fill", height=350, show="3+").image("imgs/users.svg")
示例#24
0
def outro(slides: SlideDeck):
    slide = new_slide(slides)
    content = slide_header(slide, "There are many other effects")
    list_wrapper = content.box()
    list_item(list_wrapper).text("NUMA")
    list_item(list_wrapper).text("4k aliasing")
    list_item(list_wrapper).text("Misaligned accesses, cache line boundaries")
    list_item(list_wrapper).text("Instruction data dependencies")
    list_item(list_wrapper).text("Software prefetching")
    list_item(list_wrapper).text("Non-temporal stores & cache pollution")
    list_item(list_wrapper).text("Bandwidth saturation")
    list_item(list_wrapper).text("DRAM refresh intervals")
    list_item(list_wrapper).text("AVX/SSE transition penalty")
    list_item(list_wrapper).text("...")

    slide = new_slide(slides)
    slide.box().text("Thank you!", s(bold=True, size=60))
    slide.box(p_top=60).text(
        """For more examples visit:
~tt{github.com/kobzol/hardware-effects}""", s(size=44))
    slide.box(p_top=80).text("Jakub Beránek")

    slide.box(p_top=100).text(
        "Slides built with ~tt{github.com/spirali/elsie}", s(size=30))
示例#25
0
def c_interop(slides: Slides):
    slide = slides.new_slide()
    slide.update_style("code", s(size=26))

    content = slide_header(slide, "C/C++ interop")

    code_width = 940
    c_from_rust = content.box()
    c_from_rust.text("C from Rust")
    code(content,
         """
extern {
    fn snappy_max_compressed_length(len: size_t) -> size_t;
}

let length = unsafe { snappy_max_compressed_length(100) };
""",
         width=code_width)

    content.box(height=20)
    box = content.box(show="2+")
    rust_from_c = box.box()
    rust_from_c.text("Rust from C")
    code(box,
         """
#[repr(C)]
struct Object {
    bar: i32,
}

extern "C" fn foo(param: *mut Object) {
    unsafe {
        (*target).bar = 5;
    }
}""",
         width=code_width)
示例#26
0
def denormals(slides: SlideDeck, backup: bool):
    if backup:
        slide = new_slide(slides)
        content = slide_header(slide, "Code (backup)")
        code(content.box(), """float F = static_cast<float>(std::stof(argv[1]));
std::vector<float> data(4 * 1024 * 1024, 1);

for (int r = 0; r < 100; r++)
{
    for (auto& item: data)
    {
        item *= F;
    }
}""")
        slide = new_slide(slides)
        content = slide_header(slide, "Result (backup)")
        content.box(width="50%").image("images/example2-time.png")

    slide = new_slide(slides)
    colors = ["#B22222", "#007944", "#0018AE"]
    styles = ["sign", "exponent", "significand"]
    for i, style in enumerate(styles):
        slide.set_style(style, s(color=colors[i], size=42))
    content = slide_header(slide, "Denormal floating point numbers")

    row = content.box(horizontal=True)
    box_dimension = 60

    def floating_point(wrapper: Box, colors, values):
        for i in range(len(colors)):
            box = wrapper.box(width=box_dimension, height=box_dimension)
            box.rect(color="black", bg_color=colors[i], stroke_width=2)
            box.text(str(values[i]), s(color="white", bold=True))

    floating_point(row, [colors[0]] + [colors[1]] * 5 + [colors[2]] * 10, [
        0,
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 1
    ])
    row_label = content.box(x=0, horizontal=True, show="next+")
    row_label.box(x=250, y=0).text("Zero exponent")
    row_label.box(x=670, y=0).text("Non-zero significand")

    content.box(p_top=80, width=700, height=50).image("images/float.svg")

    list_wrapper = content.box(p_top=20)
    list_item(list_wrapper, show="next+").text("Numbers close to zero")
    list_item(list_wrapper, show="last+").text("Hidden bit = 0, smaller bias")

    content.box(p_top=40, show="next+").text("Operations on denormal numbers are slow!", style=s(size=46))

    slide = new_slide(slides)
    content = slide_header(slide, "Floating point handling")
    content.box(height=600).image("images/haswell-diagram.png")
    content.box(width=130, height=32, x=800, y=52).rect(color=COLOR_FRONTEND, stroke_width=3)
    content.box(width=35, height=100, x=988, y=80).rect(color=COLOR_FRONTEND, stroke_width=3)
    content.box(width=80, height=165, x=212, y=335).rect(color=COLOR_BACKEND, stroke_width=3)

    slide = new_slide(slides)
    content = slide_header(slide, "How to measure?")
    content.box().text("~tt{fp_assist.any}", style=s(size=48))
    content.box(p_top=20).text("How many times the CPU switched to the microcode FP handler?")

    if backup:
        bash(content.box(p_top=40, show="next+"), """$ perf stat -e fp_assist.any ./example2
0   ->          0
0.3 -> 15 728 640""", text_style=s(align="left"))

    slide = new_slide(slides)
    slide.update_style("code", s(size=40))
    content = slide_header(slide, "How to fix it?")
    list_wrapper = content.box()
    list_item(list_wrapper).text("The nuclear option: ~tt{-ffast-math}")
    list_item(list_wrapper, level=1).text("Sacrifice correctness to gain more FP performance")
    list_item(list_wrapper, show="next+").text("Set CPU flags:")
    list_item(list_wrapper, level=1, show="last+").text("Flush-to-zero - treat denormal outputs as 0")
    list_item(list_wrapper, level=1, show="last+").text("Denormals-to-zero - treat denormal inputs as 0")

    code(list_wrapper.box(p_top=40, show="next+"), """_mm_setcsr(_mm_getcsr() | 0x8040);
// or
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
""")
示例#27
0
def branch_prediction(slides: SlideDeck, backup: bool):
    if backup:
        slide = new_slide(slides)
        content = slide_header(slide, "Code (backup)")
        code(
            content.box(),
            """std::vector<float> data = /* 32K random floats in [1, 10] */;
float sum = 0;
// std::sort(data.begin(), data.end());
for (auto x : data)
{
    if (x < 6.0f)
    {
        sum += x;
    }
}""")
        slide = new_slide(slides)
        content = slide_header(slide, "Result (backup)")
        content.box(width="90%").image("images/example0a-time.png")

    slide = new_slide(slides)
    content = slide_header(slide, "Most upvoted Stack Overflow question")
    content.box(height=600).image("images/stack-overflow.png")

    slide = new_slide(slides)
    content = slide_header(slide,
                           "What is going on? (Intel Amplifier - VTune)")
    content.box(height=600).image("images/vtune.png")

    slide = new_slide(slides)
    content = slide_header(slide, "What is going on? (perf)")
    bash(content.box(),
         """$ perf stat ./example0a --benchmark_filter=nosort
    853,672012  task-clock (msec) #   0,997 CPUs utilized
            30  context-switches  #   0,035 K/sec          
             0  cpu-migrations    #   0,000 K/sec
           199  page-faults       #   0,233 K/sec
 3 159 530 915  cycles            #   3,701 GHz
 1 475 799 619  instructions      #   0,47  insn per cycle
   419 608 357  branches          # 491,533 M/sec
   102 425 035  branch-misses     #  24,41% of all branches""",
         text_style=s(align="left", size=34))

    slide = new_slide(slides)
    content = slide_header(slide, "Branch predictor")
    content.box(height=600).image("images/haswell-diagram.png")
    content.box(width=130, height=40, x=595, y=140).rect(color=COLOR_FRONTEND,
                                                         stroke_width=3)

    slide = new_slide(slides)
    content = slide_header(slide, "CPU pipeline 101")
    content.box(height=400).image("images/branch-miss-pipeline.svg")

    slide = new_slide(slides)
    content = slide_header(slide, "Branch predictor")
    list_wrapper = content.box()
    list_item(list_wrapper).text("CPU tries to predict results of branches")
    list_item(list_wrapper,
              show="next+").text("Misprediction can cost ~15-20 cycles!",
                                 escape_char="#")

    slide = new_slide(slides)
    content = slide_header(slide, "Simple branch predictor - unsorted array")
    code(content.box(p_bottom=40), """if (data[i] < 6) {
    ...
}""")

    row = content.box(horizontal=True)
    box_dimension = 100

    def array(numbers, predictions, start=1, needle=6):
        stroke_width = 2
        size = 36
        for i in range(len(numbers)):
            box = row.box(width=box_dimension,
                          height=box_dimension).rect(color="black",
                                                     stroke_width=stroke_width)
            number = str(numbers[i])
            box.text(number, s(bold=True, size=size))

            predicted_correctly = (predictions[i] and numbers[i] < needle) or (
                not predictions[i] and numbers[i] >= needle)
            prediction = "green" if predicted_correctly else "red"
            show_overlay = "{}+".format(start + i * 2 + 1)
            overlay = box.overlay(show=show_overlay).rect(
                color="black", bg_color=prediction, stroke_width=stroke_width)
            overlay.text(number, s(color="white", bold=True, size=size))
            show_text = start + i * 2
            row.box(x=i * box_dimension,
                    y=box_dimension,
                    width=box_dimension,
                    show="{}-{}".format(show_text,
                                        show_text + 1)).text("{} < {}?".format(
                                            number, needle))

    values = [6, 2, 1, 7, 4, 8, 3, 9]
    text_style = s(align="left", size=42)
    width = 400

    def predict_sequence(wrapper: Box, values, start=1):
        for i in range(len(values)):
            value = "Taken" if values[i] else "Not taken"
            show_start = start + i * 2
            wrapper.overlay(
                show="{}-{}".format(show_start, show_start + 1)).rect(
                    bg_color="white").text("Prediction: {}".format(value),
                                           style=text_style)

    def predict_value(index):
        if index == 0:
            return False
        return values[index - 1] < 6

    predictions = [predict_value(i) for i in range(len(values))]

    array(values, predictions, start=2)
    prediction_wrapper = content.box(p_top=60,
                                     width=width).text("Prediction: Not taken",
                                                       style=text_style)
    predict_sequence(prediction_wrapper, predictions, start=1)

    content.box(show="next+", p_top=40).text("2 hits, 6 misses (25% hit rate)")

    slide = new_slide(slides)
    content = slide_header(slide, "Simple branch predictor - sorted array")
    code(content.box(p_bottom=40), """if (data[i] < 6) {
    ...
}""")

    row = content.box(horizontal=True)
    values = [1, 2, 3, 4, 6, 7, 8, 9]
    predictions = [predict_value(i) for i in range(len(values))]

    array(values, predictions, start=2)
    prediction_wrapper = content.box(p_top=60,
                                     width=width).text("Prediction: Not taken",
                                                       style=text_style)
    predict_sequence(prediction_wrapper, predictions, start=1)

    content.box(show="next+", p_top=40).text("6 hits, 2 misses (75% hit rate)")

    if backup:
        size = 40
        slide = new_slide(slides)
        content = slide_header(slide, "How can the compiler help?")
        row = content.box(horizontal=True)
        row.box(y=0, p_right=50, width=400).image("images/bm-float-code.png")
        row.box(y=0, width=600).image("images/bm-float-bin.png")
        content.box(p_top=20).text(
            "With ~tt{float}, there are two branches per iteration",
            style=s(size=size))

        slide = new_slide(slides)
        content = slide_header(slide, "How can the compiler help?")
        row = content.box(horizontal=True)
        row.box(y=0, p_right=50, width=400).image("images/bm-int-code.png")
        row.box(y=0, width=600).image("images/bm-int-bin.png")
        content.box(p_top=20).text(
            "With ~tt{int}, one branch is removed (using ~tt{cmov})",
            style=s(size=size))

    slide = new_slide(slides)
    content = slide_header(slide, "How to measure?")
    content.box().text("~tt{branch-misses}", style=s(size=48))
    content.box(p_top=20).text("How many times was a branch mispredicted?")

    if backup:
        bash(content.box(p_top=40, show="next+"),
             """$ perf stat -e branch-misses ./example0a
with    sort ->     383 902
without sort -> 101 652 009""",
             text_style=s(align="left"))

    slide = new_slide(slides)
    slide.update_style("code", s(size=40))
    content = slide_header(slide, "How to help the branch predictor?")
    list_wrapper = content.box()
    list_item(list_wrapper).text("More predictable data")
    list_item(list_wrapper, show="next+").text("Profile-guided optimization")
    list_item(list_wrapper,
              show="next+").text("Remove (unpredictable) branches")
    list_item(list_wrapper,
              show="next+").text("Compiler hints (use with caution)")
    code(
        list_wrapper.box(show="last+", p_top=20, p_bottom=20),
        """if (__builtin_expect(will_it_blend(), 0)) {
    // this branch is not likely to be taken
}""")

    slide = new_slide(slides)
    content = slide_header(slide, "Branch target prediction")
    list_wrapper = content.box()
    list_item(list_wrapper).text(
        "Target of a jump is not known at compile time:")
    list_item(list_wrapper, show="next+", level=1).text("Function pointer")
    list_item(list_wrapper, show="next+",
              level=1).text("Function return address")
    list_item(list_wrapper, show="next+", level=1).text("Virtual method")

    if backup:
        slide = new_slide(slides)
        slide.update_style("code", s(size=26))
        content = slide_header(slide, "Code (backup)")
        code(
            content,
            """struct A { virtual void handle(size_t* data) const = 0; };
struct B: public A { void handle(size_t* data) const final { *data += 1; } };
struct C: public A { void handle(size_t* data) const final { *data += 2; } };

std::vector<std::unique_ptr<A>> data = /* 4K random B/C instances */;
// std::sort(data.begin(), data.end(), /* sort by instance type */);
size_t sum = 0;
for (auto& x : data)
{
    x->handle(&sum);
}""")

        slide = new_slide(slides)
        content = slide_header(slide, "Result (backup)")
        content.box(width="90%").image("images/example0b-time.png")

        slide = new_slide(slides)
        content = slide_header(slide, "perf (backup)")
        bash(content.box(),
             """$ perf stat -e branch-misses ./example0b
with sort   ->     337 274
without sort -> 84 183 161""",
             text_style=s(align="left"))
示例#28
0
def borrowing(slides: Slides):
    slide = slides.new_slide()
    content = slide_header(slide, "Where's the aliasing?")
    content.box().text("So far, we only have mutability, there's no aliasing:")

    content.box(height=20)
    list = content.box()
    list_item(list, show="next+").text(
        "After a move, the original value is not accessible")
    list_item(list, show="next+").text("After a copy, a new value is created")

    slide = slides.new_slide()
    content = slide_header(slide, "Borrowing")
    content.box().text(
        "Aliasing happens when you create a reference to a value")
    content.box(show="next+").text("This is called borrowing in Rust")

    slide = slides.new_slide()
    slide.update_style("code", s(size=38))
    content = slide_header(slide, "Shared borrows")

    code_width = 800

    code(content,
         """
let value = Bitmap::load(...);
let a = &value;
let b = &value;
""",
         width=code_width)

    content.box(height=20)
    list = content.box()
    list_item(
        list,
        show="next+").text("Multiple shared borrows of a value may exist")

    list.box(height=10)
    list_item(list,
              show="next+").text("You can't mutate using a shared borrow")
    list.box(height=10)
    code(list.box(show="last+"),
         "a.width = 10; // does not compile",
         width=code_width)

    list.box(height=10)
    list_item(list, show="next+").text("You can't move out of a shared borrow")
    list.box(height=10)
    code(list.box(show="last+"),
         """
fn foo(bitmap: Bitmap) { }
foo(a); // does not compile""",
         width=code_width)

    slide = slides.new_slide()
    slide.update_style("code", s(size=38))
    content = slide_header(slide, "Unique borrows")

    code_width = 800

    code(content,
         """
let value = Bitmap::load(...);
let c = &mut value;
""",
         width=code_width)

    content.box(height=20)
    list = content.box()
    list_item(list, show="next+").text(
        """If a unique borrow exists, there are no other references
to the same value""",
        style=s(align="left"))
    list_item(list, show="next+").text(
        "You can only create a unique borrow if you own the value")

    list.box(height=10)
    list_item(list, show="next+").text("You can mutate using a unique borrow")
    list.box(height=10)
    code(list.box(show="last+"), "c.width = 10;", width=code_width)

    list.box(height=10)
    list_item(list, show="next+").text("You can't move out of a unique borrow")
    list.box(height=10)
    code(list.box(show="last+"),
         """
fn foo(bitmap: Bitmap) { }
foo(c); // does not compile""",
         width=code_width)

    slide = slides.new_slide()
    slide.update_style("code", s(size=38))
    content = slide_header(slide, "Vector example (Rust)")

    code_width = 800
    code(content.box(show="3+"),
         """
// Vec::push
fn push(&mut self, value: T)
""",
         width=code_width)
    content.box(height=10)
    code_step(content.box(width=code_width, height=300),
              """
let vec = vec!(1, 2, 3);
let p = &vec[0];
vec.push(4);
println!("{}", p);
""",
              "1", ((0, None, None, None), (0, 1, None, None), (0, 1, 2, None),
                    (0, 1, 2, 3)),
              width=code_width)

    content.box(height=10)
    content.box(height=220, show="next+").image("imgs/borrowck-error.png")

    slide = slides.new_slide()
    slide.update_style("code", s(size=34))
    content = slide_header(slide, "What if compile time is not enough?")
    content.box().text(
        """If you can't prove to the compiler that your borrows are safe,
borrow checking can be done at runtime.""")
    content.box(
        show="next+").text("If any rules are broken, the program panics.")

    content.box(height=20)
    code_box = code(
        content.box(show="next+"), """
let value = RefCell::new(5);
let a = value.borrow();     // shared borrow
let b = value.borrow_mut(); // unique borrow""")
    pointer_to_line(slide,
                    code_box,
                    2,
                    100,
                    600,
                    "4+",
                    textbox_pos=("40%", 0),
                    code_pos=("40%", "100%")).text(
                        """This would panic, since there already is
a shared borrow""",
                        style=s(color="orange", align="left"))
示例#29
0
def cpp_alias_mutate(slides: Slides):
    slide = slides.new_slide()
    slide.update_style("default", s(size=50, bold=True))
    content = slide_header(slide, "Rust's insight")
    content.box(show="next+").text("""Memory errors arise when
aliasing is combined with mutability""")

    slide = slides.new_slide()
    slide.update_style("code", s(size=32))
    slide.set_style("gray",
                    slide.get_style("code").compose(s(color="#BBBBBB")))
    content = slide_header(slide, "C++ UB example")

    style_green = s(size=40, color="green")
    style_red = s(size=style_green.size, color="red")

    header = content.box(width=500, height=50, horizontal=True)
    header.overlay(show="2").text("Aliasing ✓", style=style_green)
    header.overlay(show="3").text("Mutability ✓", style=style_green)
    header.overlay(show="4+").text("Aliasing & Mutability", style=style_red)
    header.box(show="4+", width=100, x=450).image("imgs/boom.svg")

    content.box(height=20)
    wrapper = code_step(content.box(width=700, height=200),
                        """
std::vector<int> vec = { 1, 2, 3 };
int& p = vec[0];
vec.push_back(4);
std::cout << p << std::endl;
""",
                        1, [(0, None, None, None), (0, 1, None, 3),
                            (0, None, 2, None), (0, 1, 2, 3)],
                        language="cpp")

    wrapper.line_box(2, show="4+", z_level=99,
                     width=320).rect(bg_color=CODE_HIGHLIGHT_COLOR)
    wrapper.line_box(3, show="4+", z_level=99, x=235,
                     width=45).rect(bg_color=CODE_HIGHLIGHT_COLOR)

    slide = slides.new_slide()
    content = slide_header(slide, "What to do?")
    content.box(width=1000).image("imgs/meme-rust-aliasing.jpg")

    slide = slides.new_slide()
    content = slide_header(slide, "Rust's solution")

    large = s(size=50, bold=True)

    row = content.box(horizontal=True)
    row.box().text("You can mutate", style=large)
    row.box(width=20)
    row.box(show="next+").text("||", style=large)
    row.box(width=20)
    row.box(show="next+").text("alias", style=large)

    content.box(height=10)
    content.box(show="next+").text(
        "But not both at the same time (w.r.t. a single variable)")
    content.box(height=10)
    content.box(show="next+").text(
        "Rust enforces this at compile time using its type system")
示例#30
0
def lifetimes(slides: Slides):
    def cpp_lifetime(comment=""):
        slide = slides.new_slide()
        slide.update_style("code", s(size=38))
        content = slide_header(slide, "Lifetimes (C++)")
        code(content,
             """
int* p;
{{
    int value = 5;
    p = &value;
}}{comment}
std::cout << *p << std::endl;
""".format(comment=comment),
             "cpp",
             width=800)

    cpp_lifetime()
    cpp_lifetime(" // <-- `value` is destroyed here")

    slide = slides.new_slide()
    slide.update_style("code", s(size=38))
    content = slide_header(slide, "Lifetimes (Rust)")
    code_box = code(content.box(),
                    """
let p;
{
    let value = 5;
    p = &value;
}
println!("{}", *p);""",
                    width=800)

    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)

    content.box(height=20)
    content.box(width=500, show="2+").text("Lifetime of reference `p`",
                                           style=s(color="orange",
                                                   align="left"))
    line(0, 5, "40%", "100%", "90%", 200, "orange", "2+")

    content.box(height=10)
    content.box(width=500, show="3+").text("Lifetime of `value`",
                                           style=s(color="green",
                                                   align="left"))
    line(2, 4, "100%", "10%", "100%", 50, "green", "3+")

    content.box(height=30)
    content.box(show="4+").text("""Lifetime of a value must be
>= lifetime of a reference to it""",
                                style=s(size=50))

    slide = slides.new_slide()
    slide.update_style("code", s(size=38))
    content = slide_header(slide, "Lifetimes (Rust)")
    code_box = code(content.box(),
                    """
let p;
{
    let value = 5;
    p = &value;
}
println!("{}", *p);""",
                    width=800)

    content.box(height=20)
    content.box(height=280).image("imgs/lifetime-error.png")

    slide = slides.new_slide()
    slide.update_style("code", s(size=32))
    content = slide_header(slide, "What if compile time is not enough?")
    content.box().text("""If you can't prove to the compiler that the lifetimes
are correct, lifetime can be managed at runtime.""")

    code_width = 1000
    content.box(height=20)
    code_step(content.box(width=code_width, height=400),
              """
fn main() {
    let value = Rc::new(5); // refcount == 1
    {
        let a = value.clone(); // refcount == 2
    } // refcount == 1
} // refcount == 0, value is dropped
""",
              "2", ((0, 1, None, None, None, None), (0, 1, 2, 3, None, None),
                    (0, 1, 2, 3, 4, None), (0, 1, 2, 3, 4, 5)),
              width=code_width)