WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
GoLightly: Building VM-based language runtimes in Go
1. GoLightly
Building VM-based language runtimes in Go
Eleanor McHugh
http://golightly.games-with-brains.net
Friday, 15 October 2010 1
2. portrait of an artist...
physics major
http://feyele
embedded systems
dynamic languages
dns provisioning
network scaling or.tel an
questionable taste in music Elean or McHugh
Friday, 15 October 2010 2
3. today’s menu
an overview of golightly
a crash course in go programming
application virtualisation & soft machines
Friday, 15 October 2010 3
4. caveat lector
danger! we’re entering strange territory
our map is missing major landmarks
and will be riddled with inaccuracies
so please tread carefully
try not to disturb the local wildlife
and don’t be put off by the pages of code
Friday, 15 October 2010 4
6. go...
a systems language by google
productivity, performance, concurrency
lighter than Java, safer than C
Friday, 15 October 2010 6
7. ...lightly
clean abstractions
geared to performance
non-viral open source license
Friday, 15 October 2010 7
8. inspiration
processor design
sensor and control networks
field-programmable gate arrays
Friday, 15 October 2010 8
9. perspiration
iterative empirical development
explore -> implement -> test -> benchmark
evolve towards elegance
Friday, 15 October 2010 9
10. principles
decoupling improves scalability
coherence simplifies organisation
optimisations are application specific
Friday, 15 October 2010 10
11. agnostic
no blessed programming languages
flexible platform abstractions
write once, run everywhere it matters
Friday, 15 October 2010 11
12. heterogeneous
a system comprises many components
components may differ in purpose and design
but they cooperate to solve problems
Friday, 15 October 2010 12
13. virtualisation
design discrete Turing machines
implement these machines in software
compile programs to run on them
Friday, 15 October 2010 13
14. networks
machines cooperate by sending messages
machine states can be serialised as messages
messages transcend process and host boundaries
Friday, 15 October 2010 14
16. behind the hype
a statically-typed compiled language
class-free object-orientation
nominal type declaration
structural type inference
garbage collection
concurrency via communication (CSP)
Friday, 15 October 2010 16
17. an elegant tool
the safety of a static type system
the feel of a dynamic runtime
the performance of a compiled language
no dependence on runtime libraries
Friday, 15 October 2010 17
18. nominal types
primitive (boolean, numeric, pointer)
aggregate (array, slice, map, struct)
functional (closure, channel)
all types can underpin user-defined types
methods are declared on user-defined types
types can be embedded in struct types
Friday, 15 October 2010 18
19. package Integer package main
import “Integer”
type Int int
func main() {
func (i *Int) Add(x int) { i := Integer.Buffer{0, 1, 2, 3, 4, 5}
*i += Int(x) b := i.Clone()
} b.Swap(1, 2)
b.Move(3, 2)
type Buffer []Int b[0].Add(3)
println(“b[0:2] = {”, b[0], “,”, b[1], “}”)
func (b Buffer) Clone() Buffer { }
s := make(Buffer, len(b))
copy(s, b)
return s
}
func (b Buffer) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
func (b Buffer) Move(i, n int) {
if n > len(b) - i {
n = len(b) - i
}
segment_to_move := b[:i].Clone()
copy(b, b[i:i + n])
copy(b[n:i + n], segment_to_move) produces:
} b[0:2] = { 6, 4 }
Friday, 15 October 2010 19
20. package Vector package main
import . “Integer” import “Integer”
type Vector struct { func main() {
Buffer i := Vector{Buffer{0, 1, 2, 3, 4, 5}}
} b := i.Clone()
b.Swap(1, 2)
func (v *Vector) Clone() Vector { b.Move(3, 2)
return Vector{v.Buffer.Clone()} s := b.Slice(0, 2)
} s[0].Add(3)
b.Replace(s)
func (v *Vector) Slice(i, j int) Buffer { println(“b[0:2] = {”, b.Buffer[0], “,”, b.Buffer[1], “}”)
return v.Buffer[i:j] }
}
func (v *Vector) Replace(o interface{}) {
switch o := o.(type) {
case Vector:
v=o
case Buffer:
v.Buffer = o
}
}
produces:
b[0:2] = { 6, 4 }
Friday, 15 October 2010 20
21. structural types
interfaces define method sets
they can be embedded within each other
but do not implement methods
a type can implement many interfaces
type inference determines which if any
all types implement the blank interface
Friday, 15 October 2010 21
26. goroutines
concurrent threads of control
launched by the go statement
which returns immediately
each may be a function call or method call
and can communicate via channels
Friday, 15 October 2010 26
27. channels
link concurrently executing functions
support sending and/or receiving
only accept items of a specified type
synchronous channels are unbuffered
asynchronous channels are buffered
Friday, 15 October 2010 27
28. package generalise func (f Iteration) Each(c interface{}) {
import . "reflect" switch c := NewValue(c).(type) {
case *SliceValue:
type Results chan interface{} count := c.Len()
SignalSource(func(done chan bool) {
type SignalSource func(status chan bool) for i := 0; i < count; i++ {
func (s SignalSource) Pipeline() { f.apply(i, c.Elem(i).Interface(), done)
done := make(chan bool) }
defer close(done) }).Multiplex(count)
go s(done) case *MapValue:
<-done SignalSource(func(done chan bool) {
} for _, k := range c.Keys() {
f.apply(k, c.Elem(k).Interface(), done)
func (s SignalSource) Multiplex(count int) { }
done := make(chan bool) }).Multiplex(c.Len())
defer close(done) }
go s(done) }
for i := 0; i < count; i++ {
<- done type Combination func(x, y interface{}) interface{}
} func (f Combination) Reduce(c, s interface{}) (r Results) {
} r = make(Results)
go func() {
type Iteration func(k, x interface{}) Iteration(func(k, x interface{}) {
func (i Iteration) apply(k, v interface{}, c chan bool) { s = f(s, x)
go func() { }).Each(c)
i(k, v) r <- s
c <- true }()
}() return
} }
Friday, 15 October 2010 28
29. type Transformation func(x interface{}) interface{} package main
func (t Transformation) GetValue(x interface{}) Value { import “fmt”
return NewValue(t(x)) import . “generalise”
}
var adder Combination = func(x, y interface{}) interface{} {
func (t Transformation) Map(c interface{}) interface{} { return x.(int) + y.(int)
switch n := NewValue(Allocate(c)).(type) { }
case *SliceValue:
SignalSource(func(done chan bool) { var multiplier Transformation = func(x interface{}) interface{} {
Iteration(func(k, x interface{}) { return x.(int) * 2
n.Elem(k.(int)).SetValue(t.GetValue(x)) }
}).Each(c)
done <- true func main() {
}).Pipeline() s := []int{0, 1, 2, 3, 4, 5}
return n.Interface() fmt.Println("s =", s)
case *MapValue: fmt.Println("sum s =", (<- adder.Reduce(s, 0)).(int))
SignalSource(func(done chan bool) {
Iteration(func(k, x interface{}) { c := multiplier.Map(s)
n.SetElem(NewValue(k), t.GetValue(x)) fmt.Println("c =", c)
}).Each(c) fmt.Println("sum c =", (<- adder.Reduce(c, 0)).(int))
done <- true }
}).Pipeline()
return n.Interface()
} produces:
return Duplicate(c) s = [0 1 2 3 4 5]
}
sum s = 15
c = [0 2 4 6 8 10]
sum c = 30
Friday, 15 October 2010 29
30. tooling
gotest is a testing framework
which also supports benchmarking
gofmt standardises code layout
godoc formats and serves documentation
goinstall is an automatic package installer
cgo integrates C code with go
Friday, 15 October 2010 30
32. system clock
synchronising components
Friday, 15 October 2010 32
33. package clock package main
import "syscall" import . “clock”
type Clock struct { func main() {
Period int64 c := Clock{1000, make(chan int64), make(chan bool), false}
Count chan int64 c.Start()
Control chan bool
active bool for i := 0; i < 3; i++ {
} println("pulse value", <-c.Count, "from clock")
}
func (c *Clock) Start() {
if !c.active { println("disabling clock")
go func() { c.Control <- false
c.active = true syscall.Sleep(1000000)
for i := int64(0); ; i++ { println("restarting clock")
select { c.Control <- true
case status := <- c.Control: println("pulse value", <-c.Count, "from clock")
c.active = status }
default:
if c.active {
c.Count <- i produces:
} pulse value 0 from clock
syscall.Sleep(c.Period)
pulse value 1 from clock
}
} pulse value 2 from clock
}() disabling clock
} restarting clock
} pulse value 106 from clock
Friday, 15 October 2010 33
34. instruction set
specifying operation sequences
Friday, 15 October 2010 34
35. package instructions func (i Instruction) Execute(op Operation) {
import "fmt" op(i.Operands())
}
type Operation func(o []int)
type Assembler struct {
type Executable interface { opcodes map[string] int
Opcode() int names map[int] string
Operands() []int }
Execute(op Operation)
} func NewAssember(names... string) (a Assembler) {
a = Assembler{ make(map[string] int), make(map[int] string) }
const INVALID_OPCODE = -1 a.Define(names...)
return
type Instruction []int }
func (i Instruction) Opcode() int {
if len(i) == 0 { func (a Assembler) Assemble(name string, params... int)
return INVALID_OPCODE (i Instruction) {
} i = make(Instruction, len(params) + 1)
return i[0] if opcode, ok := a.opcodes[name]; ok {
} i[0] = opcode
} else {
func (i Instruction) Operands() []int { i[0] = INVALID_OPCODE
if len(i) < 2 { }
return []int{} copy(i[1:], params)
} return
return i[1:] }
}
Friday, 15 October 2010 35
36. func (a Assembler) Define(names... string) { package main
for _, name := range names { import . “instructions”
a.opcodes[name] = len(a.names)
a.names[len(a.names)] = name func main() {
} a := NewAssembler("noop", "load", "store")
} p := Program{ a.Assemble("noop"),
a.Assemble("load", 1),
func (a Assembler) Disassemble(e Executable) (s string) { a.Assemble("store", 1, 2),
if name, ok := a.names[e.Opcode()]; ok { a.Assemble("invalid", 3, 4, 5) }
s = name p.Disassemble(a)
if params := e.Operands(); len(params) > 0 { for _, v := range p {
s = fmt.Sprintf("%vt%v", s, params[0]) if len(v.Operands()) == 2 {
for _, v := range params[1:] { v.Execute(func(o []int) {
s = fmt.Sprintf("%v, %v", s, v) o[0] += o[1]
} })
} println("op =", v.Opcode(), "result =", v.Operands()[0])
} else { }
s = "unknown" }
} }
return
}
produces:
type Program []Executable noop
func (p Program) Disassemble(a Assembler) {
load!
! 1
for _, v := range p {
fmt.Println(a.Disassemble(v)) store! 1, 2
} unknown
} op = 2 result = 3
Friday, 15 October 2010 36
57. transport triggering
register machine architecture
exposes internal buses and components
operations are side-effects of internal writes
Friday, 15 October 2010 57
58. vector machine
multi-operand instructions
data vectors read from memory into registers
operations combine registers
Friday, 15 October 2010 58
59. package vmachine type VectorMachine struct {
import . “processor” ! Core
! R! ! []Memory
func (v *VectorMachine) Run(program []Executable) { }
v.RunExclusive(program, func() {
switch v.Opcode() { func (v *VectorMachine) Load(r int, m Memory) {
case CONSTANT: ! v.R[r] = make(Memory, len(m))
v.Execute(func(o []int) { v.Load(o[0], o[1:]) }) ! copy(v.R[r], m)
case LOAD_VALUE: }
v.Execute(func(o []int) {
v.Load(o[0], v.M[o[1]:o[1] + o[2]]) func NewVMachine(CSSize, RSize, MSize int) *VectorMachine {
}) ! return &VectorMachine{
case STORE_VALUE: NewCore(CSSize, MSize),
v.Execute(func(o []int) { make([]Memory, RSize)
copy(v.M[o[0]:], v.R[o[1]]) }
}) }
case ADD:
v.Execute(func(o []int) { const (
a, b := v.R[o[0]], v.R[o[1]] CONSTANT = iota
if len(a) < len(b) { LOAD_VALUE
for i, x := range a { a[i] = x + b[i] } STORE_VALUE
} else { ADD
for i, x := range b { a[i] += x } )
}
})
! ! default:
! ! ! panic(ILLEGAL_OPERATION)
! ! }
! })
}
Friday, 15 October 2010 59
61. superscalar
multiple execution units
processor caching
out-of-order execution
Friday, 15 October 2010 61
62. close to the machine
interrupts
transport buses
peripheral drivers
Friday, 15 October 2010 62
63. finding out more
http://golightly.games-with-brains.net
http://github.com/feyeleanor/GoLightly
twitter://#golightly
wikipedia
google
Friday, 15 October 2010 63