├── results ├── benchmark-php.png ├── benchmark-pistache.png ├── benchmark-restbed.png ├── benchmark-cpprestsdk-rapidjson.png └── benchmark-cpprestsdk-default_json_impl.png ├── samples ├── php │ └── native │ │ └── main.php └── cpp │ ├── pistache │ ├── CMakeLists.txt │ └── main.cpp │ ├── restbed │ ├── CMakeLists.txt │ └── main.cpp │ ├── cpprestsdk-rapidjson │ ├── CMakeLists.txt │ └── main.cpp │ └── cpprestsdk-default_json_impl │ ├── CMakeLists.txt │ └── main.cpp ├── Vagrantfile ├── LICENSE ├── bootstrap.sh └── Readme.md /results/benchmark-php.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binaryspaceship/cpp-rest-frameworks-benchmark/HEAD/results/benchmark-php.png -------------------------------------------------------------------------------- /results/benchmark-pistache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binaryspaceship/cpp-rest-frameworks-benchmark/HEAD/results/benchmark-pistache.png -------------------------------------------------------------------------------- /results/benchmark-restbed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binaryspaceship/cpp-rest-frameworks-benchmark/HEAD/results/benchmark-restbed.png -------------------------------------------------------------------------------- /results/benchmark-cpprestsdk-rapidjson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binaryspaceship/cpp-rest-frameworks-benchmark/HEAD/results/benchmark-cpprestsdk-rapidjson.png -------------------------------------------------------------------------------- /results/benchmark-cpprestsdk-default_json_impl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/binaryspaceship/cpp-rest-frameworks-benchmark/HEAD/results/benchmark-cpprestsdk-default_json_impl.png -------------------------------------------------------------------------------- /samples/php/native/main.php: -------------------------------------------------------------------------------- 1 | 'item-'.$i, 9 | 'name' => 'Hello World', 10 | 'type' => 'application' 11 | ]; 12 | } 13 | 14 | echo json_encode($values); 15 | -------------------------------------------------------------------------------- /samples/cpp/pistache/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(main) 3 | 4 | set(THREADS_PREFER_PTHREAD_FLAG ON) 5 | 6 | find_library(PISTACHE_LIB net_static) 7 | find_package(Threads REQUIRED) 8 | find_package(RapidJSON REQUIRED) 9 | 10 | add_executable(main main.cpp) 11 | target_link_libraries(main 12 | ${CMAKE_THREAD_LIBS_INIT} 13 | ${PISTACHE_LIB} 14 | ) 15 | target_compile_features(main PRIVATE cxx_range_for) -------------------------------------------------------------------------------- /samples/cpp/restbed/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(main) 3 | 4 | set(THREADS_PREFER_PTHREAD_FLAG ON) 5 | 6 | find_library(RESTBED_LIB restbed) 7 | find_package(Threads REQUIRED) 8 | find_package(RapidJSON REQUIRED) 9 | find_package(OpenSSL 1.0.0 REQUIRED) 10 | 11 | add_executable(main main.cpp) 12 | target_link_libraries(main 13 | ${CMAKE_THREAD_LIBS_INIT} 14 | ${RESTBED_LIB} 15 | OpenSSL::SSL 16 | ) 17 | target_compile_features(main PRIVATE cxx_range_for) -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | config.vm.box = "IngussNeilands/ubuntu-16.04.2-php-7.1-nginx" 6 | config.vm.synced_folder "samples", "/vagrant" 7 | 8 | config.vm.provision "disable-apt-periodic-updates", type: "shell" do |s| 9 | s.privileged = true 10 | s.inline = "echo 'APT::Periodic::Enable \"0\";' > /etc/apt/apt.conf.d/02periodic" 11 | end 12 | config.vm.provision :shell, :path => "bootstrap.sh" 13 | end 14 | -------------------------------------------------------------------------------- /samples/cpp/cpprestsdk-rapidjson/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(main) 3 | 4 | find_library(CPPREST_LIB cpprest) 5 | find_package(Boost REQUIRED COMPONENTS random system thread filesystem chrono atomic date_time regex) 6 | find_package(OpenSSL 1.0.0 REQUIRED) 7 | 8 | add_executable(main main.cpp) 9 | target_link_libraries(main 10 | ${CPPREST_LIB} 11 | Boost::boost 12 | Boost::random 13 | Boost::system 14 | Boost::thread 15 | Boost::filesystem 16 | Boost::chrono 17 | Boost::atomic 18 | Boost::date_time 19 | Boost::regex 20 | OpenSSL::SSL 21 | ) 22 | target_compile_features(main PRIVATE cxx_range_for) -------------------------------------------------------------------------------- /samples/cpp/cpprestsdk-default_json_impl/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(main) 3 | 4 | find_library(CPPREST_LIB cpprest) 5 | find_package(Boost REQUIRED COMPONENTS random system thread filesystem chrono atomic date_time regex) 6 | find_package(RapidJSON REQUIRED) 7 | find_package(OpenSSL 1.0.0 REQUIRED) 8 | 9 | add_executable(main main.cpp) 10 | target_link_libraries(main 11 | ${CPPREST_LIB} 12 | Boost::boost 13 | Boost::random 14 | Boost::system 15 | Boost::thread 16 | Boost::filesystem 17 | Boost::chrono 18 | Boost::atomic 19 | Boost::date_time 20 | Boost::regex 21 | OpenSSL::SSL 22 | RapidJSON 23 | ) 24 | target_compile_features(main PRIVATE cxx_range_for) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Dmytro Yurchenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /samples/cpp/restbed/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | #include 7 | using namespace restbed; 8 | 9 | #include 10 | #include 11 | using namespace rapidjson; 12 | 13 | void get_method_handler( const shared_ptr< Session > session ) 14 | { 15 | char _id[20]; 16 | 17 | StringBuffer JSONStrBuffer; 18 | Writer writer(JSONStrBuffer); 19 | writer.StartArray(); 20 | 21 | for (int i = 0; i < 10000; ++i) { 22 | writer.StartObject(); 23 | snprintf(_id, sizeof(_id), "item-%d", i); 24 | writer.Key("id"); writer.String(_id); 25 | writer.Key("name"); writer.String("Hello World"); 26 | writer.Key("type"); writer.String("application"); 27 | writer.EndObject(); 28 | } 29 | writer.EndArray(); 30 | 31 | session->close(OK, JSONStrBuffer.GetString()); 32 | } 33 | 34 | int main( const int, const char** ) 35 | { 36 | auto resource = make_shared< Resource >( ); 37 | resource->set_path( "/" ); 38 | resource->set_method_handler( "GET", get_method_handler ); 39 | 40 | auto settings = make_shared< Settings >( ); 41 | settings->set_port( 9000 ); 42 | settings->set_default_header( "Connection", "close" ); 43 | 44 | Service service; 45 | service.publish( resource ); 46 | service.start( settings ); 47 | 48 | return EXIT_SUCCESS; 49 | } -------------------------------------------------------------------------------- /samples/cpp/pistache/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace rapidjson; 7 | using namespace Net; 8 | using namespace std; 9 | 10 | class HelloHandler : public Http::Handler { 11 | public: 12 | 13 | HTTP_PROTOTYPE(HelloHandler) 14 | 15 | void onRequest( 16 | const Http::Request& request, 17 | Http::ResponseWriter response 18 | ) { 19 | char _id[20]; 20 | 21 | StringBuffer JSONStrBuffer; 22 | Writer writer(JSONStrBuffer); 23 | writer.StartArray(); 24 | 25 | for (int i = 0; i < 10000; ++i) { 26 | writer.StartObject(); 27 | snprintf(_id, sizeof(_id), "item-%d", i); 28 | writer.Key("id"); writer.String(_id); 29 | writer.Key("name"); writer.String("Hello World"); 30 | writer.Key("type"); writer.String("application"); 31 | writer.EndObject(); 32 | } 33 | writer.EndArray(); 34 | 35 | response.send(Http::Code::Ok, JSONStrBuffer.GetString()); 36 | } 37 | }; 38 | 39 | int main() { 40 | Net::Address addr(Net::Ipv4::any(), Net::Port(9000)); 41 | auto opts = Net::Http::Endpoint::options() 42 | .threads(1); 43 | 44 | Http::Endpoint server(addr); 45 | server.init(opts); 46 | server.setHandler(Http::make_handler()); 47 | server.serve(); 48 | 49 | server.shutdown(); 50 | } -------------------------------------------------------------------------------- /samples/cpp/cpprestsdk-rapidjson/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace web; 4 | using namespace web::http; 5 | using namespace web::http::experimental::listener; 6 | 7 | #include 8 | using namespace std; 9 | 10 | #include 11 | #include 12 | using namespace rapidjson; 13 | 14 | /* handlers implementation */ 15 | 16 | void handle_get(const http_request& request) 17 | { 18 | char _id[20]; 19 | 20 | StringBuffer JSONStrBuffer; 21 | Writer writer(JSONStrBuffer); 22 | writer.StartArray(); 23 | 24 | for (int i = 0; i < 10000; ++i) { 25 | writer.StartObject(); 26 | snprintf(_id, sizeof(_id), "item-%d", i); 27 | writer.Key("id"); writer.String(_id); 28 | writer.Key("name"); writer.String("Hello World"); 29 | writer.Key("type"); writer.String("application"); 30 | writer.EndObject(); 31 | } 32 | writer.EndArray(); 33 | 34 | http_response response(status_codes::OK); 35 | response.headers().add("Connection", "keep-alive"); 36 | response.set_body(JSONStrBuffer.GetString()); 37 | 38 | request.reply(response); 39 | } 40 | 41 | int main() 42 | { 43 | http_listener listener("http://127.0.0.1:9000"); 44 | listener.support(methods::GET, handle_get); 45 | 46 | try { 47 | listener 48 | .open() 49 | .wait(); 50 | 51 | while (true); 52 | } catch (exception const & e) { 53 | cout << e.what() << endl; 54 | } 55 | 56 | listener 57 | .close() 58 | .wait(); 59 | 60 | return 0; 61 | } -------------------------------------------------------------------------------- /samples/cpp/cpprestsdk-default_json_impl/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace web; 5 | using namespace web::http; 6 | using namespace web::http::experimental::listener; 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | /* handlers implementation */ 15 | 16 | void handle_get(const http_request& request) 17 | { 18 | vector values; 19 | values.reserve(10000); 20 | 21 | vector> fields; 22 | fields.reserve(3); 23 | 24 | char _id[20]; 25 | 26 | for (int i = 0; i < 10000; ++i) { 27 | snprintf(_id, sizeof(_id), "item-%d", i); 28 | fields.push_back(make_pair("id", json::value::string(_id))); 29 | fields.push_back(make_pair("name", json::value::string("Hello World"))); 30 | fields.push_back(make_pair("type", json::value::string("application"))); 31 | 32 | values.push_back(json::value::object(fields)); 33 | fields.clear(); 34 | } 35 | 36 | http_response response(status_codes::OK); 37 | response.headers().add("Connection", "keep-alive"); 38 | response.set_body(json::value::array(values)); 39 | 40 | request.reply(response); 41 | } 42 | 43 | int main() 44 | { 45 | http_listener listener("http://127.0.0.1:9000"); 46 | listener.support(methods::GET, handle_get); 47 | 48 | try { 49 | listener 50 | .open() 51 | .wait(); 52 | 53 | while (true); 54 | } catch (exception const & e) { 55 | cout << e.what() << endl; 56 | } 57 | 58 | listener 59 | .close() 60 | .wait(); 61 | 62 | return 0; 63 | } -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cat << EOF 4 | |--------------------------------------------------------| 5 | | | 6 | |-- Prepare stage before frameworks installation --| 7 | | | 8 | |--------------------------------------------------------| 9 | EOF 10 | 11 | # Install build tools and ntp (to prevent clock skewing) 12 | 13 | sudo mkdir /tmp/build-libs 14 | sudo apt-get install -y --allow-downgrades --allow-remove-essential --allow-change-held-packages ntp cmake 15 | 16 | # Replace nginx configuration 17 | 18 | sudo rm /etc/nginx/sites-enabled/localtest.me 19 | sudo echo " 20 | server { 21 | server_name localhost; 22 | 23 | root /vagrant/php/; 24 | listen 80; 25 | 26 | location / { 27 | try_files \$uri \$uri; 28 | } 29 | 30 | location ~ \.php\$ { 31 | #include /etc/nginx/nginx.conf.fastcgi.cache; 32 | fastcgi_pass unix:/var/run/php.fpm.sock; 33 | include /etc/nginx/nginx.conf.fastcgi; 34 | fastcgi_param VAGRANT vagrant; 35 | } 36 | 37 | include /etc/nginx/nginx.conf.sites; 38 | error_log /var/log/nginx/error.log; 39 | } 40 | " > /etc/nginx/sites-available/default 41 | sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default 42 | sudo service nginx restart 43 | 44 | cat << EOF 45 | |-----------------------------------------| 46 | | | 47 | |-- Install C/C++ REST frameworks --| 48 | | | 49 | |-----------------------------------------| 50 | EOF 51 | 52 | # Install CppRestSDK (Casablanca) C++ REST framework 53 | 54 | sudo apt-get install -y --allow-downgrades --allow-remove-essential --allow-change-held-packages libcpprest-dev 55 | 56 | # Install RapidJSON library 57 | # RapidJSON is required for pistache and restbed samples to produce JSON result 58 | 59 | cd /tmp/build-libs 60 | git clone https://github.com/miloyip/rapidjson 61 | cd rapidjson 62 | git submodule update --init 63 | cmake -DCMAKE_BUILD_TYPE=Release . 64 | make 65 | sudo make install 66 | 67 | # Install Pistache C++ REST framework 68 | 69 | cd /tmp/build-libs 70 | git clone https://github.com/oktal/pistache.git 71 | cd pistache 72 | git submodule update --init 73 | cmake -DCMAKE_BUILD_TYPE=Release . 74 | make 75 | sudo make install 76 | 77 | # Install Restbed C++ REST framework 78 | 79 | cd /tmp/build-libs 80 | git clone --recursive https://github.com/corvusoft/restbed.git 81 | cd restbed 82 | cmake -DCMAKE_BUILD_TYPE=Release . 83 | make 84 | sudo make install 85 | sudo cp -r distribution/library/* /usr/lib/ 86 | sudo cp -r distribution/include/* /usr/include/ 87 | 88 | cat << EOF 89 | |-----------------------------------| 90 | | | 91 | |-- Build benchmark samples --| 92 | | | 93 | |-----------------------------------| 94 | EOF 95 | 96 | cd /vagrant/cpp/cpprestsdk-default_json_impl 97 | cmake -DCMAKE_BUILD_TYPE=Release . 98 | make 99 | 100 | cd /vagrant/cpp/cpprestsdk-rapidjson 101 | cmake -DCMAKE_BUILD_TYPE=Release . 102 | make 103 | 104 | cd /vagrant/cpp/pistache 105 | cmake -DCMAKE_BUILD_TYPE=Release . 106 | make 107 | 108 | cd /vagrant/cpp/restbed 109 | cmake -DCMAKE_BUILD_TYPE=Release . 110 | make 111 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | This is performance benchmark of popular C++ REST frameworks. 2 | 3 | # What this repository contains 4 | 5 | This repository contains: 6 | 7 | - Code of each sample implementation. 8 | - Vagrant configuration of virtual machine where to build all samples and run benchmark. 9 | - Benchmark results. 10 | 11 | # Samples 12 | 13 | Code of samples is located in [samples folder](https://github.com/metamaker/cpp-rest-frameworks-benchmark/tree/master/samples). 14 | 15 | Scenario of each sample is the same: 16 | 17 | 1. Client performs GET request to HTTP server. 18 | 2. HTTP server must return JSON array of 10,000 items. 19 | 20 | There are several implementations of HTTP server: 21 | 22 | - C++ : [cpprestsdk](https://github.com/Microsoft/cpprestsdk) 23 | - C++ : [restbed](https://github.com/corvusoft/restbed) 24 | - C++ : [pistache](https://github.com/oktal/pistache) 25 | - PHP : Native implementation 26 | 27 | # Benchmark 28 | 29 | Results of benchmark are located in [results folder](https://github.com/metamaker/cpp-rest-frameworks-benchmark/tree/master/results). 30 | 31 | Benchmark was done by running `ab -n 1000 -c 1 -k ` (see [Apache Benchmark](https://httpd.apache.org/docs/2.4/programs/ab.html)) against each implementation. 32 | 33 | # Summary 34 | 35 | ## cpprestsdk 36 | 37 | #### Benchmark results for default JSON implementation on Linux 38 | 39 | ![cpprestsdk benchmark results](https://raw.githubusercontent.com/metamaker/cpp-rest-frameworks-benchmark/master/results/benchmark-cpprestsdk-default_json_impl.png) 40 | 41 | #### Benchmark results with RapidJSON on Linux 42 | 43 | ![cpprestsdk benchmark results](https://raw.githubusercontent.com/metamaker/cpp-rest-frameworks-benchmark/master/results/benchmark-cpprestsdk-rapidjson.png) 44 | 45 | (+) Code documentation of cpprestsdk is one of the best amongst all projects that I have ever seen during my 8 years carreer as software developer. Examples are well structured and easy to reproduce. 46 | 47 | (+) cpprestsdk has its own implementation of JSON serializer/deserializer, so you don't need to additionally include RapidJSON or other library. 48 | 49 | (+) cpprestsdk is included in Ubuntu 16 Xenial official repository, so you can install it easily by running single `apt` command. 50 | 51 | (+) Licensed under MIT. 52 | 53 | (-) Worst performance (even worse than PHP) on Linux server. There is opened issue for this problem on project's github (https://github.com/Microsoft/cpprestsdk/issues/468), but it is not solved yet. 54 | 55 | ## restbed 56 | 57 | ![restbed benchmark results](https://raw.githubusercontent.com/metamaker/cpp-rest-frameworks-benchmark/master/results/benchmark-restbed.png) 58 | 59 | (+) Good documentation on design of framework. 60 | 61 | (+) Small and easy to use. 62 | 63 | (-) No inline code documentation. 64 | 65 | (-) Licensed under either AGPL or proprietary license. 66 | 67 | (-) Some important features are still missing, e.g. server-side caching and HTTP2 compliance. 68 | 69 | ## pistache 70 | 71 | ![pistache benchmark results](https://raw.githubusercontent.com/metamaker/cpp-rest-frameworks-benchmark/master/results/benchmark-pistache.png) 72 | 73 | (+) Fastest performance. 74 | 75 | (+) Small and easy to use. 76 | 77 | (+) Licensed under Apache License 2.0. 78 | 79 | (-) No inline code documentation. 80 | 81 | (-) No comprehensive list of implemented features. 82 | 83 | (-) Installation instructions are not present in repository and not obvious to find (you should look on "Getting started" page, not on "User's Guide" FYI). 84 | 85 | (-) Unit tests are ill-formed. 86 | 87 | ## PHP native implementation 88 | 89 | ![PHP native implementation benchmark results](https://raw.githubusercontent.com/metamaker/cpp-rest-frameworks-benchmark/master/results/benchmark-php.png) 90 | --------------------------------------------------------------------------------