From 84f39331096e663ad04192163ad435e4c4ee7133 Mon Sep 17 00:00:00 2001 From: Mathias Kraus Date: Mon, 1 Jul 2024 03:01:05 +0200 Subject: [PATCH] iox-#2301 PoC for 32-64 bit mixed mode --- .../mixed_mode_poc/CMakeLists.txt | 37 ++++++++ .../mixed_mode_poc/mixed_mode_poc_common.hpp | 84 +++++++++++++++++ .../mixed_mode_poc_follower.cpp | 85 ++++++++++++++++++ .../mixed_mode_poc/mixed_mode_poc_leader.cpp | 90 +++++++++++++++++++ .../build-mixed-mode-poc-32-bit-and-64-bit.sh | 81 +++++++++++++++++ 5 files changed, 377 insertions(+) create mode 100644 iceoryx_examples/mixed_mode_poc/CMakeLists.txt create mode 100644 iceoryx_examples/mixed_mode_poc/mixed_mode_poc_common.hpp create mode 100644 iceoryx_examples/mixed_mode_poc/mixed_mode_poc_follower.cpp create mode 100644 iceoryx_examples/mixed_mode_poc/mixed_mode_poc_leader.cpp create mode 100755 tools/build-mixed-mode-poc-32-bit-and-64-bit.sh diff --git a/iceoryx_examples/mixed_mode_poc/CMakeLists.txt b/iceoryx_examples/mixed_mode_poc/CMakeLists.txt new file mode 100644 index 0000000000..4ff5349037 --- /dev/null +++ b/iceoryx_examples/mixed_mode_poc/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright (c) 2024 by ekxide IO GmbH. All rights reserved. +# +# Licensed 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. +# +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.16) +project(example_mixed_mode_poc) + +find_package(iceoryx_platform REQUIRED) +find_package(iceoryx_hoofs CONFIG REQUIRED) + +include(IceoryxPackageHelper) +include(IceoryxPlatform) +include(IceoryxPlatformSettings) + +iox_add_executable( + TARGET mixde-mode-poc-leader + FILES mixed_mode_poc_leader.cpp + LIBS iceoryx_hoofs::iceoryx_hoofs +) + +iox_add_executable( + TARGET mixed-mode-poc-follower + FILES mixed_mode_poc_follower.cpp + LIBS iceoryx_hoofs::iceoryx_hoofs +) diff --git a/iceoryx_examples/mixed_mode_poc/mixed_mode_poc_common.hpp b/iceoryx_examples/mixed_mode_poc/mixed_mode_poc_common.hpp new file mode 100644 index 0000000000..dbe4c03e5c --- /dev/null +++ b/iceoryx_examples/mixed_mode_poc/mixed_mode_poc_common.hpp @@ -0,0 +1,84 @@ +// Copyright (c) 2024 by ekxide IO GmbH. All rights reserved. +// +// Licensed 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. +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef IOX_MIXED_MODE_POC_COMMON_HPP +#define IOX_MIXED_MODE_POC_COMMON_HPP + +#include "iox/logging.hpp" +#include "iox/mutex.hpp" +#include "iox/posix_shared_memory_object.hpp" +#include "iox/unnamed_semaphore.hpp" + +#include +#include +#include + +constexpr uint64_t ITERATIONS{50000000}; + +class PoorMansSpinSemaphore +{ + public: + void post() + { + counter++; + } + + void wait() + { + while (counter == 0) + { + std::this_thread::yield(); + } + counter--; + } + + private: + std::atomic counter{0}; +}; + +struct SharedData +{ + uint8_t dummy1{0}; + alignas(8) volatile uint64_t non_atomic_counter{0}; + uint8_t dummy2{0}; + alignas(8) std::atomic atomic_counter{0}; + uint8_t dummy3{0}; + PoorMansSpinSemaphore leader_barrier; + PoorMansSpinSemaphore follower_barrier; +}; + +auto print_sizes() +{ + IOX_LOG(INFO, "Size of shared data: " << sizeof(SharedData)); + IOX_LOG(INFO, "Size of iox::UnnamedSemaphore: " << sizeof(iox::UnnamedSemaphore)); + IOX_LOG(INFO, "Size of POSIX sem_t: " << sizeof(sem_t)); + IOX_LOG(INFO, "Size of iox::mutex: " << sizeof(iox::mutex)); + IOX_LOG(INFO, "Size of POSIX pthread_mutex_t: " << sizeof(pthread_mutex_t)); +} + +auto open_or_create_shm() +{ + constexpr uint64_t MEMORY_SIZE{4096}; + return iox::PosixSharedMemoryObjectBuilder() + .name("iox-mixed-mode-poc") + .memorySizeInBytes(MEMORY_SIZE) + .openMode(iox::OpenMode::OPEN_OR_CREATE) + .accessMode(iox::AccessMode::READ_WRITE) + .permissions(iox::perms::owner_all) + .create(); +} + +#endif // IOX_MIXED_MODE_POC_COMMON_HPP diff --git a/iceoryx_examples/mixed_mode_poc/mixed_mode_poc_follower.cpp b/iceoryx_examples/mixed_mode_poc/mixed_mode_poc_follower.cpp new file mode 100644 index 0000000000..a5cee02b6b --- /dev/null +++ b/iceoryx_examples/mixed_mode_poc/mixed_mode_poc_follower.cpp @@ -0,0 +1,85 @@ +// Copyright (c) 2024 by ekxide IO GmbH. All rights reserved. +// +// Licensed 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. +// +// SPDX-License-Identifier: Apache-2.0 + +#include "mixed_mode_poc_common.hpp" + +int main() +{ + print_sizes(); + + IOX_LOG(INFO, ""); + + auto shm_result = open_or_create_shm(); + if (shm_result.has_error()) + { + IOX_LOG(ERROR, "Could not create shared memory"); + return -1; + } + auto& shm = shm_result.value(); + + auto* shared_data = static_cast(shm.getBaseAddress()); + + auto& leader_barrier = shared_data->leader_barrier; + auto& follower_barrier = shared_data->follower_barrier; + + auto& non_atomic_counter = shared_data->non_atomic_counter; + auto& atomic_counter = shared_data->atomic_counter; + + leader_barrier.post(); + follower_barrier.wait(); + + IOX_LOG(INFO, "Racing on the non atomic counter!"); + + for (uint64_t i = 0; i < ITERATIONS; ++i) + { + non_atomic_counter++; + } + + leader_barrier.post(); + follower_barrier.wait(); + + IOX_LOG(INFO, "Non atomic counter value: " << non_atomic_counter); + IOX_LOG(INFO, "Expected any value below: " << 2 * ITERATIONS); + IOX_LOG(INFO, ""); + IOX_LOG(INFO, "Racing on the atomic counter!"); + + for (uint64_t i = 0; i < ITERATIONS; ++i) + { + // this is intentional more complex than necessary in order to test the CAS loop + auto old_counter_value = atomic_counter.load(std::memory_order_relaxed); + while (!atomic_counter.compare_exchange_weak( + old_counter_value, old_counter_value + 1, std::memory_order_acq_rel, std::memory_order_relaxed)) + { + } + } + + leader_barrier.post(); + follower_barrier.wait(); + + IOX_LOG(INFO, "Atomic counter value: " << atomic_counter); + IOX_LOG(INFO, "Expected counter value: " << 2 * ITERATIONS); + + if (atomic_counter == 2 * ITERATIONS) + { + IOX_LOG(INFO, "Success! Atomics work!"); + } + else + { + IOX_LOG(ERROR, "Failed! Atomics do not work!"); + } + + return 0; +} diff --git a/iceoryx_examples/mixed_mode_poc/mixed_mode_poc_leader.cpp b/iceoryx_examples/mixed_mode_poc/mixed_mode_poc_leader.cpp new file mode 100644 index 0000000000..3725b445d4 --- /dev/null +++ b/iceoryx_examples/mixed_mode_poc/mixed_mode_poc_leader.cpp @@ -0,0 +1,90 @@ +// Copyright (c) 2024 by ekxide IO GmbH. All rights reserved. +// +// Licensed 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. +// +// SPDX-License-Identifier: Apache-2.0 + +#include "iox/logging.hpp" +#include "mixed_mode_poc_common.hpp" +#include + +int main() +{ + print_sizes(); + + IOX_LOG(INFO, ""); + + auto shm_result = open_or_create_shm(); + if (shm_result.has_error()) + { + IOX_LOG(ERROR, "Could not create shared memory"); + return -1; + } + auto& shm = shm_result.value(); + + auto* shared_data = new (shm.getBaseAddress()) SharedData(); + + auto& leader_barrier = shared_data->leader_barrier; + auto& follower_barrier = shared_data->follower_barrier; + + auto& non_atomic_counter = shared_data->non_atomic_counter; + auto& atomic_counter = shared_data->atomic_counter; + + IOX_LOG(INFO, "Initialization done! Please run mixed-mode-poc-follower!"); + IOX_LOG(INFO, ""); + + leader_barrier.wait(); + follower_barrier.post(); + + IOX_LOG(INFO, "Racing on the non atomic counter!"); + + for (uint64_t i = 0; i < ITERATIONS; ++i) + { + non_atomic_counter++; + } + + leader_barrier.wait(); + follower_barrier.post(); + + IOX_LOG(INFO, "Non atomic counter value: " << non_atomic_counter); + IOX_LOG(INFO, "Expected any value below: " << 2 * ITERATIONS); + IOX_LOG(INFO, ""); + IOX_LOG(INFO, "Racing on the atomic counter!"); + + for (uint64_t i = 0; i < ITERATIONS; ++i) + { + // this is intentional more complex than necessary in order to test the CAS loop + auto old_counter_value = atomic_counter.load(std::memory_order_relaxed); + while (!atomic_counter.compare_exchange_weak( + old_counter_value, old_counter_value + 1, std::memory_order_acq_rel, std::memory_order_relaxed)) + { + } + } + + leader_barrier.wait(); + follower_barrier.post(); + + IOX_LOG(INFO, "Atomic counter value: " << atomic_counter); + IOX_LOG(INFO, "Expected value: " << 2 * ITERATIONS); + + if (atomic_counter == 2 * ITERATIONS) + { + IOX_LOG(INFO, "Success!"); + } + else + { + IOX_LOG(ERROR, "Failed!"); + } + + return 0; +} diff --git a/tools/build-mixed-mode-poc-32-bit-and-64-bit.sh b/tools/build-mixed-mode-poc-32-bit-and-64-bit.sh new file mode 100755 index 0000000000..19d5b0bb86 --- /dev/null +++ b/tools/build-mixed-mode-poc-32-bit-and-64-bit.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +# Copyright (c) 2024 by ekxide IO GmbH. All rights reserved. +# +# Licensed 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. +# +# SPDX-License-Identifier: Apache-2.0 + +set -e + +COLOR_RESET='\033[0m' +COLOR_GREEN='\033[1;32m' +COLOR_YELLOW='\033[1;33m' + +WORKSPACE=$(git rev-parse --show-toplevel) +BUILD_DIR=$WORKSPACE/build +NUM_JOBS=$(nproc) +CLEAN_BUILD=false + +while (( "$#" )); do + case "$1" in + -j|--jobs) + NUM_JOBS="$2" + shift 2 + ;; + "clean") + CLEAN_BUILD=true + shift 1 + ;; + "help") + echo "Build script for the 32-64 bit mixed mode PoC." + echo "" + echo "Options:" + echo " -j --jobs Specify the number of build jobs" + echo "Args:" + echo " clean Delete the build/ directory before build-step" + echo " help Print this help" + echo "" + exit 0 + ;; + *) + echo "Invalid argument '$1'. Try 'help' for options." + exit 1 + ;; + esac +done + +cd ${WORKSPACE} + +if [ "$CLEAN_BUILD" == true ] && [ -d "${WORKSPACE}/build" ]; then + echo "${COLOR_GREEN}# Cleaning build directory${COLOR_RESET}" + rm -rf "${WORKSPACE}/build/*" +fi + +echo -e "${COLOR_GREEN}# Building 64 bit iceoryx${COLOR_RESET}" +cmake -S iceoryx_meta -B build/64/iceoryx -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=build/install/64 +cmake --build build/64/iceoryx --target install -- -j$NUM_JOBS + +echo -e "${COLOR_GREEN}# Building 32 bit iceoryx${COLOR_RESET}" +cmake -S iceoryx_meta -B build/32/iceoryx -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=build/install/32 -DCMAKE_C_FLAGS="-m32" -DCMAKE_CXX_FLAGS="-m32" +cmake --build build/32/iceoryx --target install -- -j$NUM_JOBS + +echo -e "${COLOR_GREEN}# Building 64 bit mixed-mode-poc${COLOR_RESET}" +cmake -S iceoryx_examples/mixed_mode_poc -B build/64/example -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=${WORKSPACE}/build/install/64 +cmake --build build/64/example + +echo -e "${COLOR_GREEN}# Building 32 bit mixed-mode-poc${COLOR_RESET}" +cmake -S iceoryx_examples/mixed_mode_poc -B build/32/example -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=${WORKSPACE}/build/install/32 -DCMAKE_C_FLAGS="-m32" -DCMAKE_CXX_FLAGS="-m32" +cmake --build build/32/example + +echo -e "${COLOR_GREEN}# Build finished! The binaries can be found in 'build/64/example' and 'build/32/example'!${COLOR_RESET}"