Browse Source

Changed go ver to 1.11.5 in fasthttp-postgresql; added iris-prefork, iris-quicktemplate; fixed go-std; quicktemplate to go-std (#4448)

* updated Go/iris

* removed vendor from Go/iris

* fixed golang ver in Go/iris

* add go build, change go ver to 1.11.5

* add iris-prefork test

* changed go ver to 1.11.5 in fasthttp-postgresql

* added iris-quicktemplate

* fixed structure in go-std, added prefork

* add quicktemplate to go-std
chunariov 6 years ago
parent
commit
12e14c9ff1
30 changed files with 822 additions and 115 deletions
  1. 1 1
      frameworks/Go/fasthttp/fasthttp-postgresql.dockerfile
  2. 9 11
      frameworks/Go/go-std/README.md
  3. 132 20
      frameworks/Go/go-std/benchmark_config.json
  4. 13 0
      frameworks/Go/go-std/go-mongo-prefork.dockerfile
  5. 2 2
      frameworks/Go/go-std/go-mongo.dockerfile
  6. 2 2
      frameworks/Go/go-std/go-my-interpolate.dockerfile
  7. 12 0
      frameworks/Go/go-std/go-my-prefork.dockerfile
  8. 12 0
      frameworks/Go/go-std/go-my.dockerfile
  9. 18 0
      frameworks/Go/go-std/go-pg-prefork-quicktemplate.dockerfile
  10. 18 0
      frameworks/Go/go-std/go-pg-prefork.dockerfile
  11. 18 0
      frameworks/Go/go-std/go-pg-quicktemplate.dockerfile
  12. 18 0
      frameworks/Go/go-std/go-pg.dockerfile
  13. 0 12
      frameworks/Go/go-std/go-postgres.dockerfile
  14. 3 4
      frameworks/Go/go-std/go-prefork.dockerfile
  15. 3 4
      frameworks/Go/go-std/go.dockerfile
  16. 68 5
      frameworks/Go/go-std/src/mongo/main.go
  17. 8 15
      frameworks/Go/go-std/src/mysql/main.go
  18. 113 10
      frameworks/Go/go-std/src/postgres/main.go
  19. 102 0
      frameworks/Go/go-std/src/simple/main.go
  20. 22 0
      frameworks/Go/go-std/src/templates/fortunes.qtpl
  21. 59 0
      frameworks/Go/iris/benchmark_config.json
  22. 14 0
      frameworks/Go/iris/iris-prefork.dockerfile
  23. 14 0
      frameworks/Go/iris/iris-quicktemplate-prefork.dockerfile
  24. 14 0
      frameworks/Go/iris/iris-quicktemplate.dockerfile
  25. 3 0
      frameworks/Go/iris/iris.dockerfile
  26. 11 13
      frameworks/Go/iris/src/db.go
  27. 30 5
      frameworks/Go/iris/src/handlers.go
  28. 31 11
      frameworks/Go/iris/src/main.go
  29. 50 0
      frameworks/Go/iris/src/prefork.go
  30. 22 0
      frameworks/Go/iris/src/templates/fortunes.qtpl

+ 1 - 1
frameworks/Go/fasthttp/fasthttp-postgresql.dockerfile

@@ -1,4 +1,4 @@
-FROM golang:1.10.1
+FROM golang:1.11.5
 
 ADD ./ /fasthttp
 WORKDIR /fasthttp

+ 9 - 11
frameworks/Go/go-std/README.md

@@ -1,16 +1,14 @@
-# Go Benchmarking Test
+# [go-std](https://github.com/kataras/iris) (GoLang) Benchmarking Test
 
-This is the Go portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+This is the go portion of a [benchmarking test suite](https://www.techempower.com/benchmarks/) comparing a variety of web development platforms.
 
-### JSON Encoding Test
-* [JSON test source](src/hello/hello.go)
-
-## Versions
-
-* [Go 1.6](http://golang.org/)
+"Golang standard library. For database tests Postgres was used."
 
 ## Test URLs
 
-### JSON Encoding Test
-
-http://localhost:8080/json
+    http://localhost:8080/json
+    http://localhost:8080/db
+    http://localhost:8080/queries?queries=[1-500]
+    http://localhost:8080/update?queries=[1-500]
+    http://localhost:8080/plaintext
+    http://localhost:8080/fortune

+ 132 - 20
frameworks/Go/go-std/benchmark_config.json

@@ -3,15 +3,93 @@
   "tests": [{
     "default": {
       "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "None",
+      "framework": "None",
+      "language": "Go",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Go",
+      "notes": "",
+      "versus": "go"
+    },
+    "prefork": {
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "None",
+      "framework": "None",
+      "language": "Go",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Go-prefork",
+      "notes": "",
+      "versus": "go"
+    },
+    "mongo": {
       "db_url": "/db",
       "query_url": "/queries?queries=",
       "fortune_url": "/fortune",
       "update_url": "/update?queries=",
-      "plaintext_url": "/plaintext",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
-      "database": "MySQL",
+      "database": "MongoDB",
+      "framework": "None",
+      "language": "Go",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Go",
+      "notes": "mongodb implementation for go net/http",
+      "versus": "go"
+    },
+    "mongo-prefork": {
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortune",
+      "update_url": "/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MongoDB",
+      "framework": "None",
+      "language": "Go",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Go",
+      "notes": "mongodb implementation for go net/http",
+      "versus": "go"
+    },
+    "pg": {
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "fortune_url": "/fortune",
+      "update_url": "/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "Postgres",
       "framework": "None",
       "language": "Go",
       "flavor": "None",
@@ -24,15 +102,12 @@
       "notes": "",
       "versus": "go"
     },
-    "interpolate": {
-      "db_url": "/dbInterpolate",
-      "query_url": "/queriesInterpolate?queries=",
-      "fortune_url": "/fortuneInterpolate",
-      "update_url": "/updateInterpolate?queries=",
+    "pg-quicktemplate": {
+      "fortune_url": "/fortune-quick",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
-      "database": "MySQL",
+      "database": "Postgres",
       "framework": "None",
       "language": "Go",
       "flavor": "None",
@@ -41,21 +116,19 @@
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
-      "display_name": "Go-interpolate",
+      "display_name": "Go",
       "notes": "",
       "versus": "go"
     },
-    "prefork": {
-      "json_url": "/json",
+    "pg-prefork": {
       "db_url": "/db",
       "query_url": "/queries?queries=",
       "fortune_url": "/fortune",
       "update_url": "/update?queries=",
-      "plaintext_url": "/plaintext",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
-      "database": "MySQL",
+      "database": "Postgres",
       "framework": "None",
       "language": "Go",
       "flavor": "None",
@@ -64,11 +137,29 @@
       "webserver": "None",
       "os": "Linux",
       "database_os": "Linux",
-      "display_name": "Go-prefork",
+      "display_name": "Go",
       "notes": "",
       "versus": "go"
     },
-    "mongo": {
+    "pg-prefork-quicktemplate": {
+      "fortune_url": "/fortune-quick",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "Postgres",
+      "framework": "None",
+      "language": "Go",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Go",
+      "notes": "",
+      "versus": "go"
+    },
+    "my": {
       "db_url": "/db",
       "query_url": "/queries?queries=",
       "fortune_url": "/fortune",
@@ -76,7 +167,7 @@
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
-      "database": "MongoDB",
+      "database": "MySQL",
       "framework": "None",
       "language": "Go",
       "flavor": "None",
@@ -86,10 +177,10 @@
       "os": "Linux",
       "database_os": "Linux",
       "display_name": "Go",
-      "notes": "mongodb implementation for go net/http",
+      "notes": "",
       "versus": "go"
     },
-    "postgres": {
+    "my-prefork": {
       "db_url": "/db",
       "query_url": "/queries?queries=",
       "fortune_url": "/fortune",
@@ -97,7 +188,7 @@
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
-      "database": "Postgres",
+      "database": "MySQL",
       "framework": "None",
       "language": "Go",
       "flavor": "None",
@@ -109,6 +200,27 @@
       "display_name": "Go",
       "notes": "",
       "versus": "go"
+    },
+    "my-interpolate": {
+      "db_url": "/dbInterpolate",
+      "query_url": "/queriesInterpolate?queries=",
+      "fortune_url": "/fortuneInterpolate",
+      "update_url": "/updateInterpolate?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "MySQL",
+      "framework": "None",
+      "language": "Go",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Go-interpolate",
+      "notes": "",
+      "versus": "go"
     }
   }]
-}
+}

+ 13 - 0
frameworks/Go/go-std/go-mongo-prefork.dockerfile

@@ -0,0 +1,13 @@
+FROM golang:1.11.5
+
+ADD ./src/mongo/ /go-std
+WORKDIR /go-std
+
+RUN mkdir bin
+ENV GOPATH /go-std
+ENV PATH ${GOPATH}/bin:${PATH}
+
+RUN apt update -yqq && apt install -yqq libsasl2-dev
+RUN go get gopkg.in/mgo.v2
+RUN go build -o hello_mongo .
+CMD ./hello_mongo -prefork

+ 2 - 2
frameworks/Go/go-std/go-mongo.dockerfile

@@ -1,6 +1,6 @@
 FROM golang:1.11.5
 
-ADD ./ /go-std
+ADD ./src/mongo/ /go-std
 WORKDIR /go-std
 
 RUN mkdir bin
@@ -9,5 +9,5 @@ ENV PATH ${GOPATH}/bin:${PATH}
 
 RUN apt update -yqq && apt install -yqq libsasl2-dev
 RUN go get gopkg.in/mgo.v2
-RUN go build -o hello_mongo hello_mongo.go
+RUN go build -o hello_mongo .
 CMD ./hello_mongo

+ 2 - 2
frameworks/Go/go-std/go-interpolate.dockerfile → frameworks/Go/go-std/go-my-interpolate.dockerfile

@@ -1,6 +1,6 @@
 FROM golang:1.11.5
 
-ADD ./ /go-std
+ADD ./src/mysql/ /go-std
 WORKDIR /go-std
 
 RUN mkdir bin
@@ -8,5 +8,5 @@ ENV GOPATH /go-std
 ENV PATH ${GOPATH}/bin:${PATH}
 
 RUN go get github.com/go-sql-driver/mysql
-RUN go build -o hello_mysql hello_mysql.go
+RUN go build -o hello_mysql .
 CMD ./hello_mysql

+ 12 - 0
frameworks/Go/go-std/go-my-prefork.dockerfile

@@ -0,0 +1,12 @@
+FROM golang:1.11.5
+
+ADD ./src/mysql/ /go-std
+WORKDIR /go-std
+
+RUN mkdir bin
+ENV GOPATH /go-std
+ENV PATH ${GOPATH}/bin:${PATH}
+
+RUN go get github.com/go-sql-driver/mysql
+RUN go build -o hello_mysql .
+CMD ./hello_mysql -prefork

+ 12 - 0
frameworks/Go/go-std/go-my.dockerfile

@@ -0,0 +1,12 @@
+FROM golang:1.11.5
+
+ADD ./src/mysql/ /go-std
+WORKDIR /go-std
+
+RUN mkdir bin
+ENV GOPATH /go-std
+ENV PATH ${GOPATH}/bin:${PATH}
+
+RUN go get github.com/go-sql-driver/mysql
+RUN go build -o hello_mysql .
+CMD ./hello_mysql

+ 18 - 0
frameworks/Go/go-std/go-pg-prefork-quicktemplate.dockerfile

@@ -0,0 +1,18 @@
+FROM golang:1.11.5
+
+ADD ./src/postgres/ /go-std
+ADD ./src/templates/ /go-std/src/templates
+WORKDIR /go-std
+
+RUN mkdir bin
+ENV GOPATH /go-std
+ENV PATH ${GOPATH}/bin:${PATH}
+
+RUN go get github.com/lib/pq
+RUN go get github.com/valyala/quicktemplate
+RUN go get -u github.com/valyala/quicktemplate/qtc
+
+RUN qtc -file src/templates/fortunes.qtpl
+RUN go build -o hello_postgres .
+
+CMD ./hello_postgres -prefork

+ 18 - 0
frameworks/Go/go-std/go-pg-prefork.dockerfile

@@ -0,0 +1,18 @@
+FROM golang:1.11.5
+
+ADD ./src/postgres/ /go-std
+ADD ./src/templates/ /go-std/src/templates
+WORKDIR /go-std
+
+RUN mkdir bin
+ENV GOPATH /go-std
+ENV PATH ${GOPATH}/bin:${PATH}
+
+RUN go get github.com/lib/pq
+RUN go get github.com/valyala/quicktemplate
+RUN go get -u github.com/valyala/quicktemplate/qtc
+
+RUN qtc -file src/templates/fortunes.qtpl
+RUN go build -o hello_postgres .
+
+CMD ./hello_postgres -prefork

+ 18 - 0
frameworks/Go/go-std/go-pg-quicktemplate.dockerfile

@@ -0,0 +1,18 @@
+FROM golang:1.11.5
+
+ADD ./src/postgres/ /go-std
+ADD ./src/templates/ /go-std/src/templates
+WORKDIR /go-std
+
+RUN mkdir bin
+ENV GOPATH /go-std
+ENV PATH ${GOPATH}/bin:${PATH}
+
+RUN go get github.com/lib/pq
+RUN go get github.com/valyala/quicktemplate
+RUN go get -u github.com/valyala/quicktemplate/qtc
+
+RUN qtc -file src/templates/fortunes.qtpl
+RUN go build -o hello_postgres .
+
+CMD ./hello_postgres

+ 18 - 0
frameworks/Go/go-std/go-pg.dockerfile

@@ -0,0 +1,18 @@
+FROM golang:1.11.5
+
+ADD ./src/postgres/ /go-std
+ADD ./src/templates/ /go-std/src/templates
+WORKDIR /go-std
+
+RUN mkdir bin
+ENV GOPATH /go-std
+ENV PATH ${GOPATH}/bin:${PATH}
+
+RUN go get github.com/lib/pq
+RUN go get github.com/valyala/quicktemplate
+RUN go get -u github.com/valyala/quicktemplate/qtc
+
+RUN qtc -file src/templates/fortunes.qtpl
+RUN go build -o hello_postgres .
+
+CMD ./hello_postgres

+ 0 - 12
frameworks/Go/go-std/go-postgres.dockerfile

@@ -1,12 +0,0 @@
-FROM golang:1.11.5
-
-ADD ./ /go-std
-WORKDIR /go-std
-
-RUN mkdir bin
-ENV GOPATH /go-std
-ENV PATH ${GOPATH}/bin:${PATH}
-
-RUN go get github.com/lib/pq
-RUN go build -o hello_postgres hello_postgres.go
-CMD ./hello_postgres

+ 3 - 4
frameworks/Go/go-std/go-prefork.dockerfile

@@ -1,12 +1,11 @@
 FROM golang:1.11.5
 
-ADD ./ /go-std
+ADD ./src/simple/ /go-std
 WORKDIR /go-std
 
 RUN mkdir bin
 ENV GOPATH /go-std
 ENV PATH ${GOPATH}/bin:${PATH}
 
-RUN go get github.com/go-sql-driver/mysql
-RUN go build -o hello_mysql hello_mysql.go
-CMD ./hello_mysql -prefork
+RUN go build -o hello .
+CMD ./hello -prefork

+ 3 - 4
frameworks/Go/go-std/go.dockerfile

@@ -1,12 +1,11 @@
 FROM golang:1.11.5
 
-ADD ./ /go-std
+ADD ./src/simple/ /go-std
 WORKDIR /go-std
 
 RUN mkdir bin
 ENV GOPATH /go-std
 ENV PATH ${GOPATH}/bin:${PATH}
 
-RUN go get github.com/go-sql-driver/mysql
-RUN go build -o hello_mysql hello_mysql.go
-CMD ./hello_mysql
+RUN go build -o hello .
+CMD ./hello

+ 68 - 5
frameworks/Go/go-std/hello_mongo.go → frameworks/Go/go-std/src/mongo/main.go

@@ -2,14 +2,19 @@ package main
 
 import (
 	"encoding/json"
+	"flag"
 	"html/template"
 	"log"
 	"math/rand"
+	"net"
 	"net/http"
+	"os"
+	"os/exec"
+	"runtime"
 	"sort"
 	"strconv"
 
-	"gopkg.in/mgo.v2"
+	mgo "gopkg.in/mgo.v2"
 	"gopkg.in/mgo.v2/bson"
 )
 
@@ -76,7 +81,18 @@ func (s ByMessage) Less(i, j int) bool {
 	return s.Fortunes[i].Message < s.Fortunes[j].Message
 }
 
+var prefork = flag.Bool("prefork", false, "use prefork")
+var child = flag.Bool("child", false, "is child proc")
+
 func main() {
+	var listener net.Listener
+	flag.Parse()
+	if !*prefork {
+		runtime.GOMAXPROCS(runtime.NumCPU())
+	} else {
+		listener = doPrefork()
+	}
+
 	session, err := mgo.Dial(connectionString)
 	if err != nil {
 		log.Fatalf("Error opening database: %v", err)
@@ -89,7 +105,54 @@ func main() {
 	http.HandleFunc("/fortune", fortuneHandler)
 	http.HandleFunc("/queries", queriesHandler)
 	http.HandleFunc("/update", updateHandler)
-	http.ListenAndServe(":8080", nil)
+
+	if !*prefork {
+		http.ListenAndServe(":8080", nil)
+	} else {
+		http.Serve(listener, nil)
+	}
+}
+
+func doPrefork() net.Listener {
+	var listener net.Listener
+	if !*child {
+		addr, err := net.ResolveTCPAddr("tcp", ":8080")
+		if err != nil {
+			log.Fatal(err)
+		}
+		tcplistener, err := net.ListenTCP("tcp", addr)
+		if err != nil {
+			log.Fatal(err)
+		}
+		fl, err := tcplistener.File()
+		if err != nil {
+			log.Fatal(err)
+		}
+		children := make([]*exec.Cmd, runtime.NumCPU()/2)
+		for i := range children {
+			children[i] = exec.Command(os.Args[0], "-prefork", "-child")
+			children[i].Stdout = os.Stdout
+			children[i].Stderr = os.Stderr
+			children[i].ExtraFiles = []*os.File{fl}
+			err = children[i].Start()
+			if err != nil {
+				log.Fatal(err)
+			}
+		}
+		for _, ch := range children {
+			if err := ch.Wait(); err != nil {
+				log.Print(err)
+			}
+		}
+		os.Exit(0)
+	} else {
+		var err error
+		listener, err = net.FileListener(os.NewFile(3, ""))
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
+	return listener
 }
 
 // Helper for random numbers
@@ -105,7 +168,7 @@ func dbHandler(w http.ResponseWriter, r *http.Request) {
 		log.Fatalf("Error finding world with id: %s", err.Error())
 	}
 	w.Header().Set("Content-Type", "application/json")
-	w.Header().Set("Server", "go-mongodb")
+	w.Header().Set("Server", "Go")
 	json.NewEncoder(w).Encode(&world)
 }
 
@@ -138,14 +201,14 @@ func queriesHandler(w http.ResponseWriter, r *http.Request) {
 	}
 
 	w.Header().Set("Content-Type", "application/json")
-	w.Header().Set("Server", "go-mongodb")
+	w.Header().Set("Server", "Go")
 	json.NewEncoder(w).Encode(world)
 }
 
 // Test 4: Fortunes
 func fortuneHandler(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "text/html; charset=utf-8")
-	w.Header().Set("Server", "go-mongodb")
+	w.Header().Set("Server", "Go")
 	f := make(Fortunes, 16)
 	if err := fortunes.Find(nil).All(&f); err == nil {
 		f = append(f, Fortune{Message: "Additional fortune added at request time."})

+ 8 - 15
frameworks/Go/go-std/hello_mysql.go → frameworks/Go/go-std/src/mysql/main.go

@@ -120,7 +120,6 @@ func main() {
 
 	initDB()
 
-	http.HandleFunc("/json", jsonHandler)
 	http.HandleFunc("/db", dbHandler)
 	http.HandleFunc("/dbInterpolate", dbInterpolateHandler)
 	http.HandleFunc("/queries", queriesHandler)
@@ -129,7 +128,6 @@ func main() {
 	http.HandleFunc("/fortuneInterpolate", fortuneInterpolateHandler)
 	http.HandleFunc("/update", updateHandler)
 	http.HandleFunc("/updateInterpolate", updateInterpolateHandler)
-	http.HandleFunc("/plaintext", plaintextHandler)
 	if !*prefork {
 		http.ListenAndServe(":8080", nil)
 	} else {
@@ -137,21 +135,18 @@ func main() {
 	}
 }
 
-func doPrefork() (listener net.Listener) {
-	var err error
-	var fl *os.File
-	var tcplistener *net.TCPListener
+func doPrefork() net.Listener {
+	var listener net.Listener
 	if !*child {
-		var addr *net.TCPAddr
-		addr, err = net.ResolveTCPAddr("tcp", ":8080")
+		addr, err := net.ResolveTCPAddr("tcp", ":8080")
 		if err != nil {
 			log.Fatal(err)
 		}
-		tcplistener, err = net.ListenTCP("tcp", addr)
+		tcplistener, err := net.ListenTCP("tcp", addr)
 		if err != nil {
 			log.Fatal(err)
 		}
-		fl, err = tcplistener.File()
+		fl, err := tcplistener.File()
 		if err != nil {
 			log.Fatal(err)
 		}
@@ -167,19 +162,17 @@ func doPrefork() (listener net.Listener) {
 			}
 		}
 		for _, ch := range children {
-			var err error = ch.Wait()
-			if err != nil {
+			if err := ch.Wait(); err != nil {
 				log.Print(err)
 			}
 		}
 		os.Exit(0)
 	} else {
-		fl = os.NewFile(3, "")
-		listener, err = net.FileListener(fl)
+		var err error
+		listener, err = net.FileListener(os.NewFile(3, ""))
 		if err != nil {
 			log.Fatal(err)
 		}
-		runtime.GOMAXPROCS(2)
 	}
 	return listener
 }

+ 113 - 10
frameworks/Go/go-std/hello_postgres.go → frameworks/Go/go-std/src/postgres/main.go

@@ -7,9 +7,14 @@ import (
 	"html/template"
 	"log"
 	"math/rand"
+	"net"
 	"net/http"
+	"os"
+	"os/exec"
+	"runtime"
 	"sort"
 	"strconv"
+	"templates"
 
 	_ "github.com/lib/pq"
 )
@@ -71,6 +76,9 @@ var (
 	fortuneSelectPrepared *sql.Stmt
 )
 
+var prefork = flag.Bool("prefork", false, "use prefork")
+var child = flag.Bool("child", false, "is child proc")
+
 func initDB() {
 	var err error
 	db, err = sql.Open("postgres", connectionString)
@@ -95,16 +103,69 @@ func initDB() {
 }
 
 func main() {
+	var listener net.Listener
 	flag.Parse()
+	if !*prefork {
+		runtime.GOMAXPROCS(runtime.NumCPU())
+	} else {
+		listener = doPrefork()
+	}
 
 	initDB()
 
 	http.HandleFunc("/db", dbHandler)
 	http.HandleFunc("/queries", queriesHandler)
 	http.HandleFunc("/fortune", fortuneHandler)
+	http.HandleFunc("/fortune-quick", fortuneQuickHandler)
 	http.HandleFunc("/update", updateHandler)
 
-	log.Fatal(http.ListenAndServe(":8080", nil))
+	if !*prefork {
+		http.ListenAndServe(":8080", nil)
+	} else {
+		http.Serve(listener, nil)
+	}
+}
+
+func doPrefork() net.Listener {
+	var listener net.Listener
+	if !*child {
+		addr, err := net.ResolveTCPAddr("tcp", ":8080")
+		if err != nil {
+			log.Fatal(err)
+		}
+		tcplistener, err := net.ListenTCP("tcp", addr)
+		if err != nil {
+			log.Fatal(err)
+		}
+		fl, err := tcplistener.File()
+		if err != nil {
+			log.Fatal(err)
+		}
+		children := make([]*exec.Cmd, runtime.NumCPU()/2)
+		for i := range children {
+			children[i] = exec.Command(os.Args[0], "-prefork", "-child")
+			children[i].Stdout = os.Stdout
+			children[i].Stderr = os.Stderr
+			children[i].ExtraFiles = []*os.File{fl}
+			err = children[i].Start()
+			if err != nil {
+				log.Fatal(err)
+			}
+		}
+		for _, ch := range children {
+			if err := ch.Wait(); err != nil {
+				log.Print(err)
+			}
+		}
+		os.Exit(0)
+	} else {
+		var err error
+		listener, err = net.FileListener(os.NewFile(3, ""))
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
+	return listener
 }
 
 func getQueriesParam(r *http.Request) int {
@@ -159,7 +220,14 @@ func fortuneHandler(w http.ResponseWriter, r *http.Request) {
 	}
 	defer rows.Close()
 
-	fortunes := fetchFortunes(rows)
+	fortunes := make(Fortunes, 0, 16)
+	for rows.Next() {
+		fortune := Fortune{}
+		if err := rows.Scan(&fortune.Id, &fortune.Message); err != nil {
+			log.Fatalf("Error scanning fortune row: %s", err.Error())
+		}
+		fortunes = append(fortunes, &fortune)
+	}
 	fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."})
 
 	sort.Sort(ByMessage{fortunes})
@@ -170,16 +238,31 @@ func fortuneHandler(w http.ResponseWriter, r *http.Request) {
 	}
 }
 
-func fetchFortunes(rows *sql.Rows) Fortunes {
-	fortunes := make(Fortunes, 0, 16)
+// Test 4: Fortunes
+func fortuneQuickHandler(w http.ResponseWriter, r *http.Request) {
+	rows, err := fortuneSelectPrepared.Query()
+	if err != nil {
+		log.Fatalf("Error preparing statement: %v", err)
+	}
+	defer rows.Close()
+
+	fortunes := make([]templates.Fortune, 0, 16)
 	for rows.Next() { // Fetch rows
-		fortune := Fortune{}
-		if err := rows.Scan(&fortune.Id, &fortune.Message); err != nil {
+		fortune := templates.Fortune{}
+		if err := rows.Scan(&fortune.ID, &fortune.Message); err != nil {
 			log.Fatalf("Error scanning fortune row: %s", err.Error())
 		}
-		fortunes = append(fortunes, &fortune)
+		fortunes = append(fortunes, fortune)
 	}
-	return fortunes
+	fortunes = append(fortunes, templates.Fortune{Message: "Additional fortune added at request time."})
+
+	sort.Slice(fortunes, func(i, j int) bool {
+		return fortunes[i].Message < fortunes[j].Message
+	})
+
+	w.Header().Set("Server", "Go")
+	w.Header().Set("Content-Type", "text/html; charset=utf-8")
+	templates.WriteFortunePage(w, fortunes)
 }
 
 // Test 5: Database updates
@@ -192,8 +275,28 @@ func updateHandler(w http.ResponseWriter, r *http.Request) {
 			log.Fatalf("Error scanning world row: %v", err)
 		}
 		world[i].RandomNumber = uint16(rand.Intn(worldRowCount) + 1)
-		if _, err := worldUpdatePrepared.Exec(world[i].RandomNumber, world[i].Id); err != nil {
-			log.Fatalf("Error updating world row: %v", err)
+	}
+
+	if len(world) > 0 {
+		// against deadlocks
+		sort.Slice(world, func(i, j int) bool {
+			return world[i].Id < world[j].Id
+		})
+
+		tx, err := db.Begin()
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		for i := 0; i < n; i++ {
+			if _, err := tx.Stmt(worldUpdatePrepared).Exec(world[i].RandomNumber, world[i].Id); err != nil {
+				log.Printf("Error updating world row: %v\n", err)
+				tx.Rollback()
+			}
+		}
+
+		if err := tx.Commit(); err != nil {
+			log.Fatal(err)
 		}
 	}
 

+ 102 - 0
frameworks/Go/go-std/src/simple/main.go

@@ -0,0 +1,102 @@
+package main
+
+import (
+	"encoding/json"
+	"flag"
+	"log"
+	"net"
+	"net/http"
+	"os"
+	"os/exec"
+	"runtime"
+)
+
+type Message struct {
+	Message string `json:"message"`
+}
+
+const (
+	helloWorldString = "Hello, World!"
+)
+
+var (
+	helloWorldBytes = []byte(helloWorldString)
+)
+
+var prefork = flag.Bool("prefork", false, "use prefork")
+var child = flag.Bool("child", false, "is child proc")
+
+func main() {
+	var listener net.Listener
+	flag.Parse()
+	if !*prefork {
+		runtime.GOMAXPROCS(runtime.NumCPU())
+	} else {
+		listener = doPrefork()
+	}
+
+	http.HandleFunc("/json", jsonHandler)
+	http.HandleFunc("/plaintext", plaintextHandler)
+
+	if !*prefork {
+		http.ListenAndServe(":8080", nil)
+	} else {
+		http.Serve(listener, nil)
+	}
+}
+
+func doPrefork() net.Listener {
+	var listener net.Listener
+	if !*child {
+		addr, err := net.ResolveTCPAddr("tcp", ":8080")
+		if err != nil {
+			log.Fatal(err)
+		}
+		tcplistener, err := net.ListenTCP("tcp", addr)
+		if err != nil {
+			log.Fatal(err)
+		}
+		fl, err := tcplistener.File()
+		if err != nil {
+			log.Fatal(err)
+		}
+		children := make([]*exec.Cmd, runtime.NumCPU()/2)
+		for i := range children {
+			children[i] = exec.Command(os.Args[0], "-prefork", "-child")
+			children[i].Stdout = os.Stdout
+			children[i].Stderr = os.Stderr
+			children[i].ExtraFiles = []*os.File{fl}
+			err = children[i].Start()
+			if err != nil {
+				log.Fatal(err)
+			}
+		}
+		for _, ch := range children {
+			if err := ch.Wait(); err != nil {
+				log.Print(err)
+			}
+		}
+		os.Exit(0)
+	} else {
+		var err error
+		listener, err = net.FileListener(os.NewFile(3, ""))
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
+	return listener
+}
+
+// Test 1: JSON serialization
+func jsonHandler(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Server", "Go")
+	w.Header().Set("Content-Type", "application/json")
+	json.NewEncoder(w).Encode(&Message{helloWorldString})
+}
+
+// Test 6: Plaintext
+func plaintextHandler(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Server", "Go")
+	w.Header().Set("Content-Type", "text/plain")
+	w.Write(helloWorldBytes)
+}

+ 22 - 0
frameworks/Go/go-std/src/templates/fortunes.qtpl

@@ -0,0 +1,22 @@
+{% code
+type Fortune struct {
+	ID int32
+	Message string
+}
+%}
+
+{% func FortunePage(rows []Fortune) %}<!DOCTYPE html>
+<html>
+<head>
+<title>Fortunes</title>
+</head>
+<body>
+<table>
+<tr><th>id</th><th>message</th></tr>
+{% for _, r := range rows %}
+<tr><td>{%d int(r.ID) %}</td><td>{%s r.Message %}</td></tr>
+{% endfor %}
+</table>
+</body>
+</html>
+{% endfunc %}

+ 59 - 0
frameworks/Go/iris/benchmark_config.json

@@ -23,6 +23,65 @@
       "display_name": "Iris",
       "notes": "",
       "versus": "go"
+    },
+    "prefork": {
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "fortune_url": "/fortune",
+      "db_url": "/db",
+      "query_url": "/queries?queries=",
+      "update_url": "/update?queries=",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "Postgres",
+      "framework": "None",
+      "language": "Go",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Iris",
+      "notes": "",
+      "versus": "go"
+    },
+    "quicktemplate": {
+      "fortune_url": "/fortune-quick",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "Postgres",
+      "framework": "None",
+      "language": "Go",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Iris",
+      "notes": "",
+      "versus": "go"
+    },
+    "quicktemplate-prefork": {
+      "fortune_url": "/fortune-quick",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Fullstack",
+      "database": "Postgres",
+      "framework": "None",
+      "language": "Go",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "None",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "Iris",
+      "notes": "",
+      "versus": "go"
     }
   }]
 }

+ 14 - 0
frameworks/Go/iris/iris-prefork.dockerfile

@@ -0,0 +1,14 @@
+FROM golang:1.11.5
+
+WORKDIR /go/src/app
+
+RUN go get github.com/kataras/iris
+RUN go get github.com/lib/pq
+RUN go get github.com/valyala/quicktemplate
+RUN go get -u github.com/valyala/quicktemplate/qtc
+COPY src/. .
+
+RUN qtc
+RUN go build -ldflags="-s -w" -o app .
+
+CMD ./app -prefork

+ 14 - 0
frameworks/Go/iris/iris-quicktemplate-prefork.dockerfile

@@ -0,0 +1,14 @@
+FROM golang:1.11.5
+
+WORKDIR /go/src/app
+
+RUN go get github.com/kataras/iris
+RUN go get github.com/lib/pq
+RUN go get github.com/valyala/quicktemplate
+RUN go get -u github.com/valyala/quicktemplate/qtc
+COPY src/. .
+
+RUN qtc
+RUN go build -ldflags="-s -w" -o app .
+
+CMD ./app -prefork

+ 14 - 0
frameworks/Go/iris/iris-quicktemplate.dockerfile

@@ -0,0 +1,14 @@
+FROM golang:1.11.5
+
+WORKDIR /go/src/app
+
+RUN go get github.com/kataras/iris
+RUN go get github.com/lib/pq
+RUN go get github.com/valyala/quicktemplate
+RUN go get -u github.com/valyala/quicktemplate/qtc
+COPY src/. .
+
+RUN qtc
+RUN go build -ldflags="-s -w" -o app .
+
+CMD ./app

+ 3 - 0
frameworks/Go/iris/iris.dockerfile

@@ -4,8 +4,11 @@ WORKDIR /go/src/app
 
 RUN go get github.com/kataras/iris
 RUN go get github.com/lib/pq
+RUN go get github.com/valyala/quicktemplate
+RUN go get -u github.com/valyala/quicktemplate/qtc
 COPY src/. .
 
+RUN qtc
 RUN go build -ldflags="-s -w" -o app .
 
 CMD ./app

+ 11 - 13
frameworks/Go/iris/src/db.go

@@ -2,12 +2,17 @@ package main
 
 import (
 	"database/sql"
-	"fmt"
 	"log"
 	"math/rand"
 	"sort"
 )
 
+const (
+	selectQueryStr  = "SELECT id, randomNumber FROM World WHERE id = $1"
+	updateQueryStr  = "UPDATE World SET randomNumber = $1 WHERE id = $2"
+	fortuneQueryStr = "SELECT id, message FROM Fortune"
+)
+
 var (
 	selectStmt  *sql.Stmt
 	updateStmt  *sql.Stmt
@@ -66,17 +71,10 @@ func mustPrepare(db *sql.DB, query string) (*sql.Stmt, error) {
 	return stmt, nil
 }
 
-func initDatabase(dbHost string, dbUser string, dbPass string, dbName string, maxConnectionsInPool int) (*sql.DB, error) {
+func initDatabase(dbConnectionString string, maxConnectionsInPool int) (*sql.DB, error) {
 	var err error
 	var db *sql.DB
-	db, err = sql.Open("postgres",
-		fmt.Sprintf("host=%s user=%s password=%s dbname=%s sslmode=disable",
-			dbHost,
-			dbUser,
-			dbPass,
-			dbName,
-		),
-	)
+	db, err = sql.Open("postgres", dbConnectionString)
 	if err != nil {
 		return nil, err
 	}
@@ -89,13 +87,13 @@ func initDatabase(dbHost string, dbUser string, dbPass string, dbName string, ma
 	db.SetMaxOpenConns(maxConnectionsInPool)
 	db.SetMaxIdleConns(maxConnectionsInPool)
 
-	if selectStmt, err = mustPrepare(db, "SELECT id, randomNumber FROM World WHERE id = $1"); err != nil {
+	if selectStmt, err = mustPrepare(db, selectQueryStr); err != nil {
 		return nil, err
 	}
-	if fortuneStmt, err = mustPrepare(db, "SELECT id, message FROM Fortune"); err != nil {
+	if fortuneStmt, err = mustPrepare(db, fortuneQueryStr); err != nil {
 		return nil, err
 	}
-	if updateStmt, err = mustPrepare(db, "UPDATE World SET randomNumber = $1 WHERE id = $2"); err != nil {
+	if updateStmt, err = mustPrepare(db, updateQueryStr); err != nil {
 		return nil, err
 	}
 

+ 30 - 5
frameworks/Go/iris/src/handlers.go

@@ -1,6 +1,7 @@
 package main
 
 import (
+	"app/templates"
 	"database/sql"
 	"log"
 	"sort"
@@ -33,6 +34,7 @@ func queriesHandler(ctx context.Context) {
 	}
 
 	results := make([]World, q)
+
 	for i := 0; i < q; i++ {
 		results[i] = getOneRandomWorld()
 	}
@@ -56,15 +58,12 @@ func updateHandler(db *sql.DB) func(ctx context.Context) {
 }
 
 func fortuneHandler(ctx context.Context) {
-	var err error
-	var rows *sql.Rows
-	rows, err = fortuneStmt.Query()
+	rows, err := fortuneStmt.Query()
 	if err != nil {
 		log.Fatalf("Can't query fortunes: %s\n", err)
 	}
 
-	var fortunes []Fortune
-
+	fortunes := make([]Fortune, 0, 16)
 	var fortune Fortune
 	for rows.Next() {
 		if err = rows.Scan(&fortune.ID, &fortune.Message); err != nil {
@@ -84,3 +83,29 @@ func fortuneHandler(ctx context.Context) {
 		Fortunes []Fortune
 	}{fortunes})
 }
+
+func fortuneQuickHandler(ctx context.Context) {
+	rows, err := fortuneStmt.Query()
+	if err != nil {
+		log.Fatalf("Can't query fortunes: %s\n", err)
+	}
+
+	fortunes := make([]templates.Fortune, 0, 16)
+	var fortune templates.Fortune
+	for rows.Next() {
+		if err = rows.Scan(&fortune.ID, &fortune.Message); err != nil {
+			log.Fatalf("Can't scan fortune: %s\n", err)
+		}
+		fortunes = append(fortunes, fortune)
+	}
+	rows.Close()
+	fortunes = append(fortunes, templates.Fortune{Message: "Additional fortune added at request time."})
+
+	sort.Slice(fortunes, func(i, j int) bool {
+		return fortunes[i].Message < fortunes[j].Message
+	})
+
+	ctx.Header("Server", "Iris")
+	ctx.ContentType("text/html; charset=utf-8")
+	templates.WriteFortunePage(ctx.ResponseWriter(), fortunes)
+}

+ 31 - 11
frameworks/Go/iris/src/main.go

@@ -2,42 +2,57 @@ package main
 
 import (
 	"context"
+	"flag"
 	"log"
+	"net"
 	"runtime"
 	"time"
 
 	"github.com/kataras/iris"
 
-	"database/sql"
-
 	_ "github.com/lib/pq"
 
 	"github.com/kataras/iris/middleware/recover"
 )
 
 func main() {
+	// init flags
+	bindHost := flag.String("bind", ":8080", "set bind host")
+	prefork := flag.Bool("prefork", false, "use prefork")
+	child := flag.Bool("child", false, "is child proc")
+	dbConnectionString := flag.String("db_connection_string",
+		"host=tfb-database user=benchmarkdbuser password=benchmarkdbpass dbname=hello_world sslmode=disable",
+		"Set bind host")
+	flag.Parse()
+
+	// check for prefork
+	var listener net.Listener
+	if *prefork {
+		listener = doPrefork(*child, *bindHost)
+	}
+
+	// init iris app
 	app := iris.New()
 	app.Use(recover.New())
-
 	app.RegisterView(iris.HTML("./templates", ".html"))
 
-	var err error
-	var db *sql.DB
-	if db, err = initDatabase("tfb-database",
-		"benchmarkdbuser",
-		"benchmarkdbpass",
-		"hello_world",
-		runtime.NumCPU()); err != nil {
+	// init database
+	db, err := initDatabase(
+		*dbConnectionString,
+		runtime.NumCPU())
+	if err != nil {
 		log.Fatalf("Error opening database: %s", err)
 	}
 	defer db.Close()
 
+	// add handlers
 	app.Handle("GET", "/json", jsonHandler)
 	app.Handle("GET", "/plaintext", plaintextHandler)
 	app.Handle("GET", "/db", dbHandler)
 	app.Handle("GET", "/queries", queriesHandler)
 	app.Handle("GET", "/update", updateHandler(db))
 	app.Handle("GET", "/fortune", fortuneHandler)
+	app.Handle("GET", "/fortune-quick", fortuneQuickHandler)
 
 	iris.RegisterOnInterrupt(func() {
 		timeout := 10 * time.Second
@@ -46,5 +61,10 @@ func main() {
 		app.Shutdown(ctx)
 	})
 
-	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed), iris.WithoutInterruptHandler)
+	// run iris app
+	if *prefork {
+		app.Run(iris.Listener(listener), iris.WithoutServerError(iris.ErrServerClosed), iris.WithoutInterruptHandler)
+	} else {
+		app.Run(iris.Addr(*bindHost), iris.WithoutServerError(iris.ErrServerClosed), iris.WithoutInterruptHandler)
+	}
 }

+ 50 - 0
frameworks/Go/iris/src/prefork.go

@@ -0,0 +1,50 @@
+package main
+
+import (
+	"log"
+	"net"
+	"os"
+	"os/exec"
+	"runtime"
+)
+
+func doPrefork(child bool, toBind string) net.Listener {
+	var listener net.Listener
+	if !child {
+		addr, err := net.ResolveTCPAddr("tcp", toBind)
+		if err != nil {
+			log.Fatal(err)
+		}
+		tcplistener, err := net.ListenTCP("tcp", addr)
+		if err != nil {
+			log.Fatal(err)
+		}
+		fl, err := tcplistener.File()
+		if err != nil {
+			log.Fatal(err)
+		}
+		children := make([]*exec.Cmd, runtime.NumCPU()/2)
+		for i := range children {
+			children[i] = exec.Command(os.Args[0], "-prefork", "-child")
+			children[i].Stdout = os.Stdout
+			children[i].Stderr = os.Stderr
+			children[i].ExtraFiles = []*os.File{fl}
+			if err := children[i].Start(); err != nil {
+				log.Fatal(err)
+			}
+		}
+		for _, ch := range children {
+			if err := ch.Wait(); err != nil {
+				log.Print(err)
+			}
+		}
+		os.Exit(0)
+	} else {
+		var err error
+		listener, err = net.FileListener(os.NewFile(3, ""))
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
+	return listener
+}

+ 22 - 0
frameworks/Go/iris/src/templates/fortunes.qtpl

@@ -0,0 +1,22 @@
+{% code
+type Fortune struct {
+	ID int32
+	Message string
+}
+%}
+
+{% func FortunePage(rows []Fortune) %}<!DOCTYPE html>
+<html>
+<head>
+<title>Fortunes</title>
+</head>
+<body>
+<table>
+<tr><th>id</th><th>message</th></tr>
+{% for _, r := range rows %}
+<tr><td>{%d int(r.ID) %}</td><td>{%s r.Message %}</td></tr>
+{% endfor %}
+</table>
+</body>
+</html>
+{% endfunc %}