Skip to content

Commit b454d93

Browse files
committed
fix: move code from inside of an image to code blocks
1 parent c33af34 commit b454d93

File tree

7 files changed

+79
-10
lines changed

7 files changed

+79
-10
lines changed

public/images/asm-1.png

-464 KB
Binary file not shown.

public/images/asm-2.png

-355 KB
Binary file not shown.

public/images/fib-1.png

-110 KB
Binary file not shown.

public/images/fib-2.png

-154 KB
Binary file not shown.

public/images/fib-3.png

-138 KB
Binary file not shown.

public/images/fib-4.png

-258 KB
Binary file not shown.

src/app/time-travel-intro/how-time-travel-works/page.md

+79-10
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,95 @@ When the browser is replaying, it should think it is running live for the first
1414

1515
Replaying your browser is similar to writing a good test. If you’re testing a deterministic function like `fibonacci`, there’s nothing you need to do. Every time the test is run, it will return the same value.
1616

17-
{% figure alt="Elements panel" src="/images/fib-1.png" height=870 width=870/%}
18-
.
19-
{% figure alt="Elements panel" src="/images/fib-2.png" height=870 width=870/%}
17+
```javascript
18+
describe('fibonacci', () => {
19+
it('can calculate fibonacci(10)', () => {
20+
expect(fibonacci(10)).toBe(55);
21+
});
22+
});
23+
```
24+
25+
```javascript
26+
function fibonacci(n) {
27+
if (n <= 1) return n;
28+
29+
let prev = 0, current = 1;
30+
for (let i = 2; i <= n; i++) {
31+
let next = prev + current;
32+
prev = current;
33+
current = next;
34+
}
35+
return current;
36+
}
37+
```
2038

2139
If we change fibonacci slightly so that it doesn’t take `n`, but instead reads it from a file, we’ll need to mock `readFileSync` so that when the test runs, it always returns the same value.
2240

23-
{% figure alt="Elements panel" src="/images/fib-3.png" height=870 width=870/%}
24-
.
25-
{% figure alt="Elements panel" src="/images/fib-4.png" height=870 width=870/%}
41+
```javascript
42+
describe("fibonacci", () => {
43+
it("can calculate fibonacci(10)", () => {
44+
fs.readFileSync.mockReturnValue('10');
45+
expect(fibonacci()). toEqual(55)
46+
})
47+
})
48+
```
49+
50+
```javascript
51+
function fibonacci( ) {
52+
const data = fs.readFileSync('input.txt', 'utf8');
53+
const n = parseInt(data, 10);
54+
55+
if (n <= 1) return n;
56+
57+
let prev = 0, current = 1;
58+
for (let i = 2; i <= n; i++) {
59+
let next = prev + current;
60+
prev = current;
61+
current = next;
62+
}
63+
return current;
64+
}
65+
```
2666

2767
Recording a runtime like Chrome is fairly similar in theory to recording our non-deterministic fibonacci function. The one caveat is that instead of writing a test function that mocks a single non-deterministic function, we need to write a little bit of inline assembly code that can intercept low level OS library calls and replaying them later.
2868

29-
{% figure alt="Elements panel" src="/images/asm-1.png" height=870 width=870/%}
69+
```asm
70+
extern size_t
71+
RecordReplayRedirectCall(...);
72+
73+
__asm(
74+
"_RecordReplayRedirectCall:"
75+
76+
// Save the system call's original function and arguments
77+
"movq %rdi, 0(%rsp);"
78+
"movq rsi, 8(%rsp);"
79+
"movq %rdx, 16(%rsp);"
80+
"movq %rcx, 24(%rsp);"
81+
"movq %r8, 32(%rsp);"
82+
"movq %r9, 40(rsp);"
83+
"movsd %xmm0, 48(%rsp);"
84+
"movsd %xmm1, 56(%rsp);"
85+
"movsd %xmm2, 64(%rsp);"
86+
87+
// Call our real Intercept function
88+
"call RecordReplayInterceptCall;"
89+
)
90+
```
3091

3192
Once we’re able to intercept calls, and we know their signatures, the remaining task is to enumerate all of the calls that the runtime will make.
3293

33-
{% figure alt="Elements panel" src="/images/asm-2.png" height=870 width=870/%}
94+
95+
```asm
96+
// Specify every function that is being redirected. MACRO is invoked with the
97+
// function's name, followed by any hooks associated with the redirection for
98+
// saving its output or adding a preamble.
99+
#define FOR_EACH_REDIRECTION(MACRO)
100+
MACRO(mmap, nullptr, Preamble_mmap) \
101+
MACRO(munmap, nullptr, Preamble_munmap) \
102+
MACRO(read, SaveRvalHadErrorNegative<WriteBufferViaRval<1, 2>>) \
103+
MACRO(open, SaveRvalHadErrorNegative) \
104+
```
34105

35106
This approach might sound crazy, and in many ways it is, but there’s an elegance to it in that the libc level is fairly stable and well defined. Also it turns out that intercepting libc calls is incredibly cheap.
36107

37108
The overhead in practice is 3% and recordings are tiny compared to traces. A typical [Replay.io](https://replay.io/) recording is less than a Mb a second where as computers execute billions of options a second and traces are measured in GBs.
38-
39-
###

0 commit comments

Comments
 (0)