Browse Source

adding benchmarks for Nim stdlib (#6714)

* Create nim-stdlib.nimble

* Create nim-stdlib.nim

* Create handlers.nim

* Update nim-stdlib.nim

* Create nim-stdlib.dockerfile

* Create benchmark_config.json

* Create README.md

* making the repo name in lower case

* removing  "-" as nimble complains about it

* Rename nim-stdlib.nimble to nimstdlib.nimble

* https://nim-lang.org/docs/asynchttpserver.html

* Rename nim-stdlib.nim to nimstdlib.nim

* Update nim-stdlib.dockerfile

* sigh. forgot the "!"

* i might as well commit sudoku now. yet another copy paste error.

* Update handlers.nim

* Create defs.nim

* Adding db test

* Adding db test

* Adding db test

* Adding db test

* adding the libpq lib as a dependency

* Update nim-stdlib.dockerfile

* Update handlers.nim

* missing comma

* Adding the queries test

* Adding the queries test

* Adding the queries test

* Adding the queries test

* Adding the queries test

* Adding fortunes

* Adding fortunes

* Adding Fortunes

* Adding Fortunes

* added the missing "!"

* the docs are wrong here. the "!" is not needed

* let's try xmlencoding here

* Update handlers.nim

* missing table headers

* Adding updates test

* Adding Updates test

* Adding Updates test

* changing json handler to actually use the json serializer

%*{"message":"Hello, World!"}

* updated /db handler to use json serializer as well

also fixed a missing character
Rishav Sharan 4 years ago
parent
commit
cbf6b2b995

+ 29 - 0
frameworks/Nim/nim-stdlib/README.md

@@ -0,0 +1,29 @@
+# Nim-stdlib Benchmarking Test
+
+## Important Libraries
+
+The tests were run with:
+
+* [Nim-stdlib](https://nim-lang.org/docs/asynchttpserver.html)
+
+## Test URLs
+### JSON
+
+http://localhost:8080/json
+
+### PLAINTEXT
+
+http://localhost:8080/plaintext
+
+### Single Database Query
+
+http://localhost:8080/db
+
+
+### Multiple Database Queries
+
+http://localhost:8080/queries?queries=1
+
+### Fortunes
+
+http://localhost:8080/fortunes

+ 30 - 0
frameworks/Nim/nim-stdlib/benchmark_config.json

@@ -0,0 +1,30 @@
+{
+    "framework": "nim-stdlib",
+    "tests": [
+      {
+        "default": {
+          "json_url": "/json",
+          "plaintext_url": "/plaintext",
+          "db_url": "/db",
+          "query_url": "/queries?queries=",
+          "fortune_url": "/fortunes",
+          "update_url": "/updates?queries=",
+          "port": 8080,
+          "approach": "Realistic",
+          "classification": "Platform",
+          "database": "postgres",
+          "framework": "stdlib",
+          "language": "Nim",
+          "flavor": "None",
+          "orm": "Raw",
+          "platform": "asynchttprouter",
+          "webserver": "None",
+          "os": "Linux",
+          "database_os": "Linux",
+          "display_name": "nim-stdlib",
+          "notes": "",
+          "versus": "httpbeast"
+        }
+      }
+    ]
+  }

+ 13 - 0
frameworks/Nim/nim-stdlib/nim-stdlib.dockerfile

@@ -0,0 +1,13 @@
+FROM nimlang/nim:latest
+
+ADD ./ /nimstdlib
+
+WORKDIR /nimstdlib
+
+RUN apt update && apt install -y libpq5
+
+RUN nimble c --d:release --threads:on -y src/nimstdlib.nim -o:nimstdlib
+
+EXPOSE 8080
+
+CMD ./nimstdlib

+ 14 - 0
frameworks/Nim/nim-stdlib/nimstdlib.nimble

@@ -0,0 +1,14 @@
+# Package
+
+version       = "0.1.0"
+author        = "Rishav Sharan"
+description   = "A techempower project using only the nim stdlib packages"
+license       = "MIT"
+srcDir        = "src"
+binDir        = "bin"
+bin           = @["nimstdlib"]
+
+
+# Dependencies
+
+requires "nim >= 1.4.8"

+ 11 - 0
frameworks/Nim/nim-stdlib/src/defs.nim

@@ -0,0 +1,11 @@
+import db_postgres
+
+let db* = open("tfb-database:5432", "benchmarkdbuser", "benchmarkdbpass", "hello_world")
+
+type
+    DBQueryObj* = ref object of RootObj
+        id*: string
+        randomNumber*: string
+    
+    DBQueryObjsList* = seq[DBQueryObj]
+    

+ 106 - 0
frameworks/Nim/nim-stdlib/src/handlers.nim

@@ -0,0 +1,106 @@
+import asynchttpserver, asyncdispatch, times, random, db_postgres, cgi, strtabs, strutils, json, algorithm
+
+import defs
+
+proc handleHTTPErrors*(req: Request, code: HttpCode, msg: string) {.async.} =
+    let headers = {"Date": now().utc.format("ddd, dd MMM yyyy HH:mm:ss") & " GMT", "Content-type": "text/plain; charset=utf-8"}
+    await req.respond(code, msg, headers.newHttpHeaders())
+
+proc handlePlaintext*(req: Request) {.async.} =
+    let headers = {"Date": now().utc.format("ddd, dd MMM yyyy HH:mm:ss") & " GMT", "Content-type": "text/plain; charset=utf-8",  "Server": "Example"}
+    await req.respond(Http200, "Hello, World!", headers.newHttpHeaders())
+
+proc handleJson*(req: Request) {.async.} =
+    let headers = {"Date": now().utc.format("ddd, dd MMM yyyy HH:mm:ss") & " GMT", "Content-type": "application/json; charset=utf-8", "Server": "Example"}
+    await req.respond(Http200, $(%*{"message":"Hello, World!"}), headers.newHttpHeaders())
+
+proc handleDB*(req: Request) {.async.} =
+    let headers = {"Date": now().utc.format("ddd, dd MMM yyyy HH:mm:ss") & " GMT", "Content-type": "application/json; charset=utf-8", "Server": "Example"}
+    let queryResult = db.getRow(sql"""select * from "public"."World" where id = ?""", rand(1..10000))
+    await req.respond(Http200, $(%*{"id": queryResult[0] , "randomNumber": queryResult[1] }), headers.newHttpHeaders())
+
+proc handleQueries*(req: Request) {.async.} =
+    let queryObj = readData(req.url.query)
+    var count = 1
+    try:
+        count = clamp(parseInt(queryObj["queries"]), 1, 500)
+    except KeyError, ValueError:
+        count = 1
+    except:
+        await handleHTTPErrors(req, Http502, "Something is wrong")
+
+    var jsonList: DBQueryObjsList
+    for i in 1..count:
+        let queryResult = db.getRow(sql"""select * from "public"."World" where id = ?""", rand(1..10000))
+        let jsonNode = DBQueryObj(id: queryResult[0], randomNumber: queryResult[1])
+        jsonList.add(jsonNode)
+
+    let headers = {"Date": now().utc.format("ddd, dd MMM yyyy HH:mm:ss") & " GMT", "Content-type": "application/json; charset=utf-8", "Server": "Example"}
+    await req.respond(Http200, $(%*jsonList), headers.newHttpHeaders())
+
+proc handleFortunes*(req: Request) {.async.} =
+    var queryResult = db.getAllRows(sql"""select * from "public"."fortune" """)
+    queryResult.add(@["0",  "Additional fortune added at request time."])
+    let sortedResult = queryResult.sortedByIt(it[1])
+
+    var fortunesView = """
+<!DOCTYPE html>
+<html>
+<head><title>Fortunes</title></head>
+<body>
+<table>
+<tr><th>id</th><th>message</th></tr>
+"""
+
+    for i, v in sortedResult:
+        let fragment = "<tr><td>" & $v[0] & "</td><td>" & $v[1].xmlEncode() & "</td></tr>\n"
+        fortunesView.add(fragment)
+
+    fortunesView.add """
+</table>
+</body>
+</html>
+"""
+
+    let headers = {"Date": now().utc.format("ddd, dd MMM yyyy HH:mm:ss") & " GMT", "Content-type": "text/html; charset=UTF-8", "Server": "Example"}
+    await req.respond(Http200, fortunesView, headers.newHttpHeaders())
+    
+    
+proc handleUpdates*(req: Request) {.async.} =
+    let queryObj = readData(req.url.query)
+    var count = 1
+    try:
+        count = clamp(parseInt(queryObj["queries"]), 1, 500)
+    except KeyError, ValueError:
+        count = 1
+    except:
+        await handleHTTPErrors(req, Http502, "Something is wrong")
+
+    var insertStatement = """
+update "public"."World" as w set
+    randomNumber = tmp.randomNumber
+from (values """
+
+    var jsonList: seq[DBQueryObj]
+    for i in 1..count:
+        let randId = rand(1..10000)
+        let randVal = rand(1..10000)
+        let queryResult = db.getRow(sql"""select * from "public"."World" where id = ?""", randId)
+
+        insertStatement.add("(" & $randId & "," & $randVal & ")")
+
+        if i < count :
+            insertStatement.add(",")
+
+        let jsonNode = DBQueryObj(id: queryResult[0], randomNumber: $randVal)
+        jsonList.add(jsonNode)
+
+    insertStatement.add("""
+) as tmp(id, randomNumber)
+where tmp.id = w.id;
+""")
+
+    db.exec(sql insertStatement)
+
+    let headers = {"Date": now().utc.format("ddd, dd MMM yyyy HH:mm:ss") & " GMT", "Content-type": "application/json; charset=utf-8", "Server": "Example"}
+    await req.respond(Http200, $(%*jsonList), headers.newHttpHeaders())

+ 36 - 0
frameworks/Nim/nim-stdlib/src/nimstdlib.nim

@@ -0,0 +1,36 @@
+import asynchttpserver, asyncdispatch, db_postgres
+
+import defs, handlers
+
+const port = 8080
+
+proc main {.async.} =
+    var server = newAsyncHttpServer()
+
+    proc cb(req: Request) {.async.} =
+        case req.reqMethod
+        of HttpGet:
+            case req.url.path
+            of "/plaintext":    await handlePlaintext(req)
+            of "/json":         await handleJson(req)
+            of "/db":           await handleDB(req)
+            of "/queries":      await handleQueries(req)
+            of "/fortunes":     await handleFortunes(req)
+            of "/updates":      await handleUpdates(req)
+            else:               await handleHTTPErrors(req, Http404, "URL doesn't exists")
+        else:               await handleHTTPErrors(req, Http405, "Method not allowed")
+
+    server.listen Port(port)
+    echo "Starting server on port: " & $port
+    
+    let dbPing = db.getValue(sql"select now()")
+    echo "Connected to Database at: " & $dbPing
+    
+    while true:
+        if server.shouldAcceptRequest():
+            await server.acceptRequest(cb)
+        else:
+            poll()
+
+asyncCheck main()
+runForever()