talks: State of Go 2017
Change-Id: If5900ebc7b9872314ae75160489a66d0fd65cc81
Reviewed-on: https://go-review.googlesource.com/36053
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/2017/state-of-go.slide b/2017/state-of-go.slide
new file mode 100644
index 0000000..634804a
--- /dev/null
+++ b/2017/state-of-go.slide
@@ -0,0 +1,522 @@
+The State of Go
+Where we are in February 2017
+
+Francesc Campoy
+Google Developer Advocate
+@francesc
+campoy@golang.org
+
+* Time flies
+
+Go 1.6 is one year old (happy birthday!)
+
+Go 1.7 is already 6 months old!
+
+Go 1.8 to be released sometime in February.
+
+Go 1.8 Candidate Release 3 was released on January 26th.
+
+.image state-of-go/img/flying.png
+
+* Notes
+
+The slides are available on [[https://talks.golang.org/2017/state-of-go.slide]]
+
+Most of the code examples won't run except locally and using Go 1.8.
+
+The playground still runs Go 1.7.
+
+* Agenda
+
+Changes since Go 1.7:
+
+- The Language
+- The Standard Library
+- The Runtime
+- The Tooling
+- The Community
+
+* Changes to the language
+
+* Conversion rules
+
+How many times have you found yourself with two types that were *almost* equal?
+
+Let's say you define `Person`:
+
+.code state-of-go/stdlib/json_old.go /type Person/,/^}/
+
+And that for some reason, like JSON you also have:
+
+.code state-of-go/stdlib/json_old.go /var aux/,/}/
+
+* Conversion rules
+
+In order to convert `aux` to type `Person` you needed to do:
+
+.code state-of-go/stdlib/json_old.go /type Person/,/}/
+
+ return Person{
+ Name: aux.Name,
+ AgeYears: aux.AgeYears,
+ SSN: aux.SSN
+ }
+
+* Conversion rules
+
+Since Go 1.8 you can simply do:
+
+ return Person(aux)
+
+Both types still need to have:
+
+- same *sequence* of fields (the order matters)
+- corresponding fields with same type.
+
+* Conversion rules
+
+A non-constant value x can be converted to type T in any of these cases:
+
+- x is assignable to T.
+- x's type and T have identical underlying types.
+- x's type and T are unnamed pointer types and their pointer base types have identical underlying types.
+- ...
+
+* Conversion rules
+
+A non-constant value x can be converted to type T in any of these cases:
+
+- x is assignable to T.
+- *ignoring*struct*tags*, x's type and T have identical underlying types.
+- *ignoring*struct*tags*, x's type and T are unnamed pointer types and their pointer base types have identical underlying types.
+- ...
+
+* Ports to other platforms
+
+* Ports to other platforms
+
+32-bit MIPS
+
+- big-endian (`linux/mips`)
+- little-endian (`linux/mipsle`) - requires Floating Point Unit
+
+Go on DragonFly BSD now requires DragonFly 4.4.4+.
+
+Go on OpenBSD now requires OpenBSD 5.9+.
+
+Plan 9 is now better!
+
+* Ports to other platforms
+
+Go 1.8 supports OS X 10.8+. Likely last time we support 10.8.
+
+ARM:
+
+- Go 1.8 is the last version to support ARMv5E and ARMv6 processors.
+
+- Go 1.9 will require ARMv6K. Will it work on my platform?
+
+ go tool dist -check-armv6k
+
+* Tools
+
+* Fix
+
+Fixes the import path `"golang.org/x/net/context"` to `"context"`.
+
+.code state-of-go/tools/gofix.go
+
+Simply run the command below:
+
+.play state-of-go/tools/gofix.sh /go tool/
+
+Drop the `-diff` flag to rewrite the files.
+
+* Vet
+
+"Vet is stricter in some ways and looser where it previously caused false positives."
+
+Example of extra check:
+
+.play -edit state-of-go/tools/govet.go /func main/,
+
+`govet` detects the problem statically:
+
+.play state-of-go/tools/govet.sh /go vet/
+
+* SSA everywhere!
+
+The SSA backend:
+
+- generates more compact and efficient code
+- is a better platform for optimizations
+
+For 32-bit ARM systems this means 20-30% speed up!
+
+For others (where SSA was used already) gains are 0-10%.
+
+* SSA everywhere
+
+.image state-of-go/img/benchmark.png _ 800
+
+* Default GOPATH
+
+Yay!
+
+When `GOPATH` is not defined, the tool will use:
+
+- `$HOME/go` on Unix
+- `%USERPROFILE%\go` on Windows
+
+* go bug
+
+Easier way to create bugs including all relevant information.
+
+Example:
+
+.play state-of-go/tools/gobug.sh /go bug/
+
+* Runtime
+
+* Detection of concurrent map accesses
+
+Improvement on Go 1.6.
+
+.play state-of-go/runtime/mapcrash.go /const/,/Wait\(\)/
+
+Outputs:
+
+ fatal error: concurrent map read and map write
+ fatal error: concurrent map writes
+
+* Mutext Contention Profiling
+
+Profile your benchmarks and the contention on your mutexes.
+
+ go test bench=. -mutexprofile=mutex.out
+
+
+Alternatively, activate contention profiling with this new method.
+
+ runtime.SetMutexProfileFraction
+
+_Note_: For now `sync.RWMutex` is not profiled.
+
+* Mutex Contention Profiling
+
+Let's write a program to count how many times each factor appears from 2 to N.
+
+Example N = 10:
+
+ Factorizations:
+
+ 2: 2
+ 3: 3
+ 4: 2 2
+ 5: 5
+ 6: 2 3
+ 7: 7
+ 8: 2 2 2
+ 9: 3 3
+ 10: 2 5
+
+ Count:
+
+ 2: 8
+ 3: 4
+ 5: 2
+ 7: 1
+
+* Mutex Contention Profiling
+
+Which option is better?
+
+Wide protected region:
+
+.play state-of-go/runtime/mutex/main.go /WIDE/,/Unlock/
+
+Narrow protected region:
+
+.play state-of-go/runtime/mutex/main.go /NARROW/,/}/
+
+* Benchmark
+
+ $ go test -bench=.
+
+# BenchmarkNarrowSection/10-8 300000 5085 ns/op
+# BenchmarkNarrowSection/100-8 20000 77458 ns/op
+# BenchmarkNarrowSection/1000-8 2000 909658 ns/op
+# BenchmarkNarrowSection/10000-8 100 21230633 ns/op
+#
+# BenchmarkWideSection/10-8 200000 5323 ns/op
+# BenchmarkWideSection/100-8 10000 103228 ns/op
+# BenchmarkWideSection/1000-8 1000 2131861 ns/op
+# BenchmarkWideSection/10000-8 10 103575793 ns/op
+
+.image state-of-go/img/mutex_noprofile.png _ 1000
+
+* Benchmarking with Mutex Contention
+
+ $ go test -bench=. -mutexprofile=mutex.out
+
+# BenchmarkNarrowSection/10-8 300000 5464 ns/op
+# BenchmarkNarrowSection/100-8 10000 108583 ns/op
+# BenchmarkNarrowSection/1000-8 1000 1378379 ns/op
+# BenchmarkNarrowSection/10000-8 100 32828827 ns/op
+#
+# BenchmarkWideSection/10-8 200000 7155 ns/op
+# BenchmarkWideSection/100-8 10000 197001 ns/op
+# BenchmarkWideSection/1000-8 300 4339571 ns/op
+# BenchmarkWideSection/10000-8 5 303559562 ns/op
+
+.image state-of-go/img/mutex_profile.png _ 1000
+
+* Analyzing the Mutex Contention Profile
+
+ $ go tool pprof runtime.test mutex.out
+ Entering interactive mode (type "help" for commands)
+ (pprof) list
+
+ 0 5.38s (flat, cum) 43.97% of Total
+ . . 34: mu.Lock()
+ . . 35: m[f]++
+ . 5.38s 36: mu.Unlock()
+
+ 0 6.86s (flat, cum) 56.03% of Total
+ . . 53: mu.Lock()
+ . . 54: for _, f := range factors(i) {
+ . . 55: m[f]++
+ . . 56: }
+ . 6.86s 57: mu.Unlock()
+
+* So much contention ...
+
+* Contention by CPU
+
+.image state-of-go/img/mutex_procs.png _ 1000
+
+* Comparing it to sequential algorithm
+
+.image state-of-go/img/mutex_all.png _ 1000
+
+* Comparing it to sequential algorithm (zoom)
+
+.image state-of-go/img/mutex_all_zoom.png _ 1000
+
+* Performance
+
+* GC history in tweets
+
+* go 1.5
+
+.image state-of-go/img/gct1.png _ 900
+
+* go 1.6
+
+.image state-of-go/img/gct2.png _ 900
+
+* go 1.7
+
+.image state-of-go/img/gct4.png _ 900
+
+* go 1.8 (beta 1)
+
+.image state-of-go/img/gct5.png _ 700
+
+* go 1.8 (beta 1) CPU
+
+.image state-of-go/img/gctcpu.png _ 800
+
+* defer is faster
+
+ name old time/op new time/op delta
+ Defer-4 101ns ± 1% 66ns ± 0% -34.73% (p=0.000 n=20+20)
+ Defer10-4 93.2ns ± 1% 62.5ns ± 8% -33.02% (p=0.000 n=20+20)
+ DeferMany-4 148ns ± 3% 131ns ± 3% -11.42% (p=0.000 n=19+19)
+
+.image state-of-go/img/defer.png _ 500
+
+* cgo is also faster!
+
+ name old time/op new time/op delta
+ CgoNoop-8 93.5ns ± 0% 51.1ns ± 1% -45.34% (p=0.016 n=4+5)
+
+.image state-of-go/img/cgo.png _ 500
+
+Source: [[https://dave.cheney.net/2016/11/19/go-1-8-toolchain-improvements][dave.cheney.net]]
+
+* Changes to the standard library
+
+* Sorting
+
+Exercise:
+
+Given a slice of `Person`
+
+ var p []Person
+
+Print the slice sorted by name, age, and SSN.
+
+.code state-of-go/stdlib/sort/sort_test.go /sort.Sort/,/bySSN/
+
+Easy, right?
+
+* Sorting
+
+Well, you forgot about this part.
+
+.code state-of-go/stdlib/sort/sort_test.go /byName/,/bySSN\) Swap/
+
+* sort.Slice
+
+Since Go 1.8 you can simply write this:
+
+.code state-of-go/stdlib/sort/sort_test.go /sort\.Slice/,/SSN/
+
+Also new `SliceStable` and `SliceIsSorted`.
+
+* Benchmark
+
+ N=1 go test -bench=.
+ BenchmarkSortSort-8 10000000 145 ns/op
+ BenchmarkSortSlice-8 10000000 190 ns/op
+ N=10 go test -bench=.
+ BenchmarkSortSort-8 2000000 918 ns/op
+ BenchmarkSortSlice-8 1000000 1776 ns/op
+ N=100 go test -bench=.
+ BenchmarkSortSort-8 100000 16588 ns/op
+ BenchmarkSortSlice-8 50000 39035 ns/op
+ N=1000 go test -bench=.
+ BenchmarkSortSort-8 5000 320951 ns/op
+ BenchmarkSortSlice-8 3000 446677 ns/op
+ N=10000 go test -bench=.
+ BenchmarkSortSort-8 500 3644480 ns/op
+ BenchmarkSortSlice-8 300 4962263 ns/op
+ N=100000 go test -bench=.
+ BenchmarkSortSort-8 30 43573572 ns/op
+ BenchmarkSortSlice-8 20 60861706 ns/op
+
+.caption Benchmark ran on my MacBook Pro (8 cores), simply indicative.
+
+* Benchmark
+
+.image state-of-go/img/bench.png _ 800
+
+* Benchmark (log/log)
+
+.image state-of-go/img/bench_log.png _ 800
+
+
+* Plugins
+
+Define a plugin:
+
+.code state-of-go/stdlib/plugin/plugin.go
+
+Then build it:
+
+ go build -buildmode=plugin
+
+* Plugins
+
+.code state-of-go/stdlib/plugin/main.go /plugin.Open/,/Hello/
+
+* Plugins demo
+
+Demo video: [[https://twitter.com/francesc/status/827851085943566336][twitter.com/francesc]]
+
+Source code: [[https://github.com/campoy/golang-plugins][github.com/campoy/golang-plugins]]
+
+* HTTP shutdown
+
+Added `Shutdown` method to `http.Server`.
+
+Example:
+
+Call `Shutdown` when a signal is received:
+
+.code state-of-go/stdlib/shutdown.go /subscribe/,/}\(\)/
+
+* HTTP shutdown
+
+Check why the server stopped.
+
+.code state-of-go/stdlib/shutdown.go /HandleFunc/,/gracefully/
+
+
+* HTTP/2
+
+`http.Response` now satisfies the `http.Pusher` interface.
+
+ type Pusher interface {
+ Push(target string, opts *PushOptions) error
+ }
+
+A simple example:
+
+.code state-of-go/stdlib/http2/http2.go /func rootHandler/,/^}/
+
+* HTTP/2
+
+.play state-of-go/stdlib/http2/http2.go /func main/,/^}/
+
+HTTP: [[http://localhost:8080]]
+HTTP/2: [[https://localhost:8081]]
+
+* HTTP/2
+
+HTTP
+
+.image state-of-go/img/http.png _ 800
+
+HTTP/2
+
+.image state-of-go/img/http2.png _ 800
+
+* More context support
+
+Since Go 1.7:
+
+- net
+- net/http
+- os/exec
+
+Since Go 1.8:
+
+- http.Server.Shutdown
+- database/sql
+- net.Resolver
+
+* A couple more changes too
+
+.image state-of-go/img/more.png _ 1000
+.caption [[https://beta.golang.org/doc/go1.8][Go 1.8 release notes]]
+
+* The community
+
+* Women Who Go
+
+.image state-of-go/img/wwg.png _ 800
+.caption 16 chapters already! [[http://www.womenwhogo.org]]
+
+* Go meetups
+
+.image state-of-go/img/meetups.png _ 900
+.caption Gophers all around the world! [[http://go-meetups.appspot.com]]
+
+* Conferences:
+
+- [[https://fosdem.org/2017/][FOSDEM]], right here right now!
+- [[http://www.gophercon.in/][GopherCon India]], Feb 25-25th
+- [[https://gophercon.com/][Gophercon Denver]], Jul 12-15th
+- [[http://golanguk.com/][Golang UK]], August 16th-18th
+- [[http://2017.dotgo.eu/][dotGo]], Nov 6th
+
+* Go 1.8 release party, February 16th
+
+Go 1.8 ships soon!
+
+Go meetups are organising to hold a [[https://github.com/golang/go/wiki/Go-1.8-release-party][release party]] on the 16th of February.
+
+.image state-of-go/img/party-gopher.png _ 300
+.caption Join the party!!!
diff --git a/2017/state-of-go/img/bench.png b/2017/state-of-go/img/bench.png
new file mode 100644
index 0000000..76d3112
--- /dev/null
+++ b/2017/state-of-go/img/bench.png
Binary files differ
diff --git a/2017/state-of-go/img/bench_log.png b/2017/state-of-go/img/bench_log.png
new file mode 100644
index 0000000..b1e2d9c
--- /dev/null
+++ b/2017/state-of-go/img/bench_log.png
Binary files differ
diff --git a/2017/state-of-go/img/benchmark.png b/2017/state-of-go/img/benchmark.png
new file mode 100644
index 0000000..18f7163
--- /dev/null
+++ b/2017/state-of-go/img/benchmark.png
Binary files differ
diff --git a/2017/state-of-go/img/cgo.png b/2017/state-of-go/img/cgo.png
new file mode 100644
index 0000000..b05fc8d
--- /dev/null
+++ b/2017/state-of-go/img/cgo.png
Binary files differ
diff --git a/2017/state-of-go/img/defer.png b/2017/state-of-go/img/defer.png
new file mode 100644
index 0000000..cf96e09
--- /dev/null
+++ b/2017/state-of-go/img/defer.png
Binary files differ
diff --git a/2017/state-of-go/img/flying.png b/2017/state-of-go/img/flying.png
new file mode 100644
index 0000000..7157563
--- /dev/null
+++ b/2017/state-of-go/img/flying.png
Binary files differ
diff --git a/2017/state-of-go/img/gct1.png b/2017/state-of-go/img/gct1.png
new file mode 100644
index 0000000..22dbb67
--- /dev/null
+++ b/2017/state-of-go/img/gct1.png
Binary files differ
diff --git a/2017/state-of-go/img/gct2.png b/2017/state-of-go/img/gct2.png
new file mode 100644
index 0000000..a3f8a29
--- /dev/null
+++ b/2017/state-of-go/img/gct2.png
Binary files differ
diff --git a/2017/state-of-go/img/gct3.png b/2017/state-of-go/img/gct3.png
new file mode 100644
index 0000000..e1364f9
--- /dev/null
+++ b/2017/state-of-go/img/gct3.png
Binary files differ
diff --git a/2017/state-of-go/img/gct4.png b/2017/state-of-go/img/gct4.png
new file mode 100644
index 0000000..d8f0668
--- /dev/null
+++ b/2017/state-of-go/img/gct4.png
Binary files differ
diff --git a/2017/state-of-go/img/gct5.png b/2017/state-of-go/img/gct5.png
new file mode 100644
index 0000000..f34d6ea
--- /dev/null
+++ b/2017/state-of-go/img/gct5.png
Binary files differ
diff --git a/2017/state-of-go/img/gctcpu.png b/2017/state-of-go/img/gctcpu.png
new file mode 100644
index 0000000..9d57649
--- /dev/null
+++ b/2017/state-of-go/img/gctcpu.png
Binary files differ
diff --git a/2017/state-of-go/img/http.png b/2017/state-of-go/img/http.png
new file mode 100644
index 0000000..e89d9bd
--- /dev/null
+++ b/2017/state-of-go/img/http.png
Binary files differ
diff --git a/2017/state-of-go/img/http2.png b/2017/state-of-go/img/http2.png
new file mode 100644
index 0000000..552eb91
--- /dev/null
+++ b/2017/state-of-go/img/http2.png
Binary files differ
diff --git a/2017/state-of-go/img/meetups.png b/2017/state-of-go/img/meetups.png
new file mode 100644
index 0000000..85a508c
--- /dev/null
+++ b/2017/state-of-go/img/meetups.png
Binary files differ
diff --git a/2017/state-of-go/img/more.png b/2017/state-of-go/img/more.png
new file mode 100644
index 0000000..3160004
--- /dev/null
+++ b/2017/state-of-go/img/more.png
Binary files differ
diff --git a/2017/state-of-go/img/mutex_all.png b/2017/state-of-go/img/mutex_all.png
new file mode 100644
index 0000000..8429e77
--- /dev/null
+++ b/2017/state-of-go/img/mutex_all.png
Binary files differ
diff --git a/2017/state-of-go/img/mutex_all_zoom.png b/2017/state-of-go/img/mutex_all_zoom.png
new file mode 100644
index 0000000..7a1246c
--- /dev/null
+++ b/2017/state-of-go/img/mutex_all_zoom.png
Binary files differ
diff --git a/2017/state-of-go/img/mutex_noprofile.png b/2017/state-of-go/img/mutex_noprofile.png
new file mode 100644
index 0000000..42a579e
--- /dev/null
+++ b/2017/state-of-go/img/mutex_noprofile.png
Binary files differ
diff --git a/2017/state-of-go/img/mutex_procs.png b/2017/state-of-go/img/mutex_procs.png
new file mode 100644
index 0000000..340b9c0
--- /dev/null
+++ b/2017/state-of-go/img/mutex_procs.png
Binary files differ
diff --git a/2017/state-of-go/img/mutex_profile.png b/2017/state-of-go/img/mutex_profile.png
new file mode 100644
index 0000000..ff7daad
--- /dev/null
+++ b/2017/state-of-go/img/mutex_profile.png
Binary files differ
diff --git a/2017/state-of-go/img/party-gopher.png b/2017/state-of-go/img/party-gopher.png
new file mode 100644
index 0000000..d18690f
--- /dev/null
+++ b/2017/state-of-go/img/party-gopher.png
Binary files differ
diff --git a/2017/state-of-go/img/wwg.png b/2017/state-of-go/img/wwg.png
new file mode 100644
index 0000000..a86fbd2
--- /dev/null
+++ b/2017/state-of-go/img/wwg.png
Binary files differ
diff --git a/2017/state-of-go/runtime/mapcrash.go b/2017/state-of-go/runtime/mapcrash.go
new file mode 100644
index 0000000..60a07bb
--- /dev/null
+++ b/2017/state-of-go/runtime/mapcrash.go
@@ -0,0 +1,26 @@
+/// +build OMIT
+
+package main
+
+import (
+ "fmt"
+ "sync"
+)
+
+func main() {
+ const workers = 100 // what if we have 1, 2, 25?
+
+ var wg sync.WaitGroup
+ wg.Add(workers)
+ m := map[int]int{}
+ for i := 1; i <= workers; i++ {
+ go func(i int) {
+ for j := 0; j < i; j++ {
+ m[i]++ // HL
+ }
+ wg.Done()
+ }(i)
+ }
+ wg.Wait()
+ fmt.Println(m)
+}
diff --git a/2017/state-of-go/runtime/mutex/main.go b/2017/state-of-go/runtime/mutex/main.go
new file mode 100644
index 0000000..3ff277e
--- /dev/null
+++ b/2017/state-of-go/runtime/mutex/main.go
@@ -0,0 +1,89 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "sort"
+ "sync"
+)
+
+func main() {
+ n := flag.Int("n", 10, "maximum number to consider")
+ flag.Parse()
+
+ type pair struct{ n, c int }
+ var pairs []pair
+ for n, c := range countFactorsWideSection(*n) {
+ pairs = append(pairs, pair{n, c})
+ }
+ sort.Slice(pairs, func(i, j int) bool { return pairs[i].n < pairs[j].n })
+ for _, p := range pairs {
+ fmt.Printf("%3d: %3d\n", p.n, p.c)
+ }
+}
+
+func countFactorsNarrowSection(n int) map[int]int {
+ m := map[int]int{}
+ var mu sync.Mutex
+ var wg sync.WaitGroup
+
+ wg.Add(n - 1)
+ for i := 2; i <= n; i++ {
+ go func(i int) {
+ // NARROW OMIT
+ for _, f := range factors(i) {
+ mu.Lock() // HL
+ m[f]++
+ mu.Unlock() // HL
+ }
+ wg.Done()
+ }(i)
+ }
+ wg.Wait()
+ return m
+}
+
+func countFactorsWideSection(n int) map[int]int {
+ m := map[int]int{}
+ var mu sync.Mutex
+ var wg sync.WaitGroup
+
+ wg.Add(n - 1)
+ for i := 2; i <= n; i++ {
+ go func(i int) {
+ // WIDE OMIT
+ mu.Lock() // HL
+ for _, f := range factors(i) {
+ m[f]++
+ }
+ mu.Unlock() // HL
+ wg.Done()
+ }(i)
+ }
+ wg.Wait()
+ return m
+}
+
+func countFactorsSeq(n int) map[int]int {
+ m := map[int]int{}
+ for i := 2; i <= n; i++ {
+ for _, f := range factors(i) { // HL
+ m[f]++ // HL
+ } // HL
+ }
+ return m
+}
+
+func factors(v int) []int {
+ var fs []int
+ for v > 1 {
+ for f := 2; f <= v; f++ {
+ if v%f == 0 {
+ v = v / f
+ fs = append(fs, f)
+ break
+ }
+ }
+ }
+ return fs
+}
diff --git a/2017/state-of-go/runtime/mutex/main_test.go b/2017/state-of-go/runtime/mutex/main_test.go
new file mode 100644
index 0000000..be80382
--- /dev/null
+++ b/2017/state-of-go/runtime/mutex/main_test.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+ "fmt"
+ "testing"
+)
+
+func benchFunc(b *testing.B, f func(int) map[int]int) {
+ for n := 10; n <= 10000; n *= 10 {
+ b.Run(fmt.Sprint(n), func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ f(n)
+ }
+ })
+ }
+}
+
+func BenchmarkNarrowSection(b *testing.B) { benchFunc(b, countFactorsNarrowSection) }
+func BenchmarkWideSection(b *testing.B) { benchFunc(b, countFactorsWideSection) }
+func BenchmarkSq(b *testing.B) { benchFunc(b, countFactorsSeq) }
diff --git a/2017/state-of-go/runtime/mutex/mutex.out b/2017/state-of-go/runtime/mutex/mutex.out
new file mode 100644
index 0000000..59ea5b6
--- /dev/null
+++ b/2017/state-of-go/runtime/mutex/mutex.out
@@ -0,0 +1,5 @@
+--- mutex:
+cycles/second=2793570419
+sampling period=1
+19155477440 1345723 @ 0x10575f1 0x10f0266 0x1051c61
+15032825888 1091734 @ 0x10575f1 0x10f0106 0x1051c61
diff --git a/2017/state-of-go/runtime/mutex/mutex.test b/2017/state-of-go/runtime/mutex/mutex.test
new file mode 100755
index 0000000..12ef088
--- /dev/null
+++ b/2017/state-of-go/runtime/mutex/mutex.test
Binary files differ
diff --git a/2017/state-of-go/stdlib/http2/cert.pem b/2017/state-of-go/stdlib/http2/cert.pem
new file mode 100644
index 0000000..6612f86
--- /dev/null
+++ b/2017/state-of-go/stdlib/http2/cert.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIC/jCCAeagAwIBAgIQJmT9thxoUtA2lXTupgK7cDANBgkqhkiG9w0BAQsFADAS
+MRAwDgYDVQQKEwdBY21lIENvMB4XDTE3MDEyOTIwNTUxNVoXDTE4MDEyOTIwNTUx
+NVowEjEQMA4GA1UEChMHQWNtZSBDbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAL4TpHOAUq54uyrGj06xE7TZ0+SPVXWiydYP4hg1QKkhFcwc2NHwnzIf
+wgFTBGXz7TrrWpLHNJLvWKjXeFDQo35BKfWd4u2TKMU43HUdPSgFT8skhbP3FYbJ
+WIYoD2J2BaMxylMYfGGm2azqnuTPc0/Qn98RLDFe9TAykDuel3YWvdlQJGYo+cth
+bUURzTzvQzmnMpQ+CxpU+TdBz4Ngh+e29CEfZGOWXtd/7ydWyK3BznzgPLBTuU9N
+3f0mC40sDayTTBaUiI+GkSEeqK0Ft/gwozM1KOK8l5lfqtOYzqhLjAAzcD5Hf8ZK
+GsnC5ojJkuypLY/uAq/BX+2oL4wZi+UCAwEAAaNQME4wDgYDVR0PAQH/BAQDAgWg
+MBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwGQYDVR0RBBIwEIIO
+bG9jYWxob3N0OjgwODAwDQYJKoZIhvcNAQELBQADggEBACqdIJJFcow4WJ0YW6l2
+bjYj0fAf7GZdLP3tRYzxcj1ORoJf9FIN2jwlraEgtXN2hhEK15nVgrxbrWzDMkrx
+e9VhGOSWnixo3rnN2i2vUEaKqZubawhzcU2/5ZnP6Q1JH00WYqavNYhfQIOdNI6e
+s6xqz+MUhYSw3ZhjgFGMAeed0fRIksWRlbioTAOk1TxoChTaa+N+tTf9Niwr1Eaz
+Cy6ygwmlJYhi/iutknG2Fp+MjDPX2hmemgoJYbn8i1C0DQuNlKxeNwY3zfEBxazu
+nLFbDwbyCIO+2q1+eervE1TF5Vw6ODNqRWKgsl9VnGmL369p8H1plU//SnQh4TIW
+nKc=
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/2017/state-of-go/stdlib/http2/http2.go b/2017/state-of-go/stdlib/http2/http2.go
new file mode 100644
index 0000000..e370961
--- /dev/null
+++ b/2017/state-of-go/stdlib/http2/http2.go
@@ -0,0 +1,67 @@
+package main
+
+import (
+ "fmt"
+ "go/build"
+ "log"
+ "net/http"
+ "path/filepath"
+)
+
+var cert, key string
+
+func init() {
+ pkg, err := build.Import("golang.org/x/talks/2017/state-of-go/http2", ".", build.FindOnly)
+ if err != nil {
+ log.Fatal(err)
+ }
+ cert = filepath.Join(pkg.Dir, "cert.pem")
+ key = filepath.Join(pkg.Dir, "key.pem")
+}
+
+func main() {
+ http.HandleFunc("/", rootHandler)
+ http.HandleFunc("/style.css", cssHandler)
+
+ go func() {
+ log.Fatal(http.ListenAndServeTLS("127.0.0.1:8081", cert, key, nil))
+ }()
+ log.Fatal(http.ListenAndServe("127.0.0.1:8080", nil))
+}
+
+func rootHandler(w http.ResponseWriter, r *http.Request) {
+ if p, ok := w.(http.Pusher); ok { // HL
+ err := p.Push("/style.css", nil) // HL
+ if err != nil {
+ log.Printf("could not push: %v", err)
+ }
+ }
+
+ fmt.Fprintln(w, html)
+}
+
+func cssHandler(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintln(w, css)
+}
+
+const (
+ html = `
+<html>
+<head>
+ <link rel="stylesheet" href="/style.css">
+ <title>HTTP2 push test</title>
+</head>
+<body>
+ <h1>Hello</h1>
+</body>
+</html>
+`
+ css = `
+h1 {
+ color: red;
+ text-align: center;
+ text-shadow: green 0 0 40px;
+ font-size: 10em;
+}
+`
+)
diff --git a/2017/state-of-go/stdlib/http2/key.pem b/2017/state-of-go/stdlib/http2/key.pem
new file mode 100644
index 0000000..cd458b0
--- /dev/null
+++ b/2017/state-of-go/stdlib/http2/key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAvhOkc4BSrni7KsaPTrETtNnT5I9VdaLJ1g/iGDVAqSEVzBzY
+0fCfMh/CAVMEZfPtOutaksc0ku9YqNd4UNCjfkEp9Z3i7ZMoxTjcdR09KAVPyySF
+s/cVhslYhigPYnYFozHKUxh8YabZrOqe5M9zT9Cf3xEsMV71MDKQO56Xdha92VAk
+Zij5y2FtRRHNPO9DOacylD4LGlT5N0HPg2CH57b0IR9kY5Ze13/vJ1bIrcHOfOA8
+sFO5T03d/SYLjSwNrJNMFpSIj4aRIR6orQW3+DCjMzUo4ryXmV+q05jOqEuMADNw
+Pkd/xkoaycLmiMmS7Kktj+4Cr8Ff7agvjBmL5QIDAQABAoIBAFUAe76bWF5l523N
+tjC+x81MzJGd993Pmut71uR0jCIWhaTuEZhxPwAva5ckBQeC+kgrECoro7tCBigb
+k9awNy0y/wy0OtN7x/PK5ewJ01ueZHy4LIK6sInCaTA1oguqNAMzNQPMI3OYJihK
+FBzHGQ5MgfJDv7ukd4nCUvYWii1oYNoNsc/A2uYPonLRJfAnPLAfZ+ikiPdydLum
+4/nLxBKD5Yke/Y8lpxh1RzZz28G2YX9WKTwAZuBo9AJ+4U7bkjgSof5nUOlwvbcg
+Z9d/DMdWkI7yQxhaQzXaFWNmvpt6NvqHUSPYnqQnaCDPCRbUR8u3YU8vwCRN60ss
+dzac+4ECgYEA2+jYj3pllRMaifnAEVg4MS3mpQ9o+XCzQb4H7ecFztXh16Uom0e/
+gnI1cqutMdhcyAoy++RxTXLCca9xd5e8tC3N2kZG9+3vUV0kn43LbVY4sCK150wM
+UHy7TMdoAqg36W3AhTunIZ1sgDM/qc5LcesXeHVDUQF2NmteZnga9m0CgYEA3UVq
+y42mBXMuCqY8GZbTQlZqowqBjNLddhVxXjuuAHcxCTlLmD63L7UWx24dOAeVbEfq
+Aev6tsOiaNB+JPEGYfQf9ESRxbt3ZFArYP6+be94NmETzNVtekwCJqfp7Cjyzj1a
+C00r5L0qOSP0P8lvSrBOwT2Yxq3JVNL3EDj1YFkCgYAG7dpNAw1KWjS+3ji4EzCK
+FCktUEP9gBiV3LgBPgNH1iNsmQ6jfepB4PlgKJqndGrP/spGd5c+WnxX+rA3lXdj
+sgHHe+lmjH+675Vk1aHwSwQ0QJO8uv+0VYnNTIcxdj10xHmJeSy1+XDexT6fShnE
+eCTgLcm2NraT1mQ+FFC9LQKBgC3rtyMxbXAaHEcHgteIrqVIy+60QniYVm+oOZPl
+7NGZ6upQIrkg4uGawnR3DMdRA5iqQA1QDQMbDLyV8Gf4QWvYvzzxchNIOZnu7WG+
+3IRyO0+FzBcpgAPufE/Lb0eco+9bWjGYPXDGNVoQdSM7ycYFWwLNpsQs0uiws6eB
+OqNZAoGBALM48r7mA/3KuFH6CcRcsCGfcCoXkzjGogsxIfN2yKmNUu33koYkzUxc
+ihgXBGwQ5Sqdrqz9BYh1CArXQvVkb+Q0wEAVS1ikbMozTQQelI8FRiToVJF37zoS
+UgA+CE3BSuHa+zMBue+guh/+ssMlKPnpzTgWjkk50GXUAMy/NVf5
+-----END RSA PRIVATE KEY-----
diff --git a/2017/state-of-go/stdlib/json_old.go b/2017/state-of-go/stdlib/json_old.go
new file mode 100644
index 0000000..acb7041
--- /dev/null
+++ b/2017/state-of-go/stdlib/json_old.go
@@ -0,0 +1,46 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "log"
+)
+
+func main() {
+ in := []byte(`
+ {
+ "full_name": "Gopher",
+ "age": 7,
+ "social_security": 1234
+ }`)
+
+ var p Person
+ if err := json.Unmarshal(in, &p); err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("%+v\n", p)
+}
+
+type Person struct {
+ Name string
+ AgeYears int
+ SSN int
+}
+
+func (p *Person) UnmarshalJSON(data []byte) error {
+ var aux struct {
+ Name string `json:"full_name"`
+ AgeYears int `json:"age"`
+ SSN int `json:"social_security"`
+ }
+ if err := json.Unmarshal(data, &aux); err != nil {
+ return err
+ }
+ *p = Person{
+ Name: aux.Name,
+ AgeYears: aux.AgeYears,
+ SSN: aux.SSN,
+ }
+ *p = Person(aux)
+ return nil
+}
diff --git a/2017/state-of-go/stdlib/plugin/main.go b/2017/state-of-go/stdlib/plugin/main.go
new file mode 100644
index 0000000..5d5482f
--- /dev/null
+++ b/2017/state-of-go/stdlib/plugin/main.go
@@ -0,0 +1,23 @@
+package main
+
+import "plugin"
+
+func main() {
+ p, err := plugin.Open("plugin_name.so")
+ if err != nil {
+ panic(err)
+ }
+
+ v, err := p.Lookup("V")
+ if err != nil {
+ panic(err)
+ }
+
+ f, err := p.Lookup("F")
+ if err != nil {
+ panic(err)
+ }
+
+ *v.(*int) = 7
+ f.(func())() // prints "Hello, number 7"
+}
diff --git a/2017/state-of-go/stdlib/plugin/plugin.go b/2017/state-of-go/stdlib/plugin/plugin.go
new file mode 100644
index 0000000..99bb60d
--- /dev/null
+++ b/2017/state-of-go/stdlib/plugin/plugin.go
@@ -0,0 +1,10 @@
+package main
+
+// No C code needed.
+import "C"
+
+import "fmt"
+
+var V int
+
+func F() { fmt.Printf("Hello, number %d\n", V) }
diff --git a/2017/state-of-go/stdlib/shutdown.go b/2017/state-of-go/stdlib/shutdown.go
new file mode 100644
index 0000000..4dfb915
--- /dev/null
+++ b/2017/state-of-go/stdlib/shutdown.go
@@ -0,0 +1,36 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "os/signal"
+)
+
+func main() {
+ // subscribe to SIGINT signals
+ quit := make(chan os.Signal) // HL
+ signal.Notify(quit, os.Interrupt)
+
+ srv := &http.Server{Addr: ":8080", Handler: http.DefaultServeMux}
+ go func() { // HL
+ <-quit // HL
+ log.Println("Shutting down server...")
+ if err := srv.Shutdown(context.Background()); err != nil { // HL
+ log.Fatalf("could not shutdown: %v", err)
+ }
+ }()
+
+ http.HandleFunc("/", handler)
+ err := srv.ListenAndServe()
+ if err != http.ErrServerClosed { // HL
+ log.Fatalf("listen: %s\n", err)
+ }
+ log.Println("Server gracefully stopped")
+}
+
+func handler(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintln(w, "hello")
+}
diff --git a/2017/state-of-go/stdlib/sort/sort.go b/2017/state-of-go/stdlib/sort/sort.go
new file mode 100644
index 0000000..d3d75c0
--- /dev/null
+++ b/2017/state-of-go/stdlib/sort/sort.go
@@ -0,0 +1,50 @@
+package main
+
+/*
+
+import (
+ "fmt"
+ "sort"
+)
+
+type Person struct {
+ Name string
+ AgeYears int
+ SSN int
+}
+
+type byName []Person
+
+func (b byName) Len() int { return len(b) }
+func (b byName) Less(i, j int) bool { return b[i].Name < b[j].Name }
+func (b byName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+
+type byAge []Person
+
+func (b byAge) Len() int { return len(b) }
+func (b byAge) Less(i, j int) bool { return b[i].AgeYears < b[j].AgeYears }
+func (b byAge) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+
+type bySSN []Person
+
+func (b bySSN) Len() int { return len(b) }
+func (b bySSN) Less(i, j int) bool { return b[i].SSN < b[j].SSN }
+func (b bySSN) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+
+func main() {
+ p := []Person{
+ {"Alice", 20, 1234},
+ {"Bob", 10, 2345},
+ {"Carla", 15, 3456},
+ }
+
+ sort.Sort(byName(p))
+ fmt.Printf("sorted by name: %v\n", p)
+
+ sort.Sort(byAge(p))
+ fmt.Printf("sorted by age: %v\n", p)
+
+ sort.Sort(bySSN(p))
+ fmt.Printf("sorted by SSN: %v\n", p)
+}
+*/
diff --git a/2017/state-of-go/stdlib/sort/sort_new.go b/2017/state-of-go/stdlib/sort/sort_new.go
new file mode 100644
index 0000000..2b9e76c
--- /dev/null
+++ b/2017/state-of-go/stdlib/sort/sort_new.go
@@ -0,0 +1,31 @@
+package main
+
+/*
+import (
+ "fmt"
+ "sort"
+)
+
+type Person struct {
+ Name string
+ AgeYears int
+ SSN int
+}
+
+func main() {
+ p := []Person{
+ {"Alice", 20, 1234},
+ {"Bob", 10, 2345},
+ {"Carla", 15, 3456},
+ }
+
+ sort.Slice(p, func(i, j int) bool { return p[i].Name < p[j].Name })
+ fmt.Printf("sorted by name: %v\n", p)
+
+ sort.Slice(p, func(i, j int) bool { return p[i].AgeYears < p[j].AgeYears })
+ fmt.Printf("sorted by age: %v\n", p)
+
+ sort.Slice(p, func(i, j int) bool { return p[i].SSN < p[j].SSN })
+ fmt.Printf("sorted by SSN: %v\n", p)
+}
+*/
diff --git a/2017/state-of-go/stdlib/sort/sort_test.go b/2017/state-of-go/stdlib/sort/sort_test.go
new file mode 100644
index 0000000..0c50905
--- /dev/null
+++ b/2017/state-of-go/stdlib/sort/sort_test.go
@@ -0,0 +1,66 @@
+package main
+
+import (
+ "fmt"
+ "math/rand"
+ "os"
+ "sort"
+ "strconv"
+ "testing"
+)
+
+type Person struct {
+ Name string
+ AgeYears int
+ SSN int
+}
+
+type byName []Person
+
+func (b byName) Len() int { return len(b) }
+func (b byName) Less(i, j int) bool { return b[i].Name < b[j].Name }
+func (b byName) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+
+type byAge []Person
+
+func (b byAge) Len() int { return len(b) }
+func (b byAge) Less(i, j int) bool { return b[i].AgeYears < b[j].AgeYears }
+func (b byAge) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+
+type bySSN []Person
+
+func (b bySSN) Len() int { return len(b) }
+func (b bySSN) Less(i, j int) bool { return b[i].SSN < b[j].SSN }
+func (b bySSN) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+
+func BenchmarkSortSort(b *testing.B) {
+ p := manyPeople()
+ for i := 0; i < b.N; i++ {
+ sort.Sort(byName(p))
+ sort.Sort(byAge(p))
+ sort.Sort(bySSN(p))
+ }
+}
+
+func BenchmarkSortSlice(b *testing.B) {
+ p := manyPeople()
+ for i := 0; i < b.N; i++ {
+ sort.Slice(p, func(i, j int) bool { return p[i].Name < p[j].Name })
+ sort.Slice(p, func(i, j int) bool { return p[i].AgeYears < p[j].AgeYears })
+ sort.Slice(p, func(i, j int) bool { return p[i].SSN < p[j].SSN })
+ }
+}
+
+func manyPeople() []Person {
+ n, err := strconv.Atoi(os.Getenv("N"))
+ if err != nil {
+ panic(err)
+ }
+ p := make([]Person, n)
+ for i := range p {
+ p[i].AgeYears = rand.Intn(100)
+ p[i].SSN = rand.Intn(10000000000)
+ p[i].Name = fmt.Sprintf("Mr or Ms %d", p[i].AgeYears)
+ }
+ return p
+}
diff --git a/2017/state-of-go/tools/gobug.sh b/2017/state-of-go/tools/gobug.sh
new file mode 100644
index 0000000..5100fea
--- /dev/null
+++ b/2017/state-of-go/tools/gobug.sh
@@ -0,0 +1,2 @@
+#! /bin/bash
+go bug
\ No newline at end of file
diff --git a/2017/state-of-go/tools/gofix.go b/2017/state-of-go/tools/gofix.go
new file mode 100644
index 0000000..9f62814
--- /dev/null
+++ b/2017/state-of-go/tools/gofix.go
@@ -0,0 +1,12 @@
+package main
+
+import "golang.org/x/net/context" // HL
+
+func main() {
+ ctx := context.Background()
+ doSomething(ctx)
+}
+
+func doSomething(ctx context.Context) {
+ // doing something
+}
diff --git a/2017/state-of-go/tools/gofix.sh b/2017/state-of-go/tools/gofix.sh
new file mode 100644
index 0000000..f0096e6
--- /dev/null
+++ b/2017/state-of-go/tools/gofix.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+go tool fix -diff -force=context state-of-go/tools/gofix.go
\ No newline at end of file
diff --git a/2017/state-of-go/tools/govet.go b/2017/state-of-go/tools/govet.go
new file mode 100644
index 0000000..520e8a7
--- /dev/null
+++ b/2017/state-of-go/tools/govet.go
@@ -0,0 +1,17 @@
+package main
+
+import (
+ "io"
+ "log"
+ "net/http"
+ "os"
+)
+
+func main() {
+ res, err := http.Get("https://golang.org")
+ defer res.Body.Close()
+ if err != nil {
+ log.Fatal(err)
+ }
+ io.Copy(os.Stdout, res.Body)
+}
diff --git a/2017/state-of-go/tools/govet.sh b/2017/state-of-go/tools/govet.sh
new file mode 100644
index 0000000..fd3f847
--- /dev/null
+++ b/2017/state-of-go/tools/govet.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+go vet state-of-go/tools/govet.go
\ No newline at end of file