Browse Source

Add benchmark tests for the Drogon framework (#4438)

* Add benchmark tests for the Drogon framework

* Checkout a specific version of drogon
An Tao 6 years ago
parent
commit
6efa0ada6a

+ 1 - 0
.travis.yml

@@ -23,6 +23,7 @@ env:
      - "TESTDIR=C++/treefrog"
      - "TESTDIR=C++/treefrog"
      - "TESTDIR=C++/ulib"
      - "TESTDIR=C++/ulib"
      - "TESTDIR=C++/wt"
      - "TESTDIR=C++/wt"
+     - "TESTDIR=C++/drogon"
      - "TESTLANG=Clojure"
      - "TESTLANG=Clojure"
      - "TESTLANG=Crystal"
      - "TESTLANG=Crystal"
      - "TESTLANG=D"
      - "TESTLANG=D"

+ 17 - 0
frameworks/C++/drogon/README.md

@@ -0,0 +1,17 @@
+# drogon Benchmarking Test
+
+This is the [Drogon](https://github.com/an-tao/drogon) portion of a [benchmarking test suite](https://github.com/TechEmpower/FrameworkBenchmarks) comparing a variety of web development platforms.
+
+### Test Type Implementation Source Code
+
+* [JSON](drogon_benchmark/controllers/JsonCtl.cc)
+* [PLAINTEXT](drogon_benchmark/controllers/Plaintext.cc)
+
+## Test URLs
+### JSON
+
+http://localhost:8080/json
+
+### PLAINTEXT
+
+http://localhost:8080/plaintext

+ 26 - 0
frameworks/C++/drogon/benchmark_config.json

@@ -0,0 +1,26 @@
+{
+  "framework": "drogon",
+  "tests": [
+    {
+      "default": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Fullstack",
+        "database": "Postgres",
+        "framework": "drogon",
+        "language": "C++",
+        "flavor": "None",
+        "orm": "Micro",
+        "platform": "None",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "drogon",
+        "notes": "",
+        "versus": "None"
+      }
+    }
+  ]
+}

+ 48 - 0
frameworks/C++/drogon/drogon.dockerfile

@@ -0,0 +1,48 @@
+FROM ubuntu:18.04
+
+COPY ./ ./
+
+RUN  apt update -yqq && \
+     apt-get install -yqq software-properties-common && \
+	 apt install -yqq sudo curl wget cmake locales git \
+     openssl libssl-dev \
+     libjsoncpp-dev \
+     uuid-dev \
+     zlib1g-dev \
+	 postgresql-server-dev-all && \
+     add-apt-repository ppa:ubuntu-toolchain-r/test -y && \
+	 apt update -yqq && \
+	 apt install -yqq gcc-8 g++-8
+
+RUN locale-gen en_US.UTF-8
+
+ENV LANG en_US.UTF-8
+ENV LANGUAGE en_US:en
+ENV LC_ALL en_US.UTF-8
+
+ENV CC=gcc-8
+ENV CXX=g++-8
+ENV AR=gcc-ar-8
+ENV RANLIB=gcc-ranlib-8
+
+ENV IROOT=/install
+ENV DROGON_ROOT=$IROOT/drogon
+ENV TEST_PATH=/drogon_benchmark/build
+WORKDIR $IROOT
+
+RUN git clone https://github.com/an-tao/drogon
+
+WORKDIR $DROGON_ROOT
+
+RUN git checkout 8829203d0458145a93efae68aa856367e5a5757d
+
+RUN ./build.sh
+
+WORKDIR $TEST_PATH
+
+RUN cmake ..
+RUN make
+CMD ./drogon_benchmark
+
+
+

+ 36 - 0
frameworks/C++/drogon/drogon_benchmark/.gitignore

@@ -0,0 +1,36 @@
+# Prerequisites
+*.d
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+*.smod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
+
+build
+cmake-build-debug
+.idea

+ 84 - 0
frameworks/C++/drogon/drogon_benchmark/CMakeLists.txt

@@ -0,0 +1,84 @@
+cmake_minimum_required(VERSION 3.2)
+Project(drogon_benchmark)
+
+link_directories(/usr/local/lib)
+link_libraries(drogon trantor pthread dl)
+
+IF (CMAKE_SYSTEM_NAME MATCHES "Linux")
+    EXEC_PROGRAM (gcc ARGS "--version | grep '^gcc'|awk '{print $3}' | sed s'/)//g' | sed s'/-.*//g'" OUTPUT_VARIABLE version)
+    MESSAGE(STATUS "This is gcc version:: " ${version})
+    if(version LESS 5.4.0)
+        MESSAGE(STATUS "gcc is too old")
+        stop()
+    elseif(version LESS 7.1.0)
+        set(CMAKE_CXX_STD_FLAGS c++14)
+        MESSAGE(STATUS "c++14")
+    else()
+        set(CMAKE_CXX_STD_FLAGS c++17)
+        set(DR_DEFS "USE_STD_ANY")
+        MESSAGE(STATUS "c++17")
+    endif()
+else()
+    set(CMAKE_CXX_STD_FLAGS c++17)
+endif()
+
+if(CMAKE_BUILD_TYPE STREQUAL "")
+    set(CMAKE_BUILD_TYPE Release)
+endif()
+
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -std=${CMAKE_CXX_STD_FLAGS}")
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wall -std=${CMAKE_CXX_STD_FLAGS}")
+
+set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake_modules/)
+
+#jsoncpp
+find_package (Jsoncpp REQUIRED)
+include_directories(${JSONCPP_INCLUDE_DIRS})
+link_libraries(${JSONCPP_LIBRARIES})
+
+#uuid
+find_package (UUID REQUIRED)
+include_directories(${UUID_INCLUDE_DIR})
+link_libraries(${UUID_LIBRARIES})
+
+#OpenSSL
+find_package (OpenSSL)
+if(OpenSSL_FOUND)
+    link_libraries(${OPENSSL_LIBRARIES})
+endif()
+
+#zlib
+find_package(ZLIB REQUIRED)
+include_directories(${ZLIB_INCLUDE_DIR})
+link_libraries(${ZLIB_LIBRARIES})
+
+#find postgres
+find_package(PostgreSQL)
+if(PostgreSQL_FOUND)
+include_directories(${PostgreSQL_INCLUDE_DIR})
+link_libraries(${PostgreSQL_LIBRARIES})
+endif()
+
+
+AUX_SOURCE_DIRECTORY(./ SRC_DIR)
+AUX_SOURCE_DIRECTORY(controllers CTL_SRC)
+AUX_SOURCE_DIRECTORY(filters FILTER_SRC)
+AUX_SOURCE_DIRECTORY(models MODEL_SRC)
+
+include_directories(/usr/local/include)
+
+FILE(GLOB SCP_LIST ${CMAKE_CURRENT_SOURCE_DIR}/views/*.csp)
+foreach(cspFile ${SCP_LIST})
+    message(STATUS "cspFile:" ${cspFile})
+    EXEC_PROGRAM(basename ARGS "${cspFile} .csp" OUTPUT_VARIABLE classname)
+    message(STATUS "view classname:" ${classname})
+    add_custom_command(OUTPUT ${classname}.h ${classname}.cc
+            COMMAND drogon_ctl
+            ARGS create view ${cspFile}
+            DEPENDS ${cspFile}
+            VERBATIM )
+    set(VIEWSRC ${VIEWSRC} ${classname}.cc)
+endforeach()
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+add_executable(drogon_benchmark ${SRC_DIR} ${CTL_SRC} ${FILTER_SRC} ${VIEWSRC} ${MODEL_SRC})

+ 63 - 0
frameworks/C++/drogon/drogon_benchmark/cmake_modules/FindJsoncpp.cmake

@@ -0,0 +1,63 @@
+# Find jsoncpp
+#
+# Find the jsoncpp includes and library
+# 
+# if you nee to add a custom library search path, do it via via CMAKE_PREFIX_PATH 
+# 
+# This module defines
+#  JSONCPP_INCLUDE_DIRS, where to find header, etc.
+#  JSONCPP_LIBRARIES, the libraries needed to use jsoncpp.
+#  JSONCPP_FOUND, If false, do not try to use jsoncpp.
+#  JSONCPP_INCLUDE_PREFIX, include prefix for jsoncpp
+
+# only look in default directories
+find_path(
+	JSONCPP_INCLUDE_DIR 
+	NAMES jsoncpp/json/json.h json/json.h
+	DOC "jsoncpp include dir"
+)
+
+find_library(
+	JSONCPP_LIBRARY
+	NAMES jsoncpp
+	DOC "jsoncpp library"
+)
+
+set(JSONCPP_INCLUDE_DIRS ${JSONCPP_INCLUDE_DIR})
+set(JSONCPP_LIBRARIES ${JSONCPP_LIBRARY})
+
+# debug library on windows
+# same naming convention as in qt (appending debug library with d)
+# boost is using the same "hack" as us with "optimized" and "debug"
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+	find_library(
+		JSONCPP_LIBRARY_DEBUG
+		NAMES jsoncppd
+		DOC "jsoncpp debug library"
+	)
+	
+	set(JSONCPP_LIBRARIES optimized ${JSONCPP_LIBRARIES} debug ${JSONCPP_LIBRARY_DEBUG})
+
+endif()
+
+# find JSONCPP_INCLUDE_PREFIX
+find_path(
+	JSONCPP_INCLUDE_PREFIX
+	NAMES json.h
+	PATH_SUFFIXES jsoncpp/json json
+)
+
+if (${JSONCPP_INCLUDE_PREFIX} MATCHES "jsoncpp")
+	set(JSONCPP_INCLUDE_PREFIX "jsoncpp")
+	set(JSONCPP_INCLUDE_DIRS "${JSONCPP_INCLUDE_DIRS}/jsoncpp")
+else()
+	set(JSONCPP_INCLUDE_PREFIX "")
+endif()
+
+
+# handle the QUIETLY and REQUIRED arguments and set JSONCPP_FOUND to TRUE
+# if all listed variables are TRUE, hide their existence from configuration view
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(jsoncpp DEFAULT_MSG
+	JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY)
+mark_as_advanced (JSONCPP_INCLUDE_DIR JSONCPP_LIBRARY)

+ 119 - 0
frameworks/C++/drogon/drogon_benchmark/cmake_modules/FindUUID.cmake

@@ -0,0 +1,119 @@
+# - Try to find UUID
+# Once done this will define
+#
+# UUID_FOUND - system has UUID
+# UUID_INCLUDE_DIRS - the UUID include directory
+# UUID_LIBRARIES - Link these to use UUID
+# UUID_DEFINITIONS - Compiler switches required for using UUID
+#
+# Copyright (c) 2006 Andreas Schneider <[email protected]>
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+
+if (UUID_LIBRARIES AND UUID_INCLUDE_DIRS)
+	# in cache already
+	set(UUID_FOUND TRUE)
+else (UUID_LIBRARIES AND UUID_INCLUDE_DIRS)
+	find_path(UUID_INCLUDE_DIR
+		NAMES
+			uuid.h
+		PATH_SUFFIXES
+			uuid
+		HINTS
+			${UUID_DIR}/include
+			$ENV{UUID_DIR}/include
+			$ENV{UUID_DIR}
+			${DELTA3D_EXT_DIR}/inc
+			$ENV{DELTA_ROOT}/ext/inc
+			$ENV{DELTA_ROOT}
+		PATHS
+			~/Library/Frameworks
+			/Library/Frameworks
+			/usr/local/include
+			/usr/include
+			/usr/include/gdal
+			/sw/include # Fink
+			/opt/local/include # DarwinPorts
+			/opt/csw/include # Blastwave
+			/opt/include
+			[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/include
+			/usr/freeware/include
+	)
+
+	find_library(UUID_LIBRARY
+		NAMES
+			uuid ossp-uuid
+		HINTS
+			${UUID_DIR}/lib
+			$ENV{UUID_DIR}/lib
+			$ENV{UUID_DIR}
+			${DELTA3D_EXT_DIR}/lib
+			$ENV{DELTA_ROOT}/ext/lib
+			$ENV{DELTA_ROOT}
+			$ENV{OSG_ROOT}/lib
+		PATHS
+			~/Library/Frameworks
+			/Library/Frameworks
+			/usr/local/lib
+			/usr/lib
+			/sw/lib
+			/opt/local/lib
+			/opt/csw/lib
+			/opt/lib
+			/usr/freeware/lib64
+	)
+
+	find_library(UUID_LIBRARY_DEBUG
+		NAMES
+			uuidd 
+		HINTS
+			${UUID_DIR}/lib
+			$ENV{UUID_DIR}/lib
+			$ENV{UUID_DIR}
+			${DELTA3D_EXT_DIR}/lib
+			$ENV{DELTA_ROOT}/ext/lib
+			$ENV{DELTA_ROOT}
+			$ENV{OSG_ROOT}/lib
+		PATHS
+			~/Library/Frameworks
+			/Library/Frameworks
+			/usr/local/lib
+			/usr/lib
+			/sw/lib
+			/opt/local/lib
+			/opt/csw/lib
+			/opt/lib
+			/usr/freeware/lib64
+	)
+	
+	if (NOT UUID_LIBRARY AND BSD)
+		set(UUID_LIBRARY "")
+	endif(NOT UUID_LIBRARY AND BSD)
+
+	set(UUID_INCLUDE_DIRS ${UUID_INCLUDE_DIR})
+	set(UUID_LIBRARIES ${UUID_LIBRARY})
+
+	if (UUID_INCLUDE_DIRS)
+		if (BSD OR UUID_LIBRARIES)
+			set(UUID_FOUND TRUE)
+		endif (BSD OR UUID_LIBRARIES)
+	endif (UUID_INCLUDE_DIRS)
+
+	if (UUID_FOUND)
+		if (NOT UUID_FIND_QUIETLY)
+			message(STATUS "Found UUID: ${UUID_LIBRARIES}")
+		endif (NOT UUID_FIND_QUIETLY)
+	else (UUID_FOUND)
+		if (UUID_FIND_REQUIRED)
+			message(FATAL_ERROR "Could not find UUID")
+		endif (UUID_FIND_REQUIRED)
+	endif (UUID_FOUND)
+
+	# show the UUID_INCLUDE_DIRS and UUID_LIBRARIES variables only in the advanced view
+	mark_as_advanced(UUID_INCLUDE_DIRS UUID_LIBRARIES)
+
+endif (UUID_LIBRARIES AND UUID_INCLUDE_DIRS)

+ 133 - 0
frameworks/C++/drogon/drogon_benchmark/config.json

@@ -0,0 +1,133 @@
+/* This is a JSON format configuration file
+*/
+{
+  //ssl:the global ssl files setting
+  /*
+  "ssl": {
+    "cert": "../../trantor/trantor/tests/server.pem",
+    "key": "../../trantor/trantor/tests/server.pem"
+  },
+  "listeners": [
+    {
+      //address:ip address,0.0.0.0 by default
+      "address": "0.0.0.0",
+      //port:port number
+      "port": 80,
+      //https:if use https for security,false by default
+      "https": false
+    },
+    {
+      "address": "0.0.0.0",
+      "port": 443,
+      "https": true,
+      //cert,key:cert file path and key file path,empty by default,
+      //if empty,use global setting
+      "cert": "",
+      "key": ""
+    }
+  ],*/
+  /*
+  "db_clients": [
+    {
+      //name:Name of the client,'default' by default
+      //"name":"",
+      //rdbms:server type, "postgreSQL" by default
+      "rdbms": "postgreSQL",
+      //host:server address,localhost by default
+      "host": "127.0.0.1",
+      //port:server port, 5432 by default
+      "port": 5432,
+      //dbname:Database name
+      "dbname": "test",
+      //user:'postgres' by default
+      "user": "",
+      //passwd:'' by default
+      "passwd": "",
+      //connection_number:1 by default
+      "connection_number": 1
+    }
+  ],*/
+  "app": {
+    //threads_num:the number of IO threads,1 by default, if the value is set to 0, the number of threads
+<   //will be the number of processors.
+    "threads_num": 0,
+    //enable_session:false by default
+    "enable_session": false,
+    "session_timeout": 0,
+    //document_root:Root path of HTTP document,defaut path is ./
+    "document_root": "./",
+    /* file_types:
+     * HTTP download file types,The file types supported by drogon
+     * by default are "html", "js", "css", "xml", "xsl", "txt", "svg",
+     * "ttf", "otf", "woff2", "woff" , "eot", "png", "jpg", "jpeg",
+     * "gif", "bmp", "ico", "icns", etc. */
+    "file_types": [
+      "gif",
+      "png",
+      "jpg",
+      "js",
+      "css",
+      "html",
+      "ico",
+      "swf",
+      "xap",
+      "apk",
+      "cur",
+      "xml"
+    ],
+    //max_connections:max connections number,100000 by default
+    "max_connections": 100000,
+    //max_connections_per_ip:max connections number per clinet,0 by default which means no limit
+    "max_connections_per_ip": 0,
+    //Load_dynamic_views: false by default, when set to true, drogon will
+    //compile and load dynamically "CSP View Files" in directories defined
+    //by "dynamic_views_path"
+    //"load_dynamic_views":true,
+    //dynamic_views_path: if the path isn't prefixed with / or ./,
+    //it will be relative path of document_root path
+    //"dynamic_views_path":["./views"],
+    //log:set log output,drogon output logs to stdout by default
+    "log": {
+      //log_path:log file path,empty by default,in which case,log will output to the stdout
+      "log_path": "./",
+      //logfile_base_name:log file base name,empty by default which means drogon will name logfile as
+      //drogon.log ...
+      "logfile_base_name": "",
+      //log_size_limit:100000000 bytes by default,
+      //When the log file size reaches "log_size_limit", the log file will be switched.
+      "log_size_limit": 100000000,
+      //log_level:"DEBUG" by default,options:"TRACE","DEBUG","INFO","WARN"
+      //The TRACE level is only valid when built in DEBUG mode.
+      "log_level": "DEBUG"
+    },
+    //run_as_daemon:false by default
+    "run_as_daemon": false,
+    //relaunch_on_error:false by default,if true,the program will be restart by parent after exit;
+    "relaunch_on_error": false,
+    //use_sendfile:true by default,if ture,the program will
+    //use sendfile() system-call to send static file to client;
+    "use_sendfile": true,
+    //use_gzip:true by default,use gzip to compress the response body's content;
+    "use_gzip": true,
+    //static_files_cache_time:5 (seconds) by default,the time in which static file response is cached,
+    //0 means cache forever,the negative value means no cache
+    "static_files_cache_time": 5,
+    //simple_controllers_map:Configuring mapping from path to simple controller
+    "simple_controllers_map": [
+      {
+        "path": "/path/name",
+        "controller": "controllerClassName",
+        "http_methods": [
+          "get",
+          "post"
+        ],
+        "filters": [
+          "FilterClassName"
+        ]
+      }
+    ],
+    //idle_connection_timeout: defaults to 60 seconds, the lifetime 
+    //of the connection without read or write
+    "idle_connection_timeout": 60
+  }
+}

+ 8 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/JsonCtrl.cc

@@ -0,0 +1,8 @@
+#include "JsonCtrl.h"
+void JsonCtrl::asyncHandleHttpRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback)
+{
+    Json::Value ret;
+    ret["message"]="Hello, World!";
+    auto resp=HttpResponse::newHttpJsonResponse(ret);
+    callback(resp);
+}

+ 12 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/JsonCtrl.h

@@ -0,0 +1,12 @@
+#pragma once
+#include <drogon/HttpSimpleController.h>
+using namespace drogon;
+class JsonCtrl:public drogon::HttpSimpleController<JsonCtrl>
+{
+public:
+    virtual void asyncHandleHttpRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback)override;
+    PATH_LIST_BEGIN
+    //list path definitions here;
+    PATH_ADD("/json",Get);
+    PATH_LIST_END
+};

+ 9 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/PlaintextCtrl.cc

@@ -0,0 +1,9 @@
+#include "PlaintextCtrl.h"
+void PlaintextCtrl::asyncHandleHttpRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback)
+{
+    auto resp = HttpResponse::newHttpResponse();
+    resp->setBody("Hello, World!");
+    resp->setContentTypeCode(CT_TEXT_PLAIN);
+//    resp->setExpiredTime(0);
+    callback(resp);
+}

+ 12 - 0
frameworks/C++/drogon/drogon_benchmark/controllers/PlaintextCtrl.h

@@ -0,0 +1,12 @@
+#pragma once
+#include <drogon/HttpSimpleController.h>
+using namespace drogon;
+class PlaintextCtrl:public drogon::HttpSimpleController<PlaintextCtrl>
+{
+public:
+    virtual void asyncHandleHttpRequest(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)> & callback)override;
+    PATH_LIST_BEGIN
+    //list path definitions here;
+    PATH_ADD("/plaintext",Get);
+    PATH_LIST_END
+};

+ 12 - 0
frameworks/C++/drogon/drogon_benchmark/main.cc

@@ -0,0 +1,12 @@
+#include <drogon/drogon.h>
+int main() {
+    //Set HTTP listener address and port
+    //app().setLogPath("./");
+    //Print logs to standard output
+    drogon::app().setLogLevel(trantor::Logger::WARN);
+    drogon::app().addListener("0.0.0.0", 8080);
+    drogon::app().setThreadNum(std::thread::hardware_concurrency());
+    //app().enableRunAsDaemon();
+    drogon::app().run();
+    return 0;
+}

+ 13 - 0
frameworks/C++/drogon/drogon_benchmark/models/model.json

@@ -0,0 +1,13 @@
+{
+    //rdbms:server type, postgreSQL 
+    "rdbms":"postgreSQL",
+    //host:server address,localhost by default;
+    "host":"127.0.0.1",
+    //port:server port, 5432 by default;
+    "port":5432,
+    //dbname:Database name;
+    "dbname":"",
+    "user":"",
+    "passwd":"",
+    "tables":[]
+}