浏览代码

Add the facil.io framework (#3197)

* Add the facil.io framework

The [facil.io micro framework](http://facil.io) is somewhat oriented
for Websockets and pub/sub services, but it’s also used for RESTful
APIs and it powers the Ruby iodine server (an application server).

I think it would be great to add it to the benchmarking suite as well.

* Remove redundant file.

* Link to specific version

As requested… was easier than I thought :-)
Bo 7 年之前
父节点
当前提交
107df41838

+ 1 - 0
.travis.yml

@@ -12,6 +12,7 @@ python:
 env:
   matrix:
     - "TESTDIR=C/duda"
+    - "TESTDIR=C/facil.io"
     - "TESTDIR=C/onion"
     - "TESTDIR=C/h2o"
     - "TESTDIR=C/octane"

+ 5 - 0
frameworks/C/facil.io/.gitignore

@@ -0,0 +1,5 @@
+# Add any files that are created at build/run-time
+#
+# Example: *.class, *.pyc, bin/
+
+facil_app/

+ 78 - 0
frameworks/C/facil.io/README.md

@@ -0,0 +1,78 @@
+# facil.io Benchmarking Test
+
+Benchmarks for the [facil.io framework](http://facil.io).
+
+### Test Type Implementation Source Code
+
+* [JSON](bench_app.c)
+* [PLAINTEXT](bench_app.c)
+
+*Missing* tests:
+
+* [DB](bench_app.c)
+* [QUERY](bench_app.c)
+* [CACHED QUERY](bench_app.c)
+* [UPDATE](bench_app.c)
+* [FORTUNES](bench_app.c)
+
+## Important Libraries
+The tests were run with:
+* [facil.io](http://facil.io)
+
+## Adding Tests
+
+When adding tests, please remember that:
+
+* [facil.io](http://facil.io) was designed to be evented.
+
+    For example, instead of waiting for Database results, please use `http_pause` and `http_resume` to pause a request from processing until the Database results arrived (at which point, remember to resume the request).
+
+    If using the evented approach is impossible, add threads by updating the command line `-t` argument to an increased thread count.
+
+* [facil.io](http://facil.io) assumes memory ownership oriented design.
+
+    This means that functions that place data into another object (i.e., setting header values, hash values etc') take ownership of the data *but not it's key*.
+
+    For example, when adding an HTTP header, the header **name** (key) is owned by the calling function (which should free the header name when it's done with it) - but the header **value** is now owned by the header collection and can no longer be used by the calling function (unless duplicated using `fiobj_dup`).
+
+    This only applies to functions that place the data into an object (see `FIOBJ` documentation). This doesn't apply to send/receive functions such as `pubsub_publish` or pub/sub handlers where the data is "passed through" (or copied) without being placed into an accessible object.
+
+## Test URLs
+### JSON
+
+http://localhost:8080/json
+
+### PLAINTEXT
+
+http://localhost:8080/plaintext
+
+<!--
+### DB
+
+(Not implemented for this version)
+
+http://localhost:8080/db
+
+### QUERY
+
+(Not implemented for this version)
+
+http://localhost:8080/query?queries=
+
+### CACHED QUERY
+
+(Not implemented for this version)
+
+http://localhost:8080/cached_query?queries=
+
+### UPDATE
+
+(Not implemented for this version)
+
+http://localhost:8080/update?queries=
+
+### FORTUNES
+
+(Not implemented for this version)
+
+http://localhost:8080/fortunes -->

+ 202 - 0
frameworks/C/facil.io/bench_app.c

@@ -0,0 +1,202 @@
+/*
+This is an incomplete example meant to be used as a benchmark application for
+the TechEmpower Framework Benchmarks. See:
+http://frameworkbenchmarks.readthedocs.io/en/latest/
+
+At the moment it's incomplete and might be broken.
+*/
+#include "http.h"
+
+#include "fio_cli.h"
+#include "fio_hashmap.h"
+
+/* *****************************************************************************
+Internal Helpers
+***************************************************************************** */
+
+/* initialize CLI helper and manage it's default options */
+static void cli_init(int argc, char const *argv[]);
+
+/* cleanup any leftovers */
+static void cleanup(void);
+
+/* reusable objects */
+static FIOBJ HTTP_HEADER_SERVER;
+static FIOBJ HTTP_VALUE_SERVER;
+static FIOBJ JSON_KEY;
+static FIOBJ JSON_VALUE;
+
+/* *****************************************************************************
+Routing
+***************************************************************************** */
+
+/* adds a route to our simple router */
+static void route_add(char *path, void (*handler)(http_s *));
+
+/* routes a request to the correct handler */
+static void route_perform(http_s *);
+
+/* cleanup for our router */
+static void route_clear(void);
+
+/* *****************************************************************************
+Request handlers
+***************************************************************************** */
+
+/* handles JSON requests */
+static void on_request_json(http_s *h);
+
+/* handles plain text requests (Hello World) */
+static void on_request_plain_text(http_s *h);
+
+/* *****************************************************************************
+The main function
+***************************************************************************** */
+int main(int argc, char const *argv[]) {
+  /* initialize the CLI helper and options */
+  cli_init(argc, argv);
+
+  /* sertup routes */
+  route_add("/json", on_request_json);
+  route_add("/plaintext", on_request_plain_text);
+
+  /* Server name and header */
+  HTTP_HEADER_SERVER = fiobj_str_new("server", 6);
+  HTTP_VALUE_SERVER = fiobj_strprintf("facil.io %u.%u.%u", FACIL_VERSION_MAJOR,
+                                      FACIL_VERSION_MINOR, FACIL_VERSION_PATCH);
+  /* JSON values to be serialized */
+  JSON_KEY = fiobj_str_new("message", 7);
+  JSON_VALUE = fiobj_str_new("Hello, World!", 13);
+
+  /* Test for static file service */
+  const char *public_folder = fio_cli_get_str("www");
+  if (public_folder) {
+    fprintf(stderr, "* serving static files from:%s\n", public_folder);
+  }
+
+  /* listen to HTTP connections */
+  http_listen(fio_cli_get_str("port"), fio_cli_get_str("address"),
+              .on_request = route_perform, .public_folder = public_folder,
+              .log = fio_cli_get_int("log"));
+
+  /* Start the facil.io reactor */
+  facil_run(.threads = fio_cli_get_int("t"), .processes = fio_cli_get_int("w"));
+
+  /* perform cleanup */
+  cleanup();
+  return 0;
+}
+
+/* *****************************************************************************
+Request handlers
+***************************************************************************** */
+
+/* handles JSON requests */
+static void on_request_json(http_s *h) {
+  http_set_header(h, HTTP_HEADER_CONTENT_TYPE, http_mimetype_find("json", 4));
+  FIOBJ json;
+  /* create a new Hash to be serialized for every request */
+  FIOBJ hash = fiobj_hash_new();
+  fiobj_hash_set(hash, JSON_KEY, fiobj_dup(JSON_VALUE));
+  json = fiobj_obj2json(hash, 0);
+  fiobj_free(hash);
+  fio_cstr_s tmp = fiobj_obj2cstr(json);
+  http_send_body(h, tmp.data, tmp.len);
+  fiobj_free(json);
+}
+
+/* handles plain text requests (Hello World) */
+static void on_request_plain_text(http_s *h) {
+  http_set_header(h, HTTP_HEADER_CONTENT_TYPE, http_mimetype_find("txt", 3));
+  http_send_body(h, "Hello, World!", 13);
+}
+
+/* *****************************************************************************
+CLI
+***************************************************************************** */
+
+/* initialize CLI helper and manage it's default options */
+static void cli_init(int argc, char const *argv[]) {
+  fio_cli_start(argc, argv,
+                "This is a facil.io framework benchmark application.\n"
+                "\nFor details about the benchmarks visit:\n"
+                "http://frameworkbenchmarks.readthedocs.io/en/latest/\n"
+                "\nThe following arguments are supported:");
+  fio_cli_accept_num("threads t",
+                     "The number of threads to use. System dependent default.");
+  fio_cli_accept_num(
+      "workers w", "The number of processes to use. System dependent default.");
+  fio_cli_accept_num(
+      "port p", "The port number to listen to (set to 0 for Unix Sockets.");
+  fio_cli_accept_str("address b", "The address to bind to.");
+  fio_cli_accept_str("public www",
+                     "A public folder for serve an HTTP static file service.");
+  fio_cli_accept_bool("log v", "Turns logging on (logs to terminal).");
+  fio_cli_accept_str("database db", "The database adrress.");
+  fio_cli_accept_num("database-port dbp", "The database port.");
+
+  /* setup default port */
+  if (!fio_cli_get_str("p"))
+    fio_cli_set_str("p", "8080");
+
+  /* setup database address */
+  if (!fio_cli_get_str("db")) {
+    char *database = getenv("DBHOST");
+    if (!database)
+      database = "localhost";
+    fio_cli_set_str("db", database);
+  }
+  /* setup database port - default for Redis */
+  if (!fio_cli_get_str("dbp"))
+    fio_cli_set_str("dbp", "6379");
+}
+
+/* *****************************************************************************
+Routing
+***************************************************************************** */
+
+/* the router is a simple hash map */
+static fio_hash_s routes;
+
+/* adds a route to our simple router */
+static void route_add(char *path, void (*handler)(http_s *)) {
+  /* add handler to the hash map */
+  size_t len = strlen(path);
+  uint64_t hash = fio_siphash(path, len);
+  fio_hash_insert(&routes, hash, (void *)(uintptr_t)handler);
+}
+
+/* routes a request to the correct handler */
+static void route_perform(http_s *h) {
+  /* add required Serevr header */
+  http_set_header(h, HTTP_HEADER_SERVER, fiobj_dup(HTTP_VALUE_SERVER));
+  /* collect path from hash map */
+  fio_cstr_s tmp = fiobj_obj2cstr(h->path);
+  uint64_t hash = fio_siphash(tmp.data, tmp.len);
+  void (*handler)(http_s *) =
+      (void (*)(http_s *))(uintptr_t)fio_hash_find(&routes, hash);
+  /* forward request or send error */
+  if (handler) {
+    handler(h);
+    return;
+  }
+  http_send_error(h, 404);
+}
+
+/* cleanup for our router */
+static void route_clear(void) { fio_hash_free(&routes); }
+
+/* *****************************************************************************
+Cleanup
+***************************************************************************** */
+
+/* cleanup any leftovers */
+static void cleanup(void) {
+  fio_cli_end();
+  fiobj_free(HTTP_HEADER_SERVER);
+  fiobj_free(HTTP_VALUE_SERVER);
+  fiobj_free(JSON_KEY);
+  fiobj_free(JSON_VALUE);
+
+  route_clear();
+}

+ 27 - 0
frameworks/C/facil.io/benchmark_config.json

@@ -0,0 +1,27 @@
+{
+  "framework": "facil.io",
+  "tests": [
+    {
+      "default": {
+        "setup_file": "setup",
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "None",
+        "framework": "facil.io",
+        "language": "C",
+        "flavor": "None",
+        "orm": "Raw",
+        "platform": "None",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "facil.io",
+        "notes": "",
+        "versus": "None"
+      }
+    }
+  ]
+}

+ 28 - 0
frameworks/C/facil.io/setup.sh

@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# enter root folder
+cd $TROOT
+
+if ! [ -d facil_app ] ; then
+	mkdir facil_app
+	cd facil_app
+	curl -s -o facil.io.tar.gz -LJO https://api.github.com/repos/boazsegev/facil.io/tarball/v.0.6.0.beta
+	tar --strip-components=1 -xzf facil.io.tar.gz
+	if [ $? -ne 0 ]; then echo "Couldn't extract tar."; exit 1; fi
+	rm facil.io.tar.gz
+	./scripts/new/cleanup
+	cd ..
+fi
+
+# recompile test
+rm -r facil_app/src
+mkdir facil_app/src
+cp bench_app.c facil_app/src
+cd facil_app
+make -j build
+
+# run test
+cd tmp
+./demo -b TFB-server -p 8080 -db "TFB-database" -w -1 -t 1 &
+# step out
+cd ../..

+ 1 - 0
frameworks/C/facil.io/source_code

@@ -0,0 +1 @@
+./facil.io/bench_app.c