Razon Yang 5 vuotta sitten
vanhempi
commit
974fcee089

+ 1 - 1
.travis.yml

@@ -38,7 +38,7 @@ env:
     - 'TESTDIR="Go/chi Go/gin Go/goji Go/aah Go/beego Go/echo Go/gnet"'
     - 'TESTDIR="Go/chi Go/gin Go/goji Go/aah Go/beego Go/echo Go/gnet"'
     - 'TESTDIR="Go/falcore Go/fiber Go/kami Go/martini Go/revel Go/webgo"'
     - 'TESTDIR="Go/falcore Go/fiber Go/kami Go/martini Go/revel Go/webgo"'
     - 'TESTDIR="Go/evio Go/fasthttp Go/go-std Go/atreugo Go/gramework"'
     - 'TESTDIR="Go/evio Go/fasthttp Go/go-std Go/atreugo Go/gramework"'
-    - 'TESTDIR="Go/goframe"'
+    - 'TESTDIR="Go/goframe Go/clevergo"'
     - "TESTLANG=Groovy"
     - "TESTLANG=Groovy"
     - "TESTDIR=Haskell/snap"
     - "TESTDIR=Haskell/snap"
     - "TESTDIR=Haskell/yesod"
     - "TESTDIR=Haskell/yesod"

+ 12 - 0
frameworks/Go/clevergo/README.md

@@ -0,0 +1,12 @@
+# [CleverGo](https://github.com/clevergo/clevergo) Benchmarking Test
+
+[CleverGo](https://github.com/clevergo/clevergo) is a lightweight, feature rich and high performance web framework writing in Go.
+
+## Test URLs
+
+http://localhost:8080/json
+http://localhost:8080/plaintext
+http://localhost:8080/db
+http://localhost:8080/query?queries=
+http://localhost:8080/update?queries=
+http://localhost:8080/fortunes

+ 30 - 0
frameworks/Go/clevergo/benchmark_config.json

@@ -0,0 +1,30 @@
+{
+  "framework": "clevergo",
+  "tests": [
+    {
+      "default": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "query_url": "/queries?n=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?n=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "mysql",
+        "framework": "CleverGo",
+        "language": "Go",
+        "flavor": "None",
+        "orm": "Raw",
+        "platform": "None",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "CleverGo",
+        "notes": "",
+        "versus": "go"
+      }
+    }
+  ]
+}

+ 9 - 0
frameworks/Go/clevergo/clevergo.dockerfile

@@ -0,0 +1,9 @@
+FROM golang:1.14
+
+ADD ./ /clevergo
+WORKDIR /clevergo
+
+RUN go get
+
+RUN go build -o app main.go
+CMD ./app

+ 8 - 0
frameworks/Go/clevergo/go.mod

@@ -0,0 +1,8 @@
+module clevergo
+
+go 1.14
+
+require (
+	clevergo.tech/clevergo v0.3.0
+	github.com/go-sql-driver/mysql v1.5.0
+)

+ 24 - 0
frameworks/Go/clevergo/go.sum

@@ -0,0 +1,24 @@
+clevergo.tech/clevergo v0.3.0 h1:TZGTEGQzqu+1tYknWPYu3ku5APLNDf1XEQiAlS0d8ek=
+clevergo.tech/clevergo v0.3.0/go.mod h1:i8p1KgNDl2TlwfVV541OQDDRJpySNUyP6eOA0qEfI4Y=
+clevergo.tech/log v0.2.0 h1:OjA3aWWxoKt+UU9KZyYrFqp7yeW6EY1nuNmH56FD484=
+clevergo.tech/log v0.2.0/go.mod h1:61sruy0OB79q5JJlxlyi+6eZzVf/bxbUbXnL0KIzsVw=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 218 - 0
frameworks/Go/clevergo/main.go

@@ -0,0 +1,218 @@
+package main
+
+import (
+	"database/sql"
+	"html/template"
+	"log"
+	"math/rand"
+	"net/http"
+	"runtime"
+	"sort"
+	"strconv"
+
+	"clevergo.tech/clevergo"
+	_ "github.com/go-sql-driver/mysql"
+)
+
+type Fortune struct {
+	ID      uint16 `json:"id"`
+	Message string `json:"message"`
+}
+
+type Fortunes []*Fortune
+
+func (s Fortunes) Len() int {
+	return len(s)
+}
+
+func (s Fortunes) Swap(i, j int) {
+	s[i], s[j] = s[j], s[i]
+}
+
+type FortunesByMessage struct {
+	Fortunes
+}
+
+func (f FortunesByMessage) Less(i, j int) bool {
+	return f.Fortunes[i].Message < f.Fortunes[j].Message
+}
+
+var (
+	// Template
+	fortuneHTML = `<!doctype html>
+<html>
+<head>
+	<title>Fortunes</title>
+</head>
+<body>
+	<table>
+		<tr>
+        	<th>id</th>
+        	<th>message</th>
+        </tr>
+        {{range .}}
+        <tr>
+        	<td>{{ .ID }}</td>
+        	<td>{{ .Message }}</td>
+        </tr>
+        {{end}}
+	</table>
+</body>
+</html>`
+	fortuneTmpl = template.Must(template.New("fortune").Parse(fortuneHTML))
+
+	// Database
+	db                *sql.DB
+	dbDSN             = "benchmarkdbuser:benchmarkdbpass@tcp(tfb-database:3306)/hello_world"
+	worldSelect       = "SELECT id, randomNumber FROM World WHERE id = ?"
+	worldUpdate       = "UPDATE World SET randomNumber = ? WHERE id = ?"
+	fortuneSelect     = "SELECT id, message FROM Fortune"
+	worldSelectStmt   *sql.Stmt
+	worldUpdateStmt   *sql.Stmt
+	fortuneSelectStmt *sql.Stmt
+	worldRowCount     = 10000
+	maxConnections    = 256
+
+	helloWorld = "Hello, World!"
+)
+
+func init() {
+	runtime.GOMAXPROCS(runtime.NumCPU())
+}
+
+func initialize() (err error) {
+	db, err = sql.Open("mysql", dbDSN)
+	if err != nil {
+		log.Fatalf("Error opening database: %v", err)
+	}
+	db.SetMaxIdleConns(maxConnections)
+	db.SetMaxOpenConns(maxConnections)
+	worldSelectStmt, err = db.Prepare(worldSelect)
+	if err != nil {
+		log.Fatal(err)
+	}
+	worldUpdateStmt, err = db.Prepare(worldUpdate)
+	if err != nil {
+		log.Fatal(err)
+	}
+	fortuneSelectStmt, err = db.Prepare(fortuneSelect)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	return
+}
+
+func main() {
+	if err := initialize(); err != nil {
+		log.Fatal(err)
+	}
+
+	app := clevergo.Pure()
+	app.Use(clevergo.ServerHeader("CleverGo"))
+	app.Get("/plaintext", plaintextHandler)
+	app.Get("/json", jsonHandler)
+	app.Get("/db", dbHandler)
+	app.Get("/queries", queriesHandler)
+	app.Get("/fortunes", fortunesHandler)
+	app.Get("/updates", updateHandler)
+	log.Println(app.Run(":8080"))
+}
+
+func dbHandler(c *clevergo.Context) error {
+	world := new(World)
+	if err := fetchRandomWorld(world); err != nil {
+		return err
+	}
+	return c.JSON(http.StatusOK, world)
+}
+
+func getQueryCount(q string) int {
+	n, err := strconv.Atoi(q)
+	if err != nil || n < 1 {
+		return 1
+	}
+	if n > 500 {
+		return 500
+	}
+	return n
+}
+
+type World struct {
+	ID           uint16 `json:"id"`
+	RandomNumber uint16 `json:"randomNumber"`
+}
+
+func fetchRandomWorld(w *World) error {
+	n := randomWorldNum()
+	return worldSelectStmt.QueryRow(n).Scan(&w.ID, &w.RandomNumber)
+}
+
+func randomWorldNum() int {
+	return rand.Intn(worldRowCount) + 1
+}
+
+func queriesHandler(c *clevergo.Context) error {
+	n := getQueryCount(c.QueryParam("n"))
+	worlds := make([]World, n)
+	for i := 0; i < n; i++ {
+		if err := fetchRandomWorld(&worlds[i]); err != nil {
+			return err
+		}
+	}
+
+	return c.JSON(http.StatusOK, worlds)
+}
+
+func fortunesHandler(c *clevergo.Context) error {
+	rows, err := fortuneSelectStmt.Query()
+	if err != nil {
+		return err
+	}
+	defer rows.Close()
+
+	fortunes := make(Fortunes, 0, 16)
+	for rows.Next() { // Fetch rows
+		f := new(Fortune)
+		if err := rows.Scan(&f.ID, &f.Message); err != nil {
+			return err
+		}
+		fortunes = append(fortunes, f)
+	}
+	fortunes = append(fortunes, &Fortune{Message: "Additional fortune added at request time."})
+	sort.Sort(FortunesByMessage{fortunes})
+
+	return fortuneTmpl.Execute(c.Response, fortunes)
+}
+
+func updateHandler(c *clevergo.Context) error {
+	n := getQueryCount(c.QueryParam("n"))
+	worlds := make([]World, n)
+	for i := 0; i < n; i++ {
+		// Fetch and modify
+		w := &worlds[i]
+		if err := fetchRandomWorld(&worlds[i]); err != nil {
+			return err
+		}
+		w.RandomNumber = uint16(randomWorldNum())
+
+		// Update
+		if _, err := worldUpdateStmt.Exec(w.RandomNumber, w.ID); err != nil {
+			return err
+		}
+	}
+
+	return c.JSON(http.StatusOK, worlds)
+}
+
+func plaintextHandler(c *clevergo.Context) error {
+	return c.String(http.StatusOK, helloWorld)
+}
+
+type Message struct {
+	Message string `json:"message"`
+}
+
+func jsonHandler(c *clevergo.Context) error {
+	return c.JSON(http.StatusOK, Message{"Hello, World!"})
+}