Recommended Reading
Chapters 12 through 23 of the OSTEP book provide a lot more information on virtual memory. You are not expected to know details covered there that we didn't also cover in class, but should find these chapters interesting and useful to read.
Slides
Page Fault Challenge
Michael Recachinas solved the Page Fault Challenge!
His code and results are here: https://github.com/mrecachinas/Page-Faults.
Page Tables
How well does the 386 architecture work for larger memories?
Why not just make the page size bigger to support more memory?
What are the advantages of flexible page sizes over fixed page sizes?
ARMv8 White Paper ARMv8 Architecture
Qualcomm and Samsung Pass AMD in MPU Ranking, IC Insights, 20 May 2013.
Faults
What is the difference between a segmentation fault and page fault?
What does it mean if a C++ program execution generates a segmentation fault?
What does it mean if a Rust program execution generates a segmentation fault?
How often should page faults happen in a Rust program?
What does this program do? [Code]
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
char *s = (char *) malloc (1);
int i = 0;
while (1) {
printf("%d: %lx / %d\n", i, s + i, i[s]);
i += 1;
}
}
Processes, Threads, and Tasks
What is difference between a process and thread?
Is a Rust task more like a process or a thread?
How can Rust tasks provide process-like memory isolation but without the expense of a traditional process?
Spawning Tasks
The spawn
function takes in an owned function (which cannot capture
any mutable, shared objects) and runs that function in a new thread:
fn spawn(f: proc())
Channels provide a way for spawned tasked to communicate back to their parent:
let (port, chan) : (Port<int>, Chan<int>) = Chan::new();
let val = node.head;
do spawn {
chan.send(f(val));
}
let newval = port.recv();
The port.recv()
call with block until a sent value (from chan.send(f.val)
) arrives.
Faster Collatz Steps
Here's the code for my klunky multi-tasking Collatz program: [Code] (I believe, but not with a lot of confidence, that it is correct, but it sometimes leads Rust to segv)
fn collatz_steps(n: int) -> int {
if n == 1 {
0
} else {
1 + collatz_steps(if n % 2 == 0 { n / 2 } else { 3*n + 1 })
}
}
fn find_collatz(k: int) -> int {
// Returns the minimum value, n, with Collatz stopping time >= k.
let mut n = 1;
let max_tasks = 7; // keep all my cores busy
let mut found_result = false;
let mut result = -1; // need to initialize
while !found_result {
let mut ports = ~[];
for i in range(0, max_tasks) {
let val = n + i;
let (port, chan) : (Port<int>, Chan<int>) = Chan::new();
ports.push(port);
spawn(proc() {
let steps = collatz_steps(val);
println!("Result for {}: {}", val, steps);
chan.send(steps);
});
}
for i in range(0, max_tasks) {
let port = ports.pop();
let steps = port.recv();
if steps > k {
found_result = true;
result = n + i;
}
}
n += max_tasks;
}
assert!(result != -1);
result
}
fn main() {
println!("Result: {}", find_collatz(500));
}
Challenge: Write a substantially better find_collatz program that makes good use of all available cores, and always produces the correct result. (In class, I said it had to run 6 times faster than the single-threaded version on an 8-core machine, but if it is close to getting a good speedup and using an effective strategy to keep all the cores busy doing useful work nearly all the time that is good enough.)