This is an automated email from the ASF dual-hosted git repository.

jdanek pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-dispatch.git


The following commit(s) were added to refs/heads/main by this push:
     new fd3cf61  DISPATCH-1783 Add TCP EchoServer and Socket C++ fixtures in 
unittests and benchmarks (#1296)
fd3cf61 is described below

commit fd3cf618d99eab86a6dd12bcdf962d2026b57ec9
Author: Jiri Daněk <jda...@redhat.com>
AuthorDate: Sat Jul 17 09:10:41 2021 +0200

    DISPATCH-1783 Add TCP EchoServer and Socket C++ fixtures in unittests and 
benchmarks (#1296)
---
 src/adaptors/http2/http2_adaptor.c     |   1 -
 tests/c_benchmarks/CMakeLists.txt      |   8 ++
 tests/c_benchmarks/Socket.cpp          | 158 +++++++++++++++++++++++++++++++++
 tests/c_benchmarks/Socket.hpp          |  56 ++++++++++++
 tests/c_benchmarks/SocketException.cpp |  45 ++++++++++
 tests/c_benchmarks/SocketException.hpp |  40 +++++++++
 tests/c_benchmarks/TCPServerSocket.cpp |  64 +++++++++++++
 tests/c_benchmarks/TCPServerSocket.hpp |  40 +++++++++
 tests/c_benchmarks/TCPSocket.cpp       |  38 ++++++++
 tests/c_benchmarks/TCPSocket.hpp       |  41 +++++++++
 tests/c_benchmarks/bm_parse_tree.cpp   |  95 ++++++++++++++++++++
 tests/c_benchmarks/bm_tcp_adapter.cpp  | 105 ++++++++++++++++++++++
 tests/c_benchmarks/echo_server.cpp     |  22 +++++
 tests/c_benchmarks/echo_server.hpp     | 117 ++++++++++++++++++++++++
 tests/c_benchmarks/socket_utils.cpp    |  52 +++++++++++
 tests/c_benchmarks/socket_utils.hpp    |  40 +++++++++
 tests/c_unittests/helpers.hpp          |  49 ++++++++++
 17 files changed, 970 insertions(+), 1 deletion(-)

diff --git a/src/adaptors/http2/http2_adaptor.c 
b/src/adaptors/http2/http2_adaptor.c
index 775998b..b526a0d 100644
--- a/src/adaptors/http2/http2_adaptor.c
+++ b/src/adaptors/http2/http2_adaptor.c
@@ -1990,7 +1990,6 @@ static uint64_t qdr_http_deliver(void *context, 
qdr_link_t *link, qdr_delivery_t
                free_http2_stream_data(stream_data, false);
        }
        return disp;
-
 }
 
 
diff --git a/tests/c_benchmarks/CMakeLists.txt 
b/tests/c_benchmarks/CMakeLists.txt
index 3f0f52c..b0a1895 100644
--- a/tests/c_benchmarks/CMakeLists.txt
+++ b/tests/c_benchmarks/CMakeLists.txt
@@ -32,6 +32,14 @@ add_executable(c-benchmarks
         ../c_unittests/helpers.cpp
         c_benchmarks_main.cpp
         bm_router_initialization.cpp
+        bm_parse_tree.cpp
+        bm_tcp_adapter.cpp
+        echo_server.cpp echo_server.hpp
+        socket_utils.cpp socket_utils.hpp
+        Socket.cpp Socket.hpp
+        SocketException.cpp SocketException.hpp
+        TCPSocket.cpp TCPSocket.hpp
+        TCPServerSocket.cpp TCPServerSocket.hpp
         $<TARGET_OBJECTS:qpid-dispatch>)
 target_link_libraries(c-benchmarks qpid-dispatch-libraries benchmark pthread)
 
diff --git a/tests/c_benchmarks/Socket.cpp b/tests/c_benchmarks/Socket.cpp
new file mode 100644
index 0000000..0b8637e
--- /dev/null
+++ b/tests/c_benchmarks/Socket.cpp
@@ -0,0 +1,158 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "Socket.hpp"
+
+#include "SocketException.hpp"
+#include "socket_utils.hpp"
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+Socket::Socket(int type, int protocol) noexcept(false)
+{
+    mFileDescriptor = socket(PF_INET, type, protocol);
+    if (mFileDescriptor < 0) {
+        throw SocketException("Socket creation failed (socket())", true);
+    }
+}
+
+Socket::Socket(int fd)
+{
+    this->mFileDescriptor = fd;
+}
+
+Socket::~Socket()
+{
+    if (mFileDescriptor < 0) {
+        return;  // socket was moved out before
+    }
+
+    ::close(mFileDescriptor);
+    mFileDescriptor = -1;
+}
+
+std::string Socket::getLocalAddress() const
+{
+    sockaddr_in addr;
+    unsigned int addr_len = sizeof(addr);
+
+    if (getsockname(mFileDescriptor, reinterpret_cast<sockaddr *>(&addr), 
&addr_len) < 0) {
+        throw SocketException("Fetch of local address failed (getsockname())", 
true);
+    }
+    return inet_ntoa(addr.sin_addr);
+}
+
+unsigned short Socket::getLocalPort()
+{
+    sockaddr_in addr;
+    unsigned int addr_len = sizeof(addr);
+
+    if (getsockname(mFileDescriptor, reinterpret_cast<sockaddr *>(&addr), 
&addr_len) < 0) {
+        throw SocketException("Fetch of local port failed (getsockname())", 
true);
+    }
+    return ntohs(addr.sin_port);
+}
+
+void Socket::setLocalPort(unsigned short localPort)
+{
+    // Bind the socket to its port
+    sockaddr_in localAddr     = {};
+    localAddr.sin_family      = AF_INET;
+    localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+    localAddr.sin_port        = htons(localPort);
+
+    if (bind(mFileDescriptor, reinterpret_cast<const sockaddr *>(&localAddr), 
sizeof(sockaddr_in)) < 0) {
+        throw SocketException("Set of local port failed (bind())", true);
+    }
+}
+
+void Socket::setLocalAddressAndPort(const std::string &localAddress, unsigned 
short localPort)
+{
+    // Get the address of the requested host
+    sockaddr_in localAddr;
+    fillSockAddr(localAddress, localPort, localAddr);
+
+    if (bind(mFileDescriptor, reinterpret_cast<const sockaddr *>(&localAddr), 
sizeof(sockaddr_in)) < 0) {
+        throw SocketException("Set of local address and port failed (bind())", 
true);
+    }
+}
+
+unsigned short Socket::resolveService(const std::string &service, const 
std::string &protocol)
+{
+    struct servent *serv = getservbyname(service.c_str(), protocol.c_str());
+    if (serv == nullptr) {
+        return atoi(service.c_str());
+    } else {
+        return ntohs(serv->s_port);
+    }
+}
+
+void Socket::connect(const std::string &remoteAddress, unsigned short 
remotePort) noexcept(false)
+{
+    sockaddr_in destAddr;
+    fillSockAddr(remoteAddress, remotePort, destAddr);
+
+    if (::connect(mFileDescriptor, reinterpret_cast<const sockaddr 
*>(&destAddr), sizeof(destAddr)) < 0) {
+        throw SocketException("Connect failed (connect())", true);
+    }
+}
+
+void Socket::send(const void *buffer, int bufferLen) noexcept(false)
+{
+    if (::send(mFileDescriptor, buffer, bufferLen, 0) < 0) {
+        throw SocketException("Send failed (send())", true);
+    }
+}
+
+int Socket::recv(void *buffer, int bufferLen) noexcept(false)
+{
+    int rtn = ::recv(mFileDescriptor, buffer, bufferLen, 0);
+    if (rtn < 0) {
+        throw SocketException("Received failed (recv())", true);
+    }
+
+    return rtn;
+}
+
+std::string Socket::getRemoteAddress() noexcept(false)
+{
+    sockaddr_in addr;
+    unsigned int addr_len = sizeof(addr);
+
+    if (getpeername(mFileDescriptor, reinterpret_cast<sockaddr *>(&addr), 
&addr_len) < 0) {
+        throw SocketException("Fetch of remote address failed 
(getpeername())", true);
+    }
+    return inet_ntoa(addr.sin_addr);
+}
+
+unsigned short Socket::getRemotePort() noexcept(false)
+{
+    sockaddr_in addr;
+    unsigned int addr_len = sizeof(addr);
+
+    if (getpeername(mFileDescriptor, reinterpret_cast<sockaddr *>(&addr), 
&addr_len) < 0) {
+        throw SocketException("Fetch of remote port failed (getpeername())", 
true);
+    }
+    return ntohs(addr.sin_port);
+}
diff --git a/tests/c_benchmarks/Socket.hpp b/tests/c_benchmarks/Socket.hpp
new file mode 100644
index 0000000..f89ce04
--- /dev/null
+++ b/tests/c_benchmarks/Socket.hpp
@@ -0,0 +1,56 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef QPID_DISPATCH_SOCKET_HPP
+#define QPID_DISPATCH_SOCKET_HPP
+
+#include <string>
+class Socket
+{
+   public:
+    ~Socket();
+    std::string getLocalAddress() const;
+    unsigned short getLocalPort();
+    void setLocalPort(unsigned short localPort);
+    void setLocalAddressAndPort(const std::string &localAddress, unsigned 
short localPort = 0);
+    static unsigned short resolveService(const std::string &service, const 
std::string &protocol = "tcp");
+    Socket(const Socket &&sock) noexcept : 
mFileDescriptor(sock.mFileDescriptor)
+    {
+    }
+
+   private:
+    Socket(const Socket &sock);
+    void operator=(const Socket &sock);
+
+   protected:
+    int mFileDescriptor;
+    Socket(int type, int protocol) noexcept(false);
+    explicit Socket(int fd);
+
+   public:
+    void connect(const std::string &remoteAddress, unsigned short remotePort) 
noexcept(false);
+    void send(const void *buffer, int bufferLen) noexcept(false);
+    int recv(void *buffer, int bufferLen) noexcept(false);
+    std::string getRemoteAddress() noexcept(false);
+    unsigned short getRemotePort() noexcept(false);
+};
+
+#endif  // QPID_DISPATCH_SOCKET_HPP
diff --git a/tests/c_benchmarks/SocketException.cpp 
b/tests/c_benchmarks/SocketException.cpp
new file mode 100644
index 0000000..db10d78
--- /dev/null
+++ b/tests/c_benchmarks/SocketException.cpp
@@ -0,0 +1,45 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "SocketException.hpp"
+
+#include <cerrno>
+#include <cstring>
+#include <string>
+
+SocketException::SocketException(std::string message, bool captureErrno) 
noexcept : mMessage(std::move(message))
+{
+    if (captureErrno) {
+        message.append(": ");
+        message.append(strerror(errno));
+    }
+}
+
+SocketException::SocketException(const SocketException &e) noexcept : 
mMessage(e.mMessage)
+{
+}
+
+SocketException::~SocketException() noexcept = default;
+
+const char *SocketException::what() const noexcept
+{
+    return mMessage.c_str();
+}
\ No newline at end of file
diff --git a/tests/c_benchmarks/SocketException.hpp 
b/tests/c_benchmarks/SocketException.hpp
new file mode 100644
index 0000000..7132813
--- /dev/null
+++ b/tests/c_benchmarks/SocketException.hpp
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef QPID_DISPATCH_SOCKETEXCEPTION_HPP
+#define QPID_DISPATCH_SOCKETEXCEPTION_HPP
+
+#include <string>
+class SocketException : public std::exception
+{
+   private:
+    std::string mMessage;
+
+   public:
+    explicit SocketException(std::string message, bool captureErrno = false) 
noexcept;
+
+    SocketException(const SocketException &e) noexcept;
+
+    ~SocketException() noexcept override;
+    const char *what() const noexcept override;
+};
+
+#endif  // QPID_DISPATCH_SOCKETEXCEPTION_HPP
diff --git a/tests/c_benchmarks/TCPServerSocket.cpp 
b/tests/c_benchmarks/TCPServerSocket.cpp
new file mode 100644
index 0000000..3c98840
--- /dev/null
+++ b/tests/c_benchmarks/TCPServerSocket.cpp
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "TCPServerSocket.hpp"
+
+#include "SocketException.hpp"
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <string>
+
+TCPServerSocket::TCPServerSocket(unsigned short localPort, int queueLen) : 
Socket(SOCK_STREAM, IPPROTO_TCP)
+{
+    setLocalPort(localPort);
+    setListen(queueLen);
+}
+
+TCPServerSocket::TCPServerSocket(const std::string &localAddress, unsigned 
short localPort, int queueLen)
+    : Socket(SOCK_STREAM, IPPROTO_TCP)
+{
+    setLocalAddressAndPort(localAddress, localPort);
+    setListen(queueLen);
+}
+
+TCPSocket *TCPServerSocket::accept()
+{
+    int newConnSD = ::accept(mFileDescriptor, nullptr, nullptr);
+    if (newConnSD < 0) {
+        throw SocketException("Accept failed (accept())", true);
+    }
+
+    return new TCPSocket(newConnSD);
+}
+
+void TCPServerSocket::shutdown()
+{
+    ::shutdown(this->mFileDescriptor, ::SHUT_RD);
+}
+
+void TCPServerSocket::setListen(int queueLen)
+{
+    if (listen(mFileDescriptor, queueLen) < 0) {
+        throw SocketException("Set listening socket failed (listen())", true);
+    }
+}
\ No newline at end of file
diff --git a/tests/c_benchmarks/TCPServerSocket.hpp 
b/tests/c_benchmarks/TCPServerSocket.hpp
new file mode 100644
index 0000000..eb2e465
--- /dev/null
+++ b/tests/c_benchmarks/TCPServerSocket.hpp
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef QPID_DISPATCH_TCPSERVERSOCKET_HPP
+#define QPID_DISPATCH_TCPSERVERSOCKET_HPP
+
+#include "Socket.hpp"
+#include "TCPSocket.hpp"
+
+class TCPServerSocket : public Socket
+{
+   private:
+    void setListen(int queueLen);
+
+   public:
+    TCPServerSocket(unsigned short localPort, int queueLen = 10);
+    TCPServerSocket(const std::string &localAddress, unsigned short localPort, 
int queueLen = 10);
+    TCPSocket *accept();
+    void shutdown();
+};
+
+#endif  // QPID_DISPATCH_TCPSERVERSOCKET_HPP
diff --git a/tests/c_benchmarks/TCPSocket.cpp b/tests/c_benchmarks/TCPSocket.cpp
new file mode 100644
index 0000000..51ac9c6
--- /dev/null
+++ b/tests/c_benchmarks/TCPSocket.cpp
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "TCPSocket.hpp"
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+TCPSocket::TCPSocket() : Socket(SOCK_STREAM, IPPROTO_TCP)
+{
+}
+
+TCPSocket::TCPSocket(const std::string &remoteAddress, unsigned short 
remotePort) : Socket(SOCK_STREAM, IPPROTO_TCP)
+{
+    connect(remoteAddress, remotePort);
+}
+
+TCPSocket::TCPSocket(int newConnSD) : Socket(newConnSD)
+{
+}
diff --git a/tests/c_benchmarks/TCPSocket.hpp b/tests/c_benchmarks/TCPSocket.hpp
new file mode 100644
index 0000000..bffc7ce
--- /dev/null
+++ b/tests/c_benchmarks/TCPSocket.hpp
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef QPID_DISPATCH_TCPSOCKET_HPP
+#define QPID_DISPATCH_TCPSOCKET_HPP
+
+#include "Socket.hpp"
+class TCPSocket : public Socket
+{
+   private:
+    friend class TCPServerSocket;
+    explicit TCPSocket(int newConnSD);
+
+   public:
+    TCPSocket();
+    TCPSocket(const std::string& remoteAddress, unsigned short remotePort);
+    TCPSocket(TCPSocket&& socket) noexcept : TCPSocket(socket.mFileDescriptor)
+    {
+        socket.mFileDescriptor = -1;
+    };
+};
+
+#endif  // QPID_DISPATCH_TCPSOCKET_HPP
diff --git a/tests/c_benchmarks/bm_parse_tree.cpp 
b/tests/c_benchmarks/bm_parse_tree.cpp
new file mode 100644
index 0000000..3b7c9e1
--- /dev/null
+++ b/tests/c_benchmarks/bm_parse_tree.cpp
@@ -0,0 +1,95 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../c_unittests/helpers.hpp"
+
+#include <benchmark/benchmark.h>
+
+#include <thread>
+
+extern "C" {
+#include "parse_tree.h"
+}  // extern "C"
+
+static void BM_AddRemoveSinglePattern(benchmark::State &state)
+{
+    std::thread([&state] {
+        QDRMinimalEnv env{};
+
+        qd_iterator_t *piter  = qd_iterator_string("I.am.Sam", ITER_VIEW_ALL);
+        qd_parse_tree_t *node = qd_parse_tree_new(QD_PARSE_TREE_ADDRESS);
+        void *payload;
+
+        for (auto _ : state) {
+            qd_parse_tree_add_pattern(node, piter, &payload);
+            qd_parse_tree_remove_pattern(node, piter);
+        }
+
+        qd_parse_tree_free(node);
+        qd_iterator_free(piter);
+    }).join();
+}
+
+BENCHMARK(BM_AddRemoveSinglePattern)->Unit(benchmark::kMicrosecond);
+
+static void BM_AddRemoveMultiplePatterns(benchmark::State &state)
+{
+    std::thread([&state] {
+        QDRMinimalEnv env{};
+
+        int batchSize = state.range(0);
+        std::vector<std::string> data(batchSize);
+        std::vector<qd_iterator_t *> piter(batchSize);
+        for (int i = 0; i < batchSize; ++i) {
+            data[i]  = "I.am.Sam_" + std::to_string(i);
+            piter[i] = qd_iterator_string(data[i].c_str(), ITER_VIEW_ALL);
+        }
+        qd_parse_tree_t *node = qd_parse_tree_new(QD_PARSE_TREE_ADDRESS);
+        const void *payload;
+
+        for (auto _ : state) {
+            for (int i = 0; i < batchSize; ++i) {
+                qd_parse_tree_add_pattern(node, piter[i], &payload);
+            }
+            for (int i = 0; i < batchSize; ++i) {
+                qd_parse_tree_remove_pattern(node, piter[i]);
+            }
+        }
+
+        qd_parse_tree_free(node);
+        for (int i = 0; i < batchSize; ++i) {
+            qd_iterator_free(piter[i]);
+        }
+
+        state.SetComplexityN(batchSize);
+    }).join();
+}
+
+BENCHMARK(BM_AddRemoveMultiplePatterns)
+    ->Unit(benchmark::kMicrosecond)
+    ->Arg(1)
+    ->Arg(3)
+    ->Arg(10)
+    ->Arg(30)
+    ->Arg(100)
+    ->Arg(1000)
+    ->Arg(100000)
+    ->Complexity();
diff --git a/tests/c_benchmarks/bm_tcp_adapter.cpp 
b/tests/c_benchmarks/bm_tcp_adapter.cpp
new file mode 100644
index 0000000..06a4aae
--- /dev/null
+++ b/tests/c_benchmarks/bm_tcp_adapter.cpp
@@ -0,0 +1,105 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "../c_unittests/helpers.hpp"
+#include "SocketException.hpp"
+#include "TCPSocket.hpp"
+#include "echo_server.hpp"
+
+#include <benchmark/benchmark.h>
+
+#include <iostream>
+
+extern "C" {
+#include "entity_cache.h"
+#include "log_private.h"
+#include "parse_tree.h"
+
+#include "qpid/dispatch.h"
+
+// declarations that don't have .h file
+void qd_error_initialize();
+}  // extern "C"
+
+static TCPSocket try_to_connect(const std::string &servAddress, int 
echoServPort)
+{
+    auto then = std::chrono::steady_clock::now();
+    while (std::chrono::steady_clock::now() - then < std::chrono::seconds(3)) {
+        try {
+            TCPSocket sock(servAddress, echoServPort);
+            return sock;
+        } catch (SocketException &e) {
+        }
+    }
+    throw std::runtime_error("Failed to connect in time");
+}
+
+class LatencyMeasure
+{
+    static const int RCVBUFSIZE = 32;
+    char echoBuffer[RCVBUFSIZE + 1];  // '\0'
+
+    std::string servAddress = "127.0.0.1";
+    std::string echoString  = "echoString";
+    int echoStringLen       = echoString.length();
+
+   public:
+    inline void latencyMeasureLoop(benchmark::State &state, unsigned short 
echoServerPort)
+    {
+        {
+            TCPSocket sock = try_to_connect(servAddress, echoServerPort);
+            latencyMeasureSendReceive(state, sock);  // run once outside 
benchmark to clean the pipes first
+
+            for (auto _ : state) {
+                latencyMeasureSendReceive(state, sock);
+            }
+        }
+    }
+
+    inline void latencyMeasureSendReceive(benchmark::State &state, TCPSocket 
&sock)
+    {
+        sock.send(echoString.c_str(), echoStringLen);
+
+        int totalBytesReceived = 0;
+        while (totalBytesReceived < echoStringLen) {
+            int bytesReceived = sock.recv(echoBuffer, RCVBUFSIZE);
+            if (bytesReceived <= 0) {
+                state.SkipWithError("unable to read from socket");
+            }
+            totalBytesReceived += bytesReceived;
+            echoBuffer[bytesReceived] = '\0';
+        }
+    }
+};
+
+/// Measures latency between a TCP send and a receive.
+/// There is only one request in flight at all times, so this is the
+///  lowest conceivable latency at the most ideal condition
+/// In addition, all sends are of the same (tiny) size
+static void BM_TCPEchoServerLatencyWithoutQDR(benchmark::State &state)
+{
+    EchoServerThread est;
+
+    LatencyMeasure lm;
+    lm.latencyMeasureLoop(state, est.port());
+}
+
+BENCHMARK(BM_TCPEchoServerLatencyWithoutQDR)->Unit(benchmark::kMillisecond);
diff --git a/tests/c_benchmarks/echo_server.cpp 
b/tests/c_benchmarks/echo_server.cpp
new file mode 100644
index 0000000..32c5268
--- /dev/null
+++ b/tests/c_benchmarks/echo_server.cpp
@@ -0,0 +1,22 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "echo_server.hpp"
diff --git a/tests/c_benchmarks/echo_server.hpp 
b/tests/c_benchmarks/echo_server.hpp
new file mode 100644
index 0000000..3b9c3a6
--- /dev/null
+++ b/tests/c_benchmarks/echo_server.hpp
@@ -0,0 +1,117 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef QPID_DISPATCH_ECHO_SERVER_HPP
+#define QPID_DISPATCH_ECHO_SERVER_HPP
+
+#include "../c_unittests/helpers.hpp"
+#include "SocketException.hpp"
+#include "TCPServerSocket.hpp"
+
+#include <iostream>
+#include <thread>
+int run_echo_server();
+
+void stop_echo_server();
+
+const unsigned int recv_buffer_size = 32;
+
+class EchoServer
+{
+    unsigned short mPort;
+    TCPServerSocket servSock;
+
+   public:
+    // if mPort is 0, random free port will be allocated and assigned
+    EchoServer(unsigned short port = 0) : mPort(port), servSock(mPort)
+    {
+        if (mPort == 0) {
+            mPort = servSock.getLocalPort();
+        }
+    }
+
+    // will handle one TCP client and then it will return
+    void run()
+    {
+        try {
+            HandleTCPClient(servSock.accept());
+        } catch (SocketException &e) {
+            std::cerr << e.what() << std::endl;
+        }
+    }
+
+    void stop()
+    {
+        servSock.shutdown();
+    }
+
+    unsigned short port()
+    {
+        return mPort;
+    }
+
+   private:
+    void HandleTCPClient(TCPSocket *sock)
+    {
+        char echoBuffer[recv_buffer_size];
+        int recvMsgSize;
+        while ((recvMsgSize = sock->recv(echoBuffer, recv_buffer_size)) > 0) {
+            sock->send(echoBuffer, recvMsgSize);
+        }
+        delete sock;
+    }
+};
+
+class EchoServerThread
+{
+    Latch portLatch;
+    Latch echoServerLatch;
+    unsigned short echoServerPort;
+    std::thread u;
+
+   public:
+    EchoServerThread()
+    {
+        u = std::thread([this]() {
+            EchoServer es(0);
+            echoServerPort = es.port();
+            portLatch.notify();
+            es.run();
+            echoServerLatch.wait();
+            es.stop();
+        });
+
+        portLatch.wait();
+    }
+
+    ~EchoServerThread()
+    {
+        echoServerLatch.notify();
+        u.join();
+    }
+
+    unsigned short port()
+    {
+        return echoServerPort;
+    }
+};
+
+#endif  // QPID_DISPATCH_ECHO_SERVER_HPP
diff --git a/tests/c_benchmarks/socket_utils.cpp 
b/tests/c_benchmarks/socket_utils.cpp
new file mode 100644
index 0000000..0f37ae9
--- /dev/null
+++ b/tests/c_benchmarks/socket_utils.cpp
@@ -0,0 +1,52 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "socket_utils.hpp"
+
+#include "SocketException.hpp"
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <stdexcept>
+
+void fillSockAddr(const std::string &address, unsigned short port, sockaddr_in 
&addr)
+{
+    zero(addr);
+
+    hostent *host = gethostbyname(address.c_str());
+    if (host == nullptr) {
+        throw SocketException("Failed to resolve name (gethostbyname())");
+    }
+
+    addr.sin_port   = htons(port);
+    addr.sin_family = host->h_addrtype;
+    if (host->h_addrtype == AF_INET) {
+        auto sin_addr        = reinterpret_cast<struct in_addr 
*>(host->h_addr_list[0]);
+        addr.sin_addr.s_addr = sin_addr->s_addr;
+    } else if (host->h_addrtype == AF_INET6) {
+        throw std::invalid_argument("IPv6 addresses are not yet supported by 
the test");
+        // auto sin_addr = reinterpret_cast<struct in6_addr 
*>(host->h_addr_list[0]);
+    } else {
+        throw SocketException("Name was not resolved to IPv4 
(gethostbyname())");
+    }
+}
diff --git a/tests/c_benchmarks/socket_utils.hpp 
b/tests/c_benchmarks/socket_utils.hpp
new file mode 100644
index 0000000..666de99
--- /dev/null
+++ b/tests/c_benchmarks/socket_utils.hpp
@@ -0,0 +1,40 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#ifndef QPID_DISPATCH_SOCKET_UTILS_HPP
+#define QPID_DISPATCH_SOCKET_UTILS_HPP
+
+#include <netinet/in.h>
+
+#include <cstring>
+#include <string>
+
+// Saw warning to not use `= {}` to initialize socket structs; it supposedly 
does not work right
+//  due to casting and c-style polymorphism there. It's working just fine for 
me, though.
+template <class T>
+inline void zero(T &value)
+{
+    memset(&value, 0, sizeof(value));
+}
+
+void fillSockAddr(const std::string &address, unsigned short port, sockaddr_in 
&addr);
+
+#endif  // QPID_DISPATCH_SOCKET_UTILS_HPP
diff --git a/tests/c_unittests/helpers.hpp b/tests/c_unittests/helpers.hpp
index 3c084d9..6517b79 100644
--- a/tests/c_unittests/helpers.hpp
+++ b/tests/c_unittests/helpers.hpp
@@ -58,6 +58,17 @@ extern "C" {
 void qd_router_setup_late(qd_dispatch_t *qd);
 }
 
+// low-level router initialization
+extern "C" {
+#include "entity_cache.h"
+#include "log_private.h"
+
+#include "qpid/dispatch.h"
+
+// declarations that don't have .h file
+void qd_error_initialize();
+}
+
 // backport of C++14 feature
 template <class T>
 using remove_const_t = typename std::remove_const<T>::type;
@@ -232,4 +243,42 @@ class QDR
     };
 };
 
+/// Synchronizes two threads. One waits at the latch, the other releases the 
latch.
+class Latch
+{
+    std::mutex mut;
+    std::condition_variable cv;
+    bool opened = false;
+
+   public:
+    void notify()
+    {
+        std::lock_guard<std::mutex> lock(mut);
+        opened = true;
+        cv.notify_all();
+    }
+    void wait()
+    {
+        std::unique_lock<std::mutex> lock(mut);
+        cv.wait(lock, [this] { return opened; });
+    }
+};
+
+class QDRMinimalEnv
+{
+   public:
+    QDRMinimalEnv()
+    {
+        qd_alloc_initialize();
+        qd_log_initialize();
+        qd_error_initialize();
+    }
+
+    ~QDRMinimalEnv()
+    {
+        qd_log_finalize();
+        qd_alloc_finalize();
+    }
+};
+
 #endif  // QPID_DISPATCH_HELPERS_HPP

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org
For additional commands, e-mail: commits-h...@qpid.apache.org

Reply via email to