Ver Fonte

Add libsniper HTTP client/server library (#5646)

* libsniper is a small, very fast C++ library for writing highload HTTP services (f.e. RTB services)

* Add request routing
Oleg Romanenko há 5 anos atrás
pai
commit
7555405d28

+ 1 - 0
.travis.yml

@@ -25,6 +25,7 @@ env:
     - "TESTDIR=C++/wt"
     - "TESTDIR=C++/wt"
     - "TESTDIR=C++/drogon"
     - "TESTDIR=C++/drogon"
     - "TESTDIR=C++/oatpp"
     - "TESTDIR=C++/oatpp"
+    - "TESTDIR=C++/libsniper"
     - "TESTLANG=Clojure"
     - "TESTLANG=Clojure"
     - "TESTLANG=Crystal"
     - "TESTLANG=Crystal"
     - "TESTLANG=D"
     - "TESTLANG=D"

+ 22 - 0
frameworks/C++/libsniper/README.md

@@ -0,0 +1,22 @@
+# [libsniper](https://gitlab.com/rtbtech/libs/libsniper) (C++) Benchmarking Test
+
+## Description
+
+libsniper is a small, very fast C++ library for writing highload HTTP services (f.e. RTB services)
+
+## Features
+
+* Supported HTTP/1.x protocol with HTTP pipelining
+* Keep-alive and slow requests handling
+* Support WaitGroup inspired by Go
+* Client/Server library
+* Graceful server shutdown
+
+### Test Type Implementation Source Code
+
+* [PLAINTEXT](libsniper_bench/src/main.cpp)
+
+## Test URLs
+### PLAINTEXT
+
+http://localhost:8090/plaintext

+ 25 - 0
frameworks/C++/libsniper/benchmark_config.json

@@ -0,0 +1,25 @@
+{
+  "framework": "libsniper",
+  "tests": [
+    {
+      "default": {
+        "plaintext_url": "/plaintext",
+        "port": 8090,
+        "approach": "Realistic",
+        "classification": "Platform",
+        "database": "None",
+        "framework": "None",
+        "language": "C++",
+        "flavor": "None",
+        "orm": "None",
+        "platform": "None",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "libsniper",
+        "notes": "",
+        "versus": "None"
+      }
+    }
+  ]
+}

+ 40 - 0
frameworks/C++/libsniper/libsniper.dockerfile

@@ -0,0 +1,40 @@
+FROM ubuntu:20.04
+MAINTAINER [email protected]
+
+ENV DEBIAN_FRONTEND noninteractive
+
+RUN apt-get -qq -y update
+
+RUN apt-get -qq -y install --no-install-recommends git cmake libev-dev libgoogle-perftools-dev libfmt-dev make gcc-9 g++-9 libre2-dev libboost-stacktrace-dev
+
+RUN   update-alternatives --quiet --remove-all gcc \
+    ; update-alternatives --quiet --remove-all g++ \
+    ; update-alternatives --quiet --remove-all cc \
+    ; update-alternatives --quiet --remove-all cpp \
+    ; update-alternatives --quiet --install /usr/bin/gcc gcc /usr/bin/gcc-9 20 \
+    ; update-alternatives --quiet --install /usr/bin/cc cc /usr/bin/gcc-9 20 \
+    ; update-alternatives --quiet --install /usr/bin/g++ g++ /usr/bin/g++-9 20 \
+    ; update-alternatives --quiet --install /usr/bin/cpp cpp /usr/bin/g++-9 20 \
+    ; update-alternatives --quiet --config gcc \
+    ; update-alternatives --quiet --config cc \
+    ; update-alternatives --quiet --config g++ \
+    ; update-alternatives --quiet --config cpp
+
+
+COPY ./libsniper_bench /libsniper_bench
+
+WORKDIR /libsniper_bench
+
+RUN git config --global http.sslverify false
+
+RUN git clone https://gitlab.com/rtbtech/libs/libsniper.git libs/core
+
+RUN cd libs/core && git checkout 75f5cee4dcdc604d74703f5255e6f4cca20f50ce
+
+RUN mkdir build && cd /libsniper_bench/build && cmake -DCMAKE_BUILD_TYPE=Release -S .. && make --jobs=`nproc`
+
+ARG BENCHMARK_ENV
+
+EXPOSE 8090
+
+CMD ./build/bin/libsniper_bench

+ 32 - 0
frameworks/C++/libsniper/libsniper_bench/CMakeLists.txt

@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
+
+project(libsniper_bench LANGUAGES C CXX)
+
+if (NOT CMAKE_BUILD_TYPE)
+    message(STATUS "No build type selected, default is Release")
+    set(CMAKE_BUILD_TYPE "Release")
+endif ()
+
+if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
+    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+endif ()
+
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+include(cpp)
+include(flags)
+
+add_definitions(-DBOOST_STACKTRACE_USE_BACKTRACE)
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+set(Boost_USE_STATIC_LIBS ON)
+set(Boost_USE_MULTITHREADED ON)
+find_package(Boost REQUIRED)
+find_package(Threads REQUIRED)
+find_package(fmt REQUIRED)
+
+include_directories(SYSTEM ${BOOST_INCLUDE_DIRS})
+
+set(libsniper "std" "log" "cache" "xxhash" "net" "strings" "pico" "http" "event")
+
+add_subdirectory(libs)
+add_subdirectory(src)

+ 7 - 0
frameworks/C++/libsniper/libsniper_bench/cmake/cpp.cmake

@@ -0,0 +1,7 @@
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS ON)
+
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+set(CMAKE_C_EXTENSIONS ON)

+ 86 - 0
frameworks/C++/libsniper/libsniper_bench/cmake/flags.cmake

@@ -0,0 +1,86 @@
+set(COMMON_FLAGS "\
+    -march=corei7-avx \
+    -pipe \
+    -m64 \
+    -msse \
+    -msse2 \
+    -msse3 \
+    -mssse3 \
+    -msse4 \
+    -msse4.1 \
+    -msse4.2 \
+    -mavx \
+    -Wall \
+    -Wextra \
+    -Werror \
+    -Wpedantic \
+    -Wformat-security \
+    -fno-builtin-malloc \
+    -fno-builtin-calloc \
+    -fno-builtin-realloc \
+    -fno-builtin-free \
+    -Wno-unused-parameter \
+    -Wno-unused-but-set-variable \
+    ")
+
+
+set(COMMON_FLAGS_DEBUG "\
+    -Og \
+    -g \
+    -rdynamic \
+    ")
+
+set(COMMON_FLAGS_RELWITHDEBINFO "\
+    -g \
+    -DNDEBUG \
+    -Ofast \
+    -rdynamic \
+    -funroll-loops \
+    -fomit-frame-pointer \
+    -Wno-misleading-indentation \
+    ")
+
+
+set(COMMON_FLAGS_RELEASE "\
+    -DNDEBUG \
+    -Ofast \
+    -s \
+    -funroll-loops \
+    -fomit-frame-pointer \
+    -Wno-misleading-indentation \
+    ")
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
+    set(COMMON_FLAGS "\
+        ${COMMON_FLAGS} \
+         -pthread \
+        ")
+
+    set(COMMON_FLAGS_DEBUG "\
+        ${COMMON_FLAGS_DEBUG} \
+        -fsanitize=address \
+        -fsanitize=undefined \
+        -fsanitize=leak \
+        -fstack-protector \
+        -fuse-ld=gold \
+        ")
+
+endif ()
+
+if (UNIX AND !APPLE)
+    message("USE LTO")
+    include(CheckIPOSupported)
+    check_ipo_supported(RESULT supported OUTPUT error)
+    set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
+endif ()
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMMON_FLAGS}")
+set(CMAKE_C_FLAGS_DEBUG "${COMMON_FLAGS_DEBUG}")
+set(CMAKE_C_FLAGS_RELEASE "${COMMON_FLAGS_RELEASE}")
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COMMON_FLAGS} -Wno-class-memaccess")
+set(CMAKE_CXX_FLAGS_DEBUG "${COMMON_FLAGS_DEBUG}")
+set(CMAKE_CXX_FLAGS_RELEASE "${COMMON_FLAGS_RELEASE}")
+
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "${COMMON_FLAGS_RELWITHDEBINFO}")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${COMMON_FLAGS_RELWITHDEBINFO}")

+ 19 - 0
frameworks/C++/libsniper/libsniper_bench/libs/CMakeLists.txt

@@ -0,0 +1,19 @@
+set(SNIPER_INCLUDE_DIRS "" CACHE INTERNAL "sniper_include_dirs")
+set(SNIPER_LIBRARIES "" CACHE INTERNAL "sniper_libraries")
+
+# add all subfolders
+file(GLOB children RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*)
+foreach(child ${children})
+    if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${child})
+        set(SNIPER_INCLUDE_DIRS ${SNIPER_INCLUDE_DIRS} "${CMAKE_CURRENT_SOURCE_DIR}/${child}" CACHE INTERNAL "sniper_include_dirs")
+    endif()
+endforeach()
+
+include_directories(BEFORE ${SNIPER_INCLUDE_DIRS})
+
+file(GLOB children RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*)
+foreach(child ${children})
+    if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${child})
+        add_subdirectory(${child})
+    endif()
+endforeach()

+ 18 - 0
frameworks/C++/libsniper/libsniper_bench/src/CMakeLists.txt

@@ -0,0 +1,18 @@
+include_directories(.)
+include_directories(${SNIPER_INCLUDE_DIRS})
+
+set(PROJECT_LIBS
+        ${CMAKE_THREAD_LIBS_INIT}
+        ${BOOST_LIBRARIES}
+        backtrace dl
+        fmt::fmt
+        stdc++fs.a
+        tcmalloc
+        )
+
+set(PROJECT_SRC
+        main.cpp
+        )
+
+add_executable(${PROJECT_NAME} ${PROJECT_SRC})
+target_link_libraries(${PROJECT_NAME} ${SNIPER_LIBRARIES} ${PROJECT_LIBS})

+ 108 - 0
frameworks/C++/libsniper/libsniper_bench/src/main.cpp

@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2020, RTBtech, MediaSniper, Oleg Romanenko ([email protected])
+ */
+
+#include <sniper/event/Loop.h>
+#include <sniper/event/Timer.h>
+#include <sniper/http/Server.h>
+#include <sniper/log/log.h>
+#include <sniper/std/check.h>
+#include <sniper/std/vector.h>
+#include <sniper/threads/Stop.h>
+#include <thread>
+
+using namespace sniper;
+
+class Server
+{
+public:
+    explicit Server()
+    {
+        for (unsigned i = 0; i < std::thread::hardware_concurrency(); i++)
+            _workers.emplace_back(&Server::worker_noexcept, this, i);
+    }
+
+    ~Server()
+    {
+        for (auto& w : _workers)
+            if (w.joinable())
+                w.join();
+    }
+
+private:
+    void worker_noexcept(unsigned int thread_num) noexcept
+    {
+        try {
+            worker(thread_num);
+        }
+        catch (std::exception& e) {
+            log_err(e.what());
+        }
+        catch (...) {
+            log_err("[Server] non std::exception occured");
+        }
+    }
+
+    static string gen_date()
+    {
+        return fmt::format("Date: {:%a, %d %b %Y %H:%M:%S} GMT\r\n", fmt::gmtime(time(nullptr)));
+    }
+
+    void worker(unsigned thread_num)
+    {
+        auto loop = event::make_loop();
+        check(loop, "[Server] cannot init event loop");
+
+        http::server::Config config;
+        config.max_conns = 100000;
+        config.connection.keep_alive_timeout = 10min;
+        config.connection.request_read_timeout = 10s;
+
+        http::Server http_server(loop, config);
+        check(http_server.bind("", 8090), "[Server] cannot bind to localhost:8090");
+
+        string date = gen_date();
+        http_server.set_cb_request([&, this](const auto& conn, const auto& req, const auto& resp) {
+            resp->add_header_nocopy("Server: libsniper\r\n");
+            resp->add_header_copy(date);
+
+            if (req->path() == "/plaintext") {
+                resp->code = http::ResponseStatus::OK;
+                resp->add_header_nocopy("Content-Type: text/plain; charset=UTF-8\r\n");
+                resp->set_data_nocopy("Hello, World!");
+                conn->send(resp);
+                return;
+            }
+
+            resp->code = http::ResponseStatus::NO_CONTENT;
+            conn->send(resp);
+        });
+
+        event::TimerRepeat timer_stop(loop, 1s, [&loop] {
+            if (threads::Stop::get().is_stopped())
+                loop->break_loop(ev::ALL);
+        });
+
+        event::TimerRepeat timer_update_time(loop, 1s, [&date] { date = gen_date(); });
+
+        loop->run();
+    }
+
+    vector<std::thread> _workers;
+};
+
+int main(int argc, char** argv)
+{
+    auto loop = event::make_loop();
+    if (!loop) {
+        log_err("Main: cannot init event loop");
+        return EXIT_FAILURE;
+    }
+
+    signal(SIGPIPE, SIG_IGN);
+
+    Server server;
+    loop->run();
+
+    return EXIT_SUCCESS;
+}