mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
commit dceb56dd1a19be6fe9b991bb50e08902eefe36a8
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 19:27:18 2020 +0000
Fixed non-initialisation of in_use flag.
commit c7ee1d6574ca5d95869152c5f8e4e6d02a7fa6bc
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 19:20:24 2020 +0000
Fixed non-initialisation of in_use flag.
commit 36cbf21cd1b67a28255582cfb4a188a601631ab2
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 18:52:53 2020 +0000
Refactor buffer_descriptors test
commit 49c60add63153bf53f400a891d8c4fb880cacda8
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 18:44:42 2020 +0000
Refactor buffer_descriptors test
commit 7bda7678311bf2eb497483f3ef27c3af9211680b
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 18:29:02 2020 +0000
Refactor buffer_descriptors test
commit 7a68c932a7df05f66690fa63e67365cf4b0619e8
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 18:14:30 2020 +0000
Refactor buffer_descriptors test
commit a9b25ac67d175f58751a2eb819f0e5822e8f0cf9
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 18:08:21 2020 +0000
Refactor buffer_descriptors test
commit 0c721c0466733751708fcbd995ce0bc1d7c0a932
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 17:58:22 2020 +0000
Refactor buffer_descriptors test
commit 4b2dd2fce22cd0a4846b95695fbfd812e0823540
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 17:47:43 2020 +0000
Refactor buffer_descriptors test
commit 80d5776c409b416377269d543bd539bdad83dc86
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 17:32:27 2020 +0000
Refactor buffer_descriptors test
commit 3564ac5b7ef89c41b240d9f54fce36042408daa0
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 17:17:50 2020 +0000
Refactor buffer_descriptors test
commit 297ef42c60e4228bfbcb2adcddeb6b8a617c4113
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 17:08:45 2020 +0000
Refactor buffer_descriptors test
commit 658d592c96eb7eaf1afb5d09fef38e293ea6f79b
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 16:58:52 2020 +0000
Refactor buffer_descriptors test
commit e97d8f90d5527349324ea84fd578c1d879d7a5a4
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 16:48:52 2020 +0000
Refactor buffer_descriptors test
commit ed783a8ccccc8673c0f55eb1780c08668880a745
Author: John Wellbelove <github@wellbelove.co.uk>
Date: Tue Nov 24 16:43:52 2020 +0000
clang.yml hack for testing
408 lines
11 KiB
C++
408 lines
11 KiB
C++
/******************************************************************************
|
|
The MIT License(MIT)
|
|
|
|
Embedded Template Library.
|
|
https://github.com/ETLCPP/etl
|
|
https://www.etlcpp.com
|
|
|
|
Copyright(c) 2020 jwellbelove
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files(the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions :
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
#include "UnitTest++/UnitTest++.h"
|
|
|
|
#include <thread>
|
|
#include <vector>
|
|
#include <numeric>
|
|
#include <array>
|
|
#include <algorithm>
|
|
#include <queue>
|
|
#include <atomic>
|
|
|
|
#include "etl/atomic.h"
|
|
#include "etl/queue_spsc_atomic.h"
|
|
#include "etl/buffer_descriptors.h"
|
|
|
|
#if defined(ETL_TARGET_OS_WINDOWS)
|
|
#include <Windows.h>
|
|
#endif
|
|
|
|
#define REALTIME_TEST 0
|
|
|
|
namespace
|
|
{
|
|
constexpr size_t BUFFER_SIZE = 16U;
|
|
constexpr size_t N_BUFFERS = 4U;
|
|
constexpr size_t DATA_COUNT = BUFFER_SIZE / 2;
|
|
|
|
using BD = etl::buffer_descriptors<char, BUFFER_SIZE, N_BUFFERS, std::atomic_char>;
|
|
|
|
char buffers[N_BUFFERS][BUFFER_SIZE];
|
|
|
|
//***********************************
|
|
struct Receiver
|
|
{
|
|
void receive(BD::notification n)
|
|
{
|
|
pbuffer = n.get_descriptor().data();
|
|
count = n.get_count();
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
pbuffer = nullptr;
|
|
count = 0U;
|
|
}
|
|
|
|
BD::pointer pbuffer;
|
|
BD::size_type count;
|
|
};
|
|
|
|
Receiver receiver;
|
|
|
|
SUITE(test_buffer_descriptors)
|
|
{
|
|
//*************************************************************************
|
|
TEST(test_constructor_plus_buffer)
|
|
{
|
|
BD bd(&buffers[0][0]);
|
|
|
|
CHECK_EQUAL(N_BUFFERS, bd.N_BUFFERS);
|
|
CHECK_EQUAL(BUFFER_SIZE, bd.BUFFER_SIZE);
|
|
CHECK(!bd.is_valid());
|
|
}
|
|
|
|
//*************************************************************************
|
|
TEST(test_constructor_plus_buffer_and_callback)
|
|
{
|
|
receiver.clear();
|
|
BD::callback_type callback = BD::callback_type::create<Receiver, &Receiver::receive>(receiver);
|
|
|
|
BD bd(&buffers[0][0], callback);
|
|
|
|
CHECK_EQUAL(N_BUFFERS, bd.N_BUFFERS);
|
|
CHECK_EQUAL(BUFFER_SIZE, bd.BUFFER_SIZE);
|
|
CHECK(bd.is_valid());
|
|
}
|
|
|
|
//*************************************************************************
|
|
TEST(test_constructor_plus_buffer_set_callback)
|
|
{
|
|
receiver.clear();
|
|
BD::callback_type callback = BD::callback_type::create<Receiver, &Receiver::receive>(receiver);
|
|
|
|
BD bd(&buffers[0][0]);
|
|
bd.set_callback(callback);
|
|
|
|
CHECK_EQUAL(N_BUFFERS, bd.N_BUFFERS);
|
|
CHECK_EQUAL(BUFFER_SIZE, bd.BUFFER_SIZE);
|
|
CHECK(bd.is_valid());
|
|
}
|
|
|
|
//*************************************************************************
|
|
TEST(test_buffers)
|
|
{
|
|
BD bd(&buffers[0][0]);
|
|
|
|
for (size_t i = 0U; i < N_BUFFERS; ++i)
|
|
{
|
|
BD::descriptor desc = bd.allocate();
|
|
|
|
CHECK(desc.is_valid());
|
|
CHECK(desc.is_allocated());
|
|
CHECK(!desc.is_released());
|
|
CHECK_EQUAL(BUFFER_SIZE, desc.max_size());
|
|
CHECK_EQUAL(uintptr_t(&buffers[i][0]), uintptr_t(desc.data()));
|
|
}
|
|
}
|
|
|
|
//*************************************************************************
|
|
TEST(test_clear)
|
|
{
|
|
BD bd(&buffers[0][0]);
|
|
BD::descriptor desc[4];
|
|
|
|
for (size_t i = 0U; i < N_BUFFERS; ++i)
|
|
{
|
|
desc[i] = bd.allocate();
|
|
}
|
|
|
|
bd.clear();
|
|
|
|
for (size_t i = 0U; i < N_BUFFERS; ++i)
|
|
{
|
|
CHECK(desc[i].is_valid());
|
|
CHECK(!desc[i].is_allocated());
|
|
CHECK(desc[i].is_released());
|
|
}
|
|
}
|
|
|
|
//*************************************************************************
|
|
TEST(test_buffers_with_allocate_fill)
|
|
{
|
|
std::array<char, BUFFER_SIZE> test =
|
|
{
|
|
char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF),
|
|
char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF), char(0xFF)
|
|
};
|
|
|
|
BD bd(&buffers[0][0]);
|
|
|
|
for (size_t i = 0U; i < N_BUFFERS; ++i)
|
|
{
|
|
BD::descriptor desc = bd.allocate(char(0xFF));
|
|
|
|
CHECK_EQUAL(BUFFER_SIZE, desc.max_size());
|
|
CHECK_EQUAL(uintptr_t(&buffers[i][0]), uintptr_t(desc.data()));
|
|
CHECK_ARRAY_EQUAL(test.data(), desc.data(), BUFFER_SIZE);
|
|
}
|
|
}
|
|
|
|
//*************************************************************************
|
|
TEST(test_notifications)
|
|
{
|
|
std::array<char, BUFFER_SIZE> test = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
std::fill(&buffers[0][0], &buffers[N_BUFFERS - 1][0] + BUFFER_SIZE , 0U);
|
|
|
|
receiver.clear();
|
|
BD::callback_type callback = BD::callback_type::create<Receiver, &Receiver::receive>(receiver);
|
|
|
|
BD bd(&buffers[0][0], callback);
|
|
|
|
for (size_t i = 0U; i < N_BUFFERS; ++i)
|
|
{
|
|
BD::descriptor desc = bd.allocate();
|
|
|
|
CHECK(desc.is_valid());
|
|
|
|
std::copy(test.begin(), test.begin() + DATA_COUNT, desc.data());
|
|
bd.notify(BD::notification(desc, DATA_COUNT));
|
|
desc.release();
|
|
|
|
CHECK_EQUAL(DATA_COUNT, receiver.count);
|
|
CHECK_EQUAL(uintptr_t(&buffers[i][0]), uintptr_t(receiver.pbuffer));
|
|
CHECK_ARRAY_EQUAL(test.data(), desc.data(), BUFFER_SIZE);
|
|
}
|
|
}
|
|
|
|
//*************************************************************************
|
|
TEST(test_allocate_overflow)
|
|
{
|
|
BD bd(&buffers[0][0]);
|
|
|
|
// Use up all of the descriptors.
|
|
for (size_t i = 0U; i < N_BUFFERS; ++i)
|
|
{
|
|
BD::descriptor desc = bd.allocate();
|
|
CHECK(desc.is_valid());
|
|
}
|
|
|
|
BD::descriptor desc = bd.allocate();
|
|
CHECK(!desc.is_valid());
|
|
}
|
|
|
|
//*************************************************************************
|
|
TEST(test_allocate_release_rollover)
|
|
{
|
|
std::queue<BD::descriptor> desc_queue;
|
|
|
|
BD bd(&buffers[0][0]);
|
|
|
|
// Use up all of the descriptors, then release/allocate for the rest.
|
|
for (size_t i = 0U; i < (N_BUFFERS * 2); ++i)
|
|
{
|
|
BD::descriptor desc = bd.allocate();
|
|
desc_queue.push(desc);
|
|
|
|
CHECK(desc.is_valid());
|
|
|
|
if (i >= (N_BUFFERS - 1))
|
|
{
|
|
desc_queue.front().release();
|
|
desc_queue.pop();
|
|
}
|
|
}
|
|
}
|
|
|
|
//*************************************************************************
|
|
TEST(test_descriptors)
|
|
{
|
|
BD bd(&buffers[0][0]);
|
|
|
|
BD::descriptor desc1 = bd.allocate();
|
|
BD::descriptor desc2 = bd.allocate();
|
|
BD::descriptor desc3 = bd.allocate();
|
|
BD::descriptor desc4 = bd.allocate();
|
|
|
|
CHECK(desc1.is_allocated());
|
|
CHECK(desc2.is_allocated());
|
|
CHECK(desc3.is_allocated());
|
|
CHECK(desc4.is_allocated());
|
|
|
|
CHECK(desc1.data() == &buffers[0][0]);
|
|
CHECK(desc2.data() == &buffers[1][0]);
|
|
CHECK(desc3.data() == &buffers[2][0]);
|
|
CHECK(desc4.data() == &buffers[3][0]);
|
|
|
|
CHECK(desc1.max_size() == BUFFER_SIZE);
|
|
CHECK(desc2.max_size() == BUFFER_SIZE);
|
|
CHECK(desc3.max_size() == BUFFER_SIZE);
|
|
CHECK(desc4.max_size() == BUFFER_SIZE);
|
|
|
|
CHECK(desc1.MAX_SIZE == BUFFER_SIZE);
|
|
CHECK(desc2.MAX_SIZE == BUFFER_SIZE);
|
|
CHECK(desc3.MAX_SIZE == BUFFER_SIZE);
|
|
CHECK(desc4.MAX_SIZE == BUFFER_SIZE);
|
|
|
|
CHECK(desc1.is_valid());
|
|
CHECK(desc2.is_valid());
|
|
CHECK(desc3.is_valid());
|
|
CHECK(desc4.is_valid());
|
|
|
|
desc1.release();
|
|
desc2.release();
|
|
desc3.release();
|
|
desc4.release();
|
|
|
|
CHECK(desc1.is_released());
|
|
CHECK(desc2.is_released());
|
|
CHECK(desc3.is_released());
|
|
CHECK(desc4.is_released());
|
|
}
|
|
|
|
//*************************************************************************
|
|
#if REALTIME_TEST
|
|
|
|
#if defined(ETL_TARGET_OS_WINDOWS) // Only Windows priority is currently supported
|
|
#define RAISE_THREAD_PRIORITY SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)
|
|
#define FIX_PROCESSOR_AFFINITY1 SetThreadAffinityMask(GetCurrentThread(), 1)
|
|
#define FIX_PROCESSOR_AFFINITY2 SetThreadAffinityMask(GetCurrentThread(), 2)
|
|
#else
|
|
#define RAISE_THREAD_PRIORITY
|
|
#define FIX_PROCESSOR_AFFINITY1
|
|
#define FIX_PROCESSOR_AFFINITY2
|
|
#endif
|
|
|
|
std::atomic_bool start = false;
|
|
|
|
//*********************************
|
|
struct Notification
|
|
{
|
|
BD::descriptor desc;
|
|
BD::size_type count;
|
|
};
|
|
|
|
constexpr int N_ITERATIONS = 1000000;
|
|
|
|
etl::queue_spsc_atomic<BD::notification, N_ITERATIONS + 100> desc_queue;
|
|
|
|
//*********************************
|
|
void Callback(BD::notification n)
|
|
{
|
|
desc_queue.push(n);
|
|
}
|
|
|
|
//*********************************
|
|
void Producer()
|
|
{
|
|
static char buffers[N_BUFFERS][BUFFER_SIZE];
|
|
|
|
BD bd(&buffers[0][0], BD::callback_type::create<Callback>());
|
|
|
|
RAISE_THREAD_PRIORITY;
|
|
FIX_PROCESSOR_AFFINITY1;
|
|
|
|
// Wait for the start flag.
|
|
while (!start);
|
|
|
|
int errors = 0;
|
|
|
|
for (int i = 0; i < N_ITERATIONS; ++i)
|
|
{
|
|
BD::descriptor desc;
|
|
|
|
// Wait until we can allocate a descriptor.
|
|
do
|
|
{
|
|
desc = bd.allocate();
|
|
} while (desc.is_valid() == false);
|
|
|
|
if (!desc.is_allocated())
|
|
{
|
|
++errors;
|
|
}
|
|
|
|
// Send a notification to the callback function.
|
|
bd.notify(BD::notification(desc, BUFFER_SIZE));
|
|
}
|
|
|
|
CHECK_EQUAL(0, errors);
|
|
}
|
|
|
|
//*********************************
|
|
void Consumer()
|
|
{
|
|
RAISE_THREAD_PRIORITY;
|
|
FIX_PROCESSOR_AFFINITY2;
|
|
|
|
// Wait for the start flag.
|
|
while (!start);
|
|
|
|
int errors = 0;
|
|
|
|
for (int i = 0; i < N_ITERATIONS;)
|
|
{
|
|
BD::notification notification;
|
|
|
|
// Try to get a notification from the queue.
|
|
if (desc_queue.pop(notification))
|
|
{
|
|
CHECK_EQUAL(BUFFER_SIZE, notification.get_count());
|
|
CHECK(notification.get_descriptor().is_allocated());
|
|
|
|
if (!notification.get_descriptor().is_allocated())
|
|
{
|
|
++errors;
|
|
}
|
|
|
|
notification.get_descriptor().release();
|
|
++i;
|
|
}
|
|
|
|
CHECK_EQUAL(0, errors);
|
|
}
|
|
}
|
|
|
|
//*********************************
|
|
TEST(test_multi_thread)
|
|
{
|
|
std::thread t1(Producer);
|
|
std::thread t2(Consumer);
|
|
|
|
start = true;
|
|
|
|
t1.join();
|
|
t2.join();
|
|
}
|
|
#endif
|
|
};
|
|
}
|