Skip to content

Commit

Permalink
iox-eclipse-iceoryx#2301 PoC for 32-64 bit mixed mode
Browse files Browse the repository at this point in the history
  • Loading branch information
elBoberido committed Jul 1, 2024
1 parent 835bcae commit 84f3933
Show file tree
Hide file tree
Showing 5 changed files with 377 additions and 0 deletions.
37 changes: 37 additions & 0 deletions iceoryx_examples/mixed_mode_poc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
)
84 changes: 84 additions & 0 deletions iceoryx_examples/mixed_mode_poc/mixed_mode_poc_common.hpp
Original file line number Diff line number Diff line change
@@ -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 <atomic>
#include <cstdint>
#include <thread>

constexpr uint64_t ITERATIONS{50000000};

class PoorMansSpinSemaphore
{
public:
void post()
{
counter++;
}

void wait()
{
while (counter == 0)
{
std::this_thread::yield();
}
counter--;
}

private:
std::atomic<int32_t> 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<uint64_t> 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
85 changes: 85 additions & 0 deletions iceoryx_examples/mixed_mode_poc/mixed_mode_poc_follower.cpp
Original file line number Diff line number Diff line change
@@ -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<SharedData*>(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;
}
90 changes: 90 additions & 0 deletions iceoryx_examples/mixed_mode_poc/mixed_mode_poc_leader.cpp
Original file line number Diff line number Diff line change
@@ -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 <atomic>

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;
}
81 changes: 81 additions & 0 deletions tools/build-mixed-mode-poc-32-bit-and-64-bit.sh
Original file line number Diff line number Diff line change
@@ -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}"

0 comments on commit 84f3933

Please sign in to comment.