├── .gitignore ├── tests ├── new-ws-echo │ ├── certs │ │ ├── ca.srl │ │ ├── server.csr │ │ ├── server.crt │ │ ├── ca.pem │ │ ├── ca.key │ │ └── server.key │ ├── test_def.h │ ├── CMakeLists.txt │ ├── config_la1.ini │ ├── config_la1_2.ini │ └── config_la6.ini ├── CMakeLists.txt ├── ws-echo │ ├── test_def.h │ ├── CMakeLists.txt │ ├── config_la1.ini │ ├── config_la1_2.ini │ ├── config_la6.ini │ ├── config_vi01.ini │ └── config_vi02.ini ├── test-alloc │ ├── CMakeLists.txt │ ├── alloc_latency.cpp │ └── alloc_speed_compare.cpp ├── test-new-tcp-echo │ ├── CMakeLists.txt │ ├── certs │ │ ├── server.crt │ │ ├── ca.pem │ │ └── server.key │ ├── test_def.h │ ├── config_la6.ini │ └── config_la1.ini ├── test-https-client │ ├── test_def.h │ ├── CMakeLists.txt │ ├── test_search.cpp │ ├── https_client.cpp │ ├── test_http_client.cpp │ └── test_http_pool.cpp ├── test-utils │ ├── CMakeLists.txt │ └── test_mask.cpp └── test_ring_buffer │ ├── CMakeLists.txt │ └── test_block_queue.cpp ├── .gitmodules ├── include └── flashws │ ├── base │ ├── base_include.h │ ├── basic_macros.h │ ├── errno_str.h │ ├── constexpr_math.h │ ├── hw_endian.h │ ├── constants.h │ └── buffer_manager.h │ ├── crypto │ ├── sha.h │ ├── rng.h │ ├── hmac.h │ ├── ssl_manager.h │ ├── ws_mask.h │ └── base64.h │ ├── utils │ ├── singleton.h │ ├── histogram_wrapper.h │ ├── raw_histogram.h │ └── block_queue.h │ ├── flashws.h │ └── net │ └── ws_server.h ├── README.md └── CMakeLists.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .DS_Store 3 | cmake-* 4 | .clion* 5 | build/ 6 | -------------------------------------------------------------------------------- /tests/new-ws-echo/certs/ca.srl: -------------------------------------------------------------------------------- 1 | 2A8150C303E02508FBB86B161974128D62BCA21A 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | 2 | [submodule "thirdparty/HdrHistogram_c"] 3 | path = thirdparty/HdrHistogram_c 4 | url = https://github.com/HdrHistogram/HdrHistogram_c.git 5 | [submodule "thirdparty/boringssl"] 6 | path = thirdparty/boringssl 7 | url = https://github.com/google/boringssl.git 8 | -------------------------------------------------------------------------------- /include/flashws/base/base_include.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | 7 | #ifdef FWS_ENABLE_FSTACK 8 | 9 | #include "ff_config.h" 10 | #include "ff_api.h" 11 | 12 | 13 | #endif 14 | 15 | #include "basic_macros.h" 16 | #include "buffer_manager.h" 17 | #include "errno_str.h" 18 | #include "constants.h" -------------------------------------------------------------------------------- /include/flashws/crypto/sha.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "flashws/base/basic_macros.h" 5 | 6 | namespace fws { 7 | 8 | 9 | 10 | FWS_ALWAYS_INLINE void* Sha1(const void* FWS_RESTRICT src, size_t src_len, 11 | void* FWS_RESTRICT dst) { 12 | return SHA1((const unsigned char*)src, src_len, (unsigned char*)dst); 13 | } 14 | 15 | } // namespace fws -------------------------------------------------------------------------------- /include/flashws/utils/singleton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace fws { 4 | 5 | template 6 | class Singleton { 7 | public: 8 | 9 | Singleton(const Singleton &other) = delete; 10 | 11 | Singleton &operator=(const Singleton &other) = delete; 12 | 13 | static T &instance() { 14 | static T _instance; 15 | return _instance; 16 | } 17 | 18 | protected: 19 | Singleton() = default; 20 | 21 | ~Singleton() = default; 22 | 23 | }; 24 | 25 | } // namespace fws -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(flashws_tests) 3 | 4 | 5 | add_subdirectory(.. ${CMAKE_CURRENT_BINARY_DIR}/flashws) 6 | 7 | OPTION(USE_RAW_HISTOGRAM "Use raw_histogram, otherwise use HdrHistogram_c" OFF) 8 | 9 | if(USE_RAW_HISTOGRAM) 10 | ADD_DEFINITIONS(-DUSE_RAW_HISTOGRAM) 11 | SET(HDR_HIST_LIB "") 12 | else() 13 | add_subdirectory(../thirdparty/HdrHistogram_c ${CMAKE_CURRENT_BINARY_DIR}/HdrHistogram_c) 14 | SET(HDR_HIST_LIB hdr_histogram_static) 15 | endif() 16 | 17 | add_subdirectory(test-new-tcp-echo) 18 | add_subdirectory(test-https-client) 19 | add_subdirectory(new-ws-echo) 20 | add_subdirectory(test-utils) 21 | add_subdirectory(test_ring_buffer) 22 | add_subdirectory(test-alloc) -------------------------------------------------------------------------------- /tests/ws-echo/test_def.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace test { 6 | 7 | // inline constexpr const char* const SERVER_IP = "10.5.96.3"; 8 | // inline constexpr const char* const SERVER_IP = "10.5.96.7"; 9 | 10 | 11 | 12 | // inline constexpr uint16_t SERVER_PORT = 58600; 13 | 14 | 15 | // inline constexpr size_t TEST_TIMES = 100'000; 16 | // inline constexpr size_t MAX_DATA_LEN = 64; 17 | // inline constexpr size_t MAX_DATA_LEN = 1UL << 18; 18 | 19 | constexpr size_t MAX_CLIENT_EVENT_NUM = 65536; 20 | constexpr size_t MAX_SERVER_EVENT_NUM = 65536; 21 | 22 | inline constexpr bool USE_BUSY_POLL = true; 23 | inline constexpr int BUSY_POLL_US = 800; 24 | 25 | inline constexpr int LISTEN_BACKLOG = 128; 26 | 27 | #define ENABLE_NO_DELAY 1 28 | 29 | } // namespace test -------------------------------------------------------------------------------- /include/flashws/flashws.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "flashws/base/base_include.h" 7 | #include "flashws/net/fevent.h" 8 | #include "flashws/net/floop.h" 9 | #include "flashws/net/ws_client_socket.h" 10 | #include "flashws/net/ws_server_socket.h" 11 | 12 | 13 | 14 | namespace fws { 15 | 16 | 17 | inline int InitEnv(int argc, char * argv[]) { 18 | int ret = 0; 19 | #ifdef FWS_ENABLE_FSTACK 20 | ret = ff_init(argc, argv); 21 | #else 22 | (void)argc; 23 | (void)argv; 24 | #endif 25 | return ret; 26 | } 27 | 28 | using OneLoopFunc = int (*)(void*); 29 | 30 | inline void StartRunLoop(OneLoopFunc loop_func, void *arg) { 31 | #ifdef FWS_ENABLE_FSTACK 32 | ff_run(loop_func, arg); 33 | #else 34 | while (true) { 35 | loop_func(arg); 36 | } 37 | #endif 38 | } 39 | 40 | } // namespace fws 41 | 42 | -------------------------------------------------------------------------------- /tests/new-ws-echo/certs/server.csr: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE REQUEST----- 2 | MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx 3 | ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN 4 | AQEBBQADggEPADCCAQoCggEBAKfP76lxqjoj+h84D7WGqnwKEWOjMgU2otz6pKFu 5 | lmLD7zxOcY4Ou6Y4UhDxctjLoFVeJzfTerlLy24XhEs3Kcq+YeNYIm+sQEpXcxBY 6 | C78w9ODtr6zHaN9vTnq1OKbu++t3JjXMFA6ADqdmbwawOcX8tp56kcSwSVCB9+iW 7 | 7CTT0sBiLkKhOedjENmKkKf2RB3SOLwEueOb+lr/36W7k2Sk8AOcMG2XhHeR3UmV 8 | k/4yVbCSu2jaHqcFZEmn0CN4uRKZksLyMH5ENQcaUqiYp/T33IXOApvtTv5LZR9O 9 | tCoq9T/PsBc8ztOaAH+kw0vjgyw9/TYd7+b3hYKyXuGGYc8CAwEAAaAAMA0GCSqG 10 | SIb3DQEBCwUAA4IBAQAU/vx6uUIobUiUFB8aSL75iLWe57k1/7VlY/gEXJe9eVfe 11 | JhGXaYBjXYgftYKXBrht27hHoOCLrTNxbGryHP+/QsroxNdbi0xBHBjr96LlN0NC 12 | Hl/Jgk098SHGQzQU5bke4vXVagIWsSWkS1Yvsa5VhLBuOF0j6ecLm9eas/iJt/kT 13 | Zsj8rZ1gCtnX9ofWoBWv2+gMOxLcW+3h544p1lBedOmVYSydGxDJUBs8Kw9kfUlS 14 | fLN//nfDr1ijEQXgRvZIkek7yB3TQw0TTs7Ia8RxnFBR1tETpxLMrBGI2iAWim8e 15 | EE5pMVtb0FxKILcUtoMuftyERRQbFmuys9V54fuv 16 | -----END CERTIFICATE REQUEST----- 17 | -------------------------------------------------------------------------------- /tests/test-alloc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(test_alloc) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | add_executable(alloc_latency alloc_latency.cpp 7 | ) 8 | 9 | target_include_directories(alloc_latency 10 | PRIVATE 11 | ../../include 12 | ) 13 | 14 | 15 | target_link_libraries(alloc_latency 16 | PRIVATE ${HDR_HIST_LIB} 17 | ) 18 | 19 | 20 | if(NOT MSVC) 21 | target_compile_options(alloc_latency 22 | PRIVATE 23 | -Wall -Wextra 24 | ) 25 | 26 | endif() 27 | 28 | #target_compile_options(alloc_latency 29 | # PRIVATE 30 | # -fsanitize=address 31 | #) 32 | # 33 | #target_link_options(alloc_latency 34 | # PRIVATE 35 | # -fsanitize=address 36 | # ) 37 | 38 | add_executable(alloc_speed_compare alloc_speed_compare.cpp) 39 | target_include_directories(alloc_speed_compare 40 | PRIVATE 41 | ../../include 42 | ) 43 | 44 | if(NOT MSVC) 45 | target_compile_options(alloc_speed_compare 46 | PRIVATE 47 | -Wall -Wextra 48 | ) 49 | 50 | endif() -------------------------------------------------------------------------------- /tests/test-new-tcp-echo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(test_new_tcp_echo) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | add_executable(tcp_echo_client client.cpp) 7 | add_executable(tcp_echo_server server.cpp) 8 | 9 | target_link_libraries(tcp_echo_client 10 | PRIVATE ${HDR_HIST_LIB} 11 | ) 12 | 13 | #add_subdirectory(../.. ${CMAKE_CURRENT_BINARY_DIR}/flashws) 14 | target_link_libraries(tcp_echo_client PRIVATE fws::flashws) 15 | target_link_libraries(tcp_echo_server PRIVATE fws::flashws) 16 | 17 | if(NOT MSVC) 18 | target_compile_options(tcp_echo_client 19 | PRIVATE 20 | -Wall -Wextra 21 | -g 22 | # -O3 23 | # -fsanitize=address 24 | ) 25 | 26 | target_compile_options(tcp_echo_server 27 | PRIVATE 28 | -Wall -Wextra 29 | -g 30 | # -O3 31 | # -fsanitize=address 32 | ) 33 | endif() 34 | 35 | target_link_options(tcp_echo_client 36 | PRIVATE 37 | # -fsanitize=address 38 | ) 39 | 40 | target_link_options(tcp_echo_server 41 | PRIVATE 42 | # -fsanitize=address 43 | ) -------------------------------------------------------------------------------- /tests/test-https-client/test_def.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | 7 | namespace test { 8 | // const char* host_ip = "104.193.88.77"; 9 | 10 | constexpr uint16_t host_port = 443; 11 | #define REAL_HOST "www.google.com" 12 | //#define REAL_HOST "abc123456.com" 13 | //#define REAL_HOST "www.baidu.com" 14 | //#define REAL_HOST "www.cloudflare.com" 15 | //#define REAL_HOST "" 16 | constexpr const char* host_ip = "172.217.12.132"; // www.google.com 17 | // constexpr const char* host_ip = "104.193.88.77"; // www.baidu.com 18 | // constexpr const char* host_ip = "103.126.210.28"; // abc123456.com 19 | // constexpr const char* host_ip = "104.16.123.96"; // www.cloudflare.com 20 | // constexpr const char* host_ip = "127.0.0.1"; 21 | constexpr const char* host_name = REAL_HOST; 22 | constexpr const char https_request[] = "GET / HTTP/1.1\r\n" 23 | "Host: " REAL_HOST "\r\n" 24 | "\r\n"; 25 | 26 | constexpr int BUSY_POLL_US = 800; 27 | 28 | constexpr int MAX_EVENT_NUM = 4096; 29 | constexpr size_t MAX_BUFFER_SIZE = 1UL << 14; 30 | 31 | } // namespace test -------------------------------------------------------------------------------- /tests/test-utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(test_utils) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | add_executable(test_utils test_utils.cpp) 7 | add_executable(test_mask test_mask.cpp) 8 | 9 | #add_subdirectory(../.. ${CMAKE_CURRENT_BINARY_DIR}/flashws) 10 | #add_subdirectory(../../thirdparty/Compile-time-hash-functions ${CMAKE_CURRENT_BINARY_DIR}/compile_time_hash_functions) 11 | target_link_libraries(test_utils PRIVATE 12 | fws::flashws 13 | # compile_time_hash 14 | ) 15 | 16 | target_link_libraries(test_mask PRIVATE fws::flashws) 17 | 18 | if(NOT MSVC) 19 | target_compile_options(test_utils 20 | PRIVATE 21 | -Wall -Wextra 22 | -g 23 | # -O3 24 | # -march=native 25 | # -fsanitize=address 26 | ) 27 | 28 | target_compile_options(test_mask 29 | PRIVATE 30 | -Wall -Wextra 31 | -g 32 | # -O3 33 | # -march=native 34 | # -fsanitize=address 35 | ) 36 | 37 | endif() 38 | 39 | target_link_options(test_utils 40 | PRIVATE 41 | # -fsanitize=address 42 | ) 43 | 44 | -------------------------------------------------------------------------------- /tests/new-ws-echo/certs/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDWjCCAkKgAwIBAgIUKoFQwwPgJQj7uGsWGXQSjWK8ohowDQYJKoZIhvcNAQEL 3 | BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM 4 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAyMjYwNTQ1MzBaFw0yNTA3 5 | MTAwNTQ1MzBaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw 6 | HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB 7 | AQUAA4IBDwAwggEKAoIBAQCnz++pcao6I/ofOA+1hqp8ChFjozIFNqLc+qShbpZi 8 | w+88TnGODrumOFIQ8XLYy6BVXic303q5S8tuF4RLNynKvmHjWCJvrEBKV3MQWAu/ 9 | MPTg7a+sx2jfb056tTim7vvrdyY1zBQOgA6nZm8GsDnF/LaeepHEsElQgffoluwk 10 | 09LAYi5CoTnnYxDZipCn9kQd0ji8BLnjm/pa/9+lu5NkpPADnDBtl4R3kd1JlZP+ 11 | MlWwkrto2h6nBWRJp9AjeLkSmZLC8jB+RDUHGlKomKf099yFzgKb7U7+S2UfTrQq 12 | KvU/z7AXPM7TmgB/pMNL44MsPf02He/m94WCsl7hhmHPAgMBAAGjQjBAMB0GA1Ud 13 | DgQWBBQupQ4V+OKddBL2jHWsBzA3VAcXujAfBgNVHSMEGDAWgBQuEUzvSdTzEKAo 14 | jnRXpmFdBuEeYjANBgkqhkiG9w0BAQsFAAOCAQEAa4iMxfu1++MsUA/HcGtt0/Vh 15 | GAadV6qEieQMwTtT/6VvGVQSBxZRI+UMypTu8y+IBebk3Hu4HdlZcoWcyp/7SPRS 16 | JsrVmVhwsdrSbeFa3pilV64n2W0shDTQ+RFI2ayRFJ6R95WAwR3SqC+tWXaCY25G 17 | 4F/DnG0oGJ/L3R2Q9LfPG9uUBNhcNqmA0RY/eQJ245+tRnC6pBnSdPOZmfvJ/P1p 18 | lyizCmBx4MkwNDMudNskJzw57h+U+2zPRTp7r8KBE8usLW971QE0LUuZG/QbWd2s 19 | 55aBeEOv5wU10IkDyCovwoZfq2fvGzSguzA71qJwV2lM/A2yi7DOik4EE+aesg== 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /tests/test-new-tcp-echo/certs/server.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDWjCCAkKgAwIBAgIUKoFQwwPgJQj7uGsWGXQSjWK8ohowDQYJKoZIhvcNAQEL 3 | BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM 4 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAyMjYwNTQ1MzBaFw0yNTA3 5 | MTAwNTQ1MzBaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw 6 | HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB 7 | AQUAA4IBDwAwggEKAoIBAQCnz++pcao6I/ofOA+1hqp8ChFjozIFNqLc+qShbpZi 8 | w+88TnGODrumOFIQ8XLYy6BVXic303q5S8tuF4RLNynKvmHjWCJvrEBKV3MQWAu/ 9 | MPTg7a+sx2jfb056tTim7vvrdyY1zBQOgA6nZm8GsDnF/LaeepHEsElQgffoluwk 10 | 09LAYi5CoTnnYxDZipCn9kQd0ji8BLnjm/pa/9+lu5NkpPADnDBtl4R3kd1JlZP+ 11 | MlWwkrto2h6nBWRJp9AjeLkSmZLC8jB+RDUHGlKomKf099yFzgKb7U7+S2UfTrQq 12 | KvU/z7AXPM7TmgB/pMNL44MsPf02He/m94WCsl7hhmHPAgMBAAGjQjBAMB0GA1Ud 13 | DgQWBBQupQ4V+OKddBL2jHWsBzA3VAcXujAfBgNVHSMEGDAWgBQuEUzvSdTzEKAo 14 | jnRXpmFdBuEeYjANBgkqhkiG9w0BAQsFAAOCAQEAa4iMxfu1++MsUA/HcGtt0/Vh 15 | GAadV6qEieQMwTtT/6VvGVQSBxZRI+UMypTu8y+IBebk3Hu4HdlZcoWcyp/7SPRS 16 | JsrVmVhwsdrSbeFa3pilV64n2W0shDTQ+RFI2ayRFJ6R95WAwR3SqC+tWXaCY25G 17 | 4F/DnG0oGJ/L3R2Q9LfPG9uUBNhcNqmA0RY/eQJ245+tRnC6pBnSdPOZmfvJ/P1p 18 | lyizCmBx4MkwNDMudNskJzw57h+U+2zPRTp7r8KBE8usLW971QE0LUuZG/QbWd2s 19 | 55aBeEOv5wU10IkDyCovwoZfq2fvGzSguzA71qJwV2lM/A2yi7DOik4EE+aesg== 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /tests/new-ws-echo/certs/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDazCCAlOgAwIBAgIUSRhHBOLPLPdhnQk7Zdi+xisPuSUwDQYJKoZIhvcNAQEL 3 | BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM 4 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAyMjYwNTQ0MzNaFw0yNjEy 5 | MTYwNTQ0MzNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw 6 | HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB 7 | AQUAA4IBDwAwggEKAoIBAQDsR39Av1jT96syihhyQYy83zV+fzSapNre7EMpuZnr 8 | xqLUebwnNx2LuyuqF2HptN+m0ZNLAOv+NoebPGmay/XCvI2EOtaxvppbUKCKMsqv 9 | CDsZj6LYqrol20VtDPOtUS65Bsn9W3shjSLQaVdIf0v7XL86WTGr4Ot4BnV3OGC2 10 | iO+GZ0ZEt/uQ8IvG89JrBIAjzXsfK0scTaEXR9Lx95ssD2tEK1aprfb8BGKs+URo 11 | exOvflviC+FMvXgGcLVNedn4MJCBjhq10T6kqTC+ZGedTdQmDLfAxZWIfg7kUBRT 12 | cHNSViGvo+A9AepyG/hxStxTxWYs/1NlofsnxgDqwjJjAgMBAAGjUzBRMB0GA1Ud 13 | DgQWBBQuEUzvSdTzEKAojnRXpmFdBuEeYjAfBgNVHSMEGDAWgBQuEUzvSdTzEKAo 14 | jnRXpmFdBuEeYjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA0 15 | jH+wXorXXQKDhaqaS10mj94qajG9rax4bweH/6K9RPxVTNqej/kOtSek2HUBYhhC 16 | iDmU/QXuRBJ5FP75uXzjXs7eidNEHln65ziwVRhuXnYWND0ees7cN7nRbhjZzE9r 17 | tO+uz/ARk4OU/ytgsNwlitQo3UcWz4WWGThUekrHFjS6c/ms94gm01GyjtlQ0RC2 18 | P8ioBGkLHvY9a/hlBVHemKny+eRF0b47Tw9dupAUs8MIuMPHsBf1zeX+QHy7HWFj 19 | LPyGsuWdSca3sdzbbyROwMVAmPYZtL/zjWE7D0LBMGesM5Bg6TV1QkAE9p+KMw1i 20 | EsW6yhXCanesf4WCu3wB 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /tests/test-new-tcp-echo/certs/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDazCCAlOgAwIBAgIUSRhHBOLPLPdhnQk7Zdi+xisPuSUwDQYJKoZIhvcNAQEL 3 | BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM 4 | GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDAyMjYwNTQ0MzNaFw0yNjEy 5 | MTYwNTQ0MzNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw 6 | HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB 7 | AQUAA4IBDwAwggEKAoIBAQDsR39Av1jT96syihhyQYy83zV+fzSapNre7EMpuZnr 8 | xqLUebwnNx2LuyuqF2HptN+m0ZNLAOv+NoebPGmay/XCvI2EOtaxvppbUKCKMsqv 9 | CDsZj6LYqrol20VtDPOtUS65Bsn9W3shjSLQaVdIf0v7XL86WTGr4Ot4BnV3OGC2 10 | iO+GZ0ZEt/uQ8IvG89JrBIAjzXsfK0scTaEXR9Lx95ssD2tEK1aprfb8BGKs+URo 11 | exOvflviC+FMvXgGcLVNedn4MJCBjhq10T6kqTC+ZGedTdQmDLfAxZWIfg7kUBRT 12 | cHNSViGvo+A9AepyG/hxStxTxWYs/1NlofsnxgDqwjJjAgMBAAGjUzBRMB0GA1Ud 13 | DgQWBBQuEUzvSdTzEKAojnRXpmFdBuEeYjAfBgNVHSMEGDAWgBQuEUzvSdTzEKAo 14 | jnRXpmFdBuEeYjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA0 15 | jH+wXorXXQKDhaqaS10mj94qajG9rax4bweH/6K9RPxVTNqej/kOtSek2HUBYhhC 16 | iDmU/QXuRBJ5FP75uXzjXs7eidNEHln65ziwVRhuXnYWND0ees7cN7nRbhjZzE9r 17 | tO+uz/ARk4OU/ytgsNwlitQo3UcWz4WWGThUekrHFjS6c/ms94gm01GyjtlQ0RC2 18 | P8ioBGkLHvY9a/hlBVHemKny+eRF0b47Tw9dupAUs8MIuMPHsBf1zeX+QHy7HWFj 19 | LPyGsuWdSca3sdzbbyROwMVAmPYZtL/zjWE7D0LBMGesM5Bg6TV1QkAE9p+KMw1i 20 | EsW6yhXCanesf4WCu3wB 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /tests/test_ring_buffer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(test_rb) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | add_executable(test_rb test_rb.cpp) 7 | add_executable(test_block_queue test_block_queue.cpp) 8 | 9 | #add_subdirectory(../.. ${CMAKE_CURRENT_BINARY_DIR}/flashws) 10 | 11 | target_link_libraries(test_rb PRIVATE fws::flashws) 12 | target_link_libraries(test_block_queue PRIVATE fws::flashws) 13 | 14 | 15 | 16 | target_link_libraries(test_rb 17 | PRIVATE ${HDR_HIST_LIB} 18 | ) 19 | 20 | target_link_libraries(test_block_queue 21 | PRIVATE ${HDR_HIST_LIB} 22 | ) 23 | 24 | 25 | if(NOT MSVC) 26 | target_compile_options(test_rb 27 | PRIVATE 28 | -Wall -Wextra 29 | -g 30 | # -O3 31 | # -fsanitize=address 32 | ) 33 | 34 | target_compile_options(test_block_queue 35 | PRIVATE 36 | -Wall -Wextra 37 | -g 38 | # -O3 39 | # -fsanitize=address 40 | 41 | ) 42 | 43 | 44 | 45 | endif() 46 | 47 | target_link_options(test_rb 48 | PRIVATE 49 | -fsanitize=address 50 | ) 51 | 52 | target_link_options(test_block_queue 53 | PRIVATE 54 | -fsanitize=address 55 | ) -------------------------------------------------------------------------------- /include/flashws/crypto/rng.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "flashws/base/basic_macros.h" 4 | #include "flashws/utils/singleton.h" 5 | #include 6 | 7 | namespace fws { 8 | 9 | class PRNGSecret : public Singleton { 10 | public: 11 | PRNGSecret() { 12 | ReSeed(); 13 | } 14 | 15 | void ReSeed() { 16 | auto rd = std::random_device{}; 17 | rng0.seed(rd()); 18 | rng1.seed(rd()); 19 | } 20 | 21 | std::tuple secrets() { 22 | return {rng0(), rng1()}; 23 | } 24 | 25 | private: 26 | std::mt19937_64 rng0, rng1; 27 | }; 28 | 29 | // TODO: Not really CSPRNG 30 | uint32_t SemiSecureRand32() { 31 | auto [v0, v1] = PRNGSecret::instance().secrets(); 32 | uint64_t product = v0 * v1; 33 | return product >> 32; 34 | } 35 | 36 | uint64_t SemiSecureRand64() { 37 | auto [v0, v1] = PRNGSecret::instance().secrets(); 38 | __uint128_t u0 = static_cast<__uint128_t>(v0); 39 | __uint128_t u1 = static_cast<__uint128_t>(v1); 40 | uint64_t half_bits = static_cast((u0 * u1) >> 64); 41 | return half_bits; 42 | } 43 | 44 | std::tuple SemiSecureRand128() { 45 | uint64_t v0 = SemiSecureRand64(); 46 | uint64_t v1 = SemiSecureRand64(); 47 | return {v0, v1}; 48 | } 49 | 50 | 51 | 52 | } // namespace fws -------------------------------------------------------------------------------- /tests/new-ws-echo/test_def.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | namespace test { 6 | 7 | // inline constexpr const char* const SERVER_IP = "10.5.96.3"; 8 | // inline constexpr const char* const SERVER_IP = "10.5.96.7"; 9 | inline constexpr const char *SERVER_IP = "172.31.48.241"; 10 | 11 | 12 | inline constexpr int SERVER_PORT = 58600; 13 | 14 | 15 | // inline constexpr size_t MAX_DATA_LEN = 64; 16 | inline constexpr size_t MAX_DATA_LEN = 512; 17 | // inline constexpr size_t MAX_DATA_LEN = 1UL << 12; 18 | // inline constexpr size_t MAX_DATA_LEN = 1 << 21; 19 | 20 | inline constexpr size_t MSG_LIMIT_PER_CLIENT = 300'000; 21 | inline constexpr int REBORN_LIMIT_FOR_CLIENT = 1; 22 | inline constexpr size_t CON_CLIENT_NUM = 1; 23 | inline constexpr size_t TOTAL_MSG_CNT = MSG_LIMIT_PER_CLIENT * CON_CLIENT_NUM * REBORN_LIMIT_FOR_CLIENT; 24 | 25 | inline constexpr int LISTEN_BACKLOG = 128; 26 | 27 | inline constexpr bool ENABLE_TLS = true; 28 | inline constexpr bool SHOULD_VERIFY_CERT = true; 29 | inline constexpr const char* hostname = ""; 30 | inline constexpr const char* cert_file_path = "../../new-ws-echo/certs/server.crt"; 31 | inline constexpr const char* key_file_path = "../../new-ws-echo/certs/server.key"; 32 | inline constexpr const char* ca_file_path = "../../new-ws-echo/certs/ca.pem"; 33 | 34 | inline constexpr const char* log_data_file_path = "./log_data.csv"; 35 | 36 | #define ENABLE_NO_DELAY 1 37 | 38 | } // namespace test -------------------------------------------------------------------------------- /tests/new-ws-echo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(new_ws_client_basic) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | add_executable(test_ws_client test_ws_client.cpp) 7 | add_executable(test_ws_server test_ws_server.cpp) 8 | 9 | target_link_libraries(test_ws_client 10 | PRIVATE ${HDR_HIST_LIB} 11 | ) 12 | 13 | #add_subdirectory(../.. ${CMAKE_CURRENT_BINARY_DIR}/flashws) 14 | 15 | 16 | target_link_libraries(test_ws_client PRIVATE fws::flashws) 17 | target_link_libraries(test_ws_server PRIVATE fws::flashws) 18 | 19 | if(NOT MSVC) 20 | target_compile_options( 21 | test_ws_client 22 | PRIVATE 23 | # -O3 24 | -g 25 | -Wall -Wextra 26 | # -fsanitize=address 27 | # -rdynamic 28 | # -fno-omit-frame-pointer 29 | # -fsanitize=undefined 30 | ) 31 | 32 | target_compile_options( 33 | test_ws_server 34 | PRIVATE 35 | # -Og 36 | -g 37 | -Wall -Wextra 38 | # -fsanitize=address 39 | # -rdynamic 40 | # -fno-omit-frame-pointer 41 | # -fsanitize=undefined 42 | ) 43 | endif() 44 | 45 | 46 | target_link_options(test_ws_client 47 | PRIVATE 48 | -flto 49 | # -fsanitize=address 50 | # -fsanitize=undefined 51 | ) 52 | 53 | 54 | 55 | target_link_options(test_ws_server 56 | PRIVATE 57 | -flto 58 | # -fsanitize=address 59 | # -fsanitize=undefined 60 | ) -------------------------------------------------------------------------------- /include/flashws/base/basic_macros.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace fws { 4 | 5 | 6 | #define FWS_LIKELY(x) (__builtin_expect((x), 1)) 7 | #define FWS_UNLIKELY(x) (__builtin_expect((x), 0)) 8 | 9 | #define FWS_NOINLINE __attribute__((__noinline__)) 10 | #define FWS_ALWAYS_INLINE inline __attribute__((__always_inline__)) 11 | 12 | #ifdef _MSC_VER 13 | #define FWS_RESTRICT 14 | #else 15 | #define FWS_RESTRICT __restrict 16 | #endif 17 | 18 | #if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) 19 | # define FWS_FUNC_RESTRICT __restrict 20 | #else 21 | # define FWS_FUNC_RESTRICT 22 | #endif 23 | 24 | #define FWS_PRAGMA(x) _Pragma (#x) 25 | 26 | #ifdef __clang__ 27 | #define FWS_UNROLL_CNT(n) FWS_PRAGMA(clang loop unroll_count(n)) 28 | #elif defined(__GNUC__) 29 | #define FWS_UNROLL_CNT(n) FWS_PRAGMA(GCC unroll n) 30 | #else 31 | #define FWS_UNROLL_CNT(n) 32 | #endif 33 | 34 | #ifdef __clang__ 35 | #define FWS_NO_LOOP_VEC FWS_PRAGMA(clang loop vectorize(disable)) 36 | #else 37 | #define FWS_NO_LOOP_VEC 38 | #endif 39 | 40 | #if defined(__GNUC__) && !defined(__clang__) 41 | #define FWS_NO_LOOP_VEC_IN_FUNC __attribute__((optimize("no-tree-vectorize"))) 42 | #else 43 | #define FWS_NO_LOOP_VEC_IN_FUNC 44 | #endif 45 | 46 | #ifdef _MSC_VER 47 | #define FWS_MSVS 48 | #elif defined(__clang__) 49 | #define FWS_CLANG 50 | #elif defined(__GNUC__) 51 | #define FWS_GCC 52 | #else 53 | // static_assert(false, "Not supported compiler"); 54 | #endif 55 | 56 | #ifdef __linux__ 57 | #define FWS_LINUX __linux__ 58 | #endif 59 | 60 | } // namespace fws 61 | -------------------------------------------------------------------------------- /tests/ws-echo/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(test_ws_client_basic) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | add_executable(test_ws_client test_ws_client.cpp) 7 | add_executable(test_ws_server test_ws_server.cpp) 8 | 9 | OPTION(USE_RAW_HISTOGRAM "Use raw_histogram, otherwise use HdrHistogram_c" OFF) 10 | 11 | if(USE_RAW_HISTOGRAM) 12 | ADD_DEFINITIONS(-DUSE_RAW_HISTOGRAM) 13 | SET(HDR_HIST_LIB "") 14 | else() 15 | add_subdirectory(../../thirdparty/HdrHistogram_c ${CMAKE_CURRENT_BINARY_DIR}/HdrHistogram_c) 16 | SET(HDR_HIST_LIB hdr_histogram_static) 17 | endif() 18 | 19 | target_link_libraries(test_ws_client 20 | PRIVATE ${HDR_HIST_LIB} 21 | ) 22 | 23 | add_subdirectory(../.. ${CMAKE_CURRENT_BINARY_DIR}/flashws) 24 | 25 | 26 | target_link_libraries(test_ws_client PRIVATE fws::flashws) 27 | target_link_libraries(test_ws_server PRIVATE fws::flashws) 28 | 29 | if(NOT MSVC) 30 | target_compile_options( 31 | test_ws_client 32 | PRIVATE 33 | # -O3 34 | # -g 35 | -Wall -Wextra 36 | # -fsanitize=address 37 | ) 38 | 39 | target_compile_options( 40 | test_ws_server 41 | PRIVATE 42 | # -O3 43 | # -g 44 | -Wall -Wextra 45 | # -fsanitize=address 46 | ) 47 | endif() 48 | 49 | 50 | target_link_options(test_ws_client 51 | PRIVATE 52 | # -fsanitize=address 53 | ) 54 | 55 | 56 | 57 | target_link_options(test_ws_server 58 | PRIVATE 59 | # -fsanitize=address 60 | 61 | ) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FlashWS 2 | 3 | This is a performance-oriented implementation of WebSocket. Strive for lowest 4 | latency and high throughput. 5 | 6 | Our library supports DPDK (Data Plane Development Kit, a kernel-bypass network 7 | library). 8 | 9 | ## Design 10 | 11 | We abstracted the TCP layer once. Various implementations are available for TCP. 12 | Currently we have implemented [F-Stack](https://github.com/F-Stack/f-stack) 13 | (TCP/IP network library based on DPDK) and 14 | POSIX API (including epoll in Linux). Even if you don't have DPDK, you can still 15 | enjoy the high performance we provide. 16 | 17 | Technologies including Zero Copy, Huge Page, SIMD, etc. are used to optimize our 18 | implementation. 19 | 20 | ## Dependency 21 | 22 | Our current implementation is based on F-Stack to obtain the TCP/IP protocol 23 | stack. So you need to install F-Stack and DPDK beforehand, unless you want to 24 | use POSIX implementation (and then some advantages are gone). See the website of 25 | [F-Stack](https://github.com/F-Stack/f-stack) for details. 26 | 27 | Also, currently we need openssl or boringssl. If you use dpdk, openssl need to be 28 | linked to it. 29 | 30 | ## Build 31 | 32 | This is a head-only library, all you need is the installation of dependencies 33 | and properly include this code directory. 34 | 35 | After you have installed the dependent libraries, 36 | 37 | ``` 38 | git clone https://github.com/renzibei/flashws 39 | cd flashws 40 | git submodule update --init --recursive 41 | ``` 42 | 43 | Then you can compile the tests and examples. 44 | 45 | ``` 46 | cd tests 47 | mkdir build 48 | cd build 49 | cmake .. [-DFWS_ENABLE_FSTACK=OFF/ON] 50 | make -j6 51 | ``` 52 | 53 | ## Performance 54 | You can take a look at the benchmark 55 | [ws-benchmark](https://github.com/renzibei/ws-benchmark). 56 | -------------------------------------------------------------------------------- /tests/test-https-client/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(test_ws_client_basic) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | add_executable(new_https_client https_client.cpp) 7 | #add_executable(http_client test_http_client.cpp) 8 | add_executable(test_search test_search.cpp) 9 | add_executable(http_pool test_http_pool.cpp) 10 | 11 | 12 | 13 | 14 | #add_subdirectory(../.. ${CMAKE_CURRENT_BINARY_DIR}/flashws) 15 | 16 | 17 | target_link_libraries(new_https_client PRIVATE fws::flashws) 18 | #target_link_libraries(http_client PRIVATE fws::flashws) 19 | target_link_libraries(test_search PRIVATE fws::flashws) 20 | target_link_libraries(http_pool PRIVATE fws::flashws) 21 | 22 | if(NOT MSVC) 23 | 24 | target_compile_options( 25 | new_https_client 26 | PRIVATE 27 | -g 28 | -Wall -Wextra 29 | -fsanitize=address 30 | 31 | ) 32 | 33 | 34 | # target_compile_options( 35 | # http_client 36 | # PRIVATE 37 | # -g 38 | # -Wall -Wextra 39 | # -fsanitize=address 40 | # ) 41 | 42 | target_compile_options( 43 | test_search 44 | PRIVATE 45 | -g 46 | -Wall -Wextra 47 | ) 48 | 49 | target_compile_options( 50 | http_pool 51 | PRIVATE 52 | -g 53 | -Wall -Wextra 54 | -fsanitize=address 55 | ) 56 | 57 | 58 | endif() 59 | 60 | 61 | 62 | target_link_options(new_https_client 63 | PRIVATE 64 | -fsanitize=address 65 | ) 66 | 67 | #target_link_options(http_client 68 | # PRIVATE 69 | # -fsanitize=address 70 | # ) 71 | 72 | 73 | target_link_options(http_pool 74 | PRIVATE 75 | -fsanitize=address 76 | ) -------------------------------------------------------------------------------- /tests/new-ws-echo/certs/ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDsR39Av1jT96sy 3 | ihhyQYy83zV+fzSapNre7EMpuZnrxqLUebwnNx2LuyuqF2HptN+m0ZNLAOv+Noeb 4 | PGmay/XCvI2EOtaxvppbUKCKMsqvCDsZj6LYqrol20VtDPOtUS65Bsn9W3shjSLQ 5 | aVdIf0v7XL86WTGr4Ot4BnV3OGC2iO+GZ0ZEt/uQ8IvG89JrBIAjzXsfK0scTaEX 6 | R9Lx95ssD2tEK1aprfb8BGKs+URoexOvflviC+FMvXgGcLVNedn4MJCBjhq10T6k 7 | qTC+ZGedTdQmDLfAxZWIfg7kUBRTcHNSViGvo+A9AepyG/hxStxTxWYs/1Nlofsn 8 | xgDqwjJjAgMBAAECggEAAfBk78lCN4cborq1uvulEIhnviXZbtV12F4pqkYpfbZa 9 | cBJJrta0dDOb3Er8f42qR4pbwkH72Hu7vtSO7KQfhwgYxIzeZdoHFphsS4YML3CK 10 | r58upRw4PTGgpGWhUFBPaQRQabcI+nxX3KGorjchOVWzBLhmVcnu6hlqIwmAPa87 11 | omEH1vW7rFu43kCg3acYgZ1rwGNpUguTSBPpywtuToVBpk/CwnBM+arLjeUTwIdA 12 | ooPfuwkkbkWceuIb9mTbjC8c2AhqZSxBXI0AjkHCJa0cT48SqGA6/z4oTGD3xQSl 13 | /gIVr6bG6cm/Qt2nxAc22mXpfnI9p4kSt3/HJO+ZCQKBgQD64FWpPyzI8LHE4v9m 14 | jxNMPiRHxLjPyc3xvH5jBPVFL5GcvjomeBOmsxia5rN15uhlWL0ZelgKI8FmP8n7 15 | OqbisJ9Eg5WWSfL2dM0Ao6Wwyi2WKqAor186rjhLAkotWR4WsqbzIhn9RhS1OER7 16 | Y4lsKtziAsaf8yhEsHg35QhZqQKBgQDxGtgnOFwrrkHXpCywlZgeOApxt/rUv6DE 17 | 3BUZyvLv6S8b6uSzEt+H6TLp9HW7VlXqWBlv+9+RT4T0G+Olms2ZaV2PWpW0nL5f 18 | 63ZvchjhI5pq4ca76gaVfZ7BKx5YRMXcv2FEGQT6GR8BDUwzWPh4g+7VtHZfTfRR 19 | NKsrIcXrKwKBgDrSOoNyQofil2u4ZXWgej/YGh2RrFtbz6OsNF33HaLZImUD3RKD 20 | +OeO+mfnS5CLUVXh1oSQwO+vrnrQ3gS/nb1s+ArSZ1JTiFnszNwngoPPA50/5Ulk 21 | xQk3LA+6O7YiPQHJZYeAKWPO+K/8v2HG1sO70QpU6Ek8c+aXEbjZRHnxAoGAZBAP 22 | C1/xqNM+Uj+5qGO9aTU66G1BtY/+KhVo0HaREo6FVaHL3qIDkUVwMvaY8fHn4EVF 23 | 8VroM0d8V09H0FAJ6hR3luoyXW37+JUhZylEOBPtn1QqhYyfxOUIwQSjKGEKeQ4Y 24 | UQnNLfrFCku5h0nyfRnMQncN9YnFzvn72/+9Q1cCgYBSHo93rW/7pwTe04Z611p0 25 | 6tV8l9wu4ONZMQhKLVjFwN0FWzhvLE1/xA5hzxAMUCzVlzjqhFw+jydvz2C/kU0j 26 | uj4qqOL5sfnlpN8cs1cyU3EKBVmbsjVjF2dMbTZyIxuG2dq1mPFmbwMjN6HDyrW9 27 | aJabCHTra5dOSNgntzVONQ== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/new-ws-echo/certs/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCnz++pcao6I/of 3 | OA+1hqp8ChFjozIFNqLc+qShbpZiw+88TnGODrumOFIQ8XLYy6BVXic303q5S8tu 4 | F4RLNynKvmHjWCJvrEBKV3MQWAu/MPTg7a+sx2jfb056tTim7vvrdyY1zBQOgA6n 5 | Zm8GsDnF/LaeepHEsElQgffoluwk09LAYi5CoTnnYxDZipCn9kQd0ji8BLnjm/pa 6 | /9+lu5NkpPADnDBtl4R3kd1JlZP+MlWwkrto2h6nBWRJp9AjeLkSmZLC8jB+RDUH 7 | GlKomKf099yFzgKb7U7+S2UfTrQqKvU/z7AXPM7TmgB/pMNL44MsPf02He/m94WC 8 | sl7hhmHPAgMBAAECggEABgv6lU74tM6eESjqe/6FvyF3vfDf+QsedDr92qlK9vUb 9 | dj9XXSiPv24RGvYwTrqLpPfXDu5qYinmgymKxVEQCvOwQEppNz/sMyGSjli116ZS 10 | dJZr+ZxX3ZE7sTU9fNpornPlJxQa9ujLXmHVB1crRcSU6gH9pao6ghGk1rc1fCAs 11 | 4sgnAxZKXGrP0ezrl2QiXFxQFWW4C6P4MlYmy+L/MXZw+O7oLSEEsHUi0TNTrxZK 12 | 3yY0wOiU2Dh8a5vwFCGEV5PFSk4t/HWuFLmdw6BEioN10KBCNbkn6UIuU+j63Fc/ 13 | KM1NrNTIwkUh9VLw9SQXs0M3Gz1xMhTBqqJgY5JilQKBgQDek+OVTKJue034ntlY 14 | fGnYc5mnn1CyXD6jVrDabVr4aE689pPO75ncEKB7BZU6kjDqKKCETIwHHxE0zUbn 15 | ea9DT3fsZ3MAjGdsapbXiunhcDDQOZe01XraLIs9gfB+UV4gbpp8KJZVSpNStCK3 16 | 7LTg1NqgC+ilGpLaEewAKe8dLQKBgQDBAs7yzaK1qhJb2UOC0+6pukzmIjL6iQsT 17 | 4WsjItO5PDou/9IA5hfpZNkSOcutOpM66tufjAj0szngA6FIDYKC7F4ZsVt9fnJT 18 | KgQNHLQfmP67onDcVKK8ifnfFNoWsx4U01NldYLobapYwWIIwtsSEbFEgecxX/BE 19 | 9G3MzwfwawKBgCvlZMPkGkDJxqXaxiiiWMmcethJHkQe1yeliDl7ya4l/CleQ+ZS 20 | 8Lgq+0tn3Xdwr37uxkFxS0h4Qw9z0KEEKaGPwan4+QBJsHf8SYV22wtf8fCO+zFp 21 | zNHMaSWXQ9PVvkeNKKCF7KgjjgyIhDRb1Yxlzjw0PQyawg2J7U5W9tZ9AoGAObVo 22 | QQqg6qY2JQY5/ET3qAHO+kQhb+1HxaLxkKjaGxlZ4DGXDbO+VIdVq/Bh6KKJ4OTV 23 | 08df6iIoXMVZFJ0Nd63KmO4Bh+0lq531ZiI97PCmwV1ZV1dq7OpoLn4ikwTtKpbg 24 | 6YYQJQSdGTqA4FO6gpWNpgkdIhMoWMWoisMgAY8CgYAa2RxlaiLYEl7en7Ke5p9w 25 | 3xRZjJY+AE7tXPM1V6tLhG6uU7SiqwAdiqjMwXHfnOxxzgRKT2owrJApyjUteT3T 26 | Urs5Onc5SPXL0/MiHXA6N1iuTqAztn9V0Q1/eo23hPsQmArJB/8H3l8hmtrGk3Ai 27 | b0ddv61DqQLZG8035+HmoA== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /tests/test-new-tcp-echo/certs/server.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCnz++pcao6I/of 3 | OA+1hqp8ChFjozIFNqLc+qShbpZiw+88TnGODrumOFIQ8XLYy6BVXic303q5S8tu 4 | F4RLNynKvmHjWCJvrEBKV3MQWAu/MPTg7a+sx2jfb056tTim7vvrdyY1zBQOgA6n 5 | Zm8GsDnF/LaeepHEsElQgffoluwk09LAYi5CoTnnYxDZipCn9kQd0ji8BLnjm/pa 6 | /9+lu5NkpPADnDBtl4R3kd1JlZP+MlWwkrto2h6nBWRJp9AjeLkSmZLC8jB+RDUH 7 | GlKomKf099yFzgKb7U7+S2UfTrQqKvU/z7AXPM7TmgB/pMNL44MsPf02He/m94WC 8 | sl7hhmHPAgMBAAECggEABgv6lU74tM6eESjqe/6FvyF3vfDf+QsedDr92qlK9vUb 9 | dj9XXSiPv24RGvYwTrqLpPfXDu5qYinmgymKxVEQCvOwQEppNz/sMyGSjli116ZS 10 | dJZr+ZxX3ZE7sTU9fNpornPlJxQa9ujLXmHVB1crRcSU6gH9pao6ghGk1rc1fCAs 11 | 4sgnAxZKXGrP0ezrl2QiXFxQFWW4C6P4MlYmy+L/MXZw+O7oLSEEsHUi0TNTrxZK 12 | 3yY0wOiU2Dh8a5vwFCGEV5PFSk4t/HWuFLmdw6BEioN10KBCNbkn6UIuU+j63Fc/ 13 | KM1NrNTIwkUh9VLw9SQXs0M3Gz1xMhTBqqJgY5JilQKBgQDek+OVTKJue034ntlY 14 | fGnYc5mnn1CyXD6jVrDabVr4aE689pPO75ncEKB7BZU6kjDqKKCETIwHHxE0zUbn 15 | ea9DT3fsZ3MAjGdsapbXiunhcDDQOZe01XraLIs9gfB+UV4gbpp8KJZVSpNStCK3 16 | 7LTg1NqgC+ilGpLaEewAKe8dLQKBgQDBAs7yzaK1qhJb2UOC0+6pukzmIjL6iQsT 17 | 4WsjItO5PDou/9IA5hfpZNkSOcutOpM66tufjAj0szngA6FIDYKC7F4ZsVt9fnJT 18 | KgQNHLQfmP67onDcVKK8ifnfFNoWsx4U01NldYLobapYwWIIwtsSEbFEgecxX/BE 19 | 9G3MzwfwawKBgCvlZMPkGkDJxqXaxiiiWMmcethJHkQe1yeliDl7ya4l/CleQ+ZS 20 | 8Lgq+0tn3Xdwr37uxkFxS0h4Qw9z0KEEKaGPwan4+QBJsHf8SYV22wtf8fCO+zFp 21 | zNHMaSWXQ9PVvkeNKKCF7KgjjgyIhDRb1Yxlzjw0PQyawg2J7U5W9tZ9AoGAObVo 22 | QQqg6qY2JQY5/ET3qAHO+kQhb+1HxaLxkKjaGxlZ4DGXDbO+VIdVq/Bh6KKJ4OTV 23 | 08df6iIoXMVZFJ0Nd63KmO4Bh+0lq531ZiI97PCmwV1ZV1dq7OpoLn4ikwTtKpbg 24 | 6YYQJQSdGTqA4FO6gpWNpgkdIhMoWMWoisMgAY8CgYAa2RxlaiLYEl7en7Ke5p9w 25 | 3xRZjJY+AE7tXPM1V6tLhG6uU7SiqwAdiqjMwXHfnOxxzgRKT2owrJApyjUteT3T 26 | Urs5Onc5SPXL0/MiHXA6N1iuTqAztn9V0Q1/eo23hPsQmArJB/8H3l8hmtrGk3Ai 27 | b0ddv61DqQLZG8035+HmoA== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /include/flashws/crypto/hmac.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace fws { 8 | 9 | FWS_ALWAYS_INLINE void BytesToHex(char* FWS_RESTRICT dst, const unsigned char* FWS_RESTRICT src, size_t src_len) { 10 | for (size_t i = 0; i < src_len; i++) { 11 | int b1 = src[i] >> 4; 12 | dst[i * 2] = (char)(55 + b1 + (((b1-10)>>31)&-7)); 13 | int b2 = src[i] & 0xF; 14 | dst[i * 2 + 1] = (char)(55 + b2 + (((b2-10)>>31)&-7)); 15 | } 16 | } 17 | 18 | struct HMACContext { 19 | HMAC_CTX *ctx; 20 | 21 | int Init(std::string_view key) { 22 | ctx = HMAC_CTX_new(); 23 | if FWS_UNLIKELY(!ctx) { 24 | return -1; 25 | } 26 | if FWS_UNLIKELY(HMAC_Init_ex(ctx, key.data(), key.length(), EVP_sha256(), nullptr) != 1) { 27 | return -2; 28 | } 29 | return 0; 30 | } 31 | 32 | HMACContext(): ctx(nullptr) {} 33 | 34 | HMACContext(const HMACContext &) = delete; 35 | 36 | HMACContext &operator=(const HMACContext &) = delete; 37 | 38 | HMACContext(HMACContext &&o) noexcept: 39 | ctx(std::exchange(o.ctx, nullptr)) {} 40 | 41 | ~HMACContext() { 42 | if (ctx) { 43 | HMAC_CTX_free(ctx); 44 | ctx = nullptr; 45 | } 46 | } 47 | }; 48 | 49 | template 50 | ssize_t GetHMACSHA256(HMACContext& FWS_RESTRICT ctx, std::string_view msg, char* dst) { 51 | static_assert(buf_len >= 64, "Buffer must be at least 64 bytes long"); 52 | if FWS_UNLIKELY(HMAC_Init_ex(ctx.ctx, nullptr, 0, EVP_sha256(), nullptr) != 1) { 53 | return -1; 54 | // Handle errors 55 | } 56 | 57 | HMAC_Update(ctx.ctx, reinterpret_cast(msg.data()), msg.length()); 58 | 59 | unsigned int mac_length = 0; 60 | unsigned char digest[EVP_MAX_MD_SIZE]; 61 | HMAC_Final(ctx.ctx, digest, &mac_length); 62 | // Hex string length is twice the binary length 63 | ssize_t ret = mac_length * 2; 64 | 65 | BytesToHex(dst, digest, mac_length); 66 | 67 | return ret; 68 | } 69 | 70 | } // namespace fws -------------------------------------------------------------------------------- /tests/test-new-tcp-echo/test_def.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#define SERVER_PORT 58600 4 | #define SERVER_PORT 58600 5 | //#define MAX_DATA_LEN (1 << 18) 6 | #define MAX_DATA_LEN 64 7 | 8 | //#define TEST_TIMES 1'00'000 9 | 10 | #define ENABLE_NO_DELAY 1 11 | #define ENABLE_BUSY_POLL 1 12 | #define BUSY_POLL_US 800 13 | #define SET_NON_BLOCK 1 14 | // If the client side have many connections in fstack, it may bring too many TIME_WAIT 15 | // status closed socket. In this case, a linger with zero timeout can be used, 16 | // when the client side close the socket, it will send a RST to the server side, and 17 | // no TIME_WAIT status will be generated. 18 | #define SET_LINGER_ZERO_TIMEOUT 0 19 | 20 | #define MAX_WRITE_EVENT_WRITE_SIZE 65536 21 | #define FSTACK_ONE_TIME_FULL_THRES 16384 22 | #define MAX_FSTACK_ONE_TIME_WRITE_SIZE 16384 23 | 24 | #define SEND_LATENCY_DATA 0 25 | 26 | 27 | namespace test { 28 | //inline constexpr const char * SERVER_IP = "127.0.0.1"; 29 | 30 | //inline constexpr const char* const SERVER_IP = "10.5.96.3"; 31 | 32 | 33 | inline constexpr const char *SERVER_IP = "172.31.48.241"; 34 | 35 | inline constexpr bool ENABLE_TLS = true; 36 | inline constexpr bool SHOULD_VERIFY_CERT = true; 37 | inline constexpr const char* hostname = ""; 38 | inline constexpr const char* cert_file_path = "../../test-new-tcp-echo/certs/server.crt"; 39 | inline constexpr const char* key_file_path = "../../test-new-tcp-echo/certs/server.key"; 40 | inline constexpr const char* ca_file_path = "../../test-new-tcp-echo/certs/ca.pem"; 41 | 42 | 43 | inline constexpr size_t MSG_LIMIT_PER_CLIENT = 300'000; 44 | // inline constexpr size_t MSG_LIMIT_PER_CLIENT = 50; 45 | 46 | inline constexpr size_t CON_CLIENT_NUM = 1; 47 | 48 | inline constexpr size_t LISTEN_BACKLOG = 4096; 49 | 50 | inline constexpr size_t REBORN_LIMIT_FOR_CLIENT = 1; 51 | 52 | inline constexpr size_t TOTAL_MSG_CNT = MSG_LIMIT_PER_CLIENT * CON_CLIENT_NUM * REBORN_LIMIT_FOR_CLIENT; 53 | 54 | inline constexpr uint64_t CHECK_TIMEOUT_TICK = 240ULL * 4ULL * 1'000'000'000ULL; 55 | 56 | #if SEND_LATENCY_DATA 57 | inline constexpr size_t LATENCY_DATA_SIZE = sizeof(uint64_t) * 2; 58 | #else 59 | inline constexpr size_t LATENCY_DATA_SIZE = 0; 60 | #endif 61 | 62 | static_assert(LATENCY_DATA_SIZE <= MAX_DATA_LEN); 63 | 64 | 65 | #define MAX_EVENT_NUM 4096 66 | 67 | } //namespace test -------------------------------------------------------------------------------- /include/flashws/utils/histogram_wrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef USE_RAW_HISTOGRAM 4 | #include "raw_histogram.h" 5 | #else 6 | #include "hdr/hdr_histogram.h" 7 | #endif 8 | 9 | #include 10 | 11 | namespace hist { 12 | 13 | #ifdef USE_RAW_HISTOGRAM 14 | class HistWrapper: public raw_h::RawHistogram { 15 | using Base = raw_h::RawHistogram; 16 | public: 17 | explicit HistWrapper(size_t max_call_num = 10000, int64_t min_value = 1, 18 | int64_t max_value = 1'000'000'000LL):Base(max_call_num) { 19 | (void)min_value; 20 | (void)max_value; 21 | } 22 | using Base::AddValue; 23 | using Base::Quantile; 24 | using Base::SortForUse; 25 | 26 | void PrintHdr(size_t show_cnt = 15UL, FILE *out_fp = stdout, int step = 2) { 27 | (void)step; 28 | Print(show_cnt, LONG_TAIL_STYLE, out_fp); 29 | } 30 | 31 | protected: 32 | 33 | }; // class HistWrapper 34 | #else 35 | class HistWrapper { 36 | public: 37 | explicit HistWrapper(size_t max_call_num = 10000, int64_t min_value = 1, 38 | int64_t max_value = 1'000'000'000LL) 39 | : hdr_ptr(nullptr) { 40 | (void)max_call_num; 41 | hdr_init(min_value, max_value, 2, &hdr_ptr); 42 | } 43 | 44 | HistWrapper operator==(const HistWrapper&) = delete; 45 | HistWrapper(const HistWrapper&) = delete; 46 | 47 | constexpr HistWrapper(HistWrapper&& o) noexcept :hdr_ptr(o.hdr_ptr) { 48 | o.hdr_ptr = nullptr; 49 | } 50 | 51 | constexpr HistWrapper& operator=(HistWrapper&& o) { 52 | if (this != &o) { 53 | hdr_close(hdr_ptr); 54 | hdr_ptr = std::exchange(o.hdr_ptr, nullptr); 55 | } 56 | return *this; 57 | } 58 | 59 | inline void AddValue(int64_t x) { 60 | hdr_record_value(hdr_ptr, x); 61 | } 62 | 63 | int64_t Quantile(double percentile) const { 64 | return hdr_value_at_percentile(hdr_ptr, percentile * 100.0); 65 | } 66 | 67 | void SortForUse() {} 68 | 69 | void PrintHdr(size_t /*show_cnt*/, FILE *out_fp = stdout, int step = 2) { 70 | hdr_percentiles_print(hdr_ptr, out_fp, step, 1.0, CSV); 71 | } 72 | 73 | ~HistWrapper() { 74 | hdr_close(hdr_ptr); 75 | hdr_ptr = nullptr; 76 | } 77 | 78 | protected: 79 | hdr_histogram *hdr_ptr; 80 | 81 | }; // class HistWrapper 82 | #endif 83 | 84 | }// namespace hist -------------------------------------------------------------------------------- /tests/test-https-client/test_search.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "flashws/utils/cpu_timer.h" 7 | #include 8 | #include 9 | #include 10 | 11 | template 12 | static void timed(const char *name, F f) 13 | { 14 | using namespace std::chrono; 15 | int64_t start_tick = cpu_t::Start64(); 16 | // auto begin = high_resolution_clock::now(); 17 | constexpr size_t repeat = 100000; 18 | for (size_t i = 0; i < repeat; ++i) { 19 | f(); 20 | } 21 | // f(); 22 | int64_t end_tick = cpu_t::Stop64(); 23 | // auto end = high_resolution_clock::now(); 24 | int64_t pass_tick = end_tick - start_tick; 25 | double avg_pass_tick = double(pass_tick) / repeat; 26 | std::cout << name << " : " << avg_pass_tick << " ticks\n"; 27 | // std::cout << name << " : " 28 | // << duration_cast(end - begin).count() << " ns\n"; 29 | } 30 | 31 | int main(int argc, char *argv[]) 32 | { 33 | std::vector buf(1024); 34 | // std::vector buf(4 * 1024); 35 | // std::vector pattern(111); 36 | // pattern[110] = std::byte(1); 37 | std::vector pattern = {'\r', '\n', '\r', '\n'}; 38 | //warm up 39 | for (int i = 0; i < 10000; ++i) { 40 | memset(buf.data(), 0, buf.size()); 41 | } 42 | memcpy(buf.data() + 384, pattern.data(), pattern.size()); 43 | 44 | 45 | 46 | 47 | timed("std::default_searcher", [&] { 48 | // auto it = std::search(buf.begin(), buf.end(), pattern.begin(), pattern.end()); 49 | auto it = std::search(buf.begin(), buf.end(), 50 | std::default_searcher(pattern.begin(), pattern.end())); 51 | if (it == buf.end()) { 52 | std::cerr << "Incorrect result\n"; 53 | } 54 | }); 55 | 56 | timed("memmem", [&] { 57 | auto match = memmem(buf.data(), buf.size(), 58 | pattern.data(), pattern.size()); 59 | if (match == nullptr) { 60 | std::cerr << "Incorrect result\n"; 61 | } 62 | }); 63 | 64 | timed("std::boyer_moore_searcher", [&] { 65 | auto it = std::search(buf.begin(), buf.end(), 66 | std::boyer_moore_searcher(pattern.begin(), pattern.end())); 67 | if (it == buf.end()) { 68 | std::cerr << "Incorrect result\n"; 69 | } 70 | }); 71 | 72 | timed("std::boyer_moore_horspool_searcher", [&] { 73 | auto it = std::search(buf.begin(), buf.end(), 74 | std::boyer_moore_horspool_searcher(pattern.begin(), pattern.end())); 75 | if (it == buf.end()) { 76 | std::cerr << "Incorrect result\n"; 77 | } 78 | }); 79 | } -------------------------------------------------------------------------------- /include/flashws/base/errno_str.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "flashws/base/basic_macros.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace fws { 10 | 11 | 12 | 13 | namespace detail { 14 | thread_local inline char error_buf[4096] = {0}; 15 | } // namespace detail 16 | 17 | inline FWS_NOINLINE void SetErrorString(const char* src, size_t len) { 18 | strncpy(detail::error_buf, src, std::min(len, sizeof(detail::error_buf))); 19 | } 20 | 21 | inline FWS_NOINLINE void WriteToError(const void* src, size_t len) { 22 | memcpy(detail::error_buf, src, std::min(len, sizeof(detail::error_buf))); 23 | } 24 | 25 | 26 | #ifdef FWS_DEV_DEBUG 27 | inline FWS_NOINLINE void SetErrorFormatStr(const char* FWS_RESTRICT format, ...) { 28 | std::va_list arg_list; 29 | va_start(arg_list, format); 30 | vsnprintf(detail::error_buf, sizeof(detail::error_buf), format, arg_list); 31 | va_end(arg_list); 32 | } 33 | #else 34 | // template 35 | // inline FWS_NOINLINE void SetErrorFormatStr(const char* FWS_RESTRICT format, Args... args) { 36 | // snprintf(detail::error_buf, sizeof(detail::error_buf), format, std::forward(args)...); 37 | // } 38 | #define SetErrorFormatStr(format, ...) \ 39 | snprintf(detail::error_buf, sizeof(detail::error_buf), format, ##__VA_ARGS__) 40 | #endif 41 | 42 | inline std::string_view GetErrorStrV() { 43 | return {detail::error_buf}; 44 | } 45 | 46 | inline std::string GetErrorString() { 47 | return {detail::error_buf}; 48 | } 49 | 50 | inline const char* GetErrorStrP() { 51 | return detail::error_buf; 52 | } 53 | 54 | namespace detail { 55 | 56 | inline FWS_NOINLINE void FwsAssert(const char* exp, int line, 57 | const char* file) { 58 | fprintf(stderr, "Assert %s failed, line %d in %s\n", exp, line, file); 59 | std::abort(); 60 | } 61 | 62 | inline FWS_NOINLINE void FwsAssert(const char* exp, const char* msg, int line, 63 | const char* file) { 64 | fprintf(stderr, "Assert %s failed, %s, line %d in %s\n", 65 | exp, msg, line, file); 66 | std::abort(); 67 | } 68 | 69 | } // namespace detail 70 | 71 | 72 | #ifdef FWS_DEBUG 73 | #define FWS_ASSERT(EX) \ 74 | {if FWS_UNLIKELY(!(EX)) \ 75 | fws::detail::FwsAssert(#EX, __LINE__, __FILE__); } 76 | 77 | #define FWS_ASSERT_M(EX, MSG) \ 78 | {if FWS_UNLIKELY(!(EX)) \ 79 | fws::detail::FwsAssert(#EX, (MSG), __LINE__, __FILE__); } 80 | #else 81 | #define FWS_ASSERT(EX) ((void)(EX)) 82 | #define FWS_ASSERT_M(EX, MSG) ((void)(EX)) 83 | #endif 84 | 85 | } // namespace fws -------------------------------------------------------------------------------- /include/flashws/base/constexpr_math.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace fws { 7 | 8 | constexpr uint64_t RoundUpLog2(uint64_t x) { 9 | if (x <= 1UL) { 10 | return 0; 11 | } 12 | return 64 - __builtin_clzll(x - 1UL); 13 | } 14 | 15 | static_assert(RoundUpLog2(1) == 0); 16 | static_assert(RoundUpLog2(2) == 1); 17 | static_assert(RoundUpLog2(16) == 4); 18 | static_assert(RoundUpLog2(30) == 5); 19 | 20 | constexpr uint64_t RoundDownLog2(uint64_t x) { 21 | if (x == 0) { 22 | return 0; 23 | } 24 | return 64ULL - __builtin_clzll(x); 25 | } 26 | 27 | static_assert(RoundDownLog2(2) == 2); 28 | static_assert(RoundDownLog2(3) == 2); 29 | static_assert(RoundDownLog2(1) == 1); 30 | static_assert(RoundDownLog2(4) == 3); 31 | 32 | constexpr uint64_t RoundUpPow2(uint64_t x) { 33 | if (x <= 1UL) { 34 | return x; 35 | } 36 | return 1ULL << (64 - __builtin_clzll(x - 1UL)); 37 | } 38 | 39 | static_assert(RoundUpPow2(1) == 1); 40 | static_assert(RoundUpPow2(15) == 16); 41 | static_assert(RoundUpPow2(1024) == 1024); 42 | 43 | constexpr uint64_t RoundDownPow2(uint64_t x) { 44 | if (x == 0) { 45 | return 0; 46 | } 47 | return 1ULL << (RoundDownLog2(x) - 1U); 48 | } 49 | 50 | static_assert(RoundDownPow2(1) == 1); 51 | static_assert(RoundDownPow2(2) == 2); 52 | static_assert(RoundDownPow2(3) == 2); 53 | static_assert(RoundDownPow2(510) == 256); 54 | 55 | constexpr uint64_t DivPow2(uint64_t x, uint64_t d) { 56 | auto log2 = RoundUpLog2(d); 57 | return x >> log2; 58 | } 59 | 60 | static_assert(DivPow2(256, 16) == 16); 61 | static_assert(DivPow2(512, 1) == 512); 62 | static_assert(DivPow2(1024, 8) == 128); 63 | static_assert(DivPow2(4096, 4096) == 1); 64 | static_assert(DivPow2(13, 8) == 1); 65 | static_assert(DivPow2(510, 32) == 15); 66 | 67 | template 68 | constexpr T RotateR (T v, U b) 69 | { 70 | static_assert(std::is_integral::value, "rotate of non-integral type"); 71 | static_assert(! std::is_signed::value, "rotate of signed type"); 72 | static_assert(std::is_integral::value, "rotate of non-integral type"); 73 | constexpr unsigned num_bits {std::numeric_limits::digits}; 74 | static_assert(0 == (num_bits & (num_bits - 1)), "rotate value bit length not power of two"); 75 | constexpr U count_mask {num_bits - 1}; 76 | // to make sure mb < num_bits 77 | const auto mb {b & count_mask}; 78 | using promoted_type = typename std::common_type::type; 79 | using unsigned_promoted_type = typename std::make_unsigned::type; 80 | return ((unsigned_promoted_type{v} >> mb) 81 | | (unsigned_promoted_type{v} << (-mb & count_mask))); 82 | } 83 | 84 | static_assert(RotateR(0xf0000000U, 4) == 0x0f000000U); 85 | static_assert(RotateR(0xf0000000U, 32U) == 0xf0000000U); 86 | static_assert(RotateR(0xf0000000U, 8U) == 0x00f00000U); 87 | static_assert(RotateR(0xf0000000U, 36) == 0x0f000000U); 88 | 89 | } // namespace fws 90 | -------------------------------------------------------------------------------- /include/flashws/base/hw_endian.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "flashws/base/basic_macros.h" 4 | 5 | #ifdef FWS_MSC 6 | #include 7 | #endif 8 | 9 | #if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \ 10 | defined(__BIG_ENDIAN__) || \ 11 | defined(__ARMEB__) || \ 12 | defined(__THUMBEB__) || \ 13 | defined(__AARCH64EB__) || \ 14 | defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) 15 | 16 | #define FWS_BIG_ENDIAN 17 | 18 | #elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \ 19 | defined(__LITTLE_ENDIAN__) || \ 20 | defined(__ARMEL__) || \ 21 | defined(__THUMBEL__) || \ 22 | defined(__AARCH64EL__) || \ 23 | defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__) 24 | 25 | #define FWS_LITTLE_ENDIAN 26 | 27 | #else 28 | static_assert(false, "Unknown endian"); 29 | #endif 30 | 31 | namespace fws { 32 | 33 | FWS_ALWAYS_INLINE constexpr uint16_t ByteSwap16(uint16_t x) { 34 | #ifdef FWS_MSC 35 | return _byteswap_ushort(x); 36 | #elif defined(__GNUC__) 37 | return __builtin_bswap16(x); 38 | #else 39 | static_assert(false, "Not implemented for this compiler\n"); 40 | #endif 41 | } 42 | static_assert(ByteSwap16(0x1234U) == 0x3412U); 43 | 44 | FWS_ALWAYS_INLINE constexpr uint32_t ByteSwap32(uint32_t x) { 45 | #ifdef FWS_MSC 46 | return _byteswap_ulong(x); 47 | #elif defined(__GNUC__) 48 | return __builtin_bswap32(x); 49 | #else 50 | static_assert(false, "Not implemented for this compiler\n"); 51 | #endif 52 | } 53 | static_assert(ByteSwap32(0x12345678U) == 0x78563412U); 54 | 55 | FWS_ALWAYS_INLINE constexpr uint64_t ByteSwap64(uint64_t x) { 56 | #ifdef FWS_MSC 57 | return _byteswap_uint64(x); 58 | #elif defined(__GNUC__) 59 | return __builtin_bswap64(x); 60 | #else 61 | static_assert(false, "Not implemented for this compiler\n"); 62 | #endif 63 | } 64 | static_assert(ByteSwap64(0x1234567876543210ULL) == 0x1032547678563412ULL); 65 | 66 | FWS_ALWAYS_INLINE constexpr uint16_t Net2Host16(uint16_t x) { 67 | #ifdef FWS_LITTLE_ENDIAN 68 | return ByteSwap16(x); 69 | #else 70 | return x; 71 | #endif 72 | } 73 | 74 | FWS_ALWAYS_INLINE constexpr uint16_t Host2Net16(uint16_t x) { 75 | #ifdef FWS_LITTLE_ENDIAN 76 | return ByteSwap16(x); 77 | #else 78 | return x; 79 | #endif 80 | } 81 | 82 | FWS_ALWAYS_INLINE constexpr uint32_t Net2Host32(uint32_t x) { 83 | #ifdef FWS_LITTLE_ENDIAN 84 | return ByteSwap32(x); 85 | #else 86 | return x; 87 | #endif 88 | } 89 | 90 | FWS_ALWAYS_INLINE constexpr uint32_t Host2Net32(uint32_t x) { 91 | #ifdef FWS_LITTLE_ENDIAN 92 | return ByteSwap32(x); 93 | #else 94 | return x; 95 | #endif 96 | } 97 | 98 | FWS_ALWAYS_INLINE constexpr uint64_t Net2Host64(uint64_t x) { 99 | #ifdef FWS_LITTLE_ENDIAN 100 | return ByteSwap64(x); 101 | #else 102 | return x; 103 | #endif 104 | } 105 | 106 | FWS_ALWAYS_INLINE constexpr uint64_t Host2Net64(uint64_t x) { 107 | #ifdef FWS_LITTLE_ENDIAN 108 | return ByteSwap64(x); 109 | #else 110 | return x; 111 | #endif 112 | } 113 | 114 | 115 | 116 | } // namespace fws -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(flashws) 3 | 4 | 5 | 6 | add_library(flashws INTERFACE) 7 | 8 | add_library(fws::flashws ALIAS flashws) 9 | 10 | 11 | 12 | target_include_directories(flashws INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") 13 | 14 | OPTION(FWS_ENABLE_FSTACK "Use f-stack, other wise system api" ON) 15 | OPTION(FWS_DEBUG "In Debug Mode" ON) 16 | OPTION(FWS_DEV_DEBUG "Debug Mode For Development" OFF) 17 | OPTION(FWS_FORCE_NO_EPOLL "Force not to use epoll even if f-stack is turned off" OFF) 18 | OPTION(FWS_FORCE_TIMEOUT_ZERO "Force timeout of FEventWait to be zero, otherwise may keeping wait" OFF) 19 | OPTION(FWS_USE_BORINGSSL "Use BoringSSL" OFF) 20 | 21 | if(FWS_DEBUG) 22 | target_compile_definitions(flashws 23 | INTERFACE -DFWS_DEBUG) 24 | endif() 25 | 26 | if(FWS_DEV_DEBUG) 27 | target_compile_definitions(flashws 28 | INTERFACE -DFWS_DEV_DEBUG) 29 | endif() 30 | 31 | if(FWS_FORCE_NO_EPOLL) 32 | target_compile_definitions(flashws 33 | INTERFACE -DFWS_FORCE_NO_EPOLL) 34 | endif() 35 | 36 | if(FWS_FORCE_TIMEOUT_ZERO) 37 | target_compile_definitions(flashws 38 | INTERFACE -DFWS_FORCE_TIMEOUT_ZERO) 39 | endif() 40 | 41 | MESSAGE(STATUS "FWS_ENABLE_FSTACK ${FWS_ENABLE_FSTACK}") 42 | MESSAGE(STATUS "FWS_DEBUG: ${FWS_DEBUG}") 43 | MESSAGE(STATUS "FWS_DEV_DEBUG ${FWS_DEV_DEBUG}") 44 | MESSAGE(STATUS "FWS_FORCE_NO_EPOLL ${FWS_FORCE_NO_EPOLL}") 45 | MESSAGE(STATUS "FWS_FORCE_TIMEOUT_ZERO ${FWS_FORCE_TIMEOUT_ZERO}") 46 | MESSAGE(STATUS "FWS_USE_BORINGSSL ${FWS_USE_BORINGSSL}") 47 | 48 | 49 | # Check if the compiler supports AVX2 50 | include(CheckCXXCompilerFlag) 51 | CHECK_CXX_COMPILER_FLAG("-mavx2" COMPILER_SUPPORTS_AVX2) 52 | 53 | if(COMPILER_SUPPORTS_AVX2 AND (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")) 54 | message(STATUS "AVX2 supported. Adding -mavx2 flag.") 55 | target_compile_options(flashws 56 | INTERFACE 57 | -mavx2 58 | ) 59 | else() 60 | message(STATUS "AVX2 not supported by the compiler.") 61 | endif() 62 | 63 | if (FWS_USE_BORINGSSL AND NOT FWS_ENABLE_FSTACK) 64 | add_subdirectory(thirdparty/boringssl) 65 | target_compile_definitions(flashws 66 | INTERFACE 67 | -DFWS_USE_BORINGSSL) 68 | target_link_libraries( 69 | flashws 70 | INTERFACE 71 | crypto 72 | ssl 73 | ) 74 | else() 75 | find_package(OpenSSL REQUIRED) 76 | target_link_libraries( 77 | flashws 78 | INTERFACE 79 | OpenSSL::SSL 80 | OpenSSL::Crypto 81 | ) 82 | target_compile_options(flashws 83 | INTERFACE 84 | -Wno-deprecated-declarations 85 | ) 86 | endif() 87 | 88 | 89 | 90 | 91 | if(FWS_ENABLE_FSTACK) 92 | target_compile_definitions(flashws 93 | INTERFACE 94 | -DFWS_ENABLE_FSTACK) 95 | 96 | find_package(PkgConfig REQUIRED) 97 | 98 | pkg_check_modules(DPDK REQUIRED IMPORTED_TARGET libdpdk) 99 | 100 | 101 | target_compile_options(flashws 102 | INTERFACE 103 | ${DPDK_CFLAGS} 104 | ) 105 | 106 | target_link_options(flashws 107 | INTERFACE 108 | ${DPDK_STATIC_LDFLAGS} 109 | "SHELL:-Wl,--whole-archive,-lfstack,--no-whole-archive" 110 | ) 111 | 112 | target_link_options(flashws 113 | INTERFACE 114 | -pthread 115 | -lm 116 | -lrt 117 | -ldl 118 | -lnuma 119 | ) 120 | 121 | endif() 122 | 123 | 124 | -------------------------------------------------------------------------------- /include/flashws/base/constants.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | 6 | 7 | namespace fws { 8 | 9 | namespace constants { 10 | 11 | constexpr inline bool ENABLE_BUSY_POLL_BY_DEFAULT = true; 12 | constexpr inline int BUSY_POLL_US_IF_ENABLED = 800; 13 | 14 | constexpr inline bool ENABLE_NO_DELAY_BY_DEFAULT = true; 15 | constexpr inline bool ENABLE_NON_BLOCK_BY_DEFAULT = true; 16 | 17 | // If this is enabled, the FLoop will update the time every time there 18 | // is an event. Users can access the time by calling last_event_time_ns() 19 | constexpr inline bool ENABLE_FLOOP_EVENT_TIME_UPDATE = true; 20 | 21 | // If this is enabled, even when there is no active event, the FEventWait 22 | // will return immediately. This is useful for some cases like manually 23 | // busy polling and check for events like timeout. However, for epoll, 24 | // this may harm the latency compared to the linux system-level busy_poll. 25 | // F-stack will return immediately regardless of this setting. 26 | // When using POSIX poll, for maximum performance, system level busy_poll should 27 | // be used with this. 28 | #ifdef FWS_FORCE_TIMEOUT_ZERO 29 | constexpr inline bool FEVENT_WAIT_RETURN_IMMEDIATELY = true; 30 | #else 31 | constexpr inline bool FEVENT_WAIT_RETURN_IMMEDIATELY = false; 32 | #endif 33 | 34 | // This takes the stack space 35 | constexpr inline size_t MAX_REQ_URI_LENGTH = 512; 36 | 37 | constexpr inline size_t MAX_HANDSHAKE_RESP_LENGTH = 512; 38 | constexpr inline size_t MAX_HANDSHAKE_REQUEST_LENGTH = 4096; 39 | 40 | // constexpr inline size_t MAX_WRITABLE_SIZE_ONE_TIME = 16384; 41 | // TODO: dynamic change this 42 | #ifdef FWS_ENABLE_FSTACK 43 | constexpr inline size_t MAX_WRITABLE_SIZE_ONE_TIME = 65536; 44 | #else 45 | constexpr inline size_t MAX_WRITABLE_SIZE_ONE_TIME = 16384; 46 | #endif 47 | 48 | // Used in the buffer of TLS and TCP read one time. 49 | #ifdef FWS_ENABLE_FSTACK 50 | constexpr inline size_t MAX_READABLE_SIZE_ONE_TIME = 1 << 21; 51 | #else 52 | constexpr inline size_t MAX_READABLE_SIZE_ONE_TIME = 1 << 21; 53 | #endif 54 | // Padding before the buffer if using TCP/TLS read. WS may need this. 55 | constexpr inline size_t DEFAULT_READ_BUF_PRE_PADDING_SIZE = 32; 56 | 57 | // constexpr inline size_t MAX_WRITABLE_SIZE_ONE_TIME = 1UL << 21; 58 | 59 | // The actual maximum size of frame size is 4 GB for both recv and send 60 | constexpr inline size_t MAX_WS_FRAME_SIZE = (1ULL << 32); 61 | 62 | constexpr inline size_t MAX_WS_FRAME_HEADER_SIZE = 14; 63 | constexpr inline size_t MAX_WS_SERVER_RX_FRAME_HEADER_SIZE = 14; 64 | constexpr inline size_t MAX_WS_CLIENT_RX_FRAME_HEADER_SIZE = 10; 65 | // The typical frame hdr size for frame in [126, 65536] is 8 bytes 66 | // For alignment consideration, use 24 bytes ahead 67 | constexpr inline size_t SUGGEST_RESERVE_WS_HDR_SIZE = 24; 68 | constexpr inline size_t WS_SERVER_TX_CONTROL_HDR_SIZE = 2; 69 | constexpr inline size_t WS_CLIENT_TX_CONTROL_HDR_SIZE = 6; 70 | constexpr inline size_t WS_MAX_CONTROL_FRAME_SIZE = 125; 71 | 72 | static_assert(SUGGEST_RESERVE_WS_HDR_SIZE <= DEFAULT_READ_BUF_PRE_PADDING_SIZE); 73 | 74 | constexpr inline size_t HTTP_REQUEST_RESERVE_HDR_SIZE = 512; 75 | static_assert(HTTP_REQUEST_RESERVE_HDR_SIZE < MAX_READABLE_SIZE_ONE_TIME); 76 | 77 | constexpr inline size_t HTTP_MAX_RECV_BUF_SIZE = 1UL << 23; 78 | 79 | // Defined in RFC doc 80 | constexpr inline const char SEC_WS_VERSION[] = "13"; 81 | 82 | constexpr inline const char GLOBAL_WS_UUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 83 | // uuid str length is 36 84 | static_assert(sizeof(GLOBAL_WS_UUID) == 37); 85 | } // namespace constants 86 | 87 | } // namespace fws -------------------------------------------------------------------------------- /include/flashws/base/buffer_manager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "flashws/utils/flash_alloc.h" 4 | #include "flashws/utils/flat_hash_map.h" 5 | #include "errno_str.h" 6 | 7 | namespace fws { 8 | 9 | class BufferManager : public Singleton { 10 | public: 11 | 12 | FWS_ALWAYS_INLINE void AddBufRefCount(uint8_t *buf_data_ptr) noexcept { 13 | auto find_it = buf_cnt_map_.find(buf_data_ptr); 14 | if (find_it == buf_cnt_map_.end()) { 15 | auto [emplace_it, ok] = buf_cnt_map_.emplace(buf_data_ptr, uint64_t(0)); 16 | find_it = emplace_it; 17 | (void)ok; 18 | } 19 | ++(find_it->second); 20 | } 21 | 22 | FWS_ALWAYS_INLINE uint64_t DecBufRefCount(uint8_t *buf_data_ptr) { 23 | auto find_it = buf_cnt_map_.find(buf_data_ptr); 24 | // FWS_ASSERT_M(find_it != buf_cnt_map_.end(), "DecBufRefCount not found"); 25 | FWS_ASSERT_M(find_it->second > 0, "Call DecBufRefCount more than " 26 | "AddBufRefCount"); 27 | // TODO:now we do not erase data_ptr from hash map because we assume 28 | // that the freed data would be allocated again 29 | return --(find_it->second); 30 | } 31 | 32 | protected: 33 | ska::flat_hash_map buf_cnt_map_; 34 | }; 35 | 36 | struct IOBuffer { 37 | uint8_t *data = nullptr; 38 | 39 | // meaningful size of data from start_pos 40 | ssize_t size = 0; 41 | 42 | // data[start_pos] is the first byte of data 43 | size_t start_pos = 0; 44 | // capacity of the buf, start from data+0 45 | size_t capacity = 0; 46 | 47 | IOBuffer(uint8_t *data, ssize_t size, size_t start_pos, size_t cap) noexcept: 48 | data(data), size(size), start_pos(start_pos), capacity(cap) { 49 | if (data != nullptr) { 50 | BufferManager::instance().AddBufRefCount((uint8_t*)data); 51 | } 52 | } 53 | IOBuffer() noexcept: data(nullptr), size(0), start_pos(0), capacity(0) {} 54 | 55 | IOBuffer(const IOBuffer&) = delete; 56 | IOBuffer& operator=(const IOBuffer&) = delete; 57 | 58 | IOBuffer(IOBuffer &&o) noexcept: data(std::exchange(o.data, nullptr)), 59 | size(std::exchange(o.size, 0)), 60 | start_pos(std::exchange(o.start_pos, 0)), 61 | capacity(std::exchange(o.capacity, 0)) {} 62 | 63 | IOBuffer& operator=(IOBuffer &&o) noexcept { 64 | if FWS_UNLIKELY(&o == this) { 65 | return *this; 66 | } 67 | std::swap(data, o.data); 68 | std::swap(size, o.size); 69 | std::swap(start_pos, o.start_pos); 70 | std::swap(capacity, o.capacity); 71 | return *this; 72 | } 73 | 74 | ~IOBuffer() { 75 | if (data) { 76 | uint64_t ref_count = BufferManager::instance().DecBufRefCount(data); 77 | if (ref_count == 0) { 78 | MemPoolEnv::instance().deallocate(data); 79 | } 80 | data = nullptr; 81 | } 82 | } 83 | 84 | }; 85 | 86 | 87 | 88 | // TODO: maybe can set the capacity to the true capacity in underlying 89 | // data is null if fail 90 | IOBuffer RequestBuf(size_t cap, size_t start_pos = 0) { 91 | void* p = MemPoolEnv::instance().allocate(cap); 92 | // Inc ref count in the constructor 93 | IOBuffer ret((uint8_t*)p, 0, start_pos, cap); 94 | return ret; 95 | } 96 | 97 | 98 | void ReclaimBuf(IOBuffer& buf) { 99 | uint64_t ref_count = BufferManager::instance().DecBufRefCount(buf.data); 100 | if (ref_count == 0) { 101 | MemPoolEnv::instance().deallocate(buf.data); 102 | } 103 | buf.data = nullptr; 104 | } 105 | 106 | } // namespace fws -------------------------------------------------------------------------------- /include/flashws/utils/raw_histogram.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace raw_h { 10 | 11 | #if defined(__GNUC__) || defined(__clang__) 12 | #define RAW_H_LIKELY(x) (__builtin_expect(static_cast(x), 1)) 13 | #define RAW_H_UNLIKELY(x) (__builtin_expect(static_cast(x), 0)) 14 | #else 15 | #define RAW_H_LIKELY(x) (x) 16 | #define RAW_H_UNLIKELY(x) (x) 17 | #endif 18 | 19 | #ifndef RAW_H_ALWAYS_INLINE 20 | # ifdef _MSC_VER 21 | # define RAW_H_ALWAYS_INLINE __forceinline 22 | # else 23 | # define RAW_H_ALWAYS_INLINE inline __attribute__((__always_inline__)) 24 | # endif 25 | #endif 26 | 27 | template> 28 | class RawHistogram { 29 | public: 30 | 31 | explicit RawHistogram(size_t max_call_num = 10000): count_(0), max_call_num_(max_call_num), 32 | data_vec_(max_call_num, static_cast(1)) { 33 | 34 | } 35 | 36 | RAW_H_ALWAYS_INLINE int AddValue(const T& t) { 37 | if RAW_H_UNLIKELY(count_ + 1UL > max_call_num_) { 38 | return -1; 39 | } 40 | data_vec_[count_++] = t; 41 | return 0; 42 | } 43 | 44 | RAW_H_ALWAYS_INLINE int AddValue(T&& t) { 45 | if RAW_H_UNLIKELY(count_ + 1UL > max_call_num_) { 46 | return -1; 47 | } 48 | data_vec_[count_++] = std::move(t); 49 | return 0; 50 | } 51 | 52 | T Quantile(double q) const { 53 | if (q < 0.0 || q > 1.0 || count_ == 0) { 54 | return data_vec_[0]; 55 | } 56 | size_t index = static_cast(count_ - 1Ul) * q; 57 | return data_vec_[index]; 58 | } 59 | 60 | /** 61 | * Call this before Quantile if there is new added values after Print 62 | */ 63 | void SortForUse() { 64 | std::sort(data_vec_.data(), data_vec_.data() + count_); 65 | } 66 | 67 | enum PrintStyle { 68 | AVERAGE_INTERVAL_STYLE, 69 | LONG_TAIL_STYLE, 70 | }; 71 | 72 | int Print(size_t show_cnt = 10UL, PrintStyle style = LONG_TAIL_STYLE, FILE *out_fp = stdout) { 73 | if (show_cnt == 0 || count_ <= 1UL) { 74 | return -1; 75 | } 76 | std::sort(data_vec_.data(), data_vec_.data() + count_); 77 | size_t print_cnt = std::min(count_ - 1UL, show_cnt); 78 | double interval_len = static_cast(count_ - 1UL) / static_cast(print_cnt); 79 | double real_index = 0.0; 80 | double cur_interval = 0.25; 81 | fprintf(out_fp, "Value,Percentile,TotalCount\n"); 82 | for (size_t i = 0; i < print_cnt + 1UL; ++i) { 83 | size_t index = static_cast(std::round(real_index)); 84 | double percentile = real_index / static_cast(count_ - 1UL); 85 | if (i == print_cnt) { 86 | index = count_ - 1UL; 87 | percentile = 1.0; 88 | } 89 | 90 | std::stringstream ss; 91 | ss << data_vec_[index] << "," << std::setprecision(8) << std::fixed << percentile << "," << index + 1ULL << std::endl; 92 | fprintf(out_fp, "%s", ss.str().c_str()); 93 | if (style == AVERAGE_INTERVAL_STYLE) { 94 | real_index += interval_len; 95 | } 96 | else { 97 | real_index += cur_interval * static_cast(count_ - 1UL); 98 | if (i & 1UL) { 99 | cur_interval *= 0.5; 100 | } 101 | } 102 | } 103 | return 0; 104 | } 105 | 106 | protected: 107 | size_t count_; 108 | size_t max_call_num_; 109 | std::vector data_vec_; 110 | }; // class raw histogram 111 | 112 | } // namespace raw_h 113 | -------------------------------------------------------------------------------- /tests/test_ring_buffer/test_block_queue.cpp: -------------------------------------------------------------------------------- 1 | #include "flashws/utils/block_queue.h" 2 | #include "flashws/utils/flash_alloc.h" 3 | //#include "fast_alloc.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static uint64_t RandSeed = 0x12345678911ULL; 10 | static inline uint64_t CustomRand() { 11 | RandSeed = 1103515245 * RandSeed + 12345; 12 | return RandSeed; 13 | } 14 | 15 | static inline void ResetSeed() { 16 | RandSeed = 0x12345678911ULL; 17 | } 18 | 19 | static inline void setSeed(uint64_t seed) { 20 | RandSeed = seed; 21 | } 22 | 23 | void testBlockQueue() { 24 | constexpr size_t BlockSize = 1 << 21; 25 | using TestType = uint64_t; 26 | // using Uint8Allocator = fws::internal::InternalAllocator; 27 | // using Uint8PtrAllocator = fws::internal::InternalAllocator; 28 | using BlockQueueAllocator = fws::internal::InternalAllocator; 29 | using BlockQueue = fws::BlockQueue; 30 | 31 | constexpr size_t TestSizeArray[] = {0, 1, 3, 8, 16, 47238947, 1 << 21, 1 << 22, (1 << 23) + 4, ( 1 << 24) + 123789, (1 << 27) + 37489, 5000}; 32 | constexpr size_t TestNum = sizeof(TestSizeArray) / sizeof(TestSizeArray[0]); 33 | 34 | std::deque stdDeque, stdDeque2; 35 | BlockQueue blockQueue(BlockSize), blockQueue2; 36 | size_t preDataSize = 0; 37 | for (size_t t = 0; t < TestNum; ++t) { 38 | 39 | auto temp_std_queue = std::move(stdDeque); 40 | stdDeque = std::move(stdDeque2); 41 | stdDeque2 = std::move(temp_std_queue); 42 | 43 | auto temp_block_queue = std::move(blockQueue); 44 | blockQueue = std::move(blockQueue2); 45 | blockQueue2 = std::move(temp_block_queue); 46 | 47 | size_t dataSize = TestSizeArray[t]; 48 | stdDeque.resize(dataSize); 49 | blockQueue.resize(dataSize); 50 | 51 | stdDeque2.resize(0); 52 | blockQueue2.resize(0); 53 | 54 | 55 | 56 | 57 | setSeed(dataSize * 2); 58 | 59 | for (size_t i = 0; i < dataSize; ++i) { 60 | if (dataSize == 47238947 && i == 1048577) { 61 | int c = 0; 62 | } 63 | TestType x = CustomRand(); 64 | if ((x & 3) && !stdDeque2.empty()) { 65 | stdDeque2.pop_back(); 66 | blockQueue2.pop_back(); 67 | } 68 | else { 69 | stdDeque2.push_back(x); 70 | blockQueue2.push_back(x); 71 | } 72 | if (!stdDeque2.empty()) { 73 | if (stdDeque2.back() != blockQueue2.back()) { 74 | fprintf(stderr, "stdDeque2.back() != blockQueue2.back()"); 75 | return; 76 | } 77 | } 78 | } 79 | 80 | 81 | for (size_t i = 0; i < stdDeque2.size(); ++i) { 82 | if (stdDeque2[i] != blockQueue2[i]) { 83 | fprintf(stderr, "std deque[%lu] = %u while block queue[%lu] = %u", i, stdDeque2[i], i, blockQueue2[i]); 84 | return; 85 | } 86 | } 87 | 88 | setSeed(dataSize); 89 | for (size_t i = preDataSize; i < dataSize; ++i) { 90 | stdDeque[i] = CustomRand(); 91 | } 92 | setSeed(dataSize); 93 | for (size_t i = preDataSize; i < dataSize; ++i) { 94 | blockQueue[i] = CustomRand(); 95 | } 96 | 97 | for (size_t i = 0; i < dataSize; ++i) { 98 | if (stdDeque[i] != blockQueue[i]) { 99 | fprintf(stderr, "std deque[%lu] = %u while block queue[%lu] = %u", i, stdDeque[i], i, blockQueue[i]); 100 | return; 101 | } 102 | } 103 | if (stdDeque.size() != blockQueue.size()) { 104 | fprintf(stderr, "size not equal!"); 105 | return; 106 | } 107 | 108 | if (t == 2) { 109 | int c = 0; 110 | } 111 | 112 | 113 | preDataSize = dataSize; 114 | 115 | } 116 | fprintf(stderr, "BlockQueue test passed!\n"); 117 | 118 | } 119 | 120 | int main() { 121 | testBlockQueue(); 122 | } -------------------------------------------------------------------------------- /tests/test-https-client/https_client.cpp: -------------------------------------------------------------------------------- 1 | #include "test_def.h" 2 | #include "flashws/net/tls_socket.h" 3 | #include "flashws/net/fevent.h" 4 | #include "flashws/flashws.h" 5 | #include "flashws/net/floop.h" 6 | 7 | namespace test { 8 | 9 | struct ClientContext { 10 | size_t sent_size; 11 | }; 12 | 13 | int TestHTTPSClient(int argc, char** argv) { 14 | 15 | if (fws::InitEnv(argc, argv) < 0) { 16 | printf("Error in init env: %s\n", fws::GetErrorString().c_str()); 17 | return -1; 18 | } 19 | 20 | int ssl_manager_init_ret = fws::SSLManager::instance().Init(true, nullptr, nullptr, nullptr); 21 | if (ssl_manager_init_ret < 0) { 22 | printf("Error in ssl manager init, return %d, %s\n", 23 | ssl_manager_init_ret, fws::GetErrorStrP()); 24 | std::abort(); 25 | } 26 | 27 | fws::FLoop loop; 28 | if (loop.Init() < 0) { 29 | printf("Failed to init floop, %s\n", fws::GetErrorStrP()); 30 | return -1; 31 | } 32 | 33 | 34 | 35 | fws::TLSSocket socket{}; 36 | if (socket.Init(REAL_HOST) < 0) { 37 | printf("Failed to init tls socket, %s\n", fws::GetErrorStrP()); 38 | return -1; 39 | } 40 | 41 | 42 | 43 | socket.SetOnOpen([](fws::TLSSocket &sock, void *user_data){ 44 | new (user_data) ClientContext{}; 45 | ClientContext *ctx = static_cast(user_data); 46 | ctx->sent_size = 0; 47 | printf("On open called in tls socket\n"); 48 | size_t target_size = sizeof(https_request) - 1; 49 | int write_ret = sock.Write(https_request + ctx->sent_size, target_size - ctx->sent_size); 50 | if (write_ret < 0) { 51 | printf("Error in tls write, return %d, %s\n", 52 | write_ret, fws::GetErrorStrP()); 53 | std::abort(); 54 | } 55 | ctx->sent_size += write_ret; 56 | printf("Sent size: %d\n", write_ret); 57 | }); 58 | 59 | socket.SetOnWritable([](fws::TLSSocket &sock, size_t writable_size, void *user_data){ 60 | printf("On writable called in tls socket, writable size: %zu\n", writable_size); 61 | ClientContext *ctx = static_cast(user_data); 62 | size_t target_size = sizeof(https_request) - 1; 63 | if (ctx->sent_size < target_size) { 64 | int write_ret = sock.Write(https_request + ctx->sent_size, target_size - ctx->sent_size); 65 | if (write_ret < 0) { 66 | printf("Error in tls write, return %d, %s\n", 67 | write_ret, fws::GetErrorStrP()); 68 | std::abort(); 69 | } 70 | ctx->sent_size += write_ret; 71 | printf("Sent size: %d\n", write_ret); 72 | } 73 | }); 74 | 75 | socket.SetOnReadable([](fws::TLSSocket & /*sock*/, fws::IOBuffer &&buf, void * /*user_data*/){ 76 | printf("On readable called in tls socket, get %ld bytes\n", buf.size); 77 | if (buf.size > 0) { 78 | fwrite(buf.data + buf.start_pos, 1, buf.size, stdout); 79 | } 80 | 81 | }); 82 | 83 | socket.SetOnClose([&loop](fws::TLSSocket & /*sock*/, void * /*user_data*/){ 84 | printf("On close called in tls socket\n"); 85 | loop.StopRun(); 86 | }); 87 | 88 | socket.SetOnError([](fws::TLSSocket& , int code, std::string_view reason, void *) { 89 | printf("On error called in tls socket, code: %d, reason: %s\n", code, reason.data()); 90 | }); 91 | 92 | int con_ret = socket.Connect(host_ip, host_port); 93 | if FWS_UNLIKELY(con_ret < 0 && errno != EINPROGRESS) { 94 | printf("Error in connect, return %d, %s\n", 95 | con_ret, fws::GetErrorStrP()); 96 | std::abort(); 97 | } 98 | 99 | auto [add_ret, _] = loop.AddSocket(std::move(socket), sizeof(ClientContext), false); 100 | if (add_ret < 0) { 101 | printf("Failed to add tls socket to loop, %s\n", fws::GetErrorStrP()); 102 | return -1; 103 | } 104 | 105 | loop.Run(); 106 | 107 | return 0; 108 | } 109 | 110 | 111 | } // namespace test 112 | 113 | int main(int argc, char** argv) { 114 | 115 | return test::TestHTTPSClient(argc, argv); 116 | } -------------------------------------------------------------------------------- /include/flashws/net/ws_server.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "flashws/base/base_include.h" 4 | #include "flashws/net/tcp_socket.h" 5 | #include "flashws/net/fevent.h" 6 | #include "flashws/net/w_socket.h" 7 | #include "flashws/net/ws_server_socket.h" 8 | 9 | namespace fws { 10 | 11 | 12 | class WsServer { 13 | 14 | public: 15 | 16 | WsServer(bool no_delay = false, int busy_poll_us = 0) noexcept: 17 | poll_us_(busy_poll_us), no_delay_(no_delay) {} 18 | 19 | template 20 | int HandleFEvent(FQueue& FWS_RESTRICT fq, const FEvent& FWS_RESTRICT event, 21 | EventHandler& FWS_RESTRICT handler) { 22 | if FWS_UNLIKELY(event.has_error()) { 23 | SetErrorFormatStr("Error in event, flags: %u", event.socket_err_code()); 24 | return -1; 25 | } 26 | else { 27 | 28 | 29 | 30 | #ifdef FWS_ENABLE_FSTACK 31 | int available = event.available_accept_size(); 32 | #ifdef FWS_DEV_DEBUG 33 | fprintf(stderr, "ws server %d get %d sockets to accept\n", 34 | tcp_socket_.fd(), available); 35 | #endif 36 | // size_t need_fevent_size = sizeof(fws::FEvent) * available; 37 | // IOBuffer events_buf = RequestBuf(need_fevent_size); 38 | // FEvent* ev_start = (FEvent*)(events_buf.data); 39 | // size_t ev_cnt = 0; 40 | #endif 41 | 42 | while(true) { 43 | #ifdef FWS_ENABLE_FSTACK 44 | if (available-- <= 0) { 45 | break; 46 | } 47 | #endif 48 | auto new_opt_sock = tcp_socket_.Accept(nullptr, nullptr); 49 | if (!new_opt_sock.has_value()) { 50 | if FWS_LIKELY(errno == EWOULDBLOCK) { 51 | break; 52 | } 53 | SetErrorFormatStr("WS server failed to accept new socket"); 54 | return -2; 55 | } 56 | auto &new_tcp_sock = new_opt_sock.value(); 57 | int new_fd = new_tcp_sock.fd(); 58 | if FWS_UNLIKELY(new_tcp_sock.SetNonBlock() < 0) { 59 | SetErrorFormatStr("Failed to set new socket non-blocking"); 60 | return -3; 61 | } 62 | if (no_delay_) { 63 | if FWS_UNLIKELY(new_tcp_sock.SetNoDelay() < 0) { 64 | SetErrorFormatStr("Failed to set new socket no delay"); 65 | return -4; 66 | } 67 | } 68 | if (poll_us_ > 0) { 69 | if FWS_UNLIKELY(new_tcp_sock.SetBusyPoll(poll_us_) < 0) { 70 | return -7; 71 | } 72 | } 73 | int add_read_ret = AddFEvent(fq, new_fd, FEVAC_READ); 74 | if FWS_UNLIKELY(add_read_ret < 0) { 75 | SetErrorFormatStr("Error in add read event for new socket"); 76 | return -5; 77 | } 78 | //#ifdef FWS_ENABLE_FSTACK 79 | // ev_start[ev_cnt++] = FEvent(new_fd, FEVFILT_READ, FEV_ADD, FEFFLAG_NONE, 80 | // 0, nullptr); 81 | //#else 82 | // FEvent read_event(new_fd, FEVFILT_READ, FEV_ADD, FEFFLAG_NONE, 83 | // 0, nullptr); 84 | // if FWS_UNLIKELY(fws::FEventWait(fq, &read_event, 1, nullptr, 0, nullptr) < 0) { 85 | // return -5; 86 | // } 87 | //#endif 88 | fws::WSServerSocket new_wsocket{}; 89 | new_wsocket.Init(new_tcp_sock); 90 | handler.OnNewTcpConnection(new_wsocket); 91 | } 92 | //#ifdef FWS_ENABLE_FSTACK 93 | // if FWS_UNLIKELY(fws::FEventWait(fq, ev_start, ev_cnt, nullptr, 0, nullptr) < 0) { 94 | // return -6; 95 | // } 96 | //#endif 97 | } 98 | return 0; 99 | } 100 | 101 | int StartListen(const char* host_ip_addr, 102 | uint16_t port, int backlog, 103 | TCPSocket::BindMode bind_mode) { 104 | if FWS_UNLIKELY(tcp_socket_.Init() < 0) { 105 | return -1; 106 | } 107 | if FWS_UNLIKELY(tcp_socket_.SetNonBlock() < 0) { 108 | tcp_socket_.Close(); 109 | return -2; 110 | } 111 | if FWS_UNLIKELY(tcp_socket_.Bind(host_ip_addr, port, bind_mode) < 0) { 112 | tcp_socket_.Close(); 113 | return -3; 114 | } 115 | if FWS_UNLIKELY(tcp_socket_.Listen(backlog) < 0) { 116 | tcp_socket_.Close(); 117 | return -4; 118 | } 119 | return 0; 120 | } 121 | 122 | TCPSocket& tcp_socket() { 123 | return tcp_socket_; 124 | } 125 | 126 | protected: 127 | TCPSocket tcp_socket_; 128 | int poll_us_; 129 | bool no_delay_; 130 | 131 | }; // class WsServer 132 | 133 | } // namespace fws -------------------------------------------------------------------------------- /include/flashws/crypto/ssl_manager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "flashws/utils/singleton.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace fws { 9 | 10 | class SSLManager : public Singleton { 11 | public: 12 | 13 | [[nodiscard]] bool is_inited() const { 14 | return is_inited_; 15 | } 16 | 17 | SSL_CTX *ctx() const { 18 | return ctx_; 19 | } 20 | 21 | /** 22 | * This function must be called before using TLSSocket function calls 23 | * @param certfile 24 | * @param keyfile 25 | * @return 26 | */ 27 | int Init(bool should_verify, const char * certfile, const char* keyfile, const char* ca_file_path) { 28 | if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL)) { 29 | SetErrorFormatStr("Failed to initialize OpenSSL\n"); 30 | return -1; 31 | } 32 | 33 | /* create the SSL server context */ 34 | // TODO: ERR_error_string is not safe in this way 35 | ctx_ = SSL_CTX_new(TLS_method()); 36 | if (!ctx_) { 37 | SetErrorFormatStr("SSL_CTX_new failed: %s", ERR_error_string(ERR_get_error(), nullptr)); 38 | return -1; 39 | } 40 | 41 | SSL_CTX_set_read_ahead(ctx_, 1); 42 | SSL_CTX_set_mode(ctx_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); 43 | 44 | if (!SSL_CTX_set_min_proto_version(ctx_, TLS1_2_VERSION)) { 45 | SetErrorFormatStr("SSL_CTX_set_min_proto_version failed: %s", 46 | ERR_error_string(ERR_get_error(), nullptr)); 47 | return -1; 48 | } 49 | 50 | /* Load certificate and private key files, and check consistency */ 51 | if (certfile && keyfile) { 52 | // if (SSL_CTX_use_certificate_file(ctx_, certfile, SSL_FILETYPE_PEM) != 1) { 53 | if (SSL_CTX_use_certificate_chain_file(ctx_, certfile) != 1) { 54 | SetErrorFormatStr("SSL_CTX_use_certificate_file failed: %s", 55 | ERR_error_string(ERR_get_error(), nullptr)); 56 | ERR_clear_error(); 57 | return -1; 58 | } 59 | 60 | if (SSL_CTX_use_PrivateKey_file(ctx_, keyfile, SSL_FILETYPE_PEM) != 1) { 61 | SetErrorFormatStr("SSL_CTX_use_PrivateKey_file failed: %s", 62 | ERR_error_string(ERR_get_error(), nullptr)); 63 | ERR_clear_error(); 64 | return -1; 65 | } 66 | 67 | /* Make sure the key and certificate file match. */ 68 | if (SSL_CTX_check_private_key(ctx_) != 1) { 69 | SetErrorFormatStr("SSL_CTX_check_private_key failed: %s", 70 | ERR_error_string(ERR_get_error(), nullptr)); 71 | ERR_clear_error(); 72 | return -1; 73 | } 74 | 75 | } 76 | 77 | if (ca_file_path) { 78 | if (!SSL_CTX_load_verify_locations(ctx_, ca_file_path, nullptr)) { 79 | SetErrorFormatStr("Failed to load CA file: %s", ERR_error_string(ERR_get_error(), nullptr)); 80 | ERR_clear_error(); 81 | return -1; 82 | } 83 | } 84 | else if (should_verify) { 85 | if (!SSL_CTX_set_default_verify_paths(ctx_)) { 86 | SetErrorFormatStr("Failed to set default CA paths: %s", ERR_error_string(ERR_get_error(), nullptr)); 87 | return -1; 88 | } 89 | } 90 | 91 | if (should_verify) { 92 | SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER, nullptr); 93 | } 94 | 95 | 96 | // const char* ca_file_name = "/etc/ssl/certs/ca-certificates.crt"; 97 | // STACK_OF(X509_NAME) *ca_list; 98 | // ca_list = SSL_load_client_CA_file(ca_file_name); 99 | // if(ca_list == NULL) { 100 | // printf("Error creating ca list from %s\n", ca_file_name); 101 | // return -1; 102 | // } 103 | // SSL_CTX_set_client_CA_list(ctx_, ca_list); 104 | 105 | 106 | // SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER, [](int preverify_ok, X509_STORE_CTX* x509_ctx) -> int { 107 | // if (!preverify_ok) { 108 | // ERR_print_errors_fp(stdout); 109 | // X509* cert = X509_STORE_CTX_get_current_cert(x509_ctx); 110 | // int depth = X509_STORE_CTX_get_error_depth(x509_ctx); 111 | // int err = X509_STORE_CTX_get_error(x509_ctx); 112 | // // Log error, certificate, depth, etc. 113 | // SetErrorFormatStr("Certificate verification failed: %s, depth: %d, err: %d", 114 | // ERR_error_string(err, nullptr), depth, err); 115 | // printf("%s\n",GetErrorStrP()); 116 | // return 0; 117 | // } 118 | // return preverify_ok; // You can return 0 to fail the verification forcibly 119 | // }); 120 | 121 | 122 | 123 | is_inited_ = true; 124 | return 0; 125 | } 126 | protected: 127 | SSL_CTX *ctx_ = nullptr; 128 | bool is_inited_ = false; 129 | }; // class SSLManager 130 | 131 | }; // namespace fws -------------------------------------------------------------------------------- /tests/test-https-client/test_http_client.cpp: -------------------------------------------------------------------------------- 1 | #include "flashws/flashws.h" 2 | #include "flashws/net/floop.h" 3 | #include "flashws/net/http_client.h" 4 | 5 | namespace test { 6 | 7 | 8 | 9 | 10 | 11 | struct Context { 12 | int send_cnt = 0; 13 | fws::FLoop<> *loop_ptr = nullptr; 14 | }; 15 | 16 | int TestHTTPClient() { 17 | fws::FLoop loop{}; 18 | 19 | if (loop.Init() < 0) { 20 | printf("Failed to init floop, %s\n", fws::GetErrorStrP()); 21 | return -1; 22 | } 23 | 24 | int ssl_manager_init_ret = fws::SSLManager::instance().Init(true, nullptr, nullptr, nullptr); 25 | if (ssl_manager_init_ret < 0) { 26 | printf("Error in ssl manager init, return %d, %s\n", 27 | ssl_manager_init_ret, fws::GetErrorStrP()); 28 | std::abort(); 29 | } 30 | 31 | // constexpr static std::string_view HOST = "www.google.com"; 32 | // constexpr static std::string_view HOST = "www.baidu.com"; 33 | constexpr static std::string_view HOST = "www.cloudflare.com"; 34 | constexpr static std::string_view PATH = "/"; 35 | // constexpr static std::string_view IP_STR = "74.125.138.99"; // google 36 | // constexpr static std::string_view IP_STR = "103.235.47.103"; // baidu 37 | constexpr static std::string_view IP_STR = "104.16.124.96"; // cloudflare 38 | constexpr static int PORT = 443; 39 | fws::HTTPClient *http_client_ptr = nullptr; 40 | constexpr size_t REQUEST_COUNT = 4; 41 | // size_t cur_request_count = 0; 42 | { 43 | Context ctx{0, &loop}; 44 | auto [create_ret, client] = fws::HTTPClient::Create(loop, HOST, 45 | IP_STR, PORT, std::move(ctx)); 46 | if (create_ret < 0) { 47 | printf("Error in create http client, %s\n", fws::GetErrorStrP()); 48 | return -1; 49 | } 50 | // client->SetOnRecvMsg([](fws::HTTPClient &http, int status_code, 51 | // fws::IOBuffer &&buf, Context &ctx){ 52 | // printf("HTTP OnRecvMsg, status: %d, msg size %ld\n", status_code, buf.size); 53 | // fwrite(buf.data + buf.start_pos, 1, buf.size, stdout); 54 | // constexpr char ENDLINE = '\n'; 55 | // fwrite(&ENDLINE, 1, 1, stdout); 56 | // 57 | // auto [hdr_arr, hdr_cnt] = http.headers(); 58 | // for (size_t i = 0; i < hdr_cnt; ++i) { 59 | // printf("%s: %s\n", std::string(hdr_arr[i].key).c_str(), 60 | // std::string(hdr_arr[i].value).c_str()); 61 | // } 62 | // ++ctx.send_cnt; 63 | // if (ctx.send_cnt == REQUEST_COUNT) { 64 | // http.Close(); 65 | // ctx.loop_ptr->StopRun(); 66 | // return; 67 | // } 68 | // if (http.SendRequest(PATH) < 0) { 69 | // printf("Error in second send request, %s\n", fws::GetErrorStrP()); 70 | // std::exit(-1); 71 | // } 72 | // }); 73 | client->SetOnRecvPart([](fws::HTTPClient &http, int status_code, 74 | bool is_msg_end, fws::IOBuffer &&buf, Context& ctx) { 75 | printf("HTTP OnRead, status: %d, is_end: %d, buf size %ld\n", 76 | status_code, is_msg_end, buf.size); 77 | fwrite(buf.data + buf.start_pos, 1, buf.size, stdout); 78 | constexpr char ENDLINE = '\n'; 79 | fwrite(&ENDLINE, 1, 1, stdout); 80 | if (is_msg_end) { 81 | auto [hdr_arr, hdr_cnt] = http.headers(); 82 | for (size_t i = 0; i < hdr_cnt; ++i) { 83 | printf("%s: %s\n", std::string(hdr_arr[i].key).c_str(), 84 | std::string(hdr_arr[i].value).c_str()); 85 | } 86 | ++ctx.send_cnt; 87 | if (ctx.send_cnt == REQUEST_COUNT) { 88 | http.Close(); 89 | ctx.loop_ptr->StopRun(); 90 | return; 91 | } 92 | if (http.SendRequest(PATH) < 0) { 93 | printf("Error in second send request, %s\n", fws::GetErrorStrP()); 94 | std::exit(-1); 95 | } 96 | } 97 | fflush(stdout); 98 | 99 | }); 100 | client->SetOnClose([](fws::HTTPClient &http, Context&) { 101 | printf("HTTP OnClose\n"); 102 | }); 103 | client->SetOnOpen([](fws::HTTPClient &http, Context&) { 104 | printf("HTTP OnOpen\n"); 105 | if (http.SendRequest(PATH) < 0) { 106 | printf("Error in send request, %s\n", fws::GetErrorStrP()); 107 | std::exit(-1); 108 | } 109 | }); 110 | client->SetOnError([](fws::HTTPClient &http, std::string_view reason, Context&) { 111 | printf("HTTP OnError, err: %s\n", std::string(reason).c_str()); 112 | }); 113 | http_client_ptr = client; 114 | 115 | } 116 | 117 | loop.Run(); 118 | return 0; 119 | } 120 | 121 | } // namespace test 122 | 123 | int main() { 124 | return test::TestHTTPClient(); 125 | return 0; 126 | } -------------------------------------------------------------------------------- /tests/test-https-client/test_http_pool.cpp: -------------------------------------------------------------------------------- 1 | #include "flashws/flashws.h" 2 | #include "flashws/net/floop.h" 3 | #include "flashws/net/http_client.h" 4 | #include "flashws/net/http_client_pool.h" 5 | namespace test { 6 | 7 | 8 | 9 | 10 | 11 | struct Context { 12 | size_t send_cnt = 0; 13 | size_t recv_cnt = 0; 14 | size_t conn_cnt = 0; 15 | fws::FLoop<> *loop_ptr = nullptr; 16 | fws::HTTPClientPool *http_pool_ptr = nullptr; 17 | int64_t start_ns = 0; 18 | int64_t end_ns = 0; 19 | fws::HTTPClientPool::HTTPOnRecvMsgFunc on_recv_msg; 20 | fws::HTTPClientPool::HTTPOnErrorFunc on_error; 21 | 22 | }; 23 | 24 | int TestHTTPClient(int argc, char** argv) { 25 | 26 | if (fws::InitEnv(argc, argv) < 0) { 27 | printf("Failed to init env, %s\n", fws::GetErrorStrP()); 28 | return -1; 29 | } 30 | 31 | fws::FLoop loop{}; 32 | 33 | if (loop.Init() < 0) { 34 | printf("Failed to init floop, %s\n", fws::GetErrorStrP()); 35 | return -1; 36 | } 37 | 38 | int ssl_manager_init_ret = fws::SSLManager::instance().Init(true, nullptr, nullptr, nullptr); 39 | if (ssl_manager_init_ret < 0) { 40 | printf("Error in ssl manager init, return %d, %s\n", 41 | ssl_manager_init_ret, fws::GetErrorStrP()); 42 | std::abort(); 43 | } 44 | 45 | constexpr static std::string_view HOST = "www.google.com"; 46 | // constexpr static std::string_view HOST = "www.baidu.com"; 47 | // constexpr static std::string_view HOST = "www.cloudflare.com"; 48 | constexpr static std::string_view PATH = "/"; 49 | constexpr static std::string_view IP_STR = "74.125.138.99"; // google 50 | // constexpr static std::string_view IP_STR = "103.235.47.103"; // baidu 51 | // constexpr static std::string_view IP_STR = "104.16.124.96"; // cloudflare 52 | constexpr static int PORT = 443; 53 | // fws::HTTPClient *http_client_ptr = nullptr; 54 | constexpr size_t REQUEST_COUNT = 10; 55 | constexpr size_t KEEP_CONN_CNT = 3; 56 | constexpr size_t MAX_CONN_CNT = 5; 57 | 58 | constexpr size_t TEST_TARGET_CONN_CNT_SAME_TIME = 6; 59 | constexpr int64_t NS_PER_SEC = 1'000'000'000LL; 60 | 61 | constexpr int64_t WAIT_TO_SEND_NS = 1LL * NS_PER_SEC; 62 | constexpr int64_t PRE_EXIT_WAIT_NS = 0LL * NS_PER_SEC; 63 | // size_t cur_request_count = 0; 64 | fws::HTTPClientPool http_pool{}; 65 | if (http_pool.Init(loop, HOST, IP_STR, PORT, KEEP_CONN_CNT, MAX_CONN_CNT) < 0) { 66 | printf("Error in init http pool, %s\n", fws::GetErrorStrP()); 67 | return -1; 68 | } 69 | Context ctx{0, 0, 0, &loop, &http_pool, 0, 0}; 70 | ctx.start_ns = fws::GetNowNsFromEpoch(); 71 | { 72 | 73 | auto on_recv_msg = [&ctx](fws::HTTPClientPool::ClientType &http, int status_code, 74 | fws::IOBuffer &&buf){ 75 | printf("HTTP OnRecvMsg, status: %d, msg size %ld\n", status_code, buf.size); 76 | fwrite(buf.data + buf.start_pos, 1, buf.size, stdout); 77 | constexpr char ENDLINE = '\n'; 78 | fwrite(&ENDLINE, 1, 1, stdout); 79 | ++ctx.recv_cnt; 80 | auto [hdr_arr, hdr_cnt] = http.headers(); 81 | for (size_t i = 0; i < hdr_cnt; ++i) { 82 | printf("%s: %s\n", std::string(hdr_arr[i].key).c_str(), 83 | std::string(hdr_arr[i].value).c_str()); 84 | } 85 | if (ctx.send_cnt >= REQUEST_COUNT) { 86 | if (ctx.end_ns == 0) { 87 | ctx.end_ns = fws::GetNowNsFromEpoch(); 88 | // http.Close(); 89 | // ctx.loop_ptr->StopRun(); 90 | 91 | } 92 | return; 93 | } 94 | ++ctx.send_cnt; 95 | // if (ctx.http_pool_ptr->template SendRequest(PATH, ctx.on_recv_msg, ctx.on_error) < 0) { 96 | // printf("Error in send request, %s\n", fws::GetErrorStrP()); 97 | // ctx.loop_ptr->StopRun(); 98 | // } 99 | 100 | if (http.SendRequest(PATH) < 0) { 101 | printf("Error in second send request, %s\n", fws::GetErrorStrP()); 102 | ctx.loop_ptr->StopRun(); 103 | } 104 | }; 105 | 106 | auto on_error = [](fws::HTTPClientPool::ClientType &http, std::string_view reason) { 107 | printf("HTTP OnError, err: %s\n", std::string(reason).c_str()); 108 | }; 109 | ctx.on_recv_msg = std::move(on_recv_msg); 110 | ctx.on_error = std::move(on_error); 111 | 112 | // http_client_ptr = client; 113 | 114 | } 115 | loop.SetOnEventFunc([&ctx](fws::FLoop<>& loop) { 116 | if (ctx.conn_cnt < TEST_TARGET_CONN_CNT_SAME_TIME && ctx.send_cnt < REQUEST_COUNT) { 117 | int64_t now_ns = fws::GetNowNsFromEpoch(); 118 | if (now_ns - ctx.start_ns > WAIT_TO_SEND_NS) { 119 | ++ctx.send_cnt; 120 | if (ctx.http_pool_ptr->template SendRequest(PATH, ctx.on_recv_msg, ctx.on_error) < 0) { 121 | printf("Error in send request, %s\n", fws::GetErrorStrP()); 122 | ctx.loop_ptr->StopRun(); 123 | } 124 | ++ctx.conn_cnt; 125 | } 126 | } 127 | if (ctx.recv_cnt >= REQUEST_COUNT && ctx.end_ns != 0) { 128 | int64_t now_ns = fws::GetNowNsFromEpoch(); 129 | if (now_ns - ctx.end_ns > PRE_EXIT_WAIT_NS) { 130 | ctx.loop_ptr->StopRun(); 131 | } 132 | } 133 | 134 | }); 135 | 136 | loop.Run(); 137 | return 0; 138 | } 139 | 140 | } // namespace test 141 | 142 | int main(int argc, char** argv) { 143 | return test::TestHTTPClient(argc, argv); 144 | return 0; 145 | } -------------------------------------------------------------------------------- /tests/test-alloc/alloc_latency.cpp: -------------------------------------------------------------------------------- 1 | #include "flashws/utils/flash_alloc.h" 2 | #include "flashws/base/constexpr_math.h" 3 | #include "flashws/utils/histogram_wrapper.h" 4 | #include "flashws/utils/cpu_timer.h" 5 | 6 | #include // for std::max 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace test { 14 | 15 | static constexpr size_t MAX_TOTAL_SIZE = 1UL << 24; 16 | static constexpr size_t MIN_STR_LEN = 1ULL << 8; 17 | static constexpr size_t MAX_STR_LEN = (1ULL << 20) * 2UL; 18 | static constexpr size_t LOOP_NUM = fws::RoundUpLog2(MAX_STR_LEN) + 1UL; 19 | 20 | int TestAlloc1() { 21 | // Ensure the MemPoolEnv is initialized 22 | fws::MemPoolEnv::instance(); 23 | 24 | // CPU timer for measuring overhead and allocation times 25 | cpu_t::CpuTimer cpu_timer; 26 | printf("overhead ticks: %ld, ticks per ns: %lf\n", 27 | cpu_timer.overhead_ticks(), 1.0 / cpu_timer.ns_per_tick()); 28 | 29 | // Arrays/vectors to keep track of pointers and histograms 30 | std::array, LOOP_NUM> str_arr; 31 | std::vector alloc_hist_arr(LOOP_NUM); 32 | std::vector de_hist_arr(LOOP_NUM); 33 | 34 | hist::HistWrapper total_alloc_hist(1000000, 1, 10'000'000LL); 35 | hist::HistWrapper total_de_hist(1000000, 1, 10'000'000LL); 36 | 37 | constexpr size_t REPEAT_TIME = 128; 38 | 39 | for (size_t re = 0; re < REPEAT_TIME; ++re) { 40 | // Allocation phase 41 | for (size_t str_len = MIN_STR_LEN; str_len <= MAX_STR_LEN; str_len *= 2UL) { 42 | size_t construct_num = MAX_TOTAL_SIZE / str_len; 43 | size_t index = fws::RoundUpLog2(str_len); 44 | 45 | // Initialize histogram objects and vector storage once 46 | if (re == 0) { 47 | alloc_hist_arr[index] = hist::HistWrapper(construct_num, 1, 10'000'000LL); 48 | de_hist_arr[index] = hist::HistWrapper(construct_num, 1, 10'000'000LL); 49 | str_arr[index].resize(construct_num); 50 | } 51 | 52 | for (size_t i = 0; i < construct_num; ++i) { 53 | auto t0 = cpu_timer.Start(); 54 | char* new_p = static_cast(fws::MemPoolEnv::instance().allocate(str_len)); 55 | auto t1 = cpu_timer.Stop(); 56 | 57 | str_arr[index][i] = new_p; 58 | 59 | if (re != 0) { 60 | int64_t pass_ticks = t1 - t0; 61 | int64_t temp_ticks = std::max(0, pass_ticks - cpu_timer.overhead_ticks()); 62 | alloc_hist_arr[index].AddValue(temp_ticks); 63 | total_alloc_hist.AddValue(temp_ticks); 64 | } 65 | 66 | // Initialize memory 67 | memset(str_arr[index][i], 1, str_len); 68 | } 69 | } 70 | 71 | // Deallocation phase 72 | for (size_t str_len = MIN_STR_LEN; str_len <= MAX_STR_LEN; str_len *= 2UL) { 73 | size_t construct_num = MAX_TOTAL_SIZE / str_len; 74 | size_t index = fws::RoundUpLog2(str_len); 75 | 76 | for (size_t i = 0; i < construct_num; ++i) { 77 | char* to_free_p = str_arr[index][i]; 78 | 79 | auto t0 = cpu_timer.Start(); 80 | fws::MemPoolEnv::instance().deallocate(to_free_p); 81 | auto t1 = cpu_timer.Stop(); 82 | 83 | if (re != 0) { 84 | int64_t pass_ticks = t1 - t0; 85 | int64_t temp_ticks = std::max(0, pass_ticks - cpu_timer.overhead_ticks()); 86 | de_hist_arr[index].AddValue(temp_ticks); 87 | total_de_hist.AddValue(temp_ticks); 88 | } 89 | } 90 | } 91 | } 92 | 93 | // Print histograms per size 94 | for (size_t str_len = MIN_STR_LEN; str_len <= MAX_STR_LEN; str_len *= 2UL) { 95 | size_t index = fws::RoundUpLog2(str_len); 96 | printf("alloc hist for %zu size:\n", str_len); 97 | auto& alloc_hist = alloc_hist_arr[index]; 98 | alloc_hist.SortForUse(); 99 | printf("P0: %ld,\tP50: %ld,\tP99: %ld,\tP999: %ld\n", 100 | alloc_hist.Quantile(0.0), alloc_hist.Quantile(0.5), 101 | alloc_hist.Quantile(0.99), alloc_hist.Quantile(0.999)); 102 | 103 | printf("dealloc hist for %zu size:\n", str_len); 104 | auto& de_hist = de_hist_arr[index]; 105 | de_hist.SortForUse(); 106 | printf("P0: %ld,\tP50: %ld,\tP99: %ld,\tP999: %ld\n\n", 107 | de_hist.Quantile(0.0), de_hist.Quantile(0.5), 108 | de_hist.Quantile(0.99), de_hist.Quantile(0.999)); 109 | } 110 | 111 | // Print total histograms 112 | printf("Total alloc hist:\n"); 113 | total_alloc_hist.PrintHdr(10, stdout, 1); 114 | printf("\nTotal dealloc hist:\n"); 115 | total_de_hist.PrintHdr(10, stdout, 1); 116 | 117 | // Log final allocation stats 118 | fws::MemPoolEnv::instance().LogAllocStats(); 119 | 120 | return 0; 121 | } 122 | 123 | int TestAlloc2() { 124 | constexpr size_t REPEAT_TIME = 32; 125 | 126 | for (size_t re = 0; re < REPEAT_TIME; ++re) { 127 | for (size_t str_len = MIN_STR_LEN; str_len <= MAX_STR_LEN; str_len *= 2UL) { 128 | // Using FlashAllocator for demonstration 129 | std::vector> vec1(str_len); 130 | std::vector> vec2; 131 | std::list> list1; 132 | 133 | // Fill containers 134 | for (size_t i = 0; i < str_len; ++i) { 135 | vec2.push_back(rand()); 136 | list1.push_back(rand()); 137 | } 138 | } 139 | } 140 | 141 | // Log final allocation stats 142 | printf("\n"); 143 | fws::MemPoolEnv::instance().LogAllocStats(); 144 | 145 | return 0; 146 | } 147 | 148 | } // namespace test 149 | 150 | int main() { 151 | int ret1 = test::TestAlloc1(); 152 | if (ret1 != 0) { 153 | return ret1; 154 | } 155 | return test::TestAlloc2(); 156 | } 157 | -------------------------------------------------------------------------------- /include/flashws/crypto/ws_mask.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "flashws/base/constexpr_math.h" 5 | #include "flashws/base/basic_macros.h" 6 | #include 7 | #include 8 | 9 | #ifdef __AVX2__ 10 | #include 11 | #endif 12 | 13 | namespace fws { 14 | 15 | inline void WSMaskBytes(uint8_t * FWS_RESTRICT src, size_t size, 16 | uint32_t mask) { 17 | uint64_t mask64 = ((uint64_t)mask << 32U) | mask; 18 | uint8_t mask_arr[4]; 19 | 20 | memcpy(mask_arr, &mask, 4); 21 | size_t size_div_8 = size / sizeof(uint64_t); 22 | uint64_t * FWS_RESTRICT u64_src = (uint64_t* FWS_RESTRICT )src; 23 | for (size_t i = 0; i < size_div_8; ++i) { 24 | u64_src[i] = u64_src[i] ^ mask64; 25 | } 26 | for (size_t i = size_div_8 * sizeof(uint64_t); i < size; ++i) { 27 | src[i] = src[i] ^ mask_arr[i & 3UL]; 28 | } 29 | } 30 | 31 | namespace detail { 32 | inline void Mask1(uint8_t *__restrict src, size_t size, 33 | uint32_t mask) { 34 | uint8_t mask_arr[4]; 35 | memcpy(mask_arr, &mask, 4); 36 | uint32_t mask32_arr[4]; 37 | for (size_t i = 0; i < 4; ++i) { 38 | mask32_arr[i] = mask_arr[i]; 39 | } 40 | for (size_t i = 0; i < size; ++i) { 41 | src[i] = src[i] ^ mask32_arr[i & 3UL]; 42 | } 43 | } 44 | } 45 | 46 | 47 | 48 | 49 | #ifdef __AVX2__ 50 | // Use unaligned SIMD load 51 | FWS_NO_LOOP_VEC_IN_FUNC 52 | inline void MaskAVX2(uint8_t * FWS_RESTRICT src, size_t size, 53 | uint32_t mask) { 54 | uint8_t* FWS_RESTRICT data = src; 55 | uint8_t* FWS_RESTRICT data_end = src + size; 56 | 57 | 58 | uint8_t mask_arr[4]; 59 | memcpy(mask_arr, &mask, 4); 60 | 61 | 62 | __m256i w_mask = _mm256_set1_epi32(mask); 63 | 64 | uint8_t *should_stop_32 = data_end - 32; 65 | FWS_UNROLL_CNT(2) 66 | while (data <= should_stop_32) // note that N must be multiple of 32 67 | { 68 | // We use unaligned load here 69 | __m256i w = _mm256_loadu_si256((const __m256i *)data); 70 | w = _mm256_xor_si256(w, w_mask); // XOR with mask 71 | _mm256_storeu_si256((__m256i*)data, w); 72 | data += 32; 73 | } 74 | uint8_t *should_stop_8 = data_end - 8; 75 | uint64_t mask64 = ((uint64_t)mask << 32U) | mask; 76 | 77 | FWS_NO_LOOP_VEC 78 | FWS_UNROLL_CNT(2) 79 | while (data <= should_stop_8) { 80 | uint64_t* FWS_RESTRICT u64_data = (uint64_t*)data; 81 | *u64_data = *u64_data ^ mask64; 82 | data += 8; 83 | } 84 | 85 | FWS_NO_LOOP_VEC 86 | FWS_UNROLL_CNT(4) 87 | while (data < data_end) { 88 | *data = *data ^ mask_arr[(data - src) & 3]; 89 | ++data; 90 | } 91 | } 92 | 93 | // Use aligned SIMD load, this function is faster than MaskAVX2 when size is 94 | // large compiled with GCC. In Clang this is not as fast as MaskAVX2 95 | FWS_NO_LOOP_VEC_IN_FUNC 96 | inline void MaskLargeChunkAVX2(uint8_t * FWS_RESTRICT src, size_t size, 97 | uint32_t mask) { 98 | 99 | uint8_t* FWS_RESTRICT data_end = src + size; 100 | 101 | uint32_t mask_copy = mask; 102 | 103 | uint8_t mask_arr[4]; 104 | memcpy(mask_arr, &mask, 4); 105 | 106 | uint8_t* FWS_RESTRICT aligned_data = (uint8_t* FWS_RESTRICT)((uint64_t(src) + 31ULL) / 32ULL * 32ULL); 107 | if (aligned_data != src) { 108 | uint8_t* FWS_RESTRICT da = src; 109 | uint64_t mask64 = ((uint64_t)mask_copy << 32U) | mask_copy; 110 | uint8_t *should_stop = std::min(aligned_data, data_end) - 8L; 111 | 112 | FWS_NO_LOOP_VEC 113 | // FWS_UNROLL_CNT(2) 114 | while (bool(uint64_t(da) & uint64_t(31U)) & (da <= should_stop)) { 115 | uint64_t *FWS_RESTRICT u64_data = (uint64_t *) da; 116 | *u64_data = *u64_data ^ mask64; 117 | da += 8; 118 | } 119 | 120 | FWS_NO_LOOP_VEC 121 | // FWS_UNROLL_CNT(4) 122 | while (bool(uint64_t(da) & uint64_t(31U)) & (da < data_end)) { 123 | *da = *da ^ mask_arr[(da - src) & 3]; 124 | ++da; 125 | } 126 | } 127 | if (data_end <= aligned_data) { 128 | return; 129 | } 130 | 131 | 132 | uint8_t* FWS_RESTRICT data = aligned_data; 133 | mask = RotateR(mask, 8U * ((uint64_t(data - src) & 3UL))); 134 | 135 | __m256i w_mask = _mm256_set1_epi32(mask); 136 | 137 | // preferably 32 byte aligned 138 | uint8_t *should_stop_32 = data_end - 32; 139 | FWS_NO_LOOP_VEC 140 | FWS_UNROLL_CNT(2) 141 | while (data <= should_stop_32) 142 | { 143 | // aligned 32 bytes load 144 | __m256i w = _mm256_load_si256(reinterpret_cast(data)); 145 | w = _mm256_xor_si256(w, w_mask); // XOR with mask 146 | _mm256_store_si256((__m256i*)data, w); // store 32 masked bytes 147 | data += 32; 148 | } 149 | uint8_t *should_stop_8 = data_end - 8; 150 | uint64_t mask64 = ((uint64_t)mask << 32U) | mask; 151 | 152 | FWS_NO_LOOP_VEC 153 | // FWS_UNROLL_CNT(2) 154 | while (data <= should_stop_8) { 155 | uint64_t* FWS_RESTRICT u64_data = (uint64_t*)data; 156 | *u64_data = *u64_data ^ mask64; 157 | data += 8; 158 | } 159 | 160 | FWS_NO_LOOP_VEC 161 | // FWS_UNROLL_CNT(4) 162 | while (data < data_end) { 163 | *data = *data ^ mask_arr[(data - src) & 3]; 164 | ++data; 165 | } 166 | } 167 | #endif 168 | 169 | /** 170 | * Choose the fast mask method based on length 171 | * @param src 172 | * @param size 173 | * @param mask 174 | */ 175 | FWS_ALWAYS_INLINE void WSMaskBytesFast(uint8_t * FWS_RESTRICT src, size_t size, 176 | uint32_t mask) { 177 | #ifdef __AVX2__ 178 | if (size < 256U) { 179 | // detail::Mask1(src, size, mask); 180 | WSMaskBytes(src, size, mask); 181 | } 182 | # if defined(__clang__) 183 | else { 184 | MaskAVX2(src, size, mask); 185 | } 186 | # else 187 | else if (size <= 2048U){ 188 | MaskAVX2(src, size, mask); 189 | } 190 | else { 191 | MaskLargeChunkAVX2(src, size, mask); 192 | } 193 | # endif 194 | #else 195 | WSMaskBytes(src, size, mask); 196 | #endif 197 | } 198 | 199 | } // namespace fws -------------------------------------------------------------------------------- /tests/new-ws-echo/config_la1.ini: -------------------------------------------------------------------------------- 1 | [dpdk] 2 | # Hexadecimal bitmask of cores to run on. 3 | lcore_mask=8 4 | 5 | # Number of memory channels. 6 | channel=2 7 | 8 | # Specify base virtual address to map. 9 | #base_virtaddr=0x7f0000000000 10 | 11 | # Promiscuous mode of nic, defualt: enabled. 12 | promiscuous=1 13 | numa_on=1 14 | 15 | # TX checksum offload skip, default: disabled. 16 | # We need this switch enabled in the following cases: 17 | # -> The application want to enforce wrong checksum for testing purposes 18 | # -> Some cards advertize the offload capability. However, doesn't calculate checksum. 19 | tx_csum_offoad_skip=0 20 | 21 | # TCP segment offload, default: disabled. 22 | tso=1 23 | 24 | # HW vlan strip, default: enabled. 25 | vlan_strip=1 26 | 27 | # sleep when no pkts incomming 28 | # unit: microseconds 29 | idle_sleep=0 30 | 31 | # sent packet delay time(0-100) while send less than 32 pkts. 32 | # default 100 us. 33 | # if set 0, means send pkts immediately. 34 | # if set >100, will dealy 100 us. 35 | # unit: microseconds 36 | pkt_tx_delay=0 37 | 38 | # use symmetric Receive-side Scaling(RSS) key, default: disabled. 39 | symmetric_rss=0 40 | 41 | # PCI device enable list. 42 | # And driver options 43 | #pci_whitelist=02:00.0 44 | # for multiple PCI devices 45 | #pci_whitelist=02:00.0,03:00.0 46 | 47 | # enabled port list 48 | # 49 | # EBNF grammar: 50 | # 51 | # exp ::= num_list {"," num_list} 52 | # num_list ::= | 53 | # range ::= "-" 54 | # num ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' 55 | # 56 | # examples 57 | # 0-3 ports 0, 1,2,3 are enabled 58 | # 1-3,4,7 ports 1,2,3,4,7 are enabled 59 | # 60 | # If use bonding, shoule config the bonding port id in port_list 61 | # and not config slave port id in port_list 62 | # such as, port 0 and port 1 trank to a bonding port 2, 63 | # should set `port_list=2` and config `[port2]` section 64 | 65 | port_list=0 66 | 67 | # Number of vdev. 68 | nb_vdev=0 69 | 70 | # Number of bond. 71 | nb_bond=0 72 | 73 | # log level for dpdk, optional 74 | # log_level=0 75 | 76 | # Each core write into own pcap file, which is open one time, close one time if enough. 77 | # Support dump the first snaplen bytes of each packet. 78 | # if pcap file is lager than savelen bytes, it will be closed and next file was dumped into. 79 | [pcap] 80 | enable=0 81 | snaplen=256 82 | savelen=33554432 83 | savepath=. 84 | 85 | # Port config section 86 | # Correspond to dpdk.port_list's index: port0, port1... 87 | [port0] 88 | addr=10.5.96.3 89 | netmask=255.255.255.0 90 | broadcast=10.5.111.255 91 | gateway=10.5.96.1 92 | # set interface name, Optional parameter. 93 | #if_name=eno7 94 | 95 | # IPv6 net addr, Optional parameters. 96 | #addr6=ff::02 97 | #prefix_len=64 98 | #gateway6=ff::01 99 | 100 | # Multi virtual IPv4/IPv6 net addr, Optional parameters. 101 | # `vip_ifname`: default `f-stack-x` 102 | # `vip_addr`: Separated by semicolons, MAX number 64; 103 | # Only support netmask 255.255.255.255, broadcast x.x.x.255 now, hard code in `ff_veth_setvaddr`. 104 | # `vip_addr6`: Separated by semicolons, MAX number 64. 105 | # `vip_prefix_len`: All addr6 use the same prefix now, default 64. 106 | #vip_ifname=lo0 107 | #vip_addr=192.168.1.3;192.168.1.4;192.168.1.5;192.168.1.6 108 | #vip_addr6=ff::03;ff::04;ff::05;ff::06;ff::07 109 | #vip_prefix_len=64 110 | 111 | # lcore list used to handle this port 112 | # the format is same as port_list 113 | #lcore_list=0 114 | 115 | # bonding slave port list used to handle this port 116 | # need to config while this port is a bonding port 117 | # the format is same as port_list 118 | #slave_port_list=0,1 119 | 120 | # Vdev config section 121 | # orrespond to dpdk.nb_vdev's index: vdev0, vdev1... 122 | # iface : Shouldn't set always. 123 | # path : The vuser device path in container. Required. 124 | # queues : The max queues of vuser. Optional, default 1, greater or equal to the number of processes. 125 | # queue_size : Queue size.Optional, default 256. 126 | # mac : The mac address of vuser. Optional, default random, if vhost use phy NIC, it should be set to the phy NIC's mac. 127 | # cq : Optional, if queues = 1, default 0; if queues > 1 default 1. 128 | #[vdev0] 129 | ##iface=/usr/local/var/run/openvswitch/vhost-user0 130 | #path=/var/run/openvswitch/vhost-user0 131 | #queues=1 132 | #queue_size=256 133 | #mac=00:00:00:00:00:01 134 | #cq=0 135 | 136 | # bond config section 137 | # See http://doc.dpdk.org/guides/prog_guide/link_bonding_poll_mode_drv_lib.html 138 | #[bond0] 139 | #mode=4 140 | #slave=0000:0a:00.0,slave=0000:0a:00.1 141 | #primary=0000:0a:00.0 142 | #mac=f0:98:38:xx:xx:xx 143 | ## opt argument 144 | #socket_id=0 145 | #xmit_policy=l23 146 | #lsc_poll_period_ms=100 147 | #up_delay=10 148 | #down_delay=50 149 | 150 | # Kni config: if enabled and method=reject, 151 | # all packets that do not belong to the following tcp_port and udp_port 152 | # will transmit to kernel; if method=accept, all packets that belong to 153 | # the following tcp_port and udp_port will transmit to kernel. 154 | #[kni] 155 | #enable=1 156 | #method=reject 157 | # The format is same as port_list 158 | #tcp_port=80,443 159 | #udp_port=53 160 | 161 | # FreeBSD network performance tuning configurations. 162 | # Most native FreeBSD configurations are supported. 163 | [freebsd.boot] 164 | # If use rack/bbr which depend HPTS, you should set a greater value of hz, such as 100000 means a tick is 10us. 165 | hz=100 166 | 167 | # Block out a range of descriptors to avoid overlap 168 | # with the kernel's descriptor space. 169 | # You can increase this value according to your app. 170 | fd_reserve=1024 171 | 172 | kern.ipc.maxsockets=262144 173 | 174 | net.inet.tcp.syncache.hashsize=4096 175 | net.inet.tcp.syncache.bucketlimit=100 176 | 177 | net.inet.tcp.tcbhashsize=65536 178 | 179 | kern.ncallout=262144 180 | 181 | kern.features.inet6=1 182 | net.inet6.ip6.auto_linklocal=1 183 | net.inet6.ip6.accept_rtadv=2 184 | net.inet6.icmp6.rediraccept=1 185 | net.inet6.ip6.forwarding=0 186 | 187 | [freebsd.sysctl] 188 | kern.ipc.somaxconn=32768 189 | kern.ipc.maxsockbuf=16777216 190 | 191 | net.link.ether.inet.maxhold=5 192 | 193 | net.inet.tcp.fast_finwait2_recycle=1 194 | net.inet.tcp.sendspace=16384 195 | net.inet.tcp.recvspace=8192 196 | #net.inet.tcp.nolocaltimewait=1 197 | net.inet.tcp.cc.algorithm=cubic 198 | net.inet.tcp.sendbuf_max=16777216 199 | net.inet.tcp.recvbuf_max=16777216 200 | net.inet.tcp.sendbuf_auto=1 201 | net.inet.tcp.recvbuf_auto=1 202 | net.inet.tcp.sendbuf_inc=16384 203 | #net.inet.tcp.recvbuf_inc=524288 204 | net.inet.tcp.sack.enable=1 205 | net.inet.tcp.blackhole=1 206 | net.inet.tcp.msl=2000 207 | net.inet.tcp.delayed_ack=1 208 | net.inet.tcp.rfc1323=1 209 | 210 | net.inet.udp.blackhole=1 211 | net.inet.ip.redirect=0 212 | net.inet.ip.forwarding=0 213 | 214 | # set default stacks:freebsd, rack or bbr, may be you need increase the value of parameter 'freebsd.boot.hz' while use rack or bbr. 215 | net.inet.tcp.functions_default=freebsd 216 | # need by bbr, should enable it. 217 | net.inet.tcp.hpts.skip_swi=1 218 | -------------------------------------------------------------------------------- /tests/ws-echo/config_la1.ini: -------------------------------------------------------------------------------- 1 | [dpdk] 2 | # Hexadecimal bitmask of cores to run on. 3 | lcore_mask=8 4 | 5 | # Number of memory channels. 6 | channel=2 7 | 8 | # Specify base virtual address to map. 9 | #base_virtaddr=0x7f0000000000 10 | 11 | # Promiscuous mode of nic, defualt: enabled. 12 | promiscuous=1 13 | numa_on=1 14 | 15 | # TX checksum offload skip, default: disabled. 16 | # We need this switch enabled in the following cases: 17 | # -> The application want to enforce wrong checksum for testing purposes 18 | # -> Some cards advertize the offload capability. However, doesn't calculate checksum. 19 | tx_csum_offoad_skip=0 20 | 21 | # TCP segment offload, default: disabled. 22 | tso=1 23 | 24 | # HW vlan strip, default: enabled. 25 | vlan_strip=1 26 | 27 | # sleep when no pkts incomming 28 | # unit: microseconds 29 | idle_sleep=0 30 | 31 | # sent packet delay time(0-100) while send less than 32 pkts. 32 | # default 100 us. 33 | # if set 0, means send pkts immediately. 34 | # if set >100, will dealy 100 us. 35 | # unit: microseconds 36 | pkt_tx_delay=0 37 | 38 | # use symmetric Receive-side Scaling(RSS) key, default: disabled. 39 | symmetric_rss=0 40 | 41 | # PCI device enable list. 42 | # And driver options 43 | #pci_whitelist=02:00.0 44 | # for multiple PCI devices 45 | #pci_whitelist=02:00.0,03:00.0 46 | 47 | # enabled port list 48 | # 49 | # EBNF grammar: 50 | # 51 | # exp ::= num_list {"," num_list} 52 | # num_list ::= | 53 | # range ::= "-" 54 | # num ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' 55 | # 56 | # examples 57 | # 0-3 ports 0, 1,2,3 are enabled 58 | # 1-3,4,7 ports 1,2,3,4,7 are enabled 59 | # 60 | # If use bonding, shoule config the bonding port id in port_list 61 | # and not config slave port id in port_list 62 | # such as, port 0 and port 1 trank to a bonding port 2, 63 | # should set `port_list=2` and config `[port2]` section 64 | 65 | port_list=0 66 | 67 | # Number of vdev. 68 | nb_vdev=0 69 | 70 | # Number of bond. 71 | nb_bond=0 72 | 73 | # log level for dpdk, optional 74 | # log_level=0 75 | 76 | # Each core write into own pcap file, which is open one time, close one time if enough. 77 | # Support dump the first snaplen bytes of each packet. 78 | # if pcap file is lager than savelen bytes, it will be closed and next file was dumped into. 79 | [pcap] 80 | enable=0 81 | snaplen=256 82 | savelen=33554432 83 | savepath=. 84 | 85 | # Port config section 86 | # Correspond to dpdk.port_list's index: port0, port1... 87 | [port0] 88 | addr=10.5.96.3 89 | netmask=255.255.255.0 90 | broadcast=10.5.111.255 91 | gateway=10.5.96.1 92 | # set interface name, Optional parameter. 93 | #if_name=eno7 94 | 95 | # IPv6 net addr, Optional parameters. 96 | #addr6=ff::02 97 | #prefix_len=64 98 | #gateway6=ff::01 99 | 100 | # Multi virtual IPv4/IPv6 net addr, Optional parameters. 101 | # `vip_ifname`: default `f-stack-x` 102 | # `vip_addr`: Separated by semicolons, MAX number 64; 103 | # Only support netmask 255.255.255.255, broadcast x.x.x.255 now, hard code in `ff_veth_setvaddr`. 104 | # `vip_addr6`: Separated by semicolons, MAX number 64. 105 | # `vip_prefix_len`: All addr6 use the same prefix now, default 64. 106 | #vip_ifname=lo0 107 | #vip_addr=192.168.1.3;192.168.1.4;192.168.1.5;192.168.1.6 108 | #vip_addr6=ff::03;ff::04;ff::05;ff::06;ff::07 109 | #vip_prefix_len=64 110 | 111 | # lcore list used to handle this port 112 | # the format is same as port_list 113 | #lcore_list=0 114 | 115 | # bonding slave port list used to handle this port 116 | # need to config while this port is a bonding port 117 | # the format is same as port_list 118 | #slave_port_list=0,1 119 | 120 | # Vdev config section 121 | # orrespond to dpdk.nb_vdev's index: vdev0, vdev1... 122 | # iface : Shouldn't set always. 123 | # path : The vuser device path in container. Required. 124 | # queues : The max queues of vuser. Optional, default 1, greater or equal to the number of processes. 125 | # queue_size : Queue size.Optional, default 256. 126 | # mac : The mac address of vuser. Optional, default random, if vhost use phy NIC, it should be set to the phy NIC's mac. 127 | # cq : Optional, if queues = 1, default 0; if queues > 1 default 1. 128 | #[vdev0] 129 | ##iface=/usr/local/var/run/openvswitch/vhost-user0 130 | #path=/var/run/openvswitch/vhost-user0 131 | #queues=1 132 | #queue_size=256 133 | #mac=00:00:00:00:00:01 134 | #cq=0 135 | 136 | # bond config section 137 | # See http://doc.dpdk.org/guides/prog_guide/link_bonding_poll_mode_drv_lib.html 138 | #[bond0] 139 | #mode=4 140 | #slave=0000:0a:00.0,slave=0000:0a:00.1 141 | #primary=0000:0a:00.0 142 | #mac=f0:98:38:xx:xx:xx 143 | ## opt argument 144 | #socket_id=0 145 | #xmit_policy=l23 146 | #lsc_poll_period_ms=100 147 | #up_delay=10 148 | #down_delay=50 149 | 150 | # Kni config: if enabled and method=reject, 151 | # all packets that do not belong to the following tcp_port and udp_port 152 | # will transmit to kernel; if method=accept, all packets that belong to 153 | # the following tcp_port and udp_port will transmit to kernel. 154 | #[kni] 155 | #enable=1 156 | #method=reject 157 | # The format is same as port_list 158 | #tcp_port=80,443 159 | #udp_port=53 160 | 161 | # FreeBSD network performance tuning configurations. 162 | # Most native FreeBSD configurations are supported. 163 | [freebsd.boot] 164 | # If use rack/bbr which depend HPTS, you should set a greater value of hz, such as 100000 means a tick is 10us. 165 | hz=100 166 | 167 | # Block out a range of descriptors to avoid overlap 168 | # with the kernel's descriptor space. 169 | # You can increase this value according to your app. 170 | fd_reserve=1024 171 | 172 | kern.ipc.maxsockets=262144 173 | 174 | net.inet.tcp.syncache.hashsize=4096 175 | net.inet.tcp.syncache.bucketlimit=100 176 | 177 | net.inet.tcp.tcbhashsize=65536 178 | 179 | kern.ncallout=262144 180 | 181 | kern.features.inet6=1 182 | net.inet6.ip6.auto_linklocal=1 183 | net.inet6.ip6.accept_rtadv=2 184 | net.inet6.icmp6.rediraccept=1 185 | net.inet6.ip6.forwarding=0 186 | 187 | [freebsd.sysctl] 188 | kern.ipc.somaxconn=32768 189 | kern.ipc.maxsockbuf=16777216 190 | 191 | net.link.ether.inet.maxhold=5 192 | 193 | net.inet.tcp.fast_finwait2_recycle=1 194 | net.inet.tcp.sendspace=16384 195 | net.inet.tcp.recvspace=8192 196 | #net.inet.tcp.nolocaltimewait=1 197 | net.inet.tcp.cc.algorithm=cubic 198 | net.inet.tcp.sendbuf_max=16777216 199 | net.inet.tcp.recvbuf_max=16777216 200 | net.inet.tcp.sendbuf_auto=1 201 | net.inet.tcp.recvbuf_auto=1 202 | net.inet.tcp.sendbuf_inc=16384 203 | #net.inet.tcp.recvbuf_inc=524288 204 | net.inet.tcp.sack.enable=1 205 | net.inet.tcp.blackhole=1 206 | net.inet.tcp.msl=2000 207 | net.inet.tcp.delayed_ack=1 208 | net.inet.tcp.rfc1323=1 209 | 210 | net.inet.udp.blackhole=1 211 | net.inet.ip.redirect=0 212 | net.inet.ip.forwarding=0 213 | 214 | # set default stacks:freebsd, rack or bbr, may be you need increase the value of parameter 'freebsd.boot.hz' while use rack or bbr. 215 | net.inet.tcp.functions_default=freebsd 216 | # need by bbr, should enable it. 217 | net.inet.tcp.hpts.skip_swi=1 218 | -------------------------------------------------------------------------------- /tests/ws-echo/config_la1_2.ini: -------------------------------------------------------------------------------- 1 | [dpdk] 2 | # Hexadecimal bitmask of cores to run on. 3 | lcore_mask=4 4 | 5 | # Number of memory channels. 6 | channel=2 7 | 8 | # Specify base virtual address to map. 9 | #base_virtaddr=0x7f0000000000 10 | 11 | # Promiscuous mode of nic, defualt: enabled. 12 | promiscuous=1 13 | numa_on=1 14 | 15 | # TX checksum offload skip, default: disabled. 16 | # We need this switch enabled in the following cases: 17 | # -> The application want to enforce wrong checksum for testing purposes 18 | # -> Some cards advertize the offload capability. However, doesn't calculate checksum. 19 | tx_csum_offoad_skip=0 20 | 21 | # TCP segment offload, default: disabled. 22 | tso=1 23 | 24 | # HW vlan strip, default: enabled. 25 | vlan_strip=1 26 | 27 | # sleep when no pkts incomming 28 | # unit: microseconds 29 | idle_sleep=0 30 | 31 | # sent packet delay time(0-100) while send less than 32 pkts. 32 | # default 100 us. 33 | # if set 0, means send pkts immediately. 34 | # if set >100, will dealy 100 us. 35 | # unit: microseconds 36 | pkt_tx_delay=0 37 | 38 | # use symmetric Receive-side Scaling(RSS) key, default: disabled. 39 | symmetric_rss=0 40 | 41 | # PCI device enable list. 42 | # And driver options 43 | #pci_whitelist=02:00.0 44 | # for multiple PCI devices 45 | #pci_whitelist=02:00.0,03:00.0 46 | 47 | # enabled port list 48 | # 49 | # EBNF grammar: 50 | # 51 | # exp ::= num_list {"," num_list} 52 | # num_list ::= | 53 | # range ::= "-" 54 | # num ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' 55 | # 56 | # examples 57 | # 0-3 ports 0, 1,2,3 are enabled 58 | # 1-3,4,7 ports 1,2,3,4,7 are enabled 59 | # 60 | # If use bonding, shoule config the bonding port id in port_list 61 | # and not config slave port id in port_list 62 | # such as, port 0 and port 1 trank to a bonding port 2, 63 | # should set `port_list=2` and config `[port2]` section 64 | 65 | port_list=0 66 | 67 | # Number of vdev. 68 | nb_vdev=0 69 | 70 | # Number of bond. 71 | nb_bond=0 72 | 73 | # log level for dpdk, optional 74 | # log_level=0 75 | 76 | # Each core write into own pcap file, which is open one time, close one time if enough. 77 | # Support dump the first snaplen bytes of each packet. 78 | # if pcap file is lager than savelen bytes, it will be closed and next file was dumped into. 79 | [pcap] 80 | enable=0 81 | snaplen=256 82 | savelen=33554432 83 | savepath=. 84 | 85 | # Port config section 86 | # Correspond to dpdk.port_list's index: port0, port1... 87 | [port0] 88 | addr=10.5.96.3 89 | netmask=255.255.255.0 90 | broadcast=10.5.111.255 91 | gateway=10.5.96.1 92 | # set interface name, Optional parameter. 93 | #if_name=eno7 94 | 95 | # IPv6 net addr, Optional parameters. 96 | #addr6=ff::02 97 | #prefix_len=64 98 | #gateway6=ff::01 99 | 100 | # Multi virtual IPv4/IPv6 net addr, Optional parameters. 101 | # `vip_ifname`: default `f-stack-x` 102 | # `vip_addr`: Separated by semicolons, MAX number 64; 103 | # Only support netmask 255.255.255.255, broadcast x.x.x.255 now, hard code in `ff_veth_setvaddr`. 104 | # `vip_addr6`: Separated by semicolons, MAX number 64. 105 | # `vip_prefix_len`: All addr6 use the same prefix now, default 64. 106 | #vip_ifname=lo0 107 | #vip_addr=192.168.1.3;192.168.1.4;192.168.1.5;192.168.1.6 108 | #vip_addr6=ff::03;ff::04;ff::05;ff::06;ff::07 109 | #vip_prefix_len=64 110 | 111 | # lcore list used to handle this port 112 | # the format is same as port_list 113 | #lcore_list=0 114 | 115 | # bonding slave port list used to handle this port 116 | # need to config while this port is a bonding port 117 | # the format is same as port_list 118 | #slave_port_list=0,1 119 | 120 | # Vdev config section 121 | # orrespond to dpdk.nb_vdev's index: vdev0, vdev1... 122 | # iface : Shouldn't set always. 123 | # path : The vuser device path in container. Required. 124 | # queues : The max queues of vuser. Optional, default 1, greater or equal to the number of processes. 125 | # queue_size : Queue size.Optional, default 256. 126 | # mac : The mac address of vuser. Optional, default random, if vhost use phy NIC, it should be set to the phy NIC's mac. 127 | # cq : Optional, if queues = 1, default 0; if queues > 1 default 1. 128 | #[vdev0] 129 | ##iface=/usr/local/var/run/openvswitch/vhost-user0 130 | #path=/var/run/openvswitch/vhost-user0 131 | #queues=1 132 | #queue_size=256 133 | #mac=00:00:00:00:00:01 134 | #cq=0 135 | 136 | # bond config section 137 | # See http://doc.dpdk.org/guides/prog_guide/link_bonding_poll_mode_drv_lib.html 138 | #[bond0] 139 | #mode=4 140 | #slave=0000:0a:00.0,slave=0000:0a:00.1 141 | #primary=0000:0a:00.0 142 | #mac=f0:98:38:xx:xx:xx 143 | ## opt argument 144 | #socket_id=0 145 | #xmit_policy=l23 146 | #lsc_poll_period_ms=100 147 | #up_delay=10 148 | #down_delay=50 149 | 150 | # Kni config: if enabled and method=reject, 151 | # all packets that do not belong to the following tcp_port and udp_port 152 | # will transmit to kernel; if method=accept, all packets that belong to 153 | # the following tcp_port and udp_port will transmit to kernel. 154 | #[kni] 155 | #enable=1 156 | #method=reject 157 | # The format is same as port_list 158 | #tcp_port=80,443 159 | #udp_port=53 160 | 161 | # FreeBSD network performance tuning configurations. 162 | # Most native FreeBSD configurations are supported. 163 | [freebsd.boot] 164 | # If use rack/bbr which depend HPTS, you should set a greater value of hz, such as 100000 means a tick is 10us. 165 | hz=100 166 | 167 | # Block out a range of descriptors to avoid overlap 168 | # with the kernel's descriptor space. 169 | # You can increase this value according to your app. 170 | fd_reserve=1024 171 | 172 | kern.ipc.maxsockets=262144 173 | 174 | net.inet.tcp.syncache.hashsize=4096 175 | net.inet.tcp.syncache.bucketlimit=100 176 | 177 | net.inet.tcp.tcbhashsize=65536 178 | 179 | kern.ncallout=262144 180 | 181 | kern.features.inet6=1 182 | net.inet6.ip6.auto_linklocal=1 183 | net.inet6.ip6.accept_rtadv=2 184 | net.inet6.icmp6.rediraccept=1 185 | net.inet6.ip6.forwarding=0 186 | 187 | [freebsd.sysctl] 188 | kern.ipc.somaxconn=32768 189 | kern.ipc.maxsockbuf=16777216 190 | 191 | net.link.ether.inet.maxhold=5 192 | 193 | net.inet.tcp.fast_finwait2_recycle=1 194 | net.inet.tcp.sendspace=16384 195 | net.inet.tcp.recvspace=8192 196 | #net.inet.tcp.nolocaltimewait=1 197 | net.inet.tcp.cc.algorithm=cubic 198 | net.inet.tcp.sendbuf_max=16777216 199 | net.inet.tcp.recvbuf_max=16777216 200 | net.inet.tcp.sendbuf_auto=1 201 | net.inet.tcp.recvbuf_auto=1 202 | net.inet.tcp.sendbuf_inc=16384 203 | #net.inet.tcp.recvbuf_inc=524288 204 | net.inet.tcp.sack.enable=1 205 | net.inet.tcp.blackhole=1 206 | net.inet.tcp.msl=2000 207 | net.inet.tcp.delayed_ack=1 208 | net.inet.tcp.rfc1323=1 209 | 210 | net.inet.udp.blackhole=1 211 | net.inet.ip.redirect=0 212 | net.inet.ip.forwarding=0 213 | 214 | # set default stacks:freebsd, rack or bbr, may be you need increase the value of parameter 'freebsd.boot.hz' while use rack or bbr. 215 | net.inet.tcp.functions_default=freebsd 216 | # need by bbr, should enable it. 217 | net.inet.tcp.hpts.skip_swi=1 218 | -------------------------------------------------------------------------------- /tests/ws-echo/config_la6.ini: -------------------------------------------------------------------------------- 1 | [dpdk] 2 | # Hexadecimal bitmask of cores to run on. 3 | lcore_mask=10 4 | 5 | # Number of memory channels. 6 | channel=2 7 | 8 | # Specify base virtual address to map. 9 | #base_virtaddr=0x7f0000000000 10 | 11 | # Promiscuous mode of nic, defualt: enabled. 12 | promiscuous=1 13 | numa_on=1 14 | 15 | # TX checksum offload skip, default: disabled. 16 | # We need this switch enabled in the following cases: 17 | # -> The application want to enforce wrong checksum for testing purposes 18 | # -> Some cards advertize the offload capability. However, doesn't calculate checksum. 19 | tx_csum_offoad_skip=0 20 | 21 | # TCP segment offload, default: disabled. 22 | tso=1 23 | 24 | # HW vlan strip, default: enabled. 25 | vlan_strip=1 26 | 27 | # sleep when no pkts incomming 28 | # unit: microseconds 29 | idle_sleep=0 30 | 31 | # sent packet delay time(0-100) while send less than 32 pkts. 32 | # default 100 us. 33 | # if set 0, means send pkts immediately. 34 | # if set >100, will dealy 100 us. 35 | # unit: microseconds 36 | pkt_tx_delay=0 37 | 38 | # use symmetric Receive-side Scaling(RSS) key, default: disabled. 39 | symmetric_rss=0 40 | 41 | # PCI device enable list. 42 | # And driver options 43 | #pci_whitelist=02:00.0 44 | # for multiple PCI devices 45 | #pci_whitelist=02:00.0,03:00.0 46 | 47 | # enabled port list 48 | # 49 | # EBNF grammar: 50 | # 51 | # exp ::= num_list {"," num_list} 52 | # num_list ::= | 53 | # range ::= "-" 54 | # num ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' 55 | # 56 | # examples 57 | # 0-3 ports 0, 1,2,3 are enabled 58 | # 1-3,4,7 ports 1,2,3,4,7 are enabled 59 | # 60 | # If use bonding, shoule config the bonding port id in port_list 61 | # and not config slave port id in port_list 62 | # such as, port 0 and port 1 trank to a bonding port 2, 63 | # should set `port_list=2` and config `[port2]` section 64 | 65 | port_list=0 66 | 67 | # Number of vdev. 68 | nb_vdev=0 69 | 70 | # Number of bond. 71 | nb_bond=0 72 | 73 | # log level for dpdk, optional 74 | # log_level=0 75 | 76 | # Each core write into own pcap file, which is open one time, close one time if enough. 77 | # Support dump the first snaplen bytes of each packet. 78 | # if pcap file is lager than savelen bytes, it will be closed and next file was dumped into. 79 | [pcap] 80 | enable=0 81 | snaplen=256 82 | savelen=33554432 83 | savepath=. 84 | 85 | # Port config section 86 | # Correspond to dpdk.port_list's index: port0, port1... 87 | [port0] 88 | addr=10.5.96.7 89 | netmask=255.255.255.0 90 | broadcast=10.5.111.255 91 | gateway=10.5.96.1 92 | # set interface name, Optional parameter. 93 | #if_name=eno7 94 | 95 | # IPv6 net addr, Optional parameters. 96 | #addr6=ff::02 97 | #prefix_len=64 98 | #gateway6=ff::01 99 | 100 | # Multi virtual IPv4/IPv6 net addr, Optional parameters. 101 | # `vip_ifname`: default `f-stack-x` 102 | # `vip_addr`: Separated by semicolons, MAX number 64; 103 | # Only support netmask 255.255.255.255, broadcast x.x.x.255 now, hard code in `ff_veth_setvaddr`. 104 | # `vip_addr6`: Separated by semicolons, MAX number 64. 105 | # `vip_prefix_len`: All addr6 use the same prefix now, default 64. 106 | #vip_ifname=lo0 107 | #vip_addr=192.168.1.3;192.168.1.4;192.168.1.5;192.168.1.6 108 | #vip_addr6=ff::03;ff::04;ff::05;ff::06;ff::07 109 | #vip_prefix_len=64 110 | 111 | # lcore list used to handle this port 112 | # the format is same as port_list 113 | #lcore_list=0 114 | 115 | # bonding slave port list used to handle this port 116 | # need to config while this port is a bonding port 117 | # the format is same as port_list 118 | #slave_port_list=0,1 119 | 120 | # Vdev config section 121 | # orrespond to dpdk.nb_vdev's index: vdev0, vdev1... 122 | # iface : Shouldn't set always. 123 | # path : The vuser device path in container. Required. 124 | # queues : The max queues of vuser. Optional, default 1, greater or equal to the number of processes. 125 | # queue_size : Queue size.Optional, default 256. 126 | # mac : The mac address of vuser. Optional, default random, if vhost use phy NIC, it should be set to the phy NIC's mac. 127 | # cq : Optional, if queues = 1, default 0; if queues > 1 default 1. 128 | #[vdev0] 129 | ##iface=/usr/local/var/run/openvswitch/vhost-user0 130 | #path=/var/run/openvswitch/vhost-user0 131 | #queues=1 132 | #queue_size=256 133 | #mac=00:00:00:00:00:01 134 | #cq=0 135 | 136 | # bond config section 137 | # See http://doc.dpdk.org/guides/prog_guide/link_bonding_poll_mode_drv_lib.html 138 | #[bond0] 139 | #mode=4 140 | #slave=0000:0a:00.0,slave=0000:0a:00.1 141 | #primary=0000:0a:00.0 142 | #mac=f0:98:38:xx:xx:xx 143 | ## opt argument 144 | #socket_id=0 145 | #xmit_policy=l23 146 | #lsc_poll_period_ms=100 147 | #up_delay=10 148 | #down_delay=50 149 | 150 | # Kni config: if enabled and method=reject, 151 | # all packets that do not belong to the following tcp_port and udp_port 152 | # will transmit to kernel; if method=accept, all packets that belong to 153 | # the following tcp_port and udp_port will transmit to kernel. 154 | #[kni] 155 | #enable=1 156 | #method=reject 157 | # The format is same as port_list 158 | #tcp_port=80,443 159 | #udp_port=53 160 | 161 | # FreeBSD network performance tuning configurations. 162 | # Most native FreeBSD configurations are supported. 163 | [freebsd.boot] 164 | # If use rack/bbr which depend HPTS, you should set a greater value of hz, such as 100000 means a tick is 10us. 165 | hz=100 166 | 167 | # Block out a range of descriptors to avoid overlap 168 | # with the kernel's descriptor space. 169 | # You can increase this value according to your app. 170 | fd_reserve=1024 171 | 172 | kern.ipc.maxsockets=262144 173 | 174 | net.inet.tcp.syncache.hashsize=4096 175 | net.inet.tcp.syncache.bucketlimit=100 176 | 177 | net.inet.tcp.tcbhashsize=65536 178 | 179 | kern.ncallout=262144 180 | 181 | kern.features.inet6=1 182 | net.inet6.ip6.auto_linklocal=1 183 | net.inet6.ip6.accept_rtadv=2 184 | net.inet6.icmp6.rediraccept=1 185 | net.inet6.ip6.forwarding=0 186 | 187 | [freebsd.sysctl] 188 | kern.ipc.somaxconn=32768 189 | kern.ipc.maxsockbuf=16777216 190 | 191 | net.link.ether.inet.maxhold=5 192 | 193 | net.inet.tcp.fast_finwait2_recycle=1 194 | net.inet.tcp.sendspace=16384 195 | net.inet.tcp.recvspace=8192 196 | #net.inet.tcp.nolocaltimewait=1 197 | net.inet.tcp.cc.algorithm=cubic 198 | net.inet.tcp.sendbuf_max=16777216 199 | net.inet.tcp.recvbuf_max=16777216 200 | net.inet.tcp.sendbuf_auto=1 201 | net.inet.tcp.recvbuf_auto=1 202 | net.inet.tcp.sendbuf_inc=16384 203 | #net.inet.tcp.recvbuf_inc=524288 204 | net.inet.tcp.sack.enable=1 205 | net.inet.tcp.blackhole=1 206 | net.inet.tcp.msl=2000 207 | net.inet.tcp.delayed_ack=1 208 | net.inet.tcp.rfc1323=1 209 | 210 | net.inet.udp.blackhole=1 211 | net.inet.ip.redirect=0 212 | net.inet.ip.forwarding=0 213 | 214 | # set default stacks:freebsd, rack or bbr, may be you need increase the value of parameter 'freebsd.boot.hz' while use rack or bbr. 215 | net.inet.tcp.functions_default=freebsd 216 | # need by bbr, should enable it. 217 | net.inet.tcp.hpts.skip_swi=1 218 | -------------------------------------------------------------------------------- /tests/new-ws-echo/config_la1_2.ini: -------------------------------------------------------------------------------- 1 | [dpdk] 2 | # Hexadecimal bitmask of cores to run on. 3 | lcore_mask=4 4 | 5 | # Number of memory channels. 6 | channel=2 7 | 8 | # Specify base virtual address to map. 9 | #base_virtaddr=0x7f0000000000 10 | 11 | # Promiscuous mode of nic, defualt: enabled. 12 | promiscuous=1 13 | numa_on=1 14 | 15 | # TX checksum offload skip, default: disabled. 16 | # We need this switch enabled in the following cases: 17 | # -> The application want to enforce wrong checksum for testing purposes 18 | # -> Some cards advertize the offload capability. However, doesn't calculate checksum. 19 | tx_csum_offoad_skip=0 20 | 21 | # TCP segment offload, default: disabled. 22 | tso=1 23 | 24 | # HW vlan strip, default: enabled. 25 | vlan_strip=1 26 | 27 | # sleep when no pkts incomming 28 | # unit: microseconds 29 | idle_sleep=0 30 | 31 | # sent packet delay time(0-100) while send less than 32 pkts. 32 | # default 100 us. 33 | # if set 0, means send pkts immediately. 34 | # if set >100, will dealy 100 us. 35 | # unit: microseconds 36 | pkt_tx_delay=0 37 | 38 | # use symmetric Receive-side Scaling(RSS) key, default: disabled. 39 | symmetric_rss=0 40 | 41 | # PCI device enable list. 42 | # And driver options 43 | #pci_whitelist=02:00.0 44 | # for multiple PCI devices 45 | #pci_whitelist=02:00.0,03:00.0 46 | 47 | # enabled port list 48 | # 49 | # EBNF grammar: 50 | # 51 | # exp ::= num_list {"," num_list} 52 | # num_list ::= | 53 | # range ::= "-" 54 | # num ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' 55 | # 56 | # examples 57 | # 0-3 ports 0, 1,2,3 are enabled 58 | # 1-3,4,7 ports 1,2,3,4,7 are enabled 59 | # 60 | # If use bonding, shoule config the bonding port id in port_list 61 | # and not config slave port id in port_list 62 | # such as, port 0 and port 1 trank to a bonding port 2, 63 | # should set `port_list=2` and config `[port2]` section 64 | 65 | port_list=0 66 | 67 | # Number of vdev. 68 | nb_vdev=0 69 | 70 | # Number of bond. 71 | nb_bond=0 72 | 73 | # log level for dpdk, optional 74 | # log_level=0 75 | 76 | # Each core write into own pcap file, which is open one time, close one time if enough. 77 | # Support dump the first snaplen bytes of each packet. 78 | # if pcap file is lager than savelen bytes, it will be closed and next file was dumped into. 79 | [pcap] 80 | enable=0 81 | snaplen=256 82 | savelen=33554432 83 | savepath=. 84 | 85 | # Port config section 86 | # Correspond to dpdk.port_list's index: port0, port1... 87 | [port0] 88 | addr=10.5.96.3 89 | netmask=255.255.255.0 90 | broadcast=10.5.111.255 91 | gateway=10.5.96.1 92 | # set interface name, Optional parameter. 93 | #if_name=eno7 94 | 95 | # IPv6 net addr, Optional parameters. 96 | #addr6=ff::02 97 | #prefix_len=64 98 | #gateway6=ff::01 99 | 100 | # Multi virtual IPv4/IPv6 net addr, Optional parameters. 101 | # `vip_ifname`: default `f-stack-x` 102 | # `vip_addr`: Separated by semicolons, MAX number 64; 103 | # Only support netmask 255.255.255.255, broadcast x.x.x.255 now, hard code in `ff_veth_setvaddr`. 104 | # `vip_addr6`: Separated by semicolons, MAX number 64. 105 | # `vip_prefix_len`: All addr6 use the same prefix now, default 64. 106 | #vip_ifname=lo0 107 | #vip_addr=192.168.1.3;192.168.1.4;192.168.1.5;192.168.1.6 108 | #vip_addr6=ff::03;ff::04;ff::05;ff::06;ff::07 109 | #vip_prefix_len=64 110 | 111 | # lcore list used to handle this port 112 | # the format is same as port_list 113 | #lcore_list=0 114 | 115 | # bonding slave port list used to handle this port 116 | # need to config while this port is a bonding port 117 | # the format is same as port_list 118 | #slave_port_list=0,1 119 | 120 | # Vdev config section 121 | # orrespond to dpdk.nb_vdev's index: vdev0, vdev1... 122 | # iface : Shouldn't set always. 123 | # path : The vuser device path in container. Required. 124 | # queues : The max queues of vuser. Optional, default 1, greater or equal to the number of processes. 125 | # queue_size : Queue size.Optional, default 256. 126 | # mac : The mac address of vuser. Optional, default random, if vhost use phy NIC, it should be set to the phy NIC's mac. 127 | # cq : Optional, if queues = 1, default 0; if queues > 1 default 1. 128 | #[vdev0] 129 | ##iface=/usr/local/var/run/openvswitch/vhost-user0 130 | #path=/var/run/openvswitch/vhost-user0 131 | #queues=1 132 | #queue_size=256 133 | #mac=00:00:00:00:00:01 134 | #cq=0 135 | 136 | # bond config section 137 | # See http://doc.dpdk.org/guides/prog_guide/link_bonding_poll_mode_drv_lib.html 138 | #[bond0] 139 | #mode=4 140 | #slave=0000:0a:00.0,slave=0000:0a:00.1 141 | #primary=0000:0a:00.0 142 | #mac=f0:98:38:xx:xx:xx 143 | ## opt argument 144 | #socket_id=0 145 | #xmit_policy=l23 146 | #lsc_poll_period_ms=100 147 | #up_delay=10 148 | #down_delay=50 149 | 150 | # Kni config: if enabled and method=reject, 151 | # all packets that do not belong to the following tcp_port and udp_port 152 | # will transmit to kernel; if method=accept, all packets that belong to 153 | # the following tcp_port and udp_port will transmit to kernel. 154 | #[kni] 155 | #enable=1 156 | #method=reject 157 | # The format is same as port_list 158 | #tcp_port=80,443 159 | #udp_port=53 160 | 161 | # FreeBSD network performance tuning configurations. 162 | # Most native FreeBSD configurations are supported. 163 | [freebsd.boot] 164 | # If use rack/bbr which depend HPTS, you should set a greater value of hz, such as 100000 means a tick is 10us. 165 | hz=100 166 | 167 | # Block out a range of descriptors to avoid overlap 168 | # with the kernel's descriptor space. 169 | # You can increase this value according to your app. 170 | fd_reserve=1024 171 | 172 | kern.ipc.maxsockets=262144 173 | 174 | net.inet.tcp.syncache.hashsize=4096 175 | net.inet.tcp.syncache.bucketlimit=100 176 | 177 | net.inet.tcp.tcbhashsize=65536 178 | 179 | kern.ncallout=262144 180 | 181 | kern.features.inet6=1 182 | net.inet6.ip6.auto_linklocal=1 183 | net.inet6.ip6.accept_rtadv=2 184 | net.inet6.icmp6.rediraccept=1 185 | net.inet6.ip6.forwarding=0 186 | 187 | [freebsd.sysctl] 188 | kern.ipc.somaxconn=32768 189 | kern.ipc.maxsockbuf=16777216 190 | 191 | net.link.ether.inet.maxhold=5 192 | 193 | net.inet.tcp.fast_finwait2_recycle=1 194 | net.inet.tcp.sendspace=16384 195 | net.inet.tcp.recvspace=8192 196 | #net.inet.tcp.nolocaltimewait=1 197 | net.inet.tcp.cc.algorithm=cubic 198 | net.inet.tcp.sendbuf_max=16777216 199 | net.inet.tcp.recvbuf_max=16777216 200 | net.inet.tcp.sendbuf_auto=1 201 | net.inet.tcp.recvbuf_auto=1 202 | net.inet.tcp.sendbuf_inc=16384 203 | #net.inet.tcp.recvbuf_inc=524288 204 | net.inet.tcp.sack.enable=1 205 | net.inet.tcp.blackhole=1 206 | net.inet.tcp.msl=2000 207 | net.inet.tcp.delayed_ack=1 208 | net.inet.tcp.rfc1323=1 209 | 210 | net.inet.udp.blackhole=1 211 | net.inet.ip.redirect=0 212 | net.inet.ip.forwarding=0 213 | 214 | # set default stacks:freebsd, rack or bbr, may be you need increase the value of parameter 'freebsd.boot.hz' while use rack or bbr. 215 | net.inet.tcp.functions_default=freebsd 216 | # need by bbr, should enable it. 217 | net.inet.tcp.hpts.skip_swi=1 218 | -------------------------------------------------------------------------------- /tests/new-ws-echo/config_la6.ini: -------------------------------------------------------------------------------- 1 | [dpdk] 2 | # Hexadecimal bitmask of cores to run on. 3 | lcore_mask=10 4 | 5 | # Number of memory channels. 6 | channel=2 7 | 8 | # Specify base virtual address to map. 9 | #base_virtaddr=0x7f0000000000 10 | 11 | # Promiscuous mode of nic, defualt: enabled. 12 | promiscuous=1 13 | numa_on=1 14 | 15 | # TX checksum offload skip, default: disabled. 16 | # We need this switch enabled in the following cases: 17 | # -> The application want to enforce wrong checksum for testing purposes 18 | # -> Some cards advertize the offload capability. However, doesn't calculate checksum. 19 | tx_csum_offoad_skip=0 20 | 21 | # TCP segment offload, default: disabled. 22 | tso=1 23 | 24 | # HW vlan strip, default: enabled. 25 | vlan_strip=1 26 | 27 | # sleep when no pkts incomming 28 | # unit: microseconds 29 | idle_sleep=0 30 | 31 | # sent packet delay time(0-100) while send less than 32 pkts. 32 | # default 100 us. 33 | # if set 0, means send pkts immediately. 34 | # if set >100, will dealy 100 us. 35 | # unit: microseconds 36 | pkt_tx_delay=0 37 | 38 | # use symmetric Receive-side Scaling(RSS) key, default: disabled. 39 | symmetric_rss=0 40 | 41 | # PCI device enable list. 42 | # And driver options 43 | #pci_whitelist=02:00.0 44 | # for multiple PCI devices 45 | #pci_whitelist=02:00.0,03:00.0 46 | 47 | # enabled port list 48 | # 49 | # EBNF grammar: 50 | # 51 | # exp ::= num_list {"," num_list} 52 | # num_list ::= | 53 | # range ::= "-" 54 | # num ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' 55 | # 56 | # examples 57 | # 0-3 ports 0, 1,2,3 are enabled 58 | # 1-3,4,7 ports 1,2,3,4,7 are enabled 59 | # 60 | # If use bonding, shoule config the bonding port id in port_list 61 | # and not config slave port id in port_list 62 | # such as, port 0 and port 1 trank to a bonding port 2, 63 | # should set `port_list=2` and config `[port2]` section 64 | 65 | port_list=0 66 | 67 | # Number of vdev. 68 | nb_vdev=0 69 | 70 | # Number of bond. 71 | nb_bond=0 72 | 73 | # log level for dpdk, optional 74 | # log_level=0 75 | 76 | # Each core write into own pcap file, which is open one time, close one time if enough. 77 | # Support dump the first snaplen bytes of each packet. 78 | # if pcap file is lager than savelen bytes, it will be closed and next file was dumped into. 79 | [pcap] 80 | enable=0 81 | snaplen=256 82 | savelen=33554432 83 | savepath=. 84 | 85 | # Port config section 86 | # Correspond to dpdk.port_list's index: port0, port1... 87 | [port0] 88 | addr=10.5.96.7 89 | netmask=255.255.255.0 90 | broadcast=10.5.111.255 91 | gateway=10.5.96.1 92 | # set interface name, Optional parameter. 93 | #if_name=eno7 94 | 95 | # IPv6 net addr, Optional parameters. 96 | #addr6=ff::02 97 | #prefix_len=64 98 | #gateway6=ff::01 99 | 100 | # Multi virtual IPv4/IPv6 net addr, Optional parameters. 101 | # `vip_ifname`: default `f-stack-x` 102 | # `vip_addr`: Separated by semicolons, MAX number 64; 103 | # Only support netmask 255.255.255.255, broadcast x.x.x.255 now, hard code in `ff_veth_setvaddr`. 104 | # `vip_addr6`: Separated by semicolons, MAX number 64. 105 | # `vip_prefix_len`: All addr6 use the same prefix now, default 64. 106 | #vip_ifname=lo0 107 | #vip_addr=192.168.1.3;192.168.1.4;192.168.1.5;192.168.1.6 108 | #vip_addr6=ff::03;ff::04;ff::05;ff::06;ff::07 109 | #vip_prefix_len=64 110 | 111 | # lcore list used to handle this port 112 | # the format is same as port_list 113 | #lcore_list=0 114 | 115 | # bonding slave port list used to handle this port 116 | # need to config while this port is a bonding port 117 | # the format is same as port_list 118 | #slave_port_list=0,1 119 | 120 | # Vdev config section 121 | # orrespond to dpdk.nb_vdev's index: vdev0, vdev1... 122 | # iface : Shouldn't set always. 123 | # path : The vuser device path in container. Required. 124 | # queues : The max queues of vuser. Optional, default 1, greater or equal to the number of processes. 125 | # queue_size : Queue size.Optional, default 256. 126 | # mac : The mac address of vuser. Optional, default random, if vhost use phy NIC, it should be set to the phy NIC's mac. 127 | # cq : Optional, if queues = 1, default 0; if queues > 1 default 1. 128 | #[vdev0] 129 | ##iface=/usr/local/var/run/openvswitch/vhost-user0 130 | #path=/var/run/openvswitch/vhost-user0 131 | #queues=1 132 | #queue_size=256 133 | #mac=00:00:00:00:00:01 134 | #cq=0 135 | 136 | # bond config section 137 | # See http://doc.dpdk.org/guides/prog_guide/link_bonding_poll_mode_drv_lib.html 138 | #[bond0] 139 | #mode=4 140 | #slave=0000:0a:00.0,slave=0000:0a:00.1 141 | #primary=0000:0a:00.0 142 | #mac=f0:98:38:xx:xx:xx 143 | ## opt argument 144 | #socket_id=0 145 | #xmit_policy=l23 146 | #lsc_poll_period_ms=100 147 | #up_delay=10 148 | #down_delay=50 149 | 150 | # Kni config: if enabled and method=reject, 151 | # all packets that do not belong to the following tcp_port and udp_port 152 | # will transmit to kernel; if method=accept, all packets that belong to 153 | # the following tcp_port and udp_port will transmit to kernel. 154 | #[kni] 155 | #enable=1 156 | #method=reject 157 | # The format is same as port_list 158 | #tcp_port=80,443 159 | #udp_port=53 160 | 161 | # FreeBSD network performance tuning configurations. 162 | # Most native FreeBSD configurations are supported. 163 | [freebsd.boot] 164 | # If use rack/bbr which depend HPTS, you should set a greater value of hz, such as 100000 means a tick is 10us. 165 | hz=100 166 | 167 | # Block out a range of descriptors to avoid overlap 168 | # with the kernel's descriptor space. 169 | # You can increase this value according to your app. 170 | fd_reserve=1024 171 | 172 | kern.ipc.maxsockets=262144 173 | 174 | net.inet.tcp.syncache.hashsize=4096 175 | net.inet.tcp.syncache.bucketlimit=100 176 | 177 | net.inet.tcp.tcbhashsize=65536 178 | 179 | kern.ncallout=262144 180 | 181 | kern.features.inet6=1 182 | net.inet6.ip6.auto_linklocal=1 183 | net.inet6.ip6.accept_rtadv=2 184 | net.inet6.icmp6.rediraccept=1 185 | net.inet6.ip6.forwarding=0 186 | 187 | [freebsd.sysctl] 188 | kern.ipc.somaxconn=32768 189 | kern.ipc.maxsockbuf=16777216 190 | 191 | net.link.ether.inet.maxhold=5 192 | 193 | net.inet.tcp.fast_finwait2_recycle=1 194 | net.inet.tcp.sendspace=16384 195 | net.inet.tcp.recvspace=8192 196 | #net.inet.tcp.nolocaltimewait=1 197 | net.inet.tcp.cc.algorithm=cubic 198 | net.inet.tcp.sendbuf_max=16777216 199 | net.inet.tcp.recvbuf_max=16777216 200 | net.inet.tcp.sendbuf_auto=1 201 | net.inet.tcp.recvbuf_auto=1 202 | net.inet.tcp.sendbuf_inc=16384 203 | #net.inet.tcp.recvbuf_inc=524288 204 | net.inet.tcp.sack.enable=1 205 | net.inet.tcp.blackhole=1 206 | net.inet.tcp.msl=2000 207 | net.inet.tcp.delayed_ack=1 208 | net.inet.tcp.rfc1323=1 209 | 210 | net.inet.udp.blackhole=1 211 | net.inet.ip.redirect=0 212 | net.inet.ip.forwarding=0 213 | 214 | # set default stacks:freebsd, rack or bbr, may be you need increase the value of parameter 'freebsd.boot.hz' while use rack or bbr. 215 | net.inet.tcp.functions_default=freebsd 216 | # need by bbr, should enable it. 217 | net.inet.tcp.hpts.skip_swi=1 218 | -------------------------------------------------------------------------------- /tests/ws-echo/config_vi01.ini: -------------------------------------------------------------------------------- 1 | [dpdk] 2 | # Hexadecimal bitmask of cores to run on. 3 | lcore_mask=1 4 | 5 | # Number of memory channels. 6 | channel=2 7 | 8 | # Specify base virtual address to map. 9 | #base_virtaddr=0x7f0000000000 10 | 11 | # Promiscuous mode of nic, defualt: enabled. 12 | promiscuous=1 13 | numa_on=1 14 | 15 | # TX checksum offload skip, default: disabled. 16 | # We need this switch enabled in the following cases: 17 | # -> The application want to enforce wrong checksum for testing purposes 18 | # -> Some cards advertize the offload capability. However, doesn't calculate checksum. 19 | tx_csum_offoad_skip=0 20 | 21 | # TCP segment offload, default: disabled. 22 | tso=0 23 | 24 | # HW vlan strip, default: enabled. 25 | vlan_strip=1 26 | 27 | # sleep when no pkts incomming 28 | # unit: microseconds 29 | idle_sleep=0 30 | 31 | # sent packet delay time(0-100) while send less than 32 pkts. 32 | # default 100 us. 33 | # if set 0, means send pkts immediately. 34 | # if set >100, will dealy 100 us. 35 | # unit: microseconds 36 | pkt_tx_delay=0 37 | 38 | # use symmetric Receive-side Scaling(RSS) key, default: disabled. 39 | symmetric_rss=0 40 | 41 | # PCI device enable list. 42 | # And driver options 43 | #pci_whitelist=02:00.0 44 | # for multiple PCI devices 45 | #pci_whitelist=02:00.0,03:00.0 46 | 47 | # enabled port list 48 | # 49 | # EBNF grammar: 50 | # 51 | # exp ::= num_list {"," num_list} 52 | # num_list ::= | 53 | # range ::= "-" 54 | # num ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' 55 | # 56 | # examples 57 | # 0-3 ports 0, 1,2,3 are enabled 58 | # 1-3,4,7 ports 1,2,3,4,7 are enabled 59 | # 60 | # If use bonding, shoule config the bonding port id in port_list 61 | # and not config slave port id in port_list 62 | # such as, port 0 and port 1 trank to a bonding port 2, 63 | # should set `port_list=2` and config `[port2]` section 64 | 65 | port_list=0 66 | 67 | # Number of vdev. 68 | nb_vdev=0 69 | 70 | # Number of bond. 71 | nb_bond=0 72 | 73 | # log level for dpdk, optional 74 | # log_level=0 75 | 76 | # Each core write into own pcap file, which is open one time, close one time if enough. 77 | # Support dump the first snaplen bytes of each packet. 78 | # if pcap file is lager than savelen bytes, it will be closed and next file was dumped into. 79 | [pcap] 80 | enable=0 81 | snaplen=96 82 | savelen=16777216 83 | savepath=. 84 | 85 | # Port config section 86 | # Correspond to dpdk.port_list's index: port0, port1... 87 | [port0] 88 | addr=172.31.98.130 89 | netmask=255.255.255.0 90 | broadcast=172.31.98.255 91 | gateway=172.31.98.1 92 | # set interface name, Optional parameter. 93 | #if_name=eno7 94 | 95 | # IPv6 net addr, Optional parameters. 96 | #addr6=ff::02 97 | #prefix_len=64 98 | #gateway6=ff::01 99 | 100 | # Multi virtual IPv4/IPv6 net addr, Optional parameters. 101 | # `vip_ifname`: default `f-stack-x` 102 | # `vip_addr`: Separated by semicolons, MAX number 64; 103 | # Only support netmask 255.255.255.255, broadcast x.x.x.255 now, hard code in `ff_veth_setvaddr`. 104 | # `vip_addr6`: Separated by semicolons, MAX number 64. 105 | # `vip_prefix_len`: All addr6 use the same prefix now, default 64. 106 | #vip_ifname=lo0 107 | #vip_addr=192.168.1.3;192.168.1.4;192.168.1.5;192.168.1.6 108 | #vip_addr6=ff::03;ff::04;ff::05;ff::06;ff::07 109 | #vip_prefix_len=64 110 | 111 | # lcore list used to handle this port 112 | # the format is same as port_list 113 | #lcore_list=0 114 | 115 | # bonding slave port list used to handle this port 116 | # need to config while this port is a bonding port 117 | # the format is same as port_list 118 | #slave_port_list=0,1 119 | 120 | # Vdev config section 121 | # orrespond to dpdk.nb_vdev's index: vdev0, vdev1... 122 | # iface : Shouldn't set always. 123 | # path : The vuser device path in container. Required. 124 | # queues : The max queues of vuser. Optional, default 1, greater or equal to the number of processes. 125 | # queue_size : Queue size.Optional, default 256. 126 | # mac : The mac address of vuser. Optional, default random, if vhost use phy NIC, it should be set to the phy NIC's mac. 127 | # cq : Optional, if queues = 1, default 0; if queues > 1 default 1. 128 | #[vdev0] 129 | ##iface=/usr/local/var/run/openvswitch/vhost-user0 130 | #path=/var/run/openvswitch/vhost-user0 131 | #queues=1 132 | #queue_size=256 133 | #mac=00:00:00:00:00:01 134 | #cq=0 135 | 136 | # bond config section 137 | # See http://doc.dpdk.org/guides/prog_guide/link_bonding_poll_mode_drv_lib.html 138 | #[bond0] 139 | #mode=4 140 | #slave=0000:0a:00.0,slave=0000:0a:00.1 141 | #primary=0000:0a:00.0 142 | #mac=f0:98:38:xx:xx:xx 143 | ## opt argument 144 | #socket_id=0 145 | #xmit_policy=l23 146 | #lsc_poll_period_ms=100 147 | #up_delay=10 148 | #down_delay=50 149 | 150 | # Kni config: if enabled and method=reject, 151 | # all packets that do not belong to the following tcp_port and udp_port 152 | # will transmit to kernel; if method=accept, all packets that belong to 153 | # the following tcp_port and udp_port will transmit to kernel. 154 | #[kni] 155 | #enable=1 156 | #method=reject 157 | # The format is same as port_list 158 | #tcp_port=80,443 159 | #udp_port=53 160 | 161 | # FreeBSD network performance tuning configurations. 162 | # Most native FreeBSD configurations are supported. 163 | [freebsd.boot] 164 | # If use rack/bbr which depend HPTS, you should set a greater value of hz, such as 100000 means a tick is 10us. 165 | hz=100 166 | 167 | # Block out a range of descriptors to avoid overlap 168 | # with the kernel's descriptor space. 169 | # You can increase this value according to your app. 170 | fd_reserve=1024 171 | 172 | kern.ipc.maxsockets=262144 173 | 174 | net.inet.tcp.syncache.hashsize=4096 175 | net.inet.tcp.syncache.bucketlimit=100 176 | 177 | net.inet.tcp.tcbhashsize=65536 178 | 179 | kern.ncallout=262144 180 | 181 | kern.features.inet6=1 182 | net.inet6.ip6.auto_linklocal=1 183 | net.inet6.ip6.accept_rtadv=2 184 | net.inet6.icmp6.rediraccept=1 185 | net.inet6.ip6.forwarding=0 186 | 187 | [freebsd.sysctl] 188 | kern.ipc.somaxconn=32768 189 | kern.ipc.maxsockbuf=16777216 190 | 191 | net.link.ether.inet.maxhold=5 192 | 193 | net.inet.tcp.fast_finwait2_recycle=1 194 | net.inet.tcp.sendspace=16384 195 | net.inet.tcp.recvspace=8192 196 | #net.inet.tcp.nolocaltimewait=1 197 | net.inet.tcp.cc.algorithm=cubic 198 | net.inet.tcp.sendbuf_max=16777216 199 | net.inet.tcp.recvbuf_max=16777216 200 | net.inet.tcp.sendbuf_auto=1 201 | net.inet.tcp.recvbuf_auto=1 202 | net.inet.tcp.sendbuf_inc=16384 203 | #net.inet.tcp.recvbuf_inc=524288 204 | net.inet.tcp.sack.enable=1 205 | net.inet.tcp.blackhole=1 206 | net.inet.tcp.msl=2000 207 | net.inet.tcp.delayed_ack=1 208 | net.inet.tcp.rfc1323=1 209 | 210 | net.inet.udp.blackhole=1 211 | net.inet.ip.redirect=0 212 | net.inet.ip.forwarding=0 213 | 214 | # set default stacks:freebsd, rack or bbr, may be you need increase the value of parameter 'freebsd.boot.hz' while use rack or bbr. 215 | net.inet.tcp.functions_default=freebsd 216 | # need by bbr, should enable it. 217 | net.inet.tcp.hpts.skip_swi=1 218 | -------------------------------------------------------------------------------- /tests/ws-echo/config_vi02.ini: -------------------------------------------------------------------------------- 1 | [dpdk] 2 | # Hexadecimal bitmask of cores to run on. 3 | lcore_mask=1 4 | 5 | # Number of memory channels. 6 | channel=2 7 | 8 | # Specify base virtual address to map. 9 | #base_virtaddr=0x7f0000000000 10 | 11 | # Promiscuous mode of nic, defualt: enabled. 12 | promiscuous=1 13 | numa_on=1 14 | 15 | # TX checksum offload skip, default: disabled. 16 | # We need this switch enabled in the following cases: 17 | # -> The application want to enforce wrong checksum for testing purposes 18 | # -> Some cards advertize the offload capability. However, doesn't calculate checksum. 19 | tx_csum_offoad_skip=0 20 | 21 | # TCP segment offload, default: disabled. 22 | tso=0 23 | 24 | # HW vlan strip, default: enabled. 25 | vlan_strip=1 26 | 27 | # sleep when no pkts incomming 28 | # unit: microseconds 29 | idle_sleep=0 30 | 31 | # sent packet delay time(0-100) while send less than 32 pkts. 32 | # default 100 us. 33 | # if set 0, means send pkts immediately. 34 | # if set >100, will dealy 100 us. 35 | # unit: microseconds 36 | pkt_tx_delay=0 37 | 38 | # use symmetric Receive-side Scaling(RSS) key, default: disabled. 39 | symmetric_rss=0 40 | 41 | # PCI device enable list. 42 | # And driver options 43 | #pci_whitelist=02:00.0 44 | # for multiple PCI devices 45 | #pci_whitelist=02:00.0,03:00.0 46 | 47 | # enabled port list 48 | # 49 | # EBNF grammar: 50 | # 51 | # exp ::= num_list {"," num_list} 52 | # num_list ::= | 53 | # range ::= "-" 54 | # num ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' 55 | # 56 | # examples 57 | # 0-3 ports 0, 1,2,3 are enabled 58 | # 1-3,4,7 ports 1,2,3,4,7 are enabled 59 | # 60 | # If use bonding, shoule config the bonding port id in port_list 61 | # and not config slave port id in port_list 62 | # such as, port 0 and port 1 trank to a bonding port 2, 63 | # should set `port_list=2` and config `[port2]` section 64 | 65 | port_list=0 66 | 67 | # Number of vdev. 68 | nb_vdev=0 69 | 70 | # Number of bond. 71 | nb_bond=0 72 | 73 | # log level for dpdk, optional 74 | # log_level=0 75 | 76 | # Each core write into own pcap file, which is open one time, close one time if enough. 77 | # Support dump the first snaplen bytes of each packet. 78 | # if pcap file is lager than savelen bytes, it will be closed and next file was dumped into. 79 | [pcap] 80 | enable=0 81 | snaplen=96 82 | savelen=16777216 83 | savepath=. 84 | 85 | # Port config section 86 | # Correspond to dpdk.port_list's index: port0, port1... 87 | [port0] 88 | addr=172.31.98.82 89 | netmask=255.255.255.0 90 | broadcast=172.31.98.255 91 | gateway=172.31.98.1 92 | # set interface name, Optional parameter. 93 | #if_name=eno7 94 | 95 | # IPv6 net addr, Optional parameters. 96 | #addr6=ff::02 97 | #prefix_len=64 98 | #gateway6=ff::01 99 | 100 | # Multi virtual IPv4/IPv6 net addr, Optional parameters. 101 | # `vip_ifname`: default `f-stack-x` 102 | # `vip_addr`: Separated by semicolons, MAX number 64; 103 | # Only support netmask 255.255.255.255, broadcast x.x.x.255 now, hard code in `ff_veth_setvaddr`. 104 | # `vip_addr6`: Separated by semicolons, MAX number 64. 105 | # `vip_prefix_len`: All addr6 use the same prefix now, default 64. 106 | #vip_ifname=lo0 107 | #vip_addr=192.168.1.3;192.168.1.4;192.168.1.5;192.168.1.6 108 | #vip_addr6=ff::03;ff::04;ff::05;ff::06;ff::07 109 | #vip_prefix_len=64 110 | 111 | # lcore list used to handle this port 112 | # the format is same as port_list 113 | #lcore_list=0 114 | 115 | # bonding slave port list used to handle this port 116 | # need to config while this port is a bonding port 117 | # the format is same as port_list 118 | #slave_port_list=0,1 119 | 120 | # Vdev config section 121 | # orrespond to dpdk.nb_vdev's index: vdev0, vdev1... 122 | # iface : Shouldn't set always. 123 | # path : The vuser device path in container. Required. 124 | # queues : The max queues of vuser. Optional, default 1, greater or equal to the number of processes. 125 | # queue_size : Queue size.Optional, default 256. 126 | # mac : The mac address of vuser. Optional, default random, if vhost use phy NIC, it should be set to the phy NIC's mac. 127 | # cq : Optional, if queues = 1, default 0; if queues > 1 default 1. 128 | #[vdev0] 129 | ##iface=/usr/local/var/run/openvswitch/vhost-user0 130 | #path=/var/run/openvswitch/vhost-user0 131 | #queues=1 132 | #queue_size=256 133 | #mac=00:00:00:00:00:01 134 | #cq=0 135 | 136 | # bond config section 137 | # See http://doc.dpdk.org/guides/prog_guide/link_bonding_poll_mode_drv_lib.html 138 | #[bond0] 139 | #mode=4 140 | #slave=0000:0a:00.0,slave=0000:0a:00.1 141 | #primary=0000:0a:00.0 142 | #mac=f0:98:38:xx:xx:xx 143 | ## opt argument 144 | #socket_id=0 145 | #xmit_policy=l23 146 | #lsc_poll_period_ms=100 147 | #up_delay=10 148 | #down_delay=50 149 | 150 | # Kni config: if enabled and method=reject, 151 | # all packets that do not belong to the following tcp_port and udp_port 152 | # will transmit to kernel; if method=accept, all packets that belong to 153 | # the following tcp_port and udp_port will transmit to kernel. 154 | #[kni] 155 | #enable=1 156 | #method=reject 157 | # The format is same as port_list 158 | #tcp_port=80,443 159 | #udp_port=53 160 | 161 | # FreeBSD network performance tuning configurations. 162 | # Most native FreeBSD configurations are supported. 163 | [freebsd.boot] 164 | # If use rack/bbr which depend HPTS, you should set a greater value of hz, such as 100000 means a tick is 10us. 165 | hz=100 166 | 167 | # Block out a range of descriptors to avoid overlap 168 | # with the kernel's descriptor space. 169 | # You can increase this value according to your app. 170 | fd_reserve=1024 171 | 172 | kern.ipc.maxsockets=262144 173 | 174 | net.inet.tcp.syncache.hashsize=4096 175 | net.inet.tcp.syncache.bucketlimit=100 176 | 177 | net.inet.tcp.tcbhashsize=65536 178 | 179 | kern.ncallout=262144 180 | 181 | kern.features.inet6=1 182 | net.inet6.ip6.auto_linklocal=1 183 | net.inet6.ip6.accept_rtadv=2 184 | net.inet6.icmp6.rediraccept=1 185 | net.inet6.ip6.forwarding=0 186 | 187 | [freebsd.sysctl] 188 | kern.ipc.somaxconn=32768 189 | kern.ipc.maxsockbuf=16777216 190 | 191 | net.link.ether.inet.maxhold=5 192 | 193 | net.inet.tcp.fast_finwait2_recycle=1 194 | net.inet.tcp.sendspace=16384 195 | net.inet.tcp.recvspace=8192 196 | #net.inet.tcp.nolocaltimewait=1 197 | net.inet.tcp.cc.algorithm=cubic 198 | net.inet.tcp.sendbuf_max=16777216 199 | net.inet.tcp.recvbuf_max=16777216 200 | net.inet.tcp.sendbuf_auto=1 201 | net.inet.tcp.recvbuf_auto=1 202 | net.inet.tcp.sendbuf_inc=16384 203 | #net.inet.tcp.recvbuf_inc=524288 204 | net.inet.tcp.sack.enable=1 205 | net.inet.tcp.blackhole=1 206 | net.inet.tcp.msl=2000 207 | net.inet.tcp.delayed_ack=1 208 | net.inet.tcp.rfc1323=1 209 | 210 | net.inet.udp.blackhole=1 211 | net.inet.ip.redirect=0 212 | net.inet.ip.forwarding=0 213 | 214 | # set default stacks:freebsd, rack or bbr, may be you need increase the value of parameter 'freebsd.boot.hz' while use rack or bbr. 215 | net.inet.tcp.functions_default=freebsd 216 | # need by bbr, should enable it. 217 | net.inet.tcp.hpts.skip_swi=1 218 | -------------------------------------------------------------------------------- /tests/test-new-tcp-echo/config_la6.ini: -------------------------------------------------------------------------------- 1 | [dpdk] 2 | # Hexadecimal bitmask of cores to run on. 3 | lcore_mask=10 4 | 5 | # Number of memory channels. 6 | channel=2 7 | 8 | # Specify base virtual address to map. 9 | #base_virtaddr=0x7f0000000000 10 | 11 | # Promiscuous mode of nic, defualt: enabled. 12 | promiscuous=1 13 | numa_on=1 14 | 15 | # TX checksum offload skip, default: disabled. 16 | # We need this switch enabled in the following cases: 17 | # -> The application want to enforce wrong checksum for testing purposes 18 | # -> Some cards advertize the offload capability. However, doesn't calculate checksum. 19 | tx_csum_offoad_skip=0 20 | 21 | # TCP segment offload, default: disabled. 22 | tso=1 23 | 24 | # HW vlan strip, default: enabled. 25 | vlan_strip=1 26 | 27 | # sleep when no pkts incomming 28 | # unit: microseconds 29 | idle_sleep=0 30 | 31 | # sent packet delay time(0-100) while send less than 32 pkts. 32 | # default 100 us. 33 | # if set 0, means send pkts immediately. 34 | # if set >100, will dealy 100 us. 35 | # unit: microseconds 36 | pkt_tx_delay=0 37 | 38 | # use symmetric Receive-side Scaling(RSS) key, default: disabled. 39 | symmetric_rss=0 40 | 41 | # PCI device enable list. 42 | # And driver options 43 | #pci_whitelist=02:00.0 44 | # for multiple PCI devices 45 | #pci_whitelist=02:00.0,03:00.0 46 | 47 | # enabled port list 48 | # 49 | # EBNF grammar: 50 | # 51 | # exp ::= num_list {"," num_list} 52 | # num_list ::= | 53 | # range ::= "-" 54 | # num ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' 55 | # 56 | # examples 57 | # 0-3 ports 0, 1,2,3 are enabled 58 | # 1-3,4,7 ports 1,2,3,4,7 are enabled 59 | # 60 | # If use bonding, shoule config the bonding port id in port_list 61 | # and not config slave port id in port_list 62 | # such as, port 0 and port 1 trank to a bonding port 2, 63 | # should set `port_list=2` and config `[port2]` section 64 | 65 | port_list=0 66 | 67 | # Number of vdev. 68 | nb_vdev=0 69 | 70 | # Number of bond. 71 | nb_bond=0 72 | 73 | # log level for dpdk, optional 74 | # log_level=0 75 | 76 | # Each core write into own pcap file, which is open one time, close one time if enough. 77 | # Support dump the first snaplen bytes of each packet. 78 | # if pcap file is lager than savelen bytes, it will be closed and next file was dumped into. 79 | [pcap] 80 | enable=0 81 | snaplen=256 82 | savelen=2147483648 83 | savepath=. 84 | 85 | # Port config section 86 | # Correspond to dpdk.port_list's index: port0, port1... 87 | [port0] 88 | addr=10.5.96.7 89 | netmask=255.255.255.0 90 | broadcast=10.5.111.255 91 | gateway=10.5.96.1 92 | # set interface name, Optional parameter. 93 | #if_name=eno7 94 | 95 | # IPv6 net addr, Optional parameters. 96 | #addr6=ff::02 97 | #prefix_len=64 98 | #gateway6=ff::01 99 | 100 | # Multi virtual IPv4/IPv6 net addr, Optional parameters. 101 | # `vip_ifname`: default `f-stack-x` 102 | # `vip_addr`: Separated by semicolons, MAX number 64; 103 | # Only support netmask 255.255.255.255, broadcast x.x.x.255 now, hard code in `ff_veth_setvaddr`. 104 | # `vip_addr6`: Separated by semicolons, MAX number 64. 105 | # `vip_prefix_len`: All addr6 use the same prefix now, default 64. 106 | #vip_ifname=lo0 107 | #vip_addr=192.168.1.3;192.168.1.4;192.168.1.5;192.168.1.6 108 | #vip_addr6=ff::03;ff::04;ff::05;ff::06;ff::07 109 | #vip_prefix_len=64 110 | 111 | # lcore list used to handle this port 112 | # the format is same as port_list 113 | #lcore_list=0 114 | 115 | # bonding slave port list used to handle this port 116 | # need to config while this port is a bonding port 117 | # the format is same as port_list 118 | #slave_port_list=0,1 119 | 120 | # Vdev config section 121 | # orrespond to dpdk.nb_vdev's index: vdev0, vdev1... 122 | # iface : Shouldn't set always. 123 | # path : The vuser device path in container. Required. 124 | # queues : The max queues of vuser. Optional, default 1, greater or equal to the number of processes. 125 | # queue_size : Queue size.Optional, default 256. 126 | # mac : The mac address of vuser. Optional, default random, if vhost use phy NIC, it should be set to the phy NIC's mac. 127 | # cq : Optional, if queues = 1, default 0; if queues > 1 default 1. 128 | #[vdev0] 129 | ##iface=/usr/local/var/run/openvswitch/vhost-user0 130 | #path=/var/run/openvswitch/vhost-user0 131 | #queues=1 132 | #queue_size=256 133 | #mac=00:00:00:00:00:01 134 | #cq=0 135 | 136 | # bond config section 137 | # See http://doc.dpdk.org/guides/prog_guide/link_bonding_poll_mode_drv_lib.html 138 | #[bond0] 139 | #mode=4 140 | #slave=0000:0a:00.0,slave=0000:0a:00.1 141 | #primary=0000:0a:00.0 142 | #mac=f0:98:38:xx:xx:xx 143 | ## opt argument 144 | #socket_id=0 145 | #xmit_policy=l23 146 | #lsc_poll_period_ms=100 147 | #up_delay=10 148 | #down_delay=50 149 | 150 | # Kni config: if enabled and method=reject, 151 | # all packets that do not belong to the following tcp_port and udp_port 152 | # will transmit to kernel; if method=accept, all packets that belong to 153 | # the following tcp_port and udp_port will transmit to kernel. 154 | #[kni] 155 | #enable=1 156 | #method=reject 157 | # The format is same as port_list 158 | #tcp_port=80,443 159 | #udp_port=53 160 | 161 | # FreeBSD network performance tuning configurations. 162 | # Most native FreeBSD configurations are supported. 163 | [freebsd.boot] 164 | # If use rack/bbr which depend HPTS, you should set a greater value of hz, such as 100000 means a tick is 10us. 165 | hz=100 166 | 167 | # Block out a range of descriptors to avoid overlap 168 | # with the kernel's descriptor space. 169 | # You can increase this value according to your app. 170 | fd_reserve=1024 171 | 172 | kern.ipc.maxsockets=262144 173 | 174 | net.inet.tcp.syncache.hashsize=4096 175 | net.inet.tcp.syncache.bucketlimit=100 176 | 177 | net.inet.tcp.tcbhashsize=65536 178 | 179 | kern.ncallout=262144 180 | 181 | kern.features.inet6=1 182 | net.inet6.ip6.auto_linklocal=1 183 | net.inet6.ip6.accept_rtadv=2 184 | net.inet6.icmp6.rediraccept=1 185 | net.inet6.ip6.forwarding=0 186 | 187 | [freebsd.sysctl] 188 | kern.ipc.somaxconn=32768 189 | kern.ipc.maxsockbuf=16777216 190 | 191 | net.link.ether.inet.maxhold=5 192 | 193 | net.inet.tcp.fast_finwait2_recycle=1 194 | net.inet.tcp.sendspace=16384 195 | net.inet.tcp.recvspace=8192 196 | #net.inet.tcp.nolocaltimewait=1 197 | net.inet.tcp.cc.algorithm=cubic 198 | net.inet.tcp.sendbuf_max=16777216 199 | net.inet.tcp.recvbuf_max=16777216 200 | net.inet.tcp.sendbuf_auto=1 201 | net.inet.tcp.recvbuf_auto=1 202 | net.inet.tcp.sendbuf_inc=16384 203 | #net.inet.tcp.recvbuf_inc=524288 204 | net.inet.tcp.sack.enable=1 205 | net.inet.tcp.blackhole=1 206 | net.inet.tcp.msl=2000 207 | net.inet.tcp.delayed_ack=1 208 | net.inet.tcp.rfc1323=1 209 | 210 | net.inet.udp.blackhole=1 211 | net.inet.ip.redirect=0 212 | net.inet.ip.forwarding=0 213 | 214 | # set default stacks:freebsd, rack or bbr, may be you need increase the value of parameter 'freebsd.boot.hz' while use rack or bbr. 215 | net.inet.tcp.functions_default=freebsd 216 | # need by bbr, should enable it. 217 | net.inet.tcp.hpts.skip_swi=1 218 | -------------------------------------------------------------------------------- /tests/test-new-tcp-echo/config_la1.ini: -------------------------------------------------------------------------------- 1 | [dpdk] 2 | # Hexadecimal bitmask of cores to run on. 3 | lcore_mask=8 4 | ; lcore_mask=3 5 | 6 | # Number of memory channels. 7 | channel=2 8 | 9 | # Specify base virtual address to map. 10 | #base_virtaddr=0x7f0000000000 11 | 12 | # Promiscuous mode of nic, defualt: enabled. 13 | promiscuous=1 14 | numa_on=1 15 | 16 | # TX checksum offload skip, default: disabled. 17 | # We need this switch enabled in the following cases: 18 | # -> The application want to enforce wrong checksum for testing purposes 19 | # -> Some cards advertize the offload capability. However, doesn't calculate checksum. 20 | tx_csum_offoad_skip=0 21 | 22 | # TCP segment offload, default: disabled. 23 | tso=1 24 | 25 | # HW vlan strip, default: enabled. 26 | vlan_strip=1 27 | 28 | # sleep when no pkts incomming 29 | # unit: microseconds 30 | idle_sleep=0 31 | 32 | # sent packet delay time(0-100) while send less than 32 pkts. 33 | # default 100 us. 34 | # if set 0, means send pkts immediately. 35 | # if set >100, will dealy 100 us. 36 | # unit: microseconds 37 | pkt_tx_delay=0 38 | 39 | # use symmetric Receive-side Scaling(RSS) key, default: disabled. 40 | symmetric_rss=0 41 | 42 | # PCI device enable list. 43 | # And driver options 44 | #pci_whitelist=02:00.0 45 | # for multiple PCI devices 46 | #pci_whitelist=02:00.0,03:00.0 47 | 48 | # enabled port list 49 | # 50 | # EBNF grammar: 51 | # 52 | # exp ::= num_list {"," num_list} 53 | # num_list ::= | 54 | # range ::= "-" 55 | # num ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' 56 | # 57 | # examples 58 | # 0-3 ports 0, 1,2,3 are enabled 59 | # 1-3,4,7 ports 1,2,3,4,7 are enabled 60 | # 61 | # If use bonding, shoule config the bonding port id in port_list 62 | # and not config slave port id in port_list 63 | # such as, port 0 and port 1 trank to a bonding port 2, 64 | # should set `port_list=2` and config `[port2]` section 65 | 66 | port_list=0 67 | 68 | # Number of vdev. 69 | nb_vdev=0 70 | 71 | # Number of bond. 72 | nb_bond=0 73 | 74 | # log level for dpdk, optional 75 | # log_level=0 76 | 77 | # Each core write into own pcap file, which is open one time, close one time if enough. 78 | # Support dump the first snaplen bytes of each packet. 79 | # if pcap file is lager than savelen bytes, it will be closed and next file was dumped into. 80 | [pcap] 81 | enable=0 82 | snaplen=256 83 | savelen=2147483648 84 | savepath=. 85 | 86 | # Port config section 87 | # Correspond to dpdk.port_list's index: port0, port1... 88 | [port0] 89 | addr=10.5.96.3 90 | netmask=255.255.255.0 91 | broadcast=10.5.111.255 92 | gateway=10.5.96.1 93 | # set interface name, Optional parameter. 94 | #if_name=eno7 95 | 96 | # IPv6 net addr, Optional parameters. 97 | #addr6=ff::02 98 | #prefix_len=64 99 | #gateway6=ff::01 100 | 101 | # Multi virtual IPv4/IPv6 net addr, Optional parameters. 102 | # `vip_ifname`: default `f-stack-x` 103 | # `vip_addr`: Separated by semicolons, MAX number 64; 104 | # Only support netmask 255.255.255.255, broadcast x.x.x.255 now, hard code in `ff_veth_setvaddr`. 105 | # `vip_addr6`: Separated by semicolons, MAX number 64. 106 | # `vip_prefix_len`: All addr6 use the same prefix now, default 64. 107 | #vip_ifname=lo0 108 | #vip_addr=192.168.1.3;192.168.1.4;192.168.1.5;192.168.1.6 109 | #vip_addr6=ff::03;ff::04;ff::05;ff::06;ff::07 110 | #vip_prefix_len=64 111 | 112 | # lcore list used to handle this port 113 | # the format is same as port_list 114 | #lcore_list=0 115 | 116 | # bonding slave port list used to handle this port 117 | # need to config while this port is a bonding port 118 | # the format is same as port_list 119 | #slave_port_list=0,1 120 | 121 | # Vdev config section 122 | # orrespond to dpdk.nb_vdev's index: vdev0, vdev1... 123 | # iface : Shouldn't set always. 124 | # path : The vuser device path in container. Required. 125 | # queues : The max queues of vuser. Optional, default 1, greater or equal to the number of processes. 126 | # queue_size : Queue size.Optional, default 256. 127 | # mac : The mac address of vuser. Optional, default random, if vhost use phy NIC, it should be set to the phy NIC's mac. 128 | # cq : Optional, if queues = 1, default 0; if queues > 1 default 1. 129 | #[vdev0] 130 | ##iface=/usr/local/var/run/openvswitch/vhost-user0 131 | #path=/var/run/openvswitch/vhost-user0 132 | #queues=1 133 | #queue_size=256 134 | #mac=00:00:00:00:00:01 135 | #cq=0 136 | 137 | # bond config section 138 | # See http://doc.dpdk.org/guides/prog_guide/link_bonding_poll_mode_drv_lib.html 139 | #[bond0] 140 | #mode=4 141 | #slave=0000:0a:00.0,slave=0000:0a:00.1 142 | #primary=0000:0a:00.0 143 | #mac=f0:98:38:xx:xx:xx 144 | ## opt argument 145 | #socket_id=0 146 | #xmit_policy=l23 147 | #lsc_poll_period_ms=100 148 | #up_delay=10 149 | #down_delay=50 150 | 151 | # Kni config: if enabled and method=reject, 152 | # all packets that do not belong to the following tcp_port and udp_port 153 | # will transmit to kernel; if method=accept, all packets that belong to 154 | # the following tcp_port and udp_port will transmit to kernel. 155 | #[kni] 156 | #enable=1 157 | #method=reject 158 | # The format is same as port_list 159 | #tcp_port=80,443 160 | #udp_port=53 161 | 162 | # FreeBSD network performance tuning configurations. 163 | # Most native FreeBSD configurations are supported. 164 | [freebsd.boot] 165 | # If use rack/bbr which depend HPTS, you should set a greater value of hz, such as 100000 means a tick is 10us. 166 | hz=100 167 | 168 | # Block out a range of descriptors to avoid overlap 169 | # with the kernel's descriptor space. 170 | # You can increase this value according to your app. 171 | fd_reserve=1024 172 | 173 | kern.ipc.maxsockets=262144 174 | 175 | net.inet.tcp.syncache.hashsize=4096 176 | net.inet.tcp.syncache.bucketlimit=100 177 | 178 | net.inet.tcp.tcbhashsize=65536 179 | 180 | kern.ncallout=262144 181 | 182 | kern.features.inet6=1 183 | net.inet6.ip6.auto_linklocal=1 184 | net.inet6.ip6.accept_rtadv=2 185 | net.inet6.icmp6.rediraccept=1 186 | net.inet6.ip6.forwarding=0 187 | 188 | [freebsd.sysctl] 189 | kern.ipc.somaxconn=32768 190 | kern.ipc.maxsockbuf=16777216 191 | 192 | net.link.ether.inet.maxhold=5 193 | 194 | net.inet.tcp.fast_finwait2_recycle=1 195 | net.inet.tcp.sendspace=16384 196 | net.inet.tcp.recvspace=8192 197 | #net.inet.tcp.nolocaltimewait=1 198 | net.inet.tcp.cc.algorithm=cubic 199 | net.inet.tcp.sendbuf_max=16777216 200 | net.inet.tcp.recvbuf_max=16777216 201 | net.inet.tcp.sendbuf_auto=1 202 | net.inet.tcp.recvbuf_auto=1 203 | net.inet.tcp.sendbuf_inc=16384 204 | #net.inet.tcp.recvbuf_inc=524288 205 | net.inet.tcp.sack.enable=1 206 | net.inet.tcp.blackhole=1 207 | net.inet.tcp.msl=2000 208 | net.inet.tcp.delayed_ack=1 209 | net.inet.tcp.rfc1323=1 210 | 211 | net.inet.udp.blackhole=1 212 | net.inet.ip.redirect=0 213 | net.inet.ip.forwarding=0 214 | 215 | # set default stacks:freebsd, rack or bbr, may be you need increase the value of parameter 'freebsd.boot.hz' while use rack or bbr. 216 | net.inet.tcp.functions_default=freebsd 217 | # need by bbr, should enable it. 218 | net.inet.tcp.hpts.skip_swi=1 219 | -------------------------------------------------------------------------------- /tests/test-utils/test_mask.cpp: -------------------------------------------------------------------------------- 1 | #include "flashws/crypto/ws_mask.h" 2 | #include "flashws/utils/cpu_timer.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace test { 9 | 10 | void Mask1(uint8_t *__restrict src, size_t size, 11 | uint32_t mask) { 12 | uint8_t mask_arr[4]; 13 | memcpy(mask_arr, &mask, 4); 14 | uint32_t mask32_arr[4]; 15 | for (size_t i = 0; i < 4; ++i) { 16 | mask32_arr[i] = mask_arr[i]; 17 | } 18 | for (size_t i = 0; i < size; ++i) { 19 | src[i] = src[i] ^ mask32_arr[i & 3UL]; 20 | } 21 | } 22 | 23 | void Mask2(uint8_t *__restrict src, size_t size, 24 | uint32_t mask) { 25 | uint8_t mask_arr[4]; 26 | memcpy(mask_arr, &mask, 4); 27 | size_t size_div_4 = size / 4UL; 28 | // size_t size_div_16=size/16UL; 29 | uint32_t * __restrict u32_src = (uint32_t*)src; 30 | for (size_t i = 0; i < size_div_4; ++i) { 31 | // printf("in mask2, load %x\n", u32_src[i]); 32 | u32_src[i] = u32_src[i] ^ mask; 33 | // printf("in mask2, save %x\n", u32_src[i]); 34 | } 35 | // for (size_t i = 0; i < size_div_16; ++i) { 36 | // u32_src[i * 4UL + 0UL] = u32_src[i * 4UL + 0UL] ^ mask; 37 | // u32_src[i * 4UL + 1UL] = u32_src[i * 4UL + 1UL] ^ mask; 38 | // u32_src[i * 4UL + 2UL] = u32_src[i * 4UL + 2UL] ^ mask; 39 | // u32_src[i * 4UL + 3UL] = u32_src[i * 4UL + 3UL] ^ mask; 40 | // } 41 | // for (size_t i = size_div_16 * 4UL; i < size_div_4; ++i) { 42 | // u32_src[i] = u32_src[i] ^ mask; 43 | // } 44 | for (size_t i = size_div_4 * 4UL; i < size; ++i) { 45 | src[i] = src[i] ^ mask_arr[i & 3UL]; 46 | } 47 | // printf("\n"); 48 | } 49 | 50 | 51 | 52 | 53 | 54 | void Mask6(uint8_t * FWS_RESTRICT src, size_t size, 55 | uint32_t mask) { 56 | // using UInt = uint64_t; 57 | using UInt = __uint128_t; 58 | // UInt mask_uint = mask; 59 | // uint64_t mask_uint = ((uint64_t)mask << 32U) | mask; 60 | // UInt mask_uint = (UInt(mask) << 32U) | mask; 61 | UInt mask_uint = (UInt(mask) << 96U) | UInt(mask) << 64U | (UInt(mask) << 32U) | (UInt)mask; 62 | uint8_t mask_arr[4]; 63 | 64 | memcpy(mask_arr, &mask, 4); 65 | size_t size_div = size / sizeof(UInt); 66 | // size_t size_div = size / 8UL; 67 | // uint64_t * FWS_RESTRICT uint_src = (uint64_t* FWS_RESTRICT )src; 68 | UInt * FWS_RESTRICT uint_src = (UInt* FWS_RESTRICT )src; 69 | for (size_t i = 0; i < size_div; ++i) { 70 | uint_src[i] = uint_src[i] ^ mask_uint; 71 | } 72 | for (size_t i = size_div * sizeof(UInt); i < size; ++i) { 73 | src[i] = src[i] ^ mask_arr[i & 3UL]; 74 | } 75 | } 76 | 77 | 78 | 79 | 80 | 81 | FWS_ALWAYS_INLINE void Mask5(uint8_t * FWS_RESTRICT src, size_t size, 82 | uint32_t mask) { 83 | return fws::MaskLargeChunkAVX2(src, size, mask); 84 | } 85 | 86 | FWS_ALWAYS_INLINE void Mask4(uint8_t * FWS_RESTRICT src, size_t size, 87 | uint32_t mask) { 88 | 89 | return fws::MaskAVX2(src, size, mask); 90 | } 91 | 92 | size_t GetHash(const uint8_t *src, size_t len) { 93 | size_t src_hash = std::hash{}(std::string_view((char*)src, len)); 94 | return src_hash; 95 | } 96 | 97 | struct alignas(1) Pack { 98 | // uint64_t data[4]; 99 | char data; 100 | }; 101 | 102 | int test_main(int argc, const char** argv) { 103 | if (argc != 2) { 104 | printf("Invalid arguments!, Usage:\n./test_utils function_index\n"); 105 | return 0; 106 | } 107 | int m_index = atoi(argv[1]); 108 | // CB cb; 109 | // cb.Init(); 110 | cpu_t::CpuTimer cpu_timer{}; 111 | printf("cpu timer overhead ticks: %ld, ticks per ns: %lf\n", 112 | cpu_timer.overhead_ticks(), 1.0 / cpu_timer.ns_per_tick()); 113 | size_t seed = std::random_device{}(); 114 | std::mt19937_64 gen64{seed}; 115 | size_t len = 3024; 116 | size_t repeat = 65536 * 64; 117 | constexpr size_t offset = 1; 118 | using UInt = Pack; 119 | std::vector data((len + offset + sizeof(UInt) - 1UL) / sizeof(UInt)); 120 | for (size_t i = 0; i < len; ++i) { 121 | *((uint8_t*)data.data() + offset + i) = gen64(); 122 | } 123 | std::vector back_up_data(data); 124 | uint32_t mask = gen64(); 125 | printf("mask: %x\n", mask); 126 | uint64_t mask64 = (uint64_t(mask) << 32U) | mask; 127 | printf("mask64: %lx\n", mask64); 128 | uint8_t *src_data = ((uint8_t*)data.data()) + offset; 129 | // uint8_t *src_backup = ((uint8_t*)back_up_data.data()) + offset; 130 | Mask1(src_data, len, mask); 131 | size_t src_hash = GetHash(src_data, len); 132 | Mask1(src_data, len, mask); 133 | printf("src hash: %zu\n", src_hash); 134 | 135 | using MaskFunc = void (*)(uint8_t * FWS_RESTRICT src, size_t size, 136 | uint32_t mask); 137 | MaskFunc all_funcs[] = {Mask1, Mask2, fws::WSMaskBytes, Mask4, Mask5, Mask6, fws::WSMaskBytesFast}; 138 | MaskFunc mask_func; 139 | if (m_index >= 1 && m_index <= 7) { 140 | mask_func = all_funcs[m_index - 1]; 141 | } 142 | else { 143 | printf("m_index out of range!\n"); 144 | return -1; 145 | } 146 | 147 | 148 | std::vector test_lens = {34,45,67,93,131,223,225,266,329,430, 431, 432, 433, 434, 522, 528, 529, 531, 9872, 37840}; 149 | 150 | std::vector test_offsets; 151 | for (size_t i = 0; i <= 512; ++i) { 152 | test_lens.push_back(i); 153 | test_offsets.push_back(i); 154 | } 155 | for (auto test_len: test_lens) { 156 | for (auto test_offset: test_offsets) { 157 | uint8_t *test_src = ((uint8_t*)data.data()) + test_offset; 158 | Mask1(src_data, test_len, mask); 159 | size_t test_target_hash = GetHash(test_src, test_len); 160 | Mask1(src_data, test_len, mask); 161 | 162 | mask_func(src_data, test_len, mask); 163 | size_t test_custom_hash = GetHash(test_src, test_len); 164 | if (test_custom_hash != test_target_hash) { 165 | printf("Error, target hash: %zu, custom hash: %zu, len: %zu, offset: %zu\n", 166 | test_target_hash, test_custom_hash, test_len, test_offset); 167 | return -1; 168 | } 169 | mask_func(src_data, test_len, mask); 170 | for (size_t i = 0; i < data.size(); ++i) { 171 | if (data[i].data != back_up_data[i].data) { 172 | printf("Error, data is changed in %zu byte\n", i); 173 | return -1; 174 | } 175 | } 176 | } 177 | } 178 | 179 | 180 | 181 | 182 | 183 | 184 | // warmup 185 | for (size_t i = 0; i < 128; ++i) { 186 | mask_func(src_data, len, mask); 187 | } 188 | 189 | { 190 | auto t0 = cpu_timer.Start(); 191 | for (size_t i = 0; i < repeat; ++i) { 192 | mask_func(src_data, len, mask); 193 | } 194 | auto t1 = cpu_timer.Stop(); 195 | 196 | mask_func(src_data, len, mask); 197 | size_t temp_hash = GetHash(src_data, len); 198 | mask_func(src_data, len, mask); 199 | auto pass_ticks = t1 - t0; 200 | uint64_t dur0_ns = pass_ticks * cpu_timer.ns_per_tick(); 201 | double dur0_ms = dur0_ns / (1e+6); 202 | if (temp_hash != src_hash) { 203 | printf("Error, hash: %zu not equals to src_hash: %zu\n", 204 | temp_hash, src_hash); 205 | } 206 | double throughput = len * repeat / double(1024LL * 1024LL * 1024LL) / (dur0_ms / (1e+3)); 207 | printf("hash%d: %zu,\t%lf ms\t%lf GB/s\n", 208 | m_index, temp_hash, dur0_ms, throughput); 209 | } 210 | 211 | 212 | 213 | 214 | return 0; 215 | 216 | } 217 | 218 | } // namespace test 219 | 220 | 221 | int main(int argc, const char** argv) { 222 | 223 | return test::test_main(argc, argv); 224 | } -------------------------------------------------------------------------------- /include/flashws/crypto/base64.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "flashws/base/basic_macros.h" 5 | 6 | namespace fws { 7 | 8 | /** 9 | * 10 | * @param src_len 11 | * @return The length of base64 encode string, including a null terminator 12 | */ 13 | FWS_ALWAYS_INLINE constexpr size_t GetBase64EncodeLength(size_t src_len) { 14 | return (src_len + 2U) / 3U * 4U + 1U; 15 | } 16 | 17 | 18 | namespace detail { 19 | 20 | template 21 | static void Fix20Base64Encode(const char* FWS_RESTRICT data, char* FWS_RESTRICT ret) { 22 | static constexpr char sEncodingTable[] = { 23 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 24 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 25 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 26 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 27 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; 28 | 29 | constexpr size_t in_len = N; 30 | static_assert(in_len == 20); 31 | char* FWS_RESTRICT p = const_cast(ret); 32 | 33 | for (size_t i = 0; i < in_len - 2; i += 3) { 34 | *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; 35 | *p++ = sEncodingTable[((data[i] & 0x3) << 4) | 36 | ((int)(data[i + 1] & 0xF0) >> 4)]; 37 | *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | 38 | ((int)(data[i + 2] & 0xC0) >> 6)]; 39 | *p++ = sEncodingTable[data[i + 2] & 0x3F]; 40 | } 41 | constexpr size_t last = in_len - 2; 42 | ret[24] = sEncodingTable[(data[last] >> 2) & 0x3F]; 43 | ret[25] = sEncodingTable[((data[last] & 0x3) << 4) | 44 | ((int)(data[last + 1] & 0xF0) >> 4)]; 45 | ret[26] = sEncodingTable[((data[last + 1] & 0xF) << 2)]; 46 | ret[27] = '='; 47 | } 48 | 49 | template 50 | static void FixBase64Encode(const char* FWS_RESTRICT data, char* FWS_RESTRICT ret) { 51 | static constexpr char sEncodingTable[] = { 52 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 53 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 54 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 55 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 56 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; 57 | 58 | constexpr size_t in_len = N; 59 | size_t i = 0; 60 | char* FWS_RESTRICT p = const_cast(ret); 61 | 62 | for (i = 0; in_len > 2 && i < in_len - 2; i += 3) { 63 | *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; 64 | *p++ = sEncodingTable[((data[i] & 0x3) << 4) | 65 | ((int)(data[i + 1] & 0xF0) >> 4)]; 66 | *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | 67 | ((int)(data[i + 2] & 0xC0) >> 6)]; 68 | *p++ = sEncodingTable[data[i + 2] & 0x3F]; 69 | } 70 | if (i < in_len) { 71 | *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; 72 | if (i == (in_len - 1)) { 73 | *p++ = sEncodingTable[((data[i] & 0x3) << 4)]; 74 | *p++ = '='; 75 | } else { 76 | *p++ = sEncodingTable[((data[i] & 0x3) << 4) | 77 | ((int)(data[i + 1] & 0xF0) >> 4)]; 78 | *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)]; 79 | } 80 | *p++ = '='; 81 | } 82 | 83 | } 84 | 85 | static void DyBase64Encode(const char* FWS_RESTRICT data, size_t in_len, char* FWS_RESTRICT ret) { 86 | static constexpr char sEncodingTable[] = { 87 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 88 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 89 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 90 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 91 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; 92 | 93 | // constexpr size_t in_len = N; 94 | size_t i = 0; 95 | char* FWS_RESTRICT p = const_cast(ret); 96 | size_t in_len_2 = in_len - 2; 97 | for (i = 0; (in_len > 2) & (i < in_len_2); i += 3) { 98 | *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; 99 | *p++ = sEncodingTable[((data[i] & 0x3) << 4) | 100 | ((int)(data[i + 1] & 0xF0) >> 4)]; 101 | *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | 102 | ((int)(data[i + 2] & 0xC0) >> 6)]; 103 | *p++ = sEncodingTable[data[i + 2] & 0x3F]; 104 | } 105 | if (i < in_len) { 106 | *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; 107 | if (i == (in_len - 1)) { 108 | *p++ = sEncodingTable[((data[i] & 0x3) << 4)]; 109 | *p++ = '='; 110 | } else { 111 | *p++ = sEncodingTable[((data[i] & 0x3) << 4) | 112 | ((int)(data[i + 1] & 0xF0) >> 4)]; 113 | *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)]; 114 | } 115 | *p++ = '='; 116 | } 117 | 118 | } 119 | 120 | static inline void uws_base64(unsigned char * FWS_RESTRICT src, char* FWS_RESTRICT dst) { 121 | static constexpr const char * FWS_RESTRICT b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 122 | for (int i = 0; i < 18; i += 3) { 123 | *dst++ = b64[(src[i] >> 2) & 63]; 124 | *dst++ = b64[((src[i] & 3) << 4) | ((src[i + 1] & 240) >> 4)]; 125 | *dst++ = b64[((src[i + 1] & 15) << 2) | ((src[i + 2] & 192) >> 6)]; 126 | *dst++ = b64[src[i + 2] & 63]; 127 | } 128 | *dst++ = b64[(src[18] >> 2) & 63]; 129 | *dst++ = b64[((src[18] & 3) << 4) | ((src[19] & 240) >> 4)]; 130 | *dst++ = b64[((src[19] & 15) << 2)]; 131 | *dst++ = '='; 132 | } 133 | } // namespace detail 134 | 135 | /** 136 | * size for null-terminator is needed in dst 137 | * @param src 138 | * @param src_len 139 | * @param dst length should be Ceil(src_len / 3) * 4 + 1, 140 | * i.e. (src_len + 2) / 3 * 4 + 1, including one null terminator 141 | * @return size of dst, excluding the null terminator 142 | */ 143 | template 144 | inline int Fix20Base64Encode(const void* FWS_RESTRICT src, void* FWS_RESTRICT dst) { 145 | detail::Fix20Base64Encode((const char*)src, (char*)dst); 146 | constexpr size_t dst_len = GetBase64EncodeLength(src_len); 147 | return dst_len; 148 | } 149 | 150 | template 151 | inline int FixBase64Encode(const void* FWS_RESTRICT src, void* FWS_RESTRICT dst) { 152 | detail::FixBase64Encode((const char*)src, (char*)dst); 153 | constexpr size_t dst_len = GetBase64EncodeLength(src_len); 154 | return dst_len; 155 | } 156 | 157 | inline int DynamicBase64Encode(const void* FWS_RESTRICT src, int src_len, void* FWS_RESTRICT dst) { 158 | detail::DyBase64Encode((const char*)src, src_len, (char*)dst); 159 | int dst_len = GetBase64EncodeLength(src_len); 160 | return dst_len; 161 | } 162 | 163 | inline int OSLBase64Encode(const void* FWS_RESTRICT src, int src_len, void* FWS_RESTRICT dst) { 164 | int dst_len = EVP_EncodeBlock((unsigned char* FWS_RESTRICT)(dst), 165 | (const unsigned char* FWS_RESTRICT)src, 166 | src_len); 167 | return dst_len; 168 | } 169 | 170 | 171 | FWS_ALWAYS_INLINE int OSLBase64Decode(const void* FWS_RESTRICT src, int src_len, void* FWS_RESTRICT dst) { 172 | const unsigned char* FWS_RESTRICT input = (const unsigned char*)src; 173 | unsigned char* FWS_RESTRICT output = (unsigned char*) dst; 174 | int dst_len = EVP_DecodeBlock(output, input, src_len); 175 | return dst_len; 176 | } 177 | 178 | } // namespace fws -------------------------------------------------------------------------------- /tests/test-alloc/alloc_speed_compare.cpp: -------------------------------------------------------------------------------- 1 | #include "flashws/utils/flash_alloc.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // Helper class for time measurement 12 | class Timer { 13 | using Clock = std::chrono::high_resolution_clock; 14 | using TimePoint = Clock::time_point; 15 | TimePoint start_; 16 | public: 17 | Timer() : start_(Clock::now()) {} 18 | 19 | double elapsed() const { 20 | auto now = Clock::now(); 21 | return std::chrono::duration(now - start_).count(); 22 | } 23 | }; 24 | 25 | // Test configuration 26 | struct TestConfig { 27 | size_t num_ops; // Total "operations" (alloc or free) to perform 28 | size_t min_size; 29 | size_t max_size; 30 | 31 | bool mixed_ops; // Whether we do interleaved allocations & frees 32 | double alloc_probability; // Probability of "allocate" vs "free" 33 | bool include_final_free; // Whether to include time of final bulk free in the measurement 34 | }; 35 | 36 | // A lightweight pseudo-random generator for reproducible tests 37 | class FastRand { 38 | private: 39 | uint64_t state_; 40 | public: 41 | explicit FastRand(uint64_t seed = 123456789ULL) : state_(seed) {} 42 | 43 | // Returns a 64-bit pseudo-random integer 44 | uint64_t next() { 45 | // Simple LCG parameters 46 | state_ = 2862933555777941757ULL * state_ + 3037000493ULL; 47 | return state_; 48 | } 49 | 50 | // Returns a random size in [min_val, max_val] 51 | size_t next_size_t(size_t min_val, size_t max_val) { 52 | // Grab top bits from next() to produce uniform range 53 | uint64_t r = next(); 54 | return static_cast(r % (max_val - min_val + 1)) + min_val; 55 | } 56 | 57 | // Returns true w/ probability p 58 | bool next_bool(double p) { 59 | // Use top 53 bits to generate a double in [0,1) 60 | constexpr double factor = (1.0 / (1ULL << 53)); 61 | double rnd_d = static_cast(next() >> 11) * factor; 62 | return (rnd_d < p); 63 | } 64 | }; 65 | 66 | // Standard allocator wrapper class 67 | class StdAllocator { 68 | public: 69 | void* allocate(size_t n) { 70 | return std::malloc(n); 71 | } 72 | 73 | void deallocate(void* p) { 74 | std::free(p); 75 | } 76 | }; 77 | 78 | // Flash allocator wrapper class 79 | class FlashAllocWrapper { 80 | fws::MemPool pool_; 81 | public: 82 | void* allocate(size_t n) { 83 | return pool_.allocate(n); 84 | } 85 | 86 | void deallocate(void* p) { 87 | pool_.deallocate(p); 88 | } 89 | }; 90 | 91 | /** 92 | * Runs an "interleaved" allocation test (mixed allocate/free ops). 93 | * Returns a tuple of: 94 | * (total_time_in_ms, global_sum_of_data, final_bytes_live) 95 | */ 96 | template 97 | std::tuple 98 | run_mixed_alloc_test(const TestConfig& config, Allocator& alloc) 99 | { 100 | Timer timer; 101 | 102 | // Fixed seed for reproducibility 103 | FastRand rng(12345ULL); 104 | 105 | // {ptr, size} for active allocations 106 | std::vector> activePtrs; 107 | activePtrs.reserve(config.num_ops); 108 | 109 | uint64_t global_sum = 0; // sum of all data we read on free 110 | uint64_t cur_bytes = 0; // track how many bytes are currently allocated 111 | 112 | for (size_t i = 0; i < config.num_ops; i++) { 113 | bool doAlloc = rng.next_bool(config.alloc_probability); 114 | 115 | // If we have no active allocations, we must allocate 116 | if (activePtrs.empty()) { 117 | doAlloc = true; 118 | } 119 | 120 | if (doAlloc) { 121 | // Allocate 122 | size_t sz = rng.next_size_t(config.min_size, config.max_size); 123 | cur_bytes += sz; 124 | void* ptr = alloc.allocate(sz); 125 | 126 | // Write data (simple) to avoid compiler optimizations 127 | std::memset(ptr, -1, sz); 128 | 129 | // Store in active list 130 | activePtrs.emplace_back(ptr, sz); 131 | } else { 132 | // Free a random one 133 | size_t idx = rng.next_size_t(0, activePtrs.size() - 1); 134 | 135 | void* ptr = activePtrs[idx].first; 136 | size_t sz = activePtrs[idx].second; 137 | cur_bytes -= sz; 138 | 139 | // Sum data before free 140 | uint64_t sumLocal = 0; 141 | const uint64_t* p64 = reinterpret_cast(ptr); 142 | size_t words = sz / sizeof(uint64_t); 143 | for (size_t w = 0; w < words; w++) { 144 | sumLocal += p64[w]; 145 | } 146 | global_sum += sumLocal; 147 | 148 | // Deallocate 149 | alloc.deallocate(ptr); 150 | 151 | // Erase by swapping last element 152 | activePtrs[idx] = activePtrs.back(); 153 | activePtrs.pop_back(); 154 | } 155 | } 156 | 157 | // time before final free 158 | double timeBeforeFinalFree = timer.elapsed(); 159 | uint64_t final_bytes = cur_bytes; 160 | 161 | // optionally free everything left 162 | if (config.include_final_free && !activePtrs.empty()) { 163 | for (auto& kv : activePtrs) { 164 | void* ptr = kv.first; 165 | size_t sz = kv.second; 166 | 167 | // sum data 168 | uint64_t sumLocal = 0; 169 | const uint64_t* p64 = reinterpret_cast(ptr); 170 | size_t words = sz / sizeof(uint64_t); 171 | for (size_t w = 0; w < words; w++) { 172 | sumLocal += p64[w]; 173 | } 174 | global_sum += sumLocal; 175 | 176 | alloc.deallocate(ptr); 177 | } 178 | } 179 | double totalTime = timer.elapsed(); 180 | if (!config.include_final_free) { 181 | totalTime = timeBeforeFinalFree; 182 | } 183 | 184 | return {totalTime, global_sum, final_bytes}; 185 | } 186 | 187 | /** 188 | * Runs a *single* test config in this process. 189 | * Prints the result to stdout. 190 | */ 191 | void run_single_test(const TestConfig& config) 192 | { 193 | // Print test info 194 | std::cout << "Test Configuration:\n"; 195 | std::cout << "- Mixed Ops: " << (config.mixed_ops ? "Yes" : "No") << "\n"; 196 | std::cout << "- num_ops: " << config.num_ops << "\n"; 197 | std::cout << "- Size Range: " << config.min_size << " - " << config.max_size << "\n"; 198 | std::cout << "- Alloc Probability: " << config.alloc_probability << "\n"; 199 | std::cout << "- Include final free in timing: " 200 | << (config.include_final_free ? "Yes" : "No") << "\n\n"; 201 | 202 | 203 | // We will do the test for StdAllocator and FlashAllocWrapper in this process 204 | // so that side effects are isolated from other config tests. 205 | double std_time_ms = 0, flash_time_ms = 0; 206 | // Standard malloc/free 207 | { 208 | StdAllocator std_alloc; 209 | auto [timeMs, sumVal, finalBytes] = run_mixed_alloc_test(config, std_alloc); 210 | std::cout << "[StdAllocator] Time: " << timeMs << " ms, Final Bytes: " 211 | << finalBytes / (1024ULL * 1024UL) << " MB, Sum: " << sumVal << "\n"; 212 | std_time_ms = timeMs; 213 | } 214 | 215 | // Flash Alloc 216 | { 217 | FlashAllocWrapper flash_alloc; 218 | auto [timeMs, sumVal, finalBytes] = run_mixed_alloc_test(config, flash_alloc); 219 | std::cout << "[FlashAlloc ] Time: " << timeMs << " ms, Final Mem : " 220 | << finalBytes / (1024ULL * 1024UL) << " MB, Sum: " << sumVal << "\n"; 221 | flash_time_ms = timeMs; 222 | } 223 | 224 | double speedup = std_time_ms / flash_time_ms; 225 | std::cout << "Speedup: " << std::fixed << std::setprecision(2) << speedup << "x\n"; 226 | 227 | std::cout << "--------------------------------------------\n\n"; 228 | } 229 | 230 | /** 231 | * Main benchmark function that uses fork() to run 232 | * each config in its own child process. 233 | */ 234 | void run_benchmark_forked() 235 | { 236 | // Example configs 237 | std::vector configs = { 238 | {10'000'000, 8, 64, true, 0.7, false}, // test 1 239 | {1'000'000, 256, 1024, true, 0.7, false}, // test 2 240 | {100'000, 4096, 16384, true, 0.7, false}, // test 3 241 | }; 242 | 243 | for (size_t i = 0; i < configs.size(); ++i) { 244 | pid_t pid = fork(); 245 | if (pid < 0) { 246 | std::cerr << "Fork failed for config index " << i << "\n"; 247 | return; 248 | } 249 | 250 | if (pid == 0) { 251 | // Child process: run the single test in isolation 252 | run_single_test(configs[i]); 253 | // Flush output to ensure it appears in the parent logs 254 | std::fflush(stdout); 255 | 256 | // Exit so we don't continue in the parent flow 257 | _exit(0); 258 | } else { 259 | // Parent process: just wait for the child to finish 260 | int status = 0; 261 | waitpid(pid, &status, 0); 262 | 263 | if (WIFEXITED(status)) { 264 | int code = WEXITSTATUS(status); 265 | if (code != 0) { 266 | std::cerr << "Child process for config " << i 267 | << " exited with code " << code << "\n"; 268 | } 269 | } else { 270 | std::cerr << "Child process for config " << i 271 | << " did not exit normally.\n"; 272 | } 273 | } 274 | } 275 | } 276 | 277 | int main() 278 | { 279 | run_benchmark_forked(); 280 | return 0; 281 | } 282 | -------------------------------------------------------------------------------- /include/flashws/utils/block_queue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "flashws/base/basic_macros.h" 9 | #include "flashws/base/constexpr_math.h" 10 | 11 | namespace fws { 12 | 13 | // A block-queue with runtime block size setting, but should be set when 14 | // it is empty. 15 | // Won't deallocate until destroyed. Only support op in the back direction 16 | // Block size should be power of 2 for performance reason 17 | template > 18 | class BlockQueue: protected ItemAllocator { 19 | private: 20 | static constexpr bool IsPowerOfTwo(size_t x) { 21 | return (x & (x - size_t(1UL))) == 0U; 22 | } 23 | 24 | constexpr static size_t DEFAULT_BLOCK_BYTES_SIZE = 1 << 21; // make block 2 MB in default 25 | static constexpr size_t DEFAULT_BLOCK_SIZE = sizeof(ItemType) >= DEFAULT_BLOCK_BYTES_SIZE ? 16 : 26 | RoundDownPow2(DEFAULT_BLOCK_BYTES_SIZE / sizeof(ItemType)); 27 | using ItemAllocTraits = std::allocator_traits; 28 | using ItemPtrAllocator = typename std::allocator_traits::template rebind_alloc; 29 | public: 30 | 31 | 32 | 33 | BlockQueue(): item_size_(0), block_num_(0), 34 | BLOCK_SIZE(DEFAULT_BLOCK_SIZE), 35 | max_block_num_(0), cur_blk_capacity_(0), max_capacity_(0), 36 | block_ptr_vec_{}, back_ptr_(nullptr) 37 | // BLOCK_SIZE(DEFAULT_BLOCK_BYTES_SIZE <= sizeof(ItemType) ? 16 : 38 | // DEFAULT_BLOCK_BYTES_SIZE / sizeof(ItemType)) 39 | 40 | // TODO: Can replace the restriction of power of 2 to use 41 | // magic-multiplier technique 42 | {} 43 | 44 | // block_size need to be power of 2 45 | BlockQueue(size_t block_size): item_size_(0), block_num_(0), BLOCK_SIZE(block_size), 46 | max_block_num_(0), cur_blk_capacity_(0), 47 | max_capacity_(0), block_ptr_vec_{}, 48 | back_ptr_(nullptr) 49 | { 50 | if FWS_UNLIKELY(!IsPowerOfTwo(block_size)) { 51 | throw std::invalid_argument("block_size need to be power of 2!"); 52 | } 53 | } 54 | 55 | BlockQueue(const BlockQueue&) = delete; 56 | BlockQueue& operator=(const BlockQueue&) = delete; 57 | 58 | BlockQueue(BlockQueue&& o) noexcept: 59 | item_size_(std::exchange(o.item_size_, 0)), 60 | block_num_(std::exchange(o.block_num_, 0)), 61 | BLOCK_SIZE(std::exchange(o.BLOCK_SIZE, DEFAULT_BLOCK_SIZE)), 62 | max_block_num_(std::exchange(o.max_block_num_, 0)), 63 | cur_blk_capacity_(std::exchange(o.cur_blk_capacity_, 0)), 64 | max_capacity_(std::exchange(o.max_capacity_, 0)), 65 | block_ptr_vec_(std::exchange(o.block_ptr_vec_, {})), 66 | back_ptr_(std::exchange(o.back_ptr_, nullptr)) 67 | {} 68 | 69 | BlockQueue& operator=(BlockQueue&& o) noexcept { 70 | std::swap(item_size_, o.item_size_); 71 | std::swap(block_num_, o.block_num_); 72 | std::swap(BLOCK_SIZE, o.BLOCK_SIZE); 73 | std::swap(max_block_num_, o.max_block_num_); 74 | std::swap(cur_blk_capacity_, o.cur_blk_capacity_); 75 | std::swap(max_capacity_, o.max_capacity_); 76 | std::swap(block_ptr_vec_, o.block_ptr_vec_); 77 | std::swap(back_ptr_, o.back_ptr_); 78 | return *this; 79 | } 80 | 81 | size_t size() const { 82 | return item_size_; 83 | } 84 | 85 | bool empty() const { 86 | return item_size_ == 0; 87 | } 88 | 89 | size_t capacity() const { 90 | return cur_blk_capacity_; 91 | } 92 | 93 | // TODO: may use branch prediction to accelerate when pos < BLOCK_SIZE 94 | ItemType& operator[] (size_t pos) { 95 | size_t block_index = DivPow2(pos, BLOCK_SIZE); 96 | size_t offset = pos - block_index * BLOCK_SIZE; 97 | return block_ptr_vec_[block_index][offset]; 98 | } 99 | 100 | const ItemType& operator[] (size_t pos) const { 101 | size_t block_index = DivPow2(pos, BLOCK_SIZE); 102 | size_t offset = pos - block_index * BLOCK_SIZE; 103 | return block_ptr_vec_[block_index][offset]; 104 | } 105 | 106 | ItemType* GetPointer(size_t pos) { 107 | size_t block_index = DivPow2(pos, BLOCK_SIZE); 108 | size_t offset = pos - block_index * BLOCK_SIZE; 109 | return &(block_ptr_vec_[block_index][offset]); 110 | } 111 | 112 | ItemType& back() { 113 | return *back_ptr_; 114 | } 115 | 116 | const ItemType& back() const { 117 | return *back_ptr_; 118 | } 119 | 120 | void pop_back() { 121 | std::destroy_at(back_ptr_); 122 | --item_size_; 123 | --back_ptr_; 124 | 125 | if FWS_UNLIKELY(item_size_ + BLOCK_SIZE <= cur_blk_capacity_) { 126 | --block_num_; 127 | if FWS_LIKELY(item_size_ > 0) { 128 | back_ptr_ = block_ptr_vec_[block_num_ - 1] + BLOCK_SIZE - 1; 129 | } 130 | else { 131 | back_ptr_ = nullptr; 132 | } 133 | cur_blk_capacity_ -= BLOCK_SIZE; 134 | } 135 | } 136 | 137 | void push_back(const ItemType &value) { 138 | ItemType *new_ptr = this->add_back(); 139 | ItemAllocTraits::construct(static_cast(*this), new_ptr, value); 140 | } 141 | 142 | void push_back(ItemType &&value) { 143 | ItemType *new_ptr = this->add_back(); 144 | ItemAllocTraits::construct(static_cast(*this), new_ptr, std::forward(value)); 145 | } 146 | 147 | template 148 | constexpr ItemType& emplace_back(Args&&... args) { 149 | ItemType *new_ptr = this->add_back(); 150 | ItemAllocTraits::construct(static_cast(*this), new_ptr, std::forward(args)...); 151 | return *new_ptr; 152 | } 153 | 154 | // add one item back without construct it 155 | ItemType* add_back() { 156 | ++item_size_; 157 | // TODO: may need to check whether increase null pointer is bad behaviour in the deployment compiler 158 | if FWS_UNLIKELY(item_size_ > cur_blk_capacity_) { 159 | cur_blk_capacity_ += BLOCK_SIZE; 160 | // size_t temp_mul2 = BLOCK_SIZE * max_block_num_; 161 | if (item_size_ > max_capacity_) { 162 | max_capacity_ += BLOCK_SIZE; 163 | ItemType *newBlockPtr = static_cast(this)->allocate(BLOCK_SIZE); 164 | block_ptr_vec_.push_back(newBlockPtr); 165 | ++max_block_num_; 166 | } 167 | back_ptr_ = block_ptr_vec_[block_num_++]; 168 | } 169 | else { 170 | ++back_ptr_; 171 | } 172 | return back_ptr_; 173 | } 174 | 175 | void resize(size_t count) { 176 | size_t newBlockNum = RoundUpDivide(count, BLOCK_SIZE); 177 | if (newBlockNum > max_block_num_) { 178 | block_ptr_vec_.resize(newBlockNum); 179 | for (size_t i = max_block_num_; i < newBlockNum; ++i) { 180 | ItemType *newBlockPtr = static_cast(this)->allocate(BLOCK_SIZE); 181 | block_ptr_vec_[i] = newBlockPtr; 182 | } 183 | max_block_num_ = newBlockNum; 184 | max_capacity_ = max_block_num_ * BLOCK_SIZE; 185 | } 186 | if (count > item_size_) { 187 | if constexpr (need_default_construct) { 188 | for (size_t i = item_size_; i < count; ++i) { 189 | ItemAllocTraits::construct(static_cast(*this), 190 | &(*this)[i]); 191 | } 192 | } 193 | } 194 | else if (count < item_size_) { 195 | if constexpr (std::is_class_v) { 196 | for (size_t i = count; i < item_size_; ++i) { 197 | ItemAllocTraits::destroy(static_cast(*this), &(*this)[i]); 198 | } 199 | } 200 | } 201 | item_size_ = count; 202 | block_num_ = newBlockNum; 203 | cur_blk_capacity_ = block_num_ * BLOCK_SIZE; 204 | if (count == 0) { 205 | back_ptr_ = nullptr; 206 | } 207 | else { 208 | back_ptr_ = &((*this)[count - 1]); 209 | } 210 | } 211 | 212 | void reserve(size_t count) { 213 | size_t original_cnt = item_size_; 214 | resize(count); 215 | resize(original_cnt); 216 | } 217 | 218 | ~BlockQueue() { 219 | if constexpr (std::is_class_v) { 220 | for (size_t i = 0; i < item_size_; ++i) { 221 | ItemAllocTraits::destroy(static_cast(*this), &(*this)[i]); 222 | } 223 | } 224 | 225 | for (size_t i = 0; i < max_block_num_; ++i) { 226 | ItemAllocTraits::deallocate(static_cast(*this), block_ptr_vec_[i], BLOCK_SIZE); 227 | } 228 | } 229 | 230 | protected: 231 | size_t item_size_, block_num_; 232 | size_t BLOCK_SIZE; 233 | size_t max_block_num_; // the max block_num_ in history 234 | size_t cur_blk_capacity_, max_capacity_; 235 | std::vector block_ptr_vec_; 236 | ItemType *back_ptr_; 237 | 238 | 239 | constexpr static inline size_t RoundUpDivide(size_t x, size_t y) { 240 | return (x + y - 1) / y; 241 | } 242 | }; 243 | 244 | // static_assert(sizeof(BlockQueue) <= 80); 245 | } 246 | // namespace 247 | 248 | --------------------------------------------------------------------------------