Browse Source

feat: make OCaml webmachine use atdgen (#6140)

* fix Date header warning
* replace Ezjsonm with atdgen + yojson for a more production-esque setup
* restructure project to resemble a production setup
* introduce a test with the flambda compiler
Robin Björklin 4 years ago
parent
commit
bbcd14cc27

+ 21 - 0
frameworks/OCaml/webmachine/benchmark_config.json

@@ -42,6 +42,27 @@
         "display_name": "webmachine-haproxy",
         "display_name": "webmachine-haproxy",
         "notes": "",
         "notes": "",
         "versus": "None"
         "versus": "None"
+      },
+      "flambda": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "query_url": "/queries/",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "postgres",
+        "framework": "webmachine",
+        "language": "OCaml",
+        "flavor": "None",
+        "orm": "Raw",
+        "platform": "cohttp",
+        "webserver": "haproxy",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "webmachine-flambda",
+        "notes": "",
+        "versus": "None"
       }
       }
   }]
   }]
 }
 }

+ 3 - 2
frameworks/OCaml/webmachine/src/Makefile

@@ -1,4 +1,5 @@
 BINARY = tfb
 BINARY = tfb
+PROFILE ?= release
 
 
 .PHONY: install build run gen-opam
 .PHONY: install build run gen-opam
 
 
@@ -9,7 +10,7 @@ gen-opam:
 	dune build @install
 	dune build @install
 
 
 build:
 build:
-	opam exec -- dune build --profile release $(BINARY).exe
+	opam exec -- dune build --profile $(PROFILE)
 
 
 run:
 run:
-	./_build/default/bin/$(BINARY).exe
+	./_build/default/src/bin/$(BINARY).exe

+ 12 - 3
frameworks/OCaml/webmachine/src/dune-project

@@ -8,7 +8,7 @@
 (authors "Robin Björklin")
 (authors "Robin Björklin")
 
 
 (package
 (package
- (name webmachine-tfb)
+ (name tfb)
  (synopsis "Rudimentary implementation of the Tech Empower Benchmark suite")
  (synopsis "Rudimentary implementation of the Tech Empower Benchmark suite")
  (depends
  (depends
   (dune (>= 2.7.1))
   (dune (>= 2.7.1))
@@ -19,6 +19,15 @@
   (caqti-lwt (>= 1.2.0))
   (caqti-lwt (>= 1.2.0))
   (caqti-driver-postgresql (>= 1.2.4))
   (caqti-driver-postgresql (>= 1.2.4))
   (cohttp-lwt-unix (>= 2.5.4))
   (cohttp-lwt-unix (>= 2.5.4))
-  (ptime (>= 0.8.5))
-  (ezjsonm (>= 1.2.0))
   (lwt_ppx (>= 2.0.1))))
   (lwt_ppx (>= 2.0.1))))
+
+(package
+ (name lib)
+ (synopsis "WIP library")
+ (depends
+  (dune (>= 2.7.1))
+  (biniou (>= 1.2.1))
+  (yojson (>= 1.7.0))
+  (atd (>= 2.2.1))
+  (atdgen (>= 2.2.1))
+  (atdgen-runtime (>= 2.2.1))))

+ 31 - 0
frameworks/OCaml/webmachine/src/lib.opam

@@ -0,0 +1,31 @@
+# This file is generated by dune, edit dune-project instead
+opam-version: "2.0"
+synopsis: "WIP library"
+authors: ["Robin Björklin"]
+license: "MIT"
+homepage: "https://github.com/TechEmpower/FrameworkBenchmarks"
+bug-reports: "https://github.com/TechEmpower/FrameworkBenchmarks/issues"
+depends: [
+  "dune" {>= "2.7" & >= "2.7.1"}
+  "biniou" {>= "1.2.1"}
+  "yojson" {>= "1.7.0"}
+  "atd" {>= "2.2.1"}
+  "atdgen" {>= "2.2.1"}
+  "atdgen-runtime" {>= "2.2.1"}
+  "odoc" {with-doc}
+]
+build: [
+  ["dune" "subst"] {dev}
+  [
+    "dune"
+    "build"
+    "-p"
+    name
+    "-j"
+    jobs
+    "@install"
+    "@runtest" {with-test}
+    "@doc" {with-doc}
+  ]
+]
+dev-repo: "git+https://github.com/TechEmpower/FrameworkBenchmarks.git"

+ 3 - 3
frameworks/OCaml/webmachine/src/dune → frameworks/OCaml/webmachine/src/src/bin/dune

@@ -1,7 +1,7 @@
 (executable
 (executable
  (libraries webmachine lwt cohttp-lwt-unix ptime ptime.clock ptime.clock.os
  (libraries webmachine lwt cohttp-lwt-unix ptime ptime.clock ptime.clock.os
-            caqti caqti-lwt caqti-driver-postgresql ezjsonm logs)
+            caqti caqti-lwt caqti-driver-postgresql yojson atdgen-runtime lib)
  (preprocess (pps lwt_ppx))
  (preprocess (pps lwt_ppx))
- (modules tfb)
+ (public_name tfb)
+ (package tfb)
  (name tfb))
  (name tfb))
-

+ 30 - 24
frameworks/OCaml/webmachine/src/tfb.ml → frameworks/OCaml/webmachine/src/src/bin/tfb.ml

@@ -16,10 +16,6 @@ module Wm = struct
   include Webmachine.Make (Cohttp_lwt_unix__Io) (UnixClock)
   include Webmachine.Make (Cohttp_lwt_unix__Io) (UnixClock)
 end
 end
 
 
-module World = struct
-  type t = { id : int; randomNumber : int }
-end
-
 let pool =
 let pool =
   let connection_url =
   let connection_url =
     "postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?connect_timeout=15"
     "postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world?connect_timeout=15"
@@ -64,8 +60,8 @@ class hello =
       Wm.continue (`String text) rd
       Wm.continue (`String text) rd
 
 
     method private to_json rd =
     method private to_json rd =
-      let json = Ezjsonm.value (`O [ ("message", `String "Hello, World!") ]) in
-      Wm.continue (`String (Ezjsonm.value_to_string ~minify:true json)) rd
+      let json = Lib.Message_t.{ message = "Hello, World!" } in
+      Wm.continue (`String (Lib.Message_j.string_of_message json)) rd
   end
   end
 
 
 class db =
 class db =
@@ -89,14 +85,10 @@ class db =
         | Error _ -> failwith "whoops"
         | Error _ -> failwith "whoops"
       in
       in
       let json =
       let json =
-        Ezjsonm.value
-          (`O
-            [
-              ("id", `Float (float_of_int id));
-              ("randomNumber", `Float (float_of_int randomNumber));
-            ])
+        Lib.Db_t.
+          { id = float_of_int id; randomNumber = float_of_int randomNumber }
       in
       in
-      Wm.continue (`String (Ezjsonm.value_to_string ~minify:true json)) rd
+      Wm.continue (`String (Lib.Db_j.string_of_query json)) rd
   end
   end
 
 
 class queries =
 class queries =
@@ -136,18 +128,14 @@ class queries =
       in
       in
       let%lwt resolved_response = Lwt.all response in
       let%lwt resolved_response = Lwt.all response in
       let json =
       let json =
-        Ezjsonm.list
+        List.map
           (fun tup ->
           (fun tup ->
             let id, randomNumber = tup in
             let id, randomNumber = tup in
-            Ezjsonm.value
-              (`O
-                [
-                  ("id", `Float (float_of_int id));
-                  ("randomNumber", `Float (float_of_int randomNumber));
-                ]))
+            Lib.Db_t.
+              { id = float_of_int id; randomNumber = float_of_int randomNumber })
           resolved_response
           resolved_response
       in
       in
-      Wm.continue (`String (Ezjsonm.value_to_string ~minify:true json)) rd
+      Wm.continue (`String (Lib.Db_j.string_of_queries json)) rd
   end
   end
 
 
 let main () =
 let main () =
@@ -172,9 +160,7 @@ let main () =
      | Some result -> result)
      | Some result -> result)
     >>= fun (status, headers, body, _) ->
     >>= fun (status, headers, body, _) ->
     let headers = Header.add headers "Server" "webmachine" in
     let headers = Header.add headers "Server" "webmachine" in
-    let headers =
-      Header.add headers "Date" (Ptime.to_rfc3339 (Ptime_clock.now ()))
-    in
+    let headers = Header.add headers "Date" (Lib.Time.now ()) in
     Server.respond ~headers ~body ~status ()
     Server.respond ~headers ~body ~status ()
   in
   in
 
 
@@ -183,6 +169,26 @@ let main () =
   Printf.eprintf "hello_lwt: listening on 0.0.0.0:%d%!" port
   Printf.eprintf "hello_lwt: listening on 0.0.0.0:%d%!" port
 
 
 let () =
 let () =
+  let options =
+    [
+      ("fd_passing", `fd_passing);
+      ("fdatasync", `fdatasync);
+      ("get_affinity", `get_affinity);
+      ("get_cpu", `get_cpu);
+      ("get_credentials", `get_credentials);
+      ("libev", `libev);
+      ("madvise", `madvise);
+      ("mincore", `mincore);
+      ("recv_msg", `recv_msg);
+      ("send_msg", `send_msg);
+      ("set_affinity", `set_affinity);
+      ("wait4", `wait4);
+    ]
+  in
+  List.iter
+    (fun (str, opt) ->
+      print_endline ("option " ^ str ^ ": " ^ string_of_bool (Lwt_sys.have opt)))
+    options;
   (* https://github.com/mirage/ocaml-cohttp/issues/328#issuecomment-222583580 *)
   (* https://github.com/mirage/ocaml-cohttp/issues/328#issuecomment-222583580 *)
   Lwt_io.set_default_buffer_size 0x10000;
   Lwt_io.set_default_buffer_size 0x10000;
   Lwt_main.run (main ())
   Lwt_main.run (main ())

+ 6 - 0
frameworks/OCaml/webmachine/src/src/lib/db.atd

@@ -0,0 +1,6 @@
+type queries = query list
+    
+type query = {
+    id : float;
+    randomNumber : float;
+}

+ 29 - 0
frameworks/OCaml/webmachine/src/src/lib/dune

@@ -0,0 +1,29 @@
+(library
+ (name lib)
+ (public_name lib)
+ (libraries yojson atdgen-runtime)
+ (preprocess (pps lwt_ppx)))
+
+(rule
+ (targets message_t.ml
+          message_t.mli)
+ (deps    message.atd)
+ (action  (run atdgen -t %{deps})))
+
+(rule
+ (targets message_j.ml
+          message_j.mli)
+ (deps    message.atd)
+ (action  (run atdgen -j %{deps})))
+
+(rule
+ (targets db_t.ml
+          db_t.mli)
+ (deps    db.atd)
+ (action  (run atdgen -t %{deps})))
+
+(rule
+ (targets db_j.ml
+          db_j.mli)
+ (deps    db.atd)
+ (action  (run atdgen -j %{deps})))

+ 3 - 0
frameworks/OCaml/webmachine/src/src/lib/message.atd

@@ -0,0 +1,3 @@
+type message = {
+  message : string;
+}

+ 29 - 0
frameworks/OCaml/webmachine/src/src/lib/time.ml

@@ -0,0 +1,29 @@
+let weekday Unix.{tm_wday;_} = match tm_wday with
+  | 0 -> "Sun"
+  | 1 -> "Mon"
+  | 2 -> "Tue"
+  | 3 -> "Wed"
+  | 4 -> "Thu"
+  | 5 -> "Fri"
+  | 6 -> "Sat"
+  | _ -> failwith "weekday"
+
+let month Unix.{tm_mon;_} = match tm_mon with
+  | 0 -> "Jan"
+  | 1 -> "Feb"
+  | 2 -> "Mar"
+  | 3 -> "Apr"
+  | 4 -> "May"
+  | 5 -> "Jun"
+  | 6 -> "Jul"
+  | 7 -> "Aug"
+  | 8 -> "Sep"
+  | 9 -> "Oct"
+  | 10 -> "Nov"
+  | 11 -> "Dec"
+  | _ -> failwith "month"
+
+let gmt tm =
+  Printf.sprintf "%s, %02u %s %04u %02u:%02u:%02u GMT" (weekday tm) tm.tm_mday (month tm) (tm.tm_year + 1900)  tm.tm_hour tm.tm_min tm.tm_sec
+
+let now () = (gmt (Unix.gmtime (Unix.gettimeofday ())))

+ 0 - 2
frameworks/OCaml/webmachine/src/webmachine-tfb.opam → frameworks/OCaml/webmachine/src/tfb.opam

@@ -14,8 +14,6 @@ depends: [
   "caqti-lwt" {>= "1.2.0"}
   "caqti-lwt" {>= "1.2.0"}
   "caqti-driver-postgresql" {>= "1.2.4"}
   "caqti-driver-postgresql" {>= "1.2.4"}
   "cohttp-lwt-unix" {>= "2.5.4"}
   "cohttp-lwt-unix" {>= "2.5.4"}
-  "ptime" {>= "0.8.5"}
-  "ezjsonm" {>= "1.2.0"}
   "lwt_ppx" {>= "2.0.1"}
   "lwt_ppx" {>= "2.0.1"}
   "odoc" {with-doc}
   "odoc" {with-doc}
 ]
 ]

+ 1 - 1
frameworks/OCaml/webmachine/start-servers.sh

@@ -5,6 +5,6 @@ P=9000
 END=$(($P+$CPU_COUNT))
 END=$(($P+$CPU_COUNT))
 
 
 while [ $P -lt $END ]; do
 while [ $P -lt $END ]; do
-  PORT=$P /webmachine/_build/default/tfb.exe &
+  PORT=$P /webmachine/_build/default/src/bin/tfb.exe &
   let P=P+1
   let P=P+1
 done
 done

+ 25 - 0
frameworks/OCaml/webmachine/webmachine-flambda.dockerfile

@@ -0,0 +1,25 @@
+FROM ocurrent/opam:debian-10-ocaml-4.11-flambda
+
+ENV DIR webmachine
+# https://blog.packagecloud.io/eng/2017/02/21/set-environment-variable-save-thousands-of-system-calls/
+ENV TZ  :/etc/localtime
+
+# https://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html
+# https://linux.die.net/man/1/ocamlrun
+# https://blog.janestreet.com/memory-allocator-showdown/
+ENV OCAMLRUNPARAM a=2,o=240
+
+RUN sudo apt-get install -y libpq-dev libev-dev pkg-config m4
+
+WORKDIR /${DIR}
+
+COPY src/tfb.opam src/Makefile /${DIR}/
+COPY src/lib.opam src/Makefile /${DIR}/
+
+RUN make install
+
+COPY ./src /${DIR}
+
+RUN sudo chown -R opam: . && make build
+
+ENTRYPOINT _build/default/src/bin/tfb.exe

+ 4 - 1
frameworks/OCaml/webmachine/webmachine-haproxy.dockerfile

@@ -1,6 +1,8 @@
 FROM ocurrent/opam:fedora-32-ocaml-4.11
 FROM ocurrent/opam:fedora-32-ocaml-4.11
 
 
 ENV DIR webmachine
 ENV DIR webmachine
+# https://blog.packagecloud.io/eng/2017/02/21/set-environment-variable-save-thousands-of-system-calls/
+ENV TZ  :/etc/localtime
 
 
 # https://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html
 # https://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html
 # https://linux.die.net/man/1/ocamlrun
 # https://linux.die.net/man/1/ocamlrun
@@ -11,7 +13,8 @@ RUN sudo dnf install --assumeyes diffutils postgresql-devel libev-devel
 
 
 WORKDIR /${DIR}
 WORKDIR /${DIR}
 
 
-COPY src/webmachine-tfb.opam src/Makefile /${DIR}/
+COPY src/tfb.opam src/Makefile /${DIR}/
+COPY src/lib.opam src/Makefile /${DIR}/
 
 
 RUN make install
 RUN make install
 
 

+ 5 - 2
frameworks/OCaml/webmachine/webmachine.dockerfile

@@ -1,6 +1,8 @@
 FROM ocurrent/opam:fedora-32-ocaml-4.11
 FROM ocurrent/opam:fedora-32-ocaml-4.11
 
 
 ENV DIR webmachine
 ENV DIR webmachine
+# https://blog.packagecloud.io/eng/2017/02/21/set-environment-variable-save-thousands-of-system-calls/
+ENV TZ  :/etc/localtime
 
 
 # https://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html
 # https://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html
 # https://linux.die.net/man/1/ocamlrun
 # https://linux.die.net/man/1/ocamlrun
@@ -11,7 +13,8 @@ RUN sudo dnf install --assumeyes diffutils postgresql-devel libev-devel
 
 
 WORKDIR /${DIR}
 WORKDIR /${DIR}
 
 
-COPY src/webmachine-tfb.opam src/Makefile /${DIR}/
+COPY src/tfb.opam src/Makefile /${DIR}/
+COPY src/lib.opam src/Makefile /${DIR}/
 
 
 RUN make install
 RUN make install
 
 
@@ -19,4 +22,4 @@ COPY ./src /${DIR}
 
 
 RUN sudo chown -R opam: . && make build
 RUN sudo chown -R opam: . && make build
 
 
-ENTRYPOINT _build/default/tfb.exe
+ENTRYPOINT _build/default/src/bin/tfb.exe