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 433a2d5
Show file tree
Hide file tree
Showing 5 changed files with 410 additions and 0 deletions.
41 changes: 41 additions & 0 deletions iceoryx_examples/mixed_mode_poc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# 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 mixed-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
)

if(USE_EXPLICIT_ALIGNMENT)
target_compile_definitions(mixed-mode-poc-follower PUBLIC USE_EXPLICIT_ALIGNMENT)
endif()
90 changes: 90 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,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

#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>

#ifdef USE_EXPLICIT_ALIGNMENT
#define ALIGNAS(n) alignas(n)
#else
#define ALIGNAS(n)
#endif

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
{
PoorMansSpinSemaphore leader_barrier;
PoorMansSpinSemaphore follower_barrier;
ALIGNAS(8) uint8_t dummy0{0};
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};
};

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! Data layout and atomics work!");
}
else
{
IOX_LOG(ERROR, "Failed! Either data layout issues or 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 counter value: " << 2 * ITERATIONS);

if (atomic_counter == 2 * ITERATIONS)
{
IOX_LOG(INFO, "Success! Data layout and atomics work!");
}
else
{
IOX_LOG(ERROR, "Failed! Either data layout issues or atomics do not work!");
}

return 0;
}
Loading

0 comments on commit 433a2d5

Please sign in to comment.