Optimizing the Automated Programming Stack
James Bornholt
University of Washington
Optimizing the Automated Programming Stack James Bornholt - - PowerPoint PPT Presentation
Optimizing the Automated Programming Stack James Bornholt University of Washington Software is everywhere Bugs are everywhere Bugs are everywhere Automated programming tools Program Verifier + test case Specification Language
University of Washington
Verifier
Program Specification
Language
Verifier
Program Specification
Synthesizer
Specification
+ program
Language Language
Verified
[Nelson et al, SOSP’17]
Synthesized network configs
[McClurg et al, PLDI’15]
Verified SQL optimizers
[Chu et al, VLDB’18]
Synthesized crypto primitives
[Erbsen et al, Oakland’19]
Synthesized biology experiments
[Köksal et al, POPL’13]
Synthesized memory models
[Bornholt et al, PLDI’17]
Synthesized educational models
[Butler et al, VMCAI’18]
Most problems in automated programming are intractable (many undecidable). Automated programming requires a specification, which is often difficult to construct and audit.
Most problems in automated programming are intractable (many undecidable). Automated programming requires a specification, which is often difficult to construct and audit.
Specialization reduces the size
irrelevant programs/behaviors. Specialization allows for concise and expressive specifications that capture programmer intent.
SAT/SMT solving improvements in scale and expressiveness
Symbolic evaluation algorithms to translate programs to SAT/SMT SAT/SMT solving improvements in scale and expressiveness
Solver-aided languages front-end abstractions for verification/synthesis Symbolic evaluation algorithms to translate programs to SAT/SMT SAT/SMT solving improvements in scale and expressiveness
Solver-aided languages front-end abstractions for verification/synthesis Symbolic evaluation algorithms to translate programs to SAT/SMT SAT/SMT solving improvements in scale and expressiveness
MemSynth [PLDI’17]: an automated tool for synthesizing memory consistency models Ferrite [ASPLOS’16]: a tool for synthesizing crash-safe file system code
MemSynth [PLDI’17]: an automated tool for synthesizing memory consistency models Metasketches [POPL’16]: a strategy abstrac`on for synthesis problems SymPro [OOPSLA’18]: a technique for systema`cally building scalable tools Ferrite [ASPLOS’16]: a tool for synthesizing crash-safe file system code
MemSynth [PLDI’17]: an automated tool for synthesizing memory consistency models Metasketches [POPL’16]: a strategy abstrac`on for synthesis problems SymPro [OOPSLA’18]: a technique for systema`cally building scalable tools Ferrite [ASPLOS’16]: a tool for synthesizing crash-safe file system code
X = 1 Y = 1 if Y == 0: print “hello” if X == 0: print “goodbye” Thread 1 Thread 2
1 2 3 4
All variables initialized to 0
X = 1 Y = 1 if Y == 0: print “hello” if X == 0: print “goodbye” Thread 1 Thread 2
1 2 3 4
Can this print… hello?
All variables initialized to 0
X = 1 Y = 1 if Y == 0: print “hello” if X == 0: print “goodbye” Thread 1 Thread 2
1 2 3 4
Can this print… hello?
3 4 1 2
All variables initialized to 0
X = 1 Y = 1 if Y == 0: print “hello” if X == 0: print “goodbye” Thread 1 Thread 2
1 2 3 4
Can this print… hello? goodbye?
3 4 1 2
All variables initialized to 0
X = 1 Y = 1 if Y == 0: print “hello” if X == 0: print “goodbye” Thread 1 Thread 2
1 2 3 4
Can this print… hello? goodbye?
3 4 1 2 1 2 3 4
All variables initialized to 0
X = 1 Y = 1 if Y == 0: print “hello” if X == 0: print “goodbye” Thread 1 Thread 2
1 2 3 4
Can this print… hello? goodbye? nothing?
3 4 1 2 1 2 3 4
All variables initialized to 0
X = 1 Y = 1 if Y == 0: print “hello” if X == 0: print “goodbye” Thread 1 Thread 2
1 2 3 4
Can this print… hello? goodbye? nothing?
3 4 1 2 1 2 3 4 3 4 1 2
All variables initialized to 0
X = 1 Y = 1 if Y == 0: print “hello” if X == 0: print “goodbye” Thread 1 Thread 2
1 2 3 4
Can this print… hello? goodbye? nothing? both?
3 4 1 2 1 2 3 4 3 4 1 2
All variables initialized to 0
X = 1 Y = 1 if Y == 0: print “hello” if X == 0: print “goodbye” Thread 1 Thread 2
1 2 3 4
Can this print… hello? goodbye? nothing? both?
3 4 1 2 1 2 3 4 3 4 1 2
No! (sequential consistency)
All variables initialized to 0
X = 1 Y = 1 if Y == 0: print “hello” if X == 0: print “goodbye” Thread 1 Thread 2
1 2 3 4
Can this print… hello? goodbye? nothing? both?
3 4 1 2 1 2 3 4 3 4 1 2
No! (sequential consistency) Yeah! We wanna go fast!
All variables initialized to 0
…correctness of my compiler…
Compiler writers
…rules to verify against…
Verifica`on tools ✅
…possible low- level behaviors…
Kernel/library developers
…correctness of my compiler…
Compiler writers
…rules to verify against…
Verifica`on tools ✅
…possible low- level behaviors…
Kernel/library developers
Litmus tests and prose
…correctness of my compiler…
Compiler writers
…rules to verify against…
Verifica`on tools ✅
…possible low- level behaviors…
Kernel/library developers
Litmus tests and prose
∀ ∃ ∈ ∧ ∨ ∩ ∪ ⊂ ⋈ ⇒
Formal specifica`ons
…correctness of my compiler…
Compiler writers
…rules to verify against…
Verifica`on tools ✅
…possible low- level behaviors…
Kernel/library developers
Litmus tests and prose
∀ ∃ ∈ ∧ ∨ ∩ ∪ ⊂ ⋈ ⇒
Formal specifica`ons
x86 [Sewell et al, CACM’10] PowerPC [Alglave et al, CAV’10, etc] ARM [Flur et al, POPL’16]
Litmus tests and prose
∀ ∃ ∈ ∧ ∨ ∩ ∪ ⊂ ⋈ ⇒
Formal specifica`ons
Litmus tests and prose
∀ ∃ ∈ ∧ ∨ ∩ ∪ ⊂ ⋈ ⇒
Formal specifica`ons
Synthesize specifica`ons from litmus tests
Litmus tests and prose
∀ ∃ ∈ ∧ ∨ ∩ ∪ ⊂ ⋈ ⇒
Formal specifica`ons
Synthesize specifica`ons from litmus tests Detect ambigui`es in synthesized models
Litmus tests and prose
∀ ∃ ∈ ∧ ∨ ∩ ∪ ⊂ ⋈ ⇒
Formal specifica`ons
Synthesize specifica`ons from litmus tests Detect ambigui`es in synthesized models x86: 2 seconds PowerPC: 12 seconds x86: 4 ambigui`es PowerPC: 9 ambigui`es
Litmus tests and prose
∀ ∃ ∈ ∧ ∨ ∩ ∪ ⊂ ⋈ ⇒
Formal specifica`ons
Litmus tests as rela`ons Memory models as constraints Synthesis via sketches
1 2 3
X = 1 Y = 1 if Y == 0: print “hello” if X == 0: print “goodbye” Thread 1 Thread 2
1 2 3 4
All variables initialized to 0
X = 1 Y = 1 r0 = Y r1 = X Thread 1 Thread 2
1 2 3 4
All variables initialized to 0
X = 1 Y = 1 r0 = Y r1 = X Thread 1 Thread 2
1 2 3 4
All variables initialized to 0
Encode programs and behaviors as relations in relational logic (like Alloy)
X = 1 Y = 1 r0 = Y r1 = X Thread 1 Thread 2
1 2 3 4
All variables initialized to 0
Encode programs and behaviors as relations in relational logic (like Alloy) Program relations extracted from program text: po = {( , ), ( , )}
1 2 3 4
Program order: (a,b) ∈ po if b is aoer a on the same thread
X = 1 Y = 1 r0 = Y r1 = X Thread 1 Thread 2
1 2 3 4
All variables initialized to 0
Encode programs and behaviors as relations in relational logic (like Alloy) Program relations extracted from program text: po = {( , ), ( , )}
1 2 3 4
Program order: (a,b) ∈ po if b is aoer a on the same thread
Execution relations describe dynamic behavior: rf = {( , ), ( , )}
2 3 4 1
Reads-from: (r,w) ∈ rf if r reads the value wripen by w
X = 1 Y = 1 r0 = Y r1 = X Thread 1 Thread 2
1 2 3 4
All variables initialized to 0
Encode programs and behaviors as relations in relational logic (like Alloy) Program relations extracted from program text: po = {( , ), ( , )}
1 2 3 4
Program order: (a,b) ∈ po if b is aoer a on the same thread
Execution relations describe dynamic behavior: rf = {( , ), ( , )}
2 3 4 1
Reads-from: (r,w) ∈ rf if r reads the value wripen by w
Program relations extracted from program text: po = {( , ), ( , )}
1 2 3 4
Program order
Execution relations describe dynamic behavior: rf = {( , ), ( , )}
2 3 4 1
Reads-from
A memory model constrains the allowed executions of a program Written as a predicate in relational logic
Program relations extracted from program text: po = {( , ), ( , )}
1 2 3 4
Program order
Execution relations describe dynamic behavior: rf = {( , ), ( , )}
2 3 4 1
Reads-from
A memory model constrains the allowed executions of a program Written as a predicate in relational logic M(T, E) ≜
Program relations extracted from program text: po = {( , ), ( , )}
1 2 3 4
Program order
Execution relations describe dynamic behavior: rf = {( , ), ( , )}
2 3 4 1
Reads-from
A memory model constrains the allowed executions of a program Written as a predicate in relational logic M(T, E) ≜
(&& (&& (&& (in rf (& (-> Writes Reads) (join loc (~ loc)) (join data (~ data)))) (no (- (join rf (~ rf)) iden)) (all ((r4 (- Reads (join Writes rf)))) (= (join r4 data) Zero))) (&& (in ws (& (-> Writes Writes) (join loc (~ loc)))) (no (& iden ws)) (in (join ws ws) ws) (all ((r5 Writes)) (all ((r6 (- (& Writes (join loc (join r5 loc))) r5))) (or (in (-> r5 r6) ws) (in (-> r6 r5) ws)))) (in ws (join loc (~ loc))))) (no (& (^ (+ (+ rf ws (+ (join (~ rf) ws) (& (-> (- Reads (join Writes rf)) Writes) (join loc (~ loc))))) (& po (join loc (~ loc))))) iden)) (all ((r7 Writes)) (=> (&& (in r7 (- (join univ ws) (join ws univ))) (some (join (join r7 loc) finalValue))) (= (join r7 data) (join (join r7 loc) finalValue)))) (no (& (^ (+ (& po dp) ws (+ (join (~ rf) ws) (& (-> (- Reads (join Writes rf)) Writes) (join loc (~ loc)))) (-> none none) (+ (^ (+ (+ (join (:> po Syncs) po) (join (join (:> po Syncs) po) rf)) (join rf (join (:> po Syncs) po)))) (^ (+ (+ (& (join (:> po Lwsyncs) po) (+ (-> Writes Writes) (-> Reads MemoryEvent))) (:> (join rf (& (join (:> po Lwsyncs) po) (+ (-> Writes Writes) (-> Reads MemoryEvent)))) Writes)) (<: Reads (join (& (join (:> po Lwsyncs) po) (+ (-> Writes Writes) (-> Reads MemoryEvent))) rf))))))) iden))) (no (& (^ (+ po rf)) iden))
Program relations extracted from program text: po = {( , ), ( , )}
1 2 3 4
Program order
Execution relations describe dynamic behavior: rf = {( , ), ( , )}
2 3 4 1
Reads-from
A memory model constrains the allowed executions of a program Written as a predicate in relational logic M(T, E) ≜ (no (& (^ (+ po rf)) iden))
Program relations extracted from program text: po = {( , ), ( , )}
1 2 3 4
Program order
Execution relations describe dynamic behavior: rf = {( , ), ( , )}
2 3 4 1
Reads-from
A memory model constrains the allowed executions of a program Written as a predicate in relational logic M(T, E) ≜ (no (& (^ (+ po rf)) iden))
Constraining the possible values of rf… …by forbidding cycles involving rf ∪ po
Program relations extracted from program text: po = {( , ), ( , )}
1 2 3 4
Program order
Execution relations describe dynamic behavior: rf = {( , ), ( , )}
2 3 4 1
Reads-from
A memory model constrains the allowed executions of a program Written as a predicate in relational logic M(T, E) ≜ (no (& (^ (+ po rf)) iden))
Constraining the possible values of rf… …by forbidding cycles involving rf ∪ po A memory model allows a test T if there exists an execu`on E that sa`sfies the predicate
M(T, E) ≜
M(T, E) ≜ (no (& (^ (+ ?? ??)) iden))
Expression holes for a synthesizer to complete
M(T, E) ≜ (no (& (^ (+ ?? ??)) iden))
po rf po + rf po & rf po - rf … Expression holes for a synthesizer to complete
M(T, E) ≜ (no (& (^ (+ ?? ??)) iden))
po rf po + rf po & rf po - rf … Expression holes for a synthesizer to complete A sketch specifies things we know (e.g., want a happens- before ordering)…
M(T, E) ≜ (no (& (^ (+ ?? ??)) iden))
po rf po + rf po & rf po - rf … Expression holes for a synthesizer to complete A sketch specifies things we know (e.g., want a happens- before ordering)… …and defines the shape of the parts we don’t know
[Alglave et al, CAV’10]
M(T, E) ≜
Preserved program order: same-thread reorderings
[Alglave et al, CAV’10]
Global reads-from: inter-thread reorderings
M(T, E) ≜
Preserved program order: same-thread reorderings
[Alglave et al, CAV’10]
Global reads-from: inter-thread reorderings
Sequential consistency Total store
po rf po - (Wr→Rd) rf & SameThd M(T, E) ≜
Preserved program order: same-thread reorderings
[Alglave et al, CAV’10]
Global reads-from: inter-thread reorderings
Sequential consistency Total store
po rf po - (Wr→Rd) rf & SameThd M(T, E) ≜
M(T, E) ≜ Ocelot embeds rela`onal logic in the RoseZe solver-aided language [Torlak & Bodik 2014]
Also in use for SQL query synthesis and protocol reasoning
Expression holes for a synthesizer to complete
Allowed litmus tests Forbidden litmus tests
Synth
Completed memory model M Memory model sketch M ˆ
Synth x86
5 3
2 allowed tests
1 2 4 6 7 8 9 10
8 forbidden tests Total store order Memory model sketch M ˆ
Allowed litmus tests Forbidden litmus tests
Synth
Completed memory model M Memory model sketch M ˆ
Allowed litmus tests Forbidden litmus tests Memory model M Memory model sketch M ˆ
∃ M. ∀ T∈T+. M allows T
Allowed litmus tests Forbidden litmus tests Memory model M Memory model sketch M ˆ
∃ M. ∀ T∈T+. M allows T ∃ M. ∀ T∈T-. M forbids T
Allowed litmus tests Forbidden litmus tests Memory model M Memory model sketch M ˆ
∃ M. ∀ T∈T+. M allows T ∃ M. ∀ T∈T-. M forbids T
Standard exists-forall quan`fier papern for synthesis
Allowed litmus tests Forbidden litmus tests Memory model M Memory model sketch M ˆ
∃ M. ∀ T∈T+. M allows T ∃ M. ∀ T∈T-. M forbids T
M allows T: ∃ E. M(T, E)
Standard exists-forall quan`fier papern for synthesis
Allowed litmus tests Forbidden litmus tests Memory model M Memory model sketch M ˆ
∃ M. ∀ T∈T+. ∃ E. M(T,E) ∃ M. ∀ T∈T-. ∀ E. ¬M(T,E)
M allows T: ∃ E. M(T, E)
Standard exists-forall quan`fier papern for synthesis
Allowed litmus tests Forbidden litmus tests Memory model M Memory model sketch M ˆ
∃ M. ∀ T∈T+. ∃ E. M(T,E) ∃ M. ∀ T∈T-. ∀ E. ¬M(T,E)
M allows T: ∃ E. M(T, E)
Higher-order quan`fica`on
Standard exists-forall quan`fier papern for synthesis
Allowed litmus tests Forbidden litmus tests Memory model M Memory model sketch M ˆ
∃ M. ∀ T∈T+. ∃ E. M(T,E) ∃ M. ∀ T∈T-. ∀ E. ¬M(T,E)
M allows T: ∃ E. M(T, E)
Allowed litmus tests Forbidden litmus tests Memory model M Memory model sketch M ˆ
∃ M. ∀ T∈T+. ∃ E. M(T,E) ∃ M. ∀ T∈T-. ∀ E. ¬M(T,E)
M allows T: ∃ E. M(T, E)
Handled by a quan`fied boolean formula (QBF) solver
Allowed litmus tests Forbidden litmus tests Memory model M Memory model sketch M ˆ
∃ M. ∀ T∈T+. ∃ E. M(T,E) ∃ M. ∀ T∈T-. ∀ E. ¬M(T,E)
M allows T: ∃ E. M(T, E)
Handled by a quan`fied boolean formula (QBF) solver Handled by incremental synthesis engine
Allowed litmus tests Forbidden litmus tests
Synth
T T T T T T T T T T T T T T T T T1 T2
T T T T T
Allowed litmus tests Forbidden litmus tests
Synth
T T T T T T T T T T T T T T T T T1 T2
T T T T T
Allowed litmus tests Forbidden litmus tests
Synth
T T T T T T T T T T T T T T T T T1 T2
Handled by a quan`fied boolean formula (QBF) solver
T T T T T
Allowed litmus tests Forbidden litmus tests
Synth
T T T T T T T T T T T T T T T T T1 T2
M’ Handled by a quan`fied boolean formula (QBF) solver
T T T T T
Allowed litmus tests Forbidden litmus tests
Synth
T T T T T T T T T T T T T T T T T1 T2
M’
T
Handled by a quan`fied boolean formula (QBF) solver
Allowed litmus tests Forbidden litmus tests
Synth
T T T T T T T T T T T T T T T T1 T2
M’
T
Handled by a quan`fied boolean formula (QBF) solver
Allowed litmus tests Forbidden litmus tests Completed memory model M
Synth
T T T T T T T T T T T T T T T T1 T2
M’
T
Handled by a quan`fied boolean formula (QBF) solver
Allowed litmus tests Forbidden litmus tests Completed memory model M
Synth
T T T T T T T T T T T T T T T T1 T2
M’
T
Empirically, need very few itera`ons to converge Handled by a quan`fied boolean formula (QBF) solver
Ambig
Key idea: aoer synthesis, is there a different memory model that also explains the input tests?
Allowed litmus tests Forbidden litmus tests
Ambig
Key idea: aoer synthesis, is there a different memory model that also explains the input tests? Memory model sketch M ˆ
Allowed litmus tests Forbidden litmus tests
Ambig
Completed memory model M Key idea: aoer synthesis, is there a different memory model that also explains the input tests? Memory model sketch M ˆ
Allowed litmus tests Forbidden litmus tests
Ambig
Litmus test T Completed memory model M Completed memory model M2 Key idea: aoer synthesis, is there a different memory model that also explains the input tests? Memory model sketch M ˆ
Allowed litmus tests Forbidden litmus tests
Ambig
Litmus test T Completed memory model M Completed memory model M2 Key idea: aoer synthesis, is there a different memory model that also explains the input tests? Difference between M and M2 is not just syntac`c: they disagree about test T Memory model sketch M ˆ
x86 PowerPC
x86 PowerPC 768 tests
[Alglave et al, CAV’10]
10 tests
Synthesis
x86 PowerPC 768 tests
[Alglave et al, CAV’10]
10 tests ✓ 2 seconds ✓ 12 seconds
Synthesis
x86 PowerPC 768 tests
[Alglave et al, CAV’10]
10 tests ✓ 2 seconds ✓ 12 seconds
Not equivalent to TSO!
Synthesis
x86 PowerPC 768 tests
[Alglave et al, CAV’10]
10 tests ✓ 2 seconds ✓ 12 seconds
Not equivalent to published model! Not equivalent to TSO!
Synthesis
x86 PowerPC 768 tests
[Alglave et al, CAV’10]
10 tests ✓ 2 seconds ✓ 12 seconds
Not equivalent to published model!
4 new tests 9 new tests Ambiguity
Not equivalent to TSO! mfence, xchg sync, lwsync
Litmus tests and prose
∀ ∃ ∈ ∧ ∨ ∩ ∪ ⊂ ⋈ ⇒
Formal specifica`ons
Synthesize specifica`ons from litmus tests Detect ambigui`es in synthesized models x86: 2 seconds PowerPC: 12 seconds x86: 4 ambigui`es PowerPC: 9 ambigui`es
12 seconds
Time (secs) 3000 6000 9000 12000 January February March April May June
12 seconds
Time (secs) 3000 6000 9000 12000 January February March April May June
12 seconds 3 hours
Time (secs) 3000 6000 9000 12000 January February March April May June
12 seconds 3 hours Finding these op`miza`on
good performance and new func`onality
Time (secs) 3000 6000 9000 12000 January February March April May June
12 seconds 3 hours
A symbolic profiler identifies optimization
automated tool.
Time (secs) 3000 6000 9000 12000 January February March April May June
12 seconds 3 hours
A symbolic profiler identifies optimization
automated tool.
What makes scaling an automated programming tool hard? How does symbolic profiling work? How effective is symbolic profiling?
(filter even? ‘(3 6 8 2 ))
(filter even? ‘(3 6 8 2 ))
‘()
(filter even? ‘(3 6 8 2 ))
‘() ‘()
¬(even? 3)
(filter even? ‘(3 6 8 2 ))
‘() ‘() ‘(6)
¬(even? 3) (even? 6)
(filter even? ‘(3 6 8 2 ))
‘() ‘() ‘(6) ‘(6 8)
¬(even? 3) (even? 6) (even? 8)
(filter even? ‘(3 6 8 2 ))
‘() ‘() ‘(6) ‘(6 8)
¬(even? 3) (even? 6)
‘(6 8 2)
(even? 8) (even? 2)
(filter even? ‘(3 6 8 2 ))
‘() ‘() ‘(6) ‘(6 8)
¬(even? 3) (even? 6)
‘(6 8 2)
(even? 8) (even? 2)
Does this expression always return only even numbers?
Values of list elements are unknown (e.g., verifying filter for all inputs)
(filter even? ‘(x0 x1 x2 x3))
‘() ‘() ‘(6) ‘(6 8)
¬(even? 3) (even? 6)
‘(6 8 2)
(even? 8) (even? 2)
Does this expression always return only even numbers?
Values of list elements are unknown (e.g., verifying filter for all inputs)
(filter even? ‘(x0 x1 x2 x3))
‘() ‘() ‘(x1) ‘(x1 x2)
¬(even? x0) (even? x1)
‘(x0) ‘() ‘(x0) ‘(x0 x1) ‘(x2) ‘(x1) ‘(x0) ‘(x0 x2) ‘(x0 x ‘(x1 x2 x3) ‘(x1 x3)‘(x1 x2) ‘(x1) ‘(x2 x3) ‘(x0) ‘(x0 x3)‘(x0 x2) ‘(x0 x2 x3) ‘(x0 x
(even? x2) (even? x3)
Does this expression always return only even numbers?
Values of list elements are unknown (e.g., verifying filter for all inputs)
(filter even? ‘(x0 x1 x2 x3))
‘() ‘() ‘(x1) ‘(x1 x2)
¬(even? x0) (even? x1)
‘(x0) ‘() ‘(x0) ‘(x0 x1) ‘(x2) ‘(x1) ‘(x0) ‘(x0 x2) ‘(x0 x ‘(x1 x2 x3) ‘(x1 x3)‘(x1 x2) ‘(x1) ‘(x2 x3) ‘(x0) ‘(x0 x3)‘(x0 x2) ‘(x0 x2 x3) ‘(x0 x
(even? x2) (even? x3)
Does this expression always return only even numbers?
(length )
Values of list elements are unknown (e.g., verifying filter for all inputs)
(filter even? ‘(x0 x1 x2 x3))
‘() ‘() ‘(x1) ‘(x1 x2)
¬(even? x0) (even? x1)
‘(x0) ‘() ‘(x0) ‘(x0 x1) ‘(x2) ‘(x1) ‘(x0) ‘(x0 x2) ‘(x0 x ‘(x1 x2 x3) ‘(x1 x3)‘(x1 x2) ‘(x1) ‘(x2 x3) ‘(x0) ‘(x0 x3)‘(x0 x2) ‘(x0 x2 x3) ‘(x0 x
(even? x2) (even? x3)
Does this expression always return only even numbers?
(length )
2 2 3 1 2 2 3 2 1 2
Symbolic execution Bounded model checking
Always fork into independent paths (more paths, but more concrete) Merge aoer every fork (fewer paths, but less concrete)
Symbolic execution Bounded model checking
Always fork into independent paths (more paths, but more concrete) Merge aoer every fork (fewer paths, but less concrete) Rosepe [Torlak & Bodik 2014] Jalangi [Sen et al 2014] Crucible [Galois, Inc.]
Symbolic execution Bounded model checking
Always fork into independent paths (more paths, but more concrete) Merge aoer every fork (fewer paths, but less concrete) Rosepe [Torlak & Bodik 2014] Jalangi [Sen et al 2014] Crucible [Galois, Inc.] Controlling the trade-off between these strategies is key to good scalability
‘() ‘() ‘(x0) ‘() ‘(x1) ‘(x0) ‘(x0 x1)
¬(even? x0) (even? x0) (even? x1) ¬(even? x1) (even? x1) ¬(even? x1)
(even? x0) ∧ ¬ ∧ ∧ ∧ ¬ (even? x1)
Symbolic evalua\on graph Reflects the evaluator’s strategy for all-paths execu`on of the program Symbolic heap Shape of all symbolic values created by the program
‘() ‘() ‘(x0) ‘() ‘(x1) ‘(x0) ‘(x0 x1)
¬(even? x0) (even? x0) (even? x1) ¬(even? x1) (even? x1) ¬(even? x1)
(even? x0) ∧ ¬ ∧ ∧ ∧ ¬ (even? x1)
Symbolic evalua\on graph Reflects the evaluator’s strategy for all-paths execu`on of the program Symbolic heap Shape of all symbolic values created by the program
For each procedure, measure metrics that summarize the evolu`on of the symbolic evalua`on graph and symbolic heap Summarize metrics as a score to rank procedures in the program
For each procedure, measure metrics that summarize the evolu`on of the symbolic evalua`on graph and symbolic heap Summarize metrics as a score to rank procedures in the program
The most likely bopleneck is not the slowest procedure The most likely bopleneck is not the slowest procedure
We developed two implementa`ons:
Since publica`on, based on our work:
We developed two implementa`ons:
Since publica`on, based on our work:
Today
Refinement type checker for Ruby [VMCAI’18] 6× speedup Cryptographic protocol verifier [FM’18] 29× speedup SQL query verifier [CIDR’17] 75× speedup Safety-critical radiotherapy system verifier [CAV’16] 290× speedup Case studies: fixed 8 performance issues in 15 Rosette tools
Refinement type checker for Ruby [VMCAI’18] 6× speedup Cryptographic protocol verifier [FM’18] 29× speedup SQL query verifier [CIDR’17] 75× speedup Safety-critical radiotherapy system verifier [CAV’16] 290× speedup
Used in produc`on at the UW Medical Center
Case studies: fixed 8 performance issues in 15 Rosette tools
Refinement type checker for Ruby [VMCAI’18] 6× speedup Cryptographic protocol verifier [FM’18] 29× speedup SQL query verifier [CIDR’17] 75× speedup Safety-critical radiotherapy system verifier [CAV’16] 290× speedup Case studies: fixed 8 performance issues in 15 Rosette tools User study: 8 Rosette users tasked with finding known performance issues in 4 programs Users solved every task more quickly when they had access to symbolic profiling
6 failures without symbolic profiling vs. none with it
Time (secs) 3000 6000 9000 12000 January February March April May June
12 seconds 3 hours
A symbolic profiler identifies optimization
automated tool.
File systems
[ASPLOS’16, OSDI’16]
Operating systems
[SOSP’17, OSDI’18]
Memory models
[PLDI’17]
Metasketches
[POPL’16]
Symbolic profiling
[OOPSLA’18]
Solver-aided languages front-end abstractions for verification/synthesis Symbolic evaluation algorithms to translate programs to SAT/SMT SAT/SMT solving improvements in scale and expressiveness
File systems
[ASPLOS’16, OSDI’16]
Operating systems
[SOSP’17, OSDI’18]
Memory models
[PLDI’17]
Metasketches
[POPL’16]
Symbolic profiling
[OOPSLA’18]
Solver-aided languages front-end abstractions for verification/synthesis Symbolic evaluation algorithms to translate programs to SAT/SMT SAT/SMT solving improvements in scale and expressiveness ?
SAT/SMT solving improvements in scale and expressiveness
File systems
[ASPLOS’16, OSDI’16]
Operating systems
[SOSP’17, OSDI’18]
Memory models
[PLDI’17]
Metasketches
[POPL’16]
Symbolic profiling
[OOPSLA’18]
Solver-aided languages front-end abstractions for verification/synthesis Symbolic evaluation algorithms to translate programs to SAT/SMT SAT/SMT solving improvements in scale and expressiveness Solver profiling
File systems
[ASPLOS’16, OSDI’16]
Operating systems
[SOSP’17, OSDI’18]
Memory models
[PLDI’17]
Metasketches
[POPL’16]
Symbolic profiling
[OOPSLA’18]
Solver-aided languages front-end abstractions for verification/synthesis Symbolic evaluation algorithms to translate programs to SAT/SMT SAT/SMT solving improvements in scale and expressiveness Solver profiling
Exploit this profiling data for profile-guided op`miza`on
File systems
[ASPLOS’16, OSDI’16]
Operating systems
[SOSP’17, OSDI’18]
Memory models
[PLDI’17]
Hardware accelerator design/programming High-performance low-precision kernels
2 4 . . . 3 5 ⇥ . . . ⇤
<latexit sha1_base64="82XuOPTGgCFx506OuCN1kMU+8=">AHl3icdVXfj9NGEPZBuUBa4ICnqi9WA4inKM4BOXQPICpV9A2qHiBlo9N6M05Wtz/M7hgSWf47K/4YpI5/0ATbseRkPN8387MjtdxqTHyeTr0bXrP904Hty8Nfz5l9t37p7cu/e28wJuBWfcx5h6UNHCBEhV8TB1wHSv4EF/9UeIfPoPz0p/cJvCQvOVkYkUHMl1efKJKUhwPmQxrKTJuXN8W+SiGLzkLEhW1r0lXE+ZGCWDWHInFytcRH2R4syvozsi7k8GU3GZ7Ppi6fPQzLOTl8m9bGbDoLo/GkukZBc729vHd8h8REpsGgUNz7eTRJcUGyKIUCEs48pFxc8RXMyTRcg1/kVW+K8BF5lmFiHd0Gw8q7H5Fz7f1Wx8TUHNe+jZXOPmyeYXK2yKVJMwQj6oWSTIVow7LR4VI6EKi2ZHDhJOUaijV3XCBtx5AZ+CKs1pz6w/4u5tEip175zEG5Us6q9ZJ8FBUF23has6xzP0YoW7K7kQgbRKz/uRdSCumoeQVJ9StlRn4uKIm8MlqgsQYqsDJaoFyCqcDKaIOGCqVZxKbnxf5X/DB9KSxiM3KDnCIYUdYafx6AcRVae/H21TcBytK8ckr/ADCehMoUzrBjtQfMNkorVdQp2B0+XusPOCgfIwilgi+3WMLb6LURfbfJWw6vnlqMuoSG0LMLbl0Z0divjxUmAfdHRulYprNK8BwFIXMueapvRiX5Y6XITG98JVBjSBnh2gs7tfdVaLfHqnS26HSi9xlkrObnaZDE3xfig3SDUmSPjp5uxkrtSupfGgTYEMnt9xmucWDVqVP24TEnRZe2ybvCqkw084jWB/QA21IzBLe0aAm5WCev8r89D8pCK+WlngFLu6Iheg5eRM7D0ZTu03KY9pADmpgWOY0ylx7G0Qw2bB3bTf6QeTo6U/S4VcC81A/LSugL8v0zER423k/H0WQcvXs6evW6+ZbcDH4Lfg+eBFEwC14Fb4K3wUgn+Db0fHR4PBr4OXgz8Hb2rqtaMm5kHwzV49x8Tq9ah</latexit><latexit sha1_base64="82XuOPTGgCFx506OuCN1kMU+8=">AHl3icdVXfj9NGEPZBuUBa4ICnqi9WA4inKM4BOXQPICpV9A2qHiBlo9N6M05Wtz/M7hgSWf47K/4YpI5/0ATbseRkPN8387MjtdxqTHyeTr0bXrP904Hty8Nfz5l9t37p7cu/e28wJuBWfcx5h6UNHCBEhV8TB1wHSv4EF/9UeIfPoPz0p/cJvCQvOVkYkUHMl1efKJKUhwPmQxrKTJuXN8W+SiGLzkLEhW1r0lXE+ZGCWDWHInFytcRH2R4syvozsi7k8GU3GZ7Ppi6fPQzLOTl8m9bGbDoLo/GkukZBc729vHd8h8REpsGgUNz7eTRJcUGyKIUCEs48pFxc8RXMyTRcg1/kVW+K8BF5lmFiHd0Gw8q7H5Fz7f1Wx8TUHNe+jZXOPmyeYXK2yKVJMwQj6oWSTIVow7LR4VI6EKi2ZHDhJOUaijV3XCBtx5AZ+CKs1pz6w/4u5tEip175zEG5Us6q9ZJ8FBUF23has6xzP0YoW7K7kQgbRKz/uRdSCumoeQVJ9StlRn4uKIm8MlqgsQYqsDJaoFyCqcDKaIOGCqVZxKbnxf5X/DB9KSxiM3KDnCIYUdYafx6AcRVae/H21TcBytK8ckr/ADCehMoUzrBjtQfMNkorVdQp2B0+XusPOCgfIwilgi+3WMLb6LURfbfJWw6vnlqMuoSG0LMLbl0Z0divjxUmAfdHRulYprNK8BwFIXMueapvRiX5Y6XITG98JVBjSBnh2gs7tfdVaLfHqnS26HSi9xlkrObnaZDE3xfig3SDUmSPjp5uxkrtSupfGgTYEMnt9xmucWDVqVP24TEnRZe2ybvCqkw084jWB/QA21IzBLe0aAm5WCev8r89D8pCK+WlngFLu6Iheg5eRM7D0ZTu03KY9pADmpgWOY0ylx7G0Qw2bB3bTf6QeTo6U/S4VcC81A/LSugL8v0zER423k/H0WQcvXs6evW6+ZbcDH4Lfg+eBFEwC14Fb4K3wUgn+Db0fHR4PBr4OXgz8Hb2rqtaMm5kHwzV49x8Tq9ah</latexit><latexit sha1_base64="82XuOPTGgCFx506OuCN1kMU+8=">AHl3icdVXfj9NGEPZBuUBa4ICnqi9WA4inKM4BOXQPICpV9A2qHiBlo9N6M05Wtz/M7hgSWf47K/4YpI5/0ATbseRkPN8387MjtdxqTHyeTr0bXrP904Hty8Nfz5l9t37p7cu/e28wJuBWfcx5h6UNHCBEhV8TB1wHSv4EF/9UeIfPoPz0p/cJvCQvOVkYkUHMl1efKJKUhwPmQxrKTJuXN8W+SiGLzkLEhW1r0lXE+ZGCWDWHInFytcRH2R4syvozsi7k8GU3GZ7Ppi6fPQzLOTl8m9bGbDoLo/GkukZBc729vHd8h8REpsGgUNz7eTRJcUGyKIUCEs48pFxc8RXMyTRcg1/kVW+K8BF5lmFiHd0Gw8q7H5Fz7f1Wx8TUHNe+jZXOPmyeYXK2yKVJMwQj6oWSTIVow7LR4VI6EKi2ZHDhJOUaijV3XCBtx5AZ+CKs1pz6w/4u5tEip175zEG5Us6q9ZJ8FBUF23has6xzP0YoW7K7kQgbRKz/uRdSCumoeQVJ9StlRn4uKIm8MlqgsQYqsDJaoFyCqcDKaIOGCqVZxKbnxf5X/DB9KSxiM3KDnCIYUdYafx6AcRVae/H21TcBytK8ckr/ADCehMoUzrBjtQfMNkorVdQp2B0+XusPOCgfIwilgi+3WMLb6LURfbfJWw6vnlqMuoSG0LMLbl0Z0divjxUmAfdHRulYprNK8BwFIXMueapvRiX5Y6XITG98JVBjSBnh2gs7tfdVaLfHqnS26HSi9xlkrObnaZDE3xfig3SDUmSPjp5uxkrtSupfGgTYEMnt9xmucWDVqVP24TEnRZe2ybvCqkw084jWB/QA21IzBLe0aAm5WCev8r89D8pCK+WlngFLu6Iheg5eRM7D0ZTu03KY9pADmpgWOY0ylx7G0Qw2bB3bTf6QeTo6U/S4VcC81A/LSugL8v0zER423k/H0WQcvXs6evW6+ZbcDH4Lfg+eBFEwC14Fb4K3wUgn+Db0fHR4PBr4OXgz8Hb2rqtaMm5kHwzV49x8Tq9ah</latexit><latexit sha1_base64="82XuOPTGgCFx506OuCN1kMU+8=">AHl3icdVXfj9NGEPZBuUBa4ICnqi9WA4inKM4BOXQPICpV9A2qHiBlo9N6M05Wtz/M7hgSWf47K/4YpI5/0ATbseRkPN8387MjtdxqTHyeTr0bXrP904Hty8Nfz5l9t37p7cu/e28wJuBWfcx5h6UNHCBEhV8TB1wHSv4EF/9UeIfPoPz0p/cJvCQvOVkYkUHMl1efKJKUhwPmQxrKTJuXN8W+SiGLzkLEhW1r0lXE+ZGCWDWHInFytcRH2R4syvozsi7k8GU3GZ7Ppi6fPQzLOTl8m9bGbDoLo/GkukZBc729vHd8h8REpsGgUNz7eTRJcUGyKIUCEs48pFxc8RXMyTRcg1/kVW+K8BF5lmFiHd0Gw8q7H5Fz7f1Wx8TUHNe+jZXOPmyeYXK2yKVJMwQj6oWSTIVow7LR4VI6EKi2ZHDhJOUaijV3XCBtx5AZ+CKs1pz6w/4u5tEip175zEG5Us6q9ZJ8FBUF23has6xzP0YoW7K7kQgbRKz/uRdSCumoeQVJ9StlRn4uKIm8MlqgsQYqsDJaoFyCqcDKaIOGCqVZxKbnxf5X/DB9KSxiM3KDnCIYUdYafx6AcRVae/H21TcBytK8ckr/ADCehMoUzrBjtQfMNkorVdQp2B0+XusPOCgfIwilgi+3WMLb6LURfbfJWw6vnlqMuoSG0LMLbl0Z0divjxUmAfdHRulYprNK8BwFIXMueapvRiX5Y6XITG98JVBjSBnh2gs7tfdVaLfHqnS26HSi9xlkrObnaZDE3xfig3SDUmSPjp5uxkrtSupfGgTYEMnt9xmucWDVqVP24TEnRZe2ybvCqkw084jWB/QA21IzBLe0aAm5WCev8r89D8pCK+WlngFLu6Iheg5eRM7D0ZTu03KY9pADmpgWOY0ylx7G0Qw2bB3bTf6QeTo6U/S4VcC81A/LSugL8v0zER423k/H0WQcvXs6evW6+ZbcDH4Lfg+eBFEwC14Fb4K3wUgn+Db0fHR4PBr4OXgz8Hb2rqtaMm5kHwzV49x8Tq9ah</latexit>File systems
[ASPLOS’16, OSDI’16]
Operating systems
[SOSP’17, OSDI’18]
Memory models
[PLDI’17]
Metasketches
[POPL’16]
Symbolic profiling
[OOPSLA’18]
Solver profiling
Hardware accelerator design/programming High-performance low-precision kernels
2 4 . . . 3 5 ⇥ . . . ⇤
<latexit sha1_base64="82XuOPTGgCFx506OuCN1kMU+8=">AHl3icdVXfj9NGEPZBuUBa4ICnqi9WA4inKM4BOXQPICpV9A2qHiBlo9N6M05Wtz/M7hgSWf47K/4YpI5/0ATbseRkPN8387MjtdxqTHyeTr0bXrP904Hty8Nfz5l9t37p7cu/e28wJuBWfcx5h6UNHCBEhV8TB1wHSv4EF/9UeIfPoPz0p/cJvCQvOVkYkUHMl1efKJKUhwPmQxrKTJuXN8W+SiGLzkLEhW1r0lXE+ZGCWDWHInFytcRH2R4syvozsi7k8GU3GZ7Ppi6fPQzLOTl8m9bGbDoLo/GkukZBc729vHd8h8REpsGgUNz7eTRJcUGyKIUCEs48pFxc8RXMyTRcg1/kVW+K8BF5lmFiHd0Gw8q7H5Fz7f1Wx8TUHNe+jZXOPmyeYXK2yKVJMwQj6oWSTIVow7LR4VI6EKi2ZHDhJOUaijV3XCBtx5AZ+CKs1pz6w/4u5tEip175zEG5Us6q9ZJ8FBUF23has6xzP0YoW7K7kQgbRKz/uRdSCumoeQVJ9StlRn4uKIm8MlqgsQYqsDJaoFyCqcDKaIOGCqVZxKbnxf5X/DB9KSxiM3KDnCIYUdYafx6AcRVae/H21TcBytK8ckr/ADCehMoUzrBjtQfMNkorVdQp2B0+XusPOCgfIwilgi+3WMLb6LURfbfJWw6vnlqMuoSG0LMLbl0Z0divjxUmAfdHRulYprNK8BwFIXMueapvRiX5Y6XITG98JVBjSBnh2gs7tfdVaLfHqnS26HSi9xlkrObnaZDE3xfig3SDUmSPjp5uxkrtSupfGgTYEMnt9xmucWDVqVP24TEnRZe2ybvCqkw084jWB/QA21IzBLe0aAm5WCev8r89D8pCK+WlngFLu6Iheg5eRM7D0ZTu03KY9pADmpgWOY0ylx7G0Qw2bB3bTf6QeTo6U/S4VcC81A/LSugL8v0zER423k/H0WQcvXs6evW6+ZbcDH4Lfg+eBFEwC14Fb4K3wUgn+Db0fHR4PBr4OXgz8Hb2rqtaMm5kHwzV49x8Tq9ah</latexit><latexit sha1_base64="82XuOPTGgCFx506OuCN1kMU+8=">AHl3icdVXfj9NGEPZBuUBa4ICnqi9WA4inKM4BOXQPICpV9A2qHiBlo9N6M05Wtz/M7hgSWf47K/4YpI5/0ATbseRkPN8387MjtdxqTHyeTr0bXrP904Hty8Nfz5l9t37p7cu/e28wJuBWfcx5h6UNHCBEhV8TB1wHSv4EF/9UeIfPoPz0p/cJvCQvOVkYkUHMl1efKJKUhwPmQxrKTJuXN8W+SiGLzkLEhW1r0lXE+ZGCWDWHInFytcRH2R4syvozsi7k8GU3GZ7Ppi6fPQzLOTl8m9bGbDoLo/GkukZBc729vHd8h8REpsGgUNz7eTRJcUGyKIUCEs48pFxc8RXMyTRcg1/kVW+K8BF5lmFiHd0Gw8q7H5Fz7f1Wx8TUHNe+jZXOPmyeYXK2yKVJMwQj6oWSTIVow7LR4VI6EKi2ZHDhJOUaijV3XCBtx5AZ+CKs1pz6w/4u5tEip175zEG5Us6q9ZJ8FBUF23has6xzP0YoW7K7kQgbRKz/uRdSCumoeQVJ9StlRn4uKIm8MlqgsQYqsDJaoFyCqcDKaIOGCqVZxKbnxf5X/DB9KSxiM3KDnCIYUdYafx6AcRVae/H21TcBytK8ckr/ADCehMoUzrBjtQfMNkorVdQp2B0+XusPOCgfIwilgi+3WMLb6LURfbfJWw6vnlqMuoSG0LMLbl0Z0divjxUmAfdHRulYprNK8BwFIXMueapvRiX5Y6XITG98JVBjSBnh2gs7tfdVaLfHqnS26HSi9xlkrObnaZDE3xfig3SDUmSPjp5uxkrtSupfGgTYEMnt9xmucWDVqVP24TEnRZe2ybvCqkw084jWB/QA21IzBLe0aAm5WCev8r89D8pCK+WlngFLu6Iheg5eRM7D0ZTu03KY9pADmpgWOY0ylx7G0Qw2bB3bTf6QeTo6U/S4VcC81A/LSugL8v0zER423k/H0WQcvXs6evW6+ZbcDH4Lfg+eBFEwC14Fb4K3wUgn+Db0fHR4PBr4OXgz8Hb2rqtaMm5kHwzV49x8Tq9ah</latexit><latexit sha1_base64="82XuOPTGgCFx506OuCN1kMU+8=">AHl3icdVXfj9NGEPZBuUBa4ICnqi9WA4inKM4BOXQPICpV9A2qHiBlo9N6M05Wtz/M7hgSWf47K/4YpI5/0ATbseRkPN8387MjtdxqTHyeTr0bXrP904Hty8Nfz5l9t37p7cu/e28wJuBWfcx5h6UNHCBEhV8TB1wHSv4EF/9UeIfPoPz0p/cJvCQvOVkYkUHMl1efKJKUhwPmQxrKTJuXN8W+SiGLzkLEhW1r0lXE+ZGCWDWHInFytcRH2R4syvozsi7k8GU3GZ7Ppi6fPQzLOTl8m9bGbDoLo/GkukZBc729vHd8h8REpsGgUNz7eTRJcUGyKIUCEs48pFxc8RXMyTRcg1/kVW+K8BF5lmFiHd0Gw8q7H5Fz7f1Wx8TUHNe+jZXOPmyeYXK2yKVJMwQj6oWSTIVow7LR4VI6EKi2ZHDhJOUaijV3XCBtx5AZ+CKs1pz6w/4u5tEip175zEG5Us6q9ZJ8FBUF23has6xzP0YoW7K7kQgbRKz/uRdSCumoeQVJ9StlRn4uKIm8MlqgsQYqsDJaoFyCqcDKaIOGCqVZxKbnxf5X/DB9KSxiM3KDnCIYUdYafx6AcRVae/H21TcBytK8ckr/ADCehMoUzrBjtQfMNkorVdQp2B0+XusPOCgfIwilgi+3WMLb6LURfbfJWw6vnlqMuoSG0LMLbl0Z0divjxUmAfdHRulYprNK8BwFIXMueapvRiX5Y6XITG98JVBjSBnh2gs7tfdVaLfHqnS26HSi9xlkrObnaZDE3xfig3SDUmSPjp5uxkrtSupfGgTYEMnt9xmucWDVqVP24TEnRZe2ybvCqkw084jWB/QA21IzBLe0aAm5WCev8r89D8pCK+WlngFLu6Iheg5eRM7D0ZTu03KY9pADmpgWOY0ylx7G0Qw2bB3bTf6QeTo6U/S4VcC81A/LSugL8v0zER423k/H0WQcvXs6evW6+ZbcDH4Lfg+eBFEwC14Fb4K3wUgn+Db0fHR4PBr4OXgz8Hb2rqtaMm5kHwzV49x8Tq9ah</latexit><latexit sha1_base64="82XuOPTGgCFx506OuCN1kMU+8=">AHl3icdVXfj9NGEPZBuUBa4ICnqi9WA4inKM4BOXQPICpV9A2qHiBlo9N6M05Wtz/M7hgSWf47K/4YpI5/0ATbseRkPN8387MjtdxqTHyeTr0bXrP904Hty8Nfz5l9t37p7cu/e28wJuBWfcx5h6UNHCBEhV8TB1wHSv4EF/9UeIfPoPz0p/cJvCQvOVkYkUHMl1efKJKUhwPmQxrKTJuXN8W+SiGLzkLEhW1r0lXE+ZGCWDWHInFytcRH2R4syvozsi7k8GU3GZ7Ppi6fPQzLOTl8m9bGbDoLo/GkukZBc729vHd8h8REpsGgUNz7eTRJcUGyKIUCEs48pFxc8RXMyTRcg1/kVW+K8BF5lmFiHd0Gw8q7H5Fz7f1Wx8TUHNe+jZXOPmyeYXK2yKVJMwQj6oWSTIVow7LR4VI6EKi2ZHDhJOUaijV3XCBtx5AZ+CKs1pz6w/4u5tEip175zEG5Us6q9ZJ8FBUF23has6xzP0YoW7K7kQgbRKz/uRdSCumoeQVJ9StlRn4uKIm8MlqgsQYqsDJaoFyCqcDKaIOGCqVZxKbnxf5X/DB9KSxiM3KDnCIYUdYafx6AcRVae/H21TcBytK8ckr/ADCehMoUzrBjtQfMNkorVdQp2B0+XusPOCgfIwilgi+3WMLb6LURfbfJWw6vnlqMuoSG0LMLbl0Z0divjxUmAfdHRulYprNK8BwFIXMueapvRiX5Y6XITG98JVBjSBnh2gs7tfdVaLfHqnS26HSi9xlkrObnaZDE3xfig3SDUmSPjp5uxkrtSupfGgTYEMnt9xmucWDVqVP24TEnRZe2ybvCqkw084jWB/QA21IzBLe0aAm5WCev8r89D8pCK+WlngFLu6Iheg5eRM7D0ZTu03KY9pADmpgWOY0ylx7G0Qw2bB3bTf6QeTo6U/S4VcC81A/LSugL8v0zER423k/H0WQcvXs6evW6+ZbcDH4Lfg+eBFEwC14Fb4K3wUgn+Db0fHR4PBr4OXgz8Hb2rqtaMm5kHwzV49x8Tq9ah</latexit>Thanks!
bornholt@uw.edu https://unsat.org