Browse Source

Adds crystal toro (#5639)

* adds Toro framework for Crystal

* adds format

* fixes the README

* removes unnecessary license

Co-authored-by: Carlos Donderis <[email protected]>
Carlos Donderis 5 years ago
parent
commit
db8fcb9b65

+ 51 - 0
frameworks/Crystal/toro/README.md

@@ -0,0 +1,51 @@
+This is the [Toro]https://github.com/soveran/toro) test of the Framework Benchmarks.
+Crystal is a new language that closely resembles Ruby with a goal of removing typed variables and parameters (instead inferencing), whilst maintaining top speed through bindings into C.
+
+Toro is a minimalistic tree oriented routing web framework for Crystal.
+
+
+
+
+
+
+# Toro Benchmarking Test
+
+### Test Type Implementation Source Code
+
+* [JSON](toro.cr)
+* [PLAINTEXT](toro.cr)
+* [DB](toro.cr)
+* [QUERY](toro.cr)
+* [CACHED QUERY](toro.cr)
+* [UPDATE](toro.cr)
+* [FORTUNES](toro.cr)
+
+
+## Test URLs
+### JSON
+
+http://localhost:8080/json
+
+### PLAINTEXT
+
+http://localhost:8080/plaintext
+
+### DB
+
+http://localhost:8080/db
+
+### QUERY
+
+http://localhost:8080/query?queries=
+
+### CACHED QUERY
+
+http://localhost:8080/cached_query?queries=
+
+### UPDATE
+
+http://localhost:8080/update?queries=
+
+### FORTUNES
+
+http://localhost:8080/fortunes

+ 30 - 0
frameworks/Crystal/toro/benchmark_config.json

@@ -0,0 +1,30 @@
+{
+  "framework": "toro",
+  "tests": [
+    {
+      "default": {
+        "json_url": "/json",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "Toro",
+        "language": "Crystal",
+        "flavor": "None",
+        "orm": "Raw",
+        "platform": "None",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "Toro (PostgreSQL)",
+        "notes": "",
+        "versus": "crystal"
+      }
+    }
+  ]
+}

+ 7 - 0
frameworks/Crystal/toro/run.sh

@@ -0,0 +1,7 @@
+#!/bin/bash
+
+for i in $(seq 1 $(nproc --all)); do
+  ./toro -p 8080 &
+done
+
+wait

+ 16 - 0
frameworks/Crystal/toro/shard.yml

@@ -0,0 +1,16 @@
+name: toro
+version: 0.1.0
+
+dependencies:
+  toro:
+    github: soveran/toro
+    version: 0.4.1
+  pg:
+    github: will/crystal-pg
+    version: 0.20.0
+
+targets:
+  toro:
+    main: toro.cr
+
+crystal: 0.34.0

+ 134 - 0
frameworks/Crystal/toro/toro.cr

@@ -0,0 +1,134 @@
+require "toro"
+require "pg"
+
+APPDB      = DB.open(ENV["DATABASE_URL"])
+ID_MAXIMUM = 10_000
+
+# Includes some monkey patches for Toro to make the benchmarks work
+module Toro
+  abstract class Router
+    # By fefault html macro doesn't adds '; charset=UTF-8'
+    macro html(template)
+      header "Content-Type", "text/html; charset=UTF-8"
+      render {{template}}
+    end
+
+    # Original write uses context.response.puts(str)
+    # this adds 1 extra byte to the response \n that might affect the performance
+    def write(str)
+      context.response.print(str)
+    end
+  end
+end
+
+private def random_world
+  id = rand(1..ID_MAXIMUM)
+  id, random_number = APPDB.query_one("SELECT id, randomNumber FROM world WHERE id = $1", id, as: {Int32, Int32})
+  {id: id, randomNumber: random_number}
+end
+
+private def set_world(world)
+  APPDB.exec("UPDATE world SET randomNumber = $1 WHERE id = $2", world[:randomNumber], world[:id])
+  world
+end
+
+private def fortunes
+  data = Array(NamedTuple(id: Int32, message: String)).new
+
+  APPDB.query_each("SELECT id, message FROM Fortune") do |rs|
+    data.push({id: rs.read(Int32), message: rs.read(String)})
+  end
+
+  data
+end
+
+private def sanitized_query_count(request)
+  queries = request.query_params["queries"]? || "1"
+  queries = queries.to_i? || 1
+  queries.clamp(1..500)
+end
+
+class App < Toro::Router
+  def routes
+    #
+    # Basic Tests
+    #
+
+    # Test 1: JSON Serialization
+    on "json" do
+      get do
+        header("Server", "Toro")
+        header("Date", HTTP.format_time(Time.utc))
+        json({message: "Hello, World!"})
+      end
+    end
+
+    # Test 6: Plaintext
+    on "plaintext" do
+      get do
+        header("Server", "Toro")
+        header("Date", HTTP.format_time(Time.utc))
+        text "Hello, World!"
+      end
+    end
+
+    #
+    # Postgres DatabaseTests
+    #
+
+    # Postgres Test 2: Single database query
+    on "db" do
+      get do
+        header("Server", "Toro")
+        header("Date", HTTP.format_time(Time.utc))
+        json random_world
+      end
+    end
+
+    on "queries" do
+      get do
+        results = (1..sanitized_query_count(context.request)).map do
+          random_world
+        end
+
+        header("Server", "Toro")
+        header("Date", HTTP.format_time(Time.utc))
+        json results
+      end
+    end
+
+    on "fortunes" do
+      get do
+        data = fortunes
+        additional_fortune = {
+          id:      0,
+          message: "Additional fortune added at request time.",
+        }
+        data.push(additional_fortune)
+
+        data.sort_by! { |fortune| fortune[:message] }
+
+        header("Server", "Toro")
+        header("Date", HTTP.format_time(Time.utc))
+        html "views/fortunes"
+      end
+    end
+
+    on "updates" do
+      get do
+        updated = (1..sanitized_query_count(context.request)).map do
+          set_world({id: random_world[:id], randomNumber: rand(1..ID_MAXIMUM)})
+        end
+
+        header("Server", "Toro")
+        header("Date", HTTP.format_time(Time.utc))
+        json updated
+      end
+    end
+  end
+end
+
+# Start the app on port 8080.
+App.run(8080) do |server|
+  server.listen("0.0.0.0", 8080, reuse_port: true)
+end

+ 14 - 0
frameworks/Crystal/toro/toro.dockerfile

@@ -0,0 +1,14 @@
+FROM crystallang/crystal:0.34.0
+
+WORKDIR /toro
+COPY views views
+COPY run.sh run.sh
+COPY toro.cr toro.cr
+COPY shard.yml shard.yml
+
+ENV DATABASE_URL postgres://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world
+
+RUN shards install
+RUN crystal build  --release --no-debug toro.cr
+
+CMD bash run.sh

+ 20 - 0
frameworks/Crystal/toro/views/fortunes.ecr

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<title>Fortunes</title>
+</head>
+<body>
+	<table>
+		<tr>
+		<th>id</th>
+		<th>message</th>
+		</tr>
+		<% data.each do |fortune| %>
+			<tr>
+			<td><%= fortune[:id] %></td>
+			<td><%= HTML.escape(fortune[:message]) %></td>
+			</tr>
+		<% end %>
+	</table>
+</body>
+</html>