diff --git a/bench1/fast-timer.go b/bench1/fast-timer.go new file mode 100644 index 0000000..875d1f3 --- /dev/null +++ b/bench1/fast-timer.go @@ -0,0 +1,33 @@ +package main + +import ( + "fmt" + "time" +) + +var start time.Time + +func init() { + start = time.Now() +} + +func main() { + fmt.Println("main() started", time.Since(start)) + chan1 := make(chan string, 2) + chan2 := make(chan string, 2) + + chan1 <- "Value 1" + chan1 <- "Value 2" + chan2 <- "Value 1" + chan2 <- "Value 2" + + select { + case res := <-chan1: + fmt.Println("Response from chan1", res, time.Since(start)) + case res := <-chan2: + fmt.Println("Response from chan2", res, time.Since(start)) + } + + fmt.Println("main() stopped", time.Since(start)) + for {} +} diff --git a/bench1/readWriteOps.go b/bench1/readWriteOps.go new file mode 100644 index 0000000..a8b7fad --- /dev/null +++ b/bench1/readWriteOps.go @@ -0,0 +1,115 @@ +// In the previous example we used explicit locking with +// [mutexes](mutexes) to synchronize access to shared state +// across multiple goroutines. Another option is to use the +// built-in synchronization features of goroutines and +// channels to achieve the same result. This channel-based +// approach aligns with Go's ideas of sharing memory by +// communicating and having each piece of data owned +// by exactly 1 goroutine. + +package main + +import ( + "fmt" + "math/rand" + "sync/atomic" + "time" +) + +// In this example our state will be owned by a single +// goroutine. This will guarantee that the data is never +// corrupted with concurrent access. In order to read or +// write that state, other goroutines will send messages +// to the owning goroutine and receive corresponding +// replies. These `readOp` and `writeOp` `struct`s +// encapsulate those requests and a way for the owning +// goroutine to respond. +type readOp struct { + key int + resp chan int +} +type writeOp struct { + key int + val int + resp chan bool +} + +func main() { + + // As before we'll count how many operations we perform. + var readOps uint64 + var writeOps uint64 + + // The `reads` and `writes` channels will be used by + // other goroutines to issue read and write requests, + // respectively. + reads := make(chan readOp) + writes := make(chan writeOp) + + // Here is the goroutine that owns the `state`, which + // is a map as in the previous example but now private + // to the stateful goroutine. This goroutine repeatedly + // selects on the `reads` and `writes` channels, + // responding to requests as they arrive. A response + // is executed by first performing the requested + // operation and then sending a value on the response + // channel `resp` to indicate success (and the desired + // value in the case of `reads`). + go func() { + var state = make(map[int]int) + for { + select { + case read := <-reads: + read.resp <- state[read.key] + case write := <-writes: + state[write.key] = write.val + write.resp <- true + } + } + }() + + // This starts 100 goroutines to issue reads to the + // state-owning goroutine via the `reads` channel. + // Each read requires constructing a `readOp`, sending + // it over the `reads` channel, and the receiving the + // result over the provided `resp` channel. + for r := 0; r < 100; r++ { + go func() { + for { + read := readOp{ + key: rand.Intn(5), + resp: make(chan int)} + reads <- read + <-read.resp + atomic.AddUint64(&readOps, 1) + time.Sleep(time.Millisecond) + } + }() + } + + // We start 10 writes as well, using a similar + // approach. + for w := 0; w < 10; w++ { + go func() { + for { + write := writeOp{ + key: rand.Intn(5), + val: rand.Intn(100), + resp: make(chan bool)} + writes <- write + <-write.resp + atomic.AddUint64(&writeOps, 1) + time.Sleep(time.Millisecond) + } + }() + } + + // Let the goroutines work for a second. + time.Sleep(time.Second) + + // Finally, capture and report the op counts. + readOpsFinal := atomic.LoadUint64(&readOps) + fmt.Println("readOps:", readOpsFinal) + writeOpsFinal := atomic.LoadUint64(&writeOps) + fmt.Println("writeOps:", writeOpsFinal) +} diff --git a/bench1/stuff.go b/bench1/stuff.go new file mode 100644 index 0000000..e69de29 diff --git a/build/main.go b/build/main.go index 126d1ca..a866fed 100644 --- a/build/main.go +++ b/build/main.go @@ -1,5 +1,7 @@ package main +// This should build and upload the binary to mirrors + import "log" // import "fmt" import "os" @@ -20,7 +22,22 @@ var builddir string var homedir string func main() { - os.Chdir("~/go/src/wit/cloud-control-panel") + // os.Chdir("~/go/src/wit/cloud-control-panel") + + // set epoch, version, + // set build cloud-control-panel + + // get build time + // go build -ldflags + // " + // -X main.GITCOMMIT=${GITCOMMIT} + // -X main.GOVERSION='${GOVERSION}' + // -X main.BUILDTIME='${BUILDTIME}' + // -X main.VERSION=${VERSION} + // " + + // upload binary to mirrors.wit.com/cloud/control-panel + setupUser() @@ -36,39 +53,13 @@ func main() { shell.Run("pwd") for { - time.Sleep(time.Second * 5) build() os.Exit(0) + time.Sleep(time.Second * 5) } } - /* - // slow down the polling to every 2 seconds - shell.SetDelayInMsec(2000) - shell.Run("ping -c 6 localhost") - - // capture ping output into a file - fout, _ := os.Create("/tmp/example1.ping.stdout") - ferr, _ := os.Create("/tmp/example1.ping.stderr") - shell.SetStdout(fout) - shell.SetStderr(ferr) - - shell.Run("ping -c 5 localhost") - - // turn out process exit debugging - shell.SpewOn() - - fout, _ = os.Create("/tmp/example1.fail.stdout") - ferr, _ = os.Create("/tmp/example1.fail.stderr") - shell.SetStdout(fout) - shell.SetStderr(ferr) - - // TODO: this might not be working - // check error handling - shell.Run("ls /tmpthisisnothere") - */ - func build() { // shell.SetDelayInMsec(50) shell.Run("go get -v .") @@ -91,7 +82,6 @@ func ping() { shell.Run("ping -c 6 localhost") } - // func setupUser() string, string, string { func setupUser() { // look up the user information diff --git a/config.go b/config.go index af65b8d..c813c32 100644 --- a/config.go +++ b/config.go @@ -16,10 +16,12 @@ import "os/user" import "flag" import "fmt" import "runtime" +// import "runtime/debug" import "io/ioutil" import "strings" import "reflect" import "bytes" +// import "sys" import "github.com/golang/protobuf/jsonpb" import pb "git.wit.com/wit/witProtobuf" @@ -271,6 +273,33 @@ func parseConfig() { log.Println("config.Gitref =", config.Gitref) log.Println("config.Goversion =", config.Goversion) log.Println("config.Dirty =", config.Dirty) + + log.Println("runtime.Version =", runtime.Version()) + log.Println("runtime Number of CPUs =", runtime.NumCPU()) + log.Println("runtime Number of GoRoutines =", runtime.NumGoroutine()) + + log.Println("runtime.GOARCH =", runtime.GOARCH) + + stackSlice := make([]byte, 12512) + s := runtime.Stack(stackSlice, false) + fmt.Printf("\n%s", stackSlice[0:s]) + // blah := runtime.Stack() + spew.Dump(s) + + // bi, biok := debug.ReadBuildInfo() + // log.Println("debug.BuildInfo() ok =", biok) + // spew.Dump(bi.Path) + // spew.Dump(bi.Main) + // log.Println("debug.BuildInfo.Path =", bi.Path) + + errChan <- "hello" + errChan <- "hello" + errChan <- "hello" + errChan <- fmt.Errorf("mainMouseClick() got b = nil") + errChan <- "hello" + + // for {} + // os.Exit(0) } func chompBytesBuffer(buf *bytes.Buffer) string { diff --git a/example-pprof/main.go b/example-pprof/main.go new file mode 100644 index 0000000..6051db6 --- /dev/null +++ b/example-pprof/main.go @@ -0,0 +1,78 @@ +package main + +// run this and then hit: +// http://localhost:6060/debug/pprof/ +// +// Also run from the command line: +// go tool pprof 'localhost:6060/debug/pprof/wit_pprof_experiment_thing?debug=1' +// +// https://medium.com/@cep21/creating-custom-go-profiles-with-pprof-b737dfc58e11 + +import "fmt" +import "log" +import "net/http" +import _ "net/http/pprof" // the _ means only the init() is needed +import "os" +import "runtime/pprof" +import "sync/atomic" +import "time" + +var libProfile *pprof.Profile + +func init() { + profName := "wit_pprof_experiment_thing" // this ends up in the URL + libProfile = pprof.Lookup(profName) + if libProfile == nil { + libProfile = pprof.NewProfile(profName) + } +} + +type someResource struct { + *os.File +} + +var fileIndex = int64(0) + +func MustResource() *someResource { + f, err := os.Create(fmt.Sprintf("/tmp/%d.txt", atomic.AddInt64(&fileIndex, 1))) + if err != nil { + panic(err) + } + r := &someResource{f} + libProfile.Add(r, 1) + return r +} + +func (r *someResource) Close() error { + libProfile.Remove(r) + return r.File.Close() +} + +func trackAFunction() { + tracked := new(byte) + libProfile.Add(tracked, 1) + defer libProfile.Remove(tracked) + time.Sleep(time.Second) +} + +func usesAResource() { + res := MustResource() + defer res.Close() + for i := 0; i < 10; i++ { + time.Sleep(time.Second) + } +} + +func main() { + http.HandleFunc("/nonblock", func(rw http.ResponseWriter, req *http.Request) { + go usesAResource() + }) + http.HandleFunc("/functiontrack", func(rw http.ResponseWriter, req *http.Request) { + trackAFunction() + }) + http.HandleFunc("/block", func(rw http.ResponseWriter, req *http.Request) { + usesAResource() + }) + log.Println("Running!") + log.Println(http.ListenAndServe("localhost:6060", nil)) +} diff --git a/example-pprof/profile001.pdf b/example-pprof/profile001.pdf new file mode 100644 index 0000000..29b15f3 Binary files /dev/null and b/example-pprof/profile001.pdf differ diff --git a/main.go b/main.go index 1ef12d7..e29bf7e 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,9 @@ package main import "log" import "os" import "time" -// import "reflect" +import "reflect" +import "os/signal" +import "syscall" // this is the king of dns libraries import "github.com/miekg/dns" @@ -11,6 +13,7 @@ import "github.com/miekg/dns" import "git.wit.com/wit/gui" import pb "git.wit.com/wit/witProtobuf" import "git.wit.com/jcarr/dnssecsocket" +import "git.wit.com/wit/shell" import "github.com/gobuffalo/packr" import "github.com/davecgh/go-spew/spew" @@ -21,6 +24,8 @@ var BUILDTIME string // this is passed in as an ldflag var VERSION string // this is passed in as an ldflag var State string // used as a State machine +var sigChan chan os.Signal +var errChan chan interface{} type myButtonInfo struct { Account *pb.Account // associated with what account? @@ -57,6 +62,9 @@ type myButtonInfo struct { // i18n with 'po' file support // https://github.com/leonelquinteros/gotext +// a good example of using interface{} +// https://github.com/Jeffail/tunny + func onExit(err error) { log.Println("Sleep for 1 second") time.Sleep(1 * 1000 * 1000 * 1000) @@ -86,6 +94,8 @@ func lookupAAAA(hostname string) string { } func main() { + go handleErrors() + // This puts all the files in that directory in the binary // This directory includes the default config file if there is not already one packrBox = packr.NewBox("./resources") @@ -167,3 +177,39 @@ func r() { } } } + +func init() { + log.Println("init() WAS HERE") + log.Println("init() WAS HERE") + log.Println("init() WAS HERE") + + errChan = make(chan interface{}, 3) + shell.InitCallback(handleShell) // asks for all the shell errors to be sent here + + sigChan = make(chan os.Signal, 3) + signal.Notify(sigChan, syscall.SIGUSR1) +} + +// get's sent the return values and errors from git.wit.com/wit/shell/ +func handleShell(err interface{}, ret int) { + log.Println("shell.Run() END Returned ", ret) + errChan <- err +} + +func handleErrors() { + for val := range errChan { + log.Println("handleErrors() val =", val) + log.Println("handleErrors() reflect.TypeOf(val) =", reflect.TypeOf(val)) + log.Printf("handleErrors() val type T = %T\n", val) + } +} + +// trap signals +/* +go func() { + s := make(chan os.Signal, 1) + signal.Notify(s, syscall.SIGQUIT) + <-s + panic("give me the stack") +}() +*/ diff --git a/go.mod b/resources/go.mod similarity index 100% rename from go.mod rename to resources/go.mod diff --git a/go.sum b/resources/go.sum similarity index 100% rename from go.sum rename to resources/go.sum