Skip to content

Commit

Permalink
Indexable_deque for use in new hip sync.
Browse files Browse the repository at this point in the history
  • Loading branch information
AWoloszyn committed Oct 19, 2024
1 parent 9f87f92 commit aaa52bc
Show file tree
Hide file tree
Showing 6 changed files with 331 additions and 1 deletion.
24 changes: 24 additions & 0 deletions runtime/src/iree/base/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,27 @@ iree_runtime_cc_test(
"//runtime/src/iree/testing:gtest_main",
],
)

iree_runtime_cc_library(
name = "indexable_deque",
srcs = ["indexable_deque.c"],
hdrs = ["indexable_deque.h"],
deps = [
":base",
"//runtime/src/iree/base/internal",
"//runtime/src/iree/base/internal:wait_handle",
],
)

iree_runtime_cc_test(
name = "indexable_deque_test",
srcs = [
"indexable_deque_test.cc",
],
deps = [
":base",
":indexable_deque",
"//runtime/src/iree/testing:gtest",
"//runtime/src/iree/testing:gtest_main",
],
)
28 changes: 28 additions & 0 deletions runtime/src/iree/base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,34 @@ iree_cc_test(
iree::testing::gtest_main
)


iree_cc_library(
NAME
indexable_deque
HDRS
"indexable_deque.h"
SRCS
"indexable_deque.c"
DEPS
::base
iree::base::internal
iree::base::internal::wait_handle
PUBLIC
)

iree_cc_test(
NAME
indexable_deque_test
SRCS
"indexable_deque_test.cc"
DEPS
::base
::indexable_deque
iree::testing::gtest
iree::testing::gtest_main
)


if(EMSCRIPTEN)
iree_cc_library(
NAME
Expand Down
73 changes: 73 additions & 0 deletions runtime/src/iree/base/indexable_deque.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2024 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree/base/indexable_deque.h"

#include "iree/base/assert.h"

void iree_indexable_queue_initialize(iree_indexable_queue_t* queue,
iree_allocator_t allocator,
iree_host_size_t element_size,
iree_host_size_t inline_count) {
queue->allocator = allocator;
queue->elements = &queue->initial_allocation[0];
queue->element_size = element_size;
queue->element_count = 0;
queue->capacity = inline_count;
queue->head = 0;
}

void iree_indexable_queue_deinitialize(iree_indexable_queue_t* queue) {
IREE_ASSERT_ARGUMENT(queue);
if (queue->elements != &queue->initial_allocation[0]) {
iree_allocator_free(queue->allocator, queue->elements);
}
}

iree_status_t iree_indexable_queue_push_back(iree_indexable_queue_t* queue,
void* element) {
// Expand
if (queue->capacity == queue->element_count) {
uint8_t* new_mem;
queue->capacity = iree_max(16, queue->capacity << 1);
IREE_RETURN_IF_ERROR(iree_allocator_malloc(
queue->allocator, queue->element_size * queue->capacity,
(void**)&new_mem));
memcpy(new_mem, queue->elements + (queue->head * queue->element_size),
(queue->element_count - queue->head) * queue->element_size);
memcpy(
new_mem + ((queue->element_count - queue->head) * queue->element_size),
queue->elements, queue->head * queue->element_size);
if (queue->elements != &queue->initial_allocation[0]) {
iree_allocator_free(queue->allocator, queue->elements);
}
queue->head = 0;
queue->elements = new_mem;
}
memcpy(queue->elements +
(((queue->head + queue->element_count) % queue->capacity) *
queue->element_size),
element, queue->element_size);
queue->element_count++;
return iree_ok_status();
}

void iree_indexable_queue_pop_front(iree_indexable_queue_t* queue,
iree_host_size_t count) {
IREE_ASSERT_ARGUMENT(queue);
IREE_ASSERT(count <= queue->element_count, "Popping too many elements");
queue->head += count;
queue->head = queue->head % queue->capacity;
queue->element_count -= count;
}

void* iree_indexable_queue_at(iree_indexable_queue_t* queue,
iree_host_size_t i) {
IREE_ASSERT_ARGUMENT(queue);
IREE_ASSERT(i < queue->element_count, "Index out of range");
return queue->elements +
((queue->head + i) % queue->capacity) * queue->element_size;
}
96 changes: 96 additions & 0 deletions runtime/src/iree/base/indexable_deque.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright 2024 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef IREE_BASE_INDEXABLE_DEQUE_H__
#define IREE_BASE_INDEXABLE_DEQUE_H__

#include "iree/base/allocator.h"

#ifdef __cplusplus
extern "C" {
#endif

// The indexable deque essentially a circular array
// where we can push to the back and pop from the front.
// The helper functions allow you to index into the array.
// Furthermore an initial allocation may be provided inline
// as an optimization.
typedef struct iree_indexable_queue_t {
iree_allocator_t allocator;
uint8_t* elements;
iree_host_size_t element_size;
iree_host_size_t element_count;
iree_host_size_t capacity;
iree_host_size_t head;
uint8_t initial_allocation[];
} iree_indexable_queue_t;

// Initializes the indexable_queue with the given allocator, element size and
// number of inline elements (which may be 0).
void iree_indexable_queue_initialize(iree_indexable_queue_t* queue,
iree_allocator_t allocator,
iree_host_size_t element_size,
iree_host_size_t inline_count);

// Deinitializes the list, it does not have to be empty.
void iree_indexable_queue_deinitialize(iree_indexable_queue_t* queue);

// Copies the given element into the back of the array. This may cause a
// re-allocation of data.
iree_status_t iree_indexable_queue_push_back(iree_indexable_queue_t* queue,
void* element);

// Pops the element from the front of the array and moves the head.
void iree_indexable_queue_pop_front(iree_indexable_queue_t* queue,
iree_host_size_t count);

// Returns a pointer to the element at index i
void* iree_indexable_queue_at(iree_indexable_queue_t* queue,
iree_host_size_t i);

#define IREE_TYPED_INDEXABLE_QUEUE_WRAPPER(name, type, default_element_count) \
typedef struct name##_indexable_queue_t { \
iree_allocator_t allocator; \
void* elements; \
iree_host_size_t element_size; \
iree_host_size_t element_count; \
iree_host_size_t capacity; \
iree_host_size_t head; \
iree_alignas(iree_max_align_t) uint8_t \
initial_allocation[default_element_count * sizeof(type)]; \
} name##_indexable_queue_t; \
static inline void name##_initialize(name##_indexable_queue_t* out_queue, \
iree_allocator_t allocator) { \
iree_indexable_queue_initialize((iree_indexable_queue_t*)out_queue, \
allocator, sizeof(type), \
default_element_count); \
} \
static inline void name##_deinitialize( \
name##_indexable_queue_t* out_queue) { \
iree_indexable_queue_deinitialize((iree_indexable_queue_t*)out_queue); \
} \
iree_status_t name##_push_back(name##_indexable_queue_t* queue, \
type element) { \
return iree_indexable_queue_push_back((iree_indexable_queue_t*)queue, \
&element); \
} \
void name##_pop_front(name##_indexable_queue_t* queue, \
iree_host_size_t count) { \
return iree_indexable_queue_pop_front((iree_indexable_queue_t*)queue, \
count); \
} \
type name##_at(name##_indexable_queue_t* queue, iree_host_size_t i) { \
type t; \
memcpy(&t, iree_indexable_queue_at((iree_indexable_queue_t*)queue, i), \
sizeof(type)); \
return t; \
}

#ifdef __cplusplus
}
#endif

#endif // IREE_BASE_INTERNAL_INDEXABLE_DEQUE_H__
110 changes: 110 additions & 0 deletions runtime/src/iree/base/indexable_deque_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright 2024 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include "iree/base/indexable_deque.h"

#include "iree/testing/gtest.h"

IREE_TYPED_INDEXABLE_QUEUE_WRAPPER(test_queue, int32_t, 4);

class IndexableDequeTest : public ::testing::Test {
protected:
void SetUp() override {
test_queue_initialize(&queue_, iree_allocator_system());
}

void TearDown() override { test_queue_deinitialize(&queue_); }

test_queue_indexable_queue_t queue_;
};

TEST_F(IndexableDequeTest, initialize) {
EXPECT_EQ(queue_.element_count, 0);
EXPECT_EQ(queue_.capacity, 4);
EXPECT_EQ(queue_.element_size, sizeof(int));
}

TEST_F(IndexableDequeTest, push_back) {
int value = 42;
IREE_CHECK_OK(test_queue_push_back(&queue_, value));
EXPECT_EQ(queue_.element_count, 1);
EXPECT_EQ(test_queue_at(&queue_, 0), value);
}

TEST_F(IndexableDequeTest, push_back_and_expand) {
for (int i = 0; i < 5; ++i) {
IREE_CHECK_OK(test_queue_push_back(&queue_, i));
}
EXPECT_EQ(queue_.element_count, 5);
EXPECT_GT(queue_.capacity, 4);
}

TEST_F(IndexableDequeTest, pop_front) {
IREE_CHECK_OK(test_queue_push_back(&queue_, 12));
IREE_CHECK_OK(test_queue_push_back(&queue_, 15));
test_queue_pop_front(&queue_, 1);
EXPECT_EQ(queue_.element_count, 1);
EXPECT_EQ(test_queue_at(&queue_, 0), 15);
}

TEST_F(IndexableDequeTest, at) {
int value1 = 42;
int value2 = 84;
IREE_CHECK_OK(test_queue_push_back(&queue_, value1));
IREE_CHECK_OK(test_queue_push_back(&queue_, value2));
EXPECT_EQ(test_queue_at(&queue_, 0), value1);
EXPECT_EQ(test_queue_at(&queue_, 1), value2);
}

TEST_F(IndexableDequeTest, cycle_around_queue) {
for (int i = 0; i < 4; ++i) {
IREE_CHECK_OK(test_queue_push_back(&queue_, i));
}
for (int i = 0; i < 4; ++i) {
test_queue_pop_front(&queue_, 1);
IREE_CHECK_OK(test_queue_push_back(&queue_, i + 4));
}
for (int i = 0; i < 4; ++i) {
EXPECT_EQ(test_queue_at(&queue_, i), i + 4);
}
EXPECT_EQ(queue_.element_count, 4);
}

TEST_F(IndexableDequeTest, cycle_around_queue_twice) {
for (int i = 0; i < 4; ++i) {
IREE_CHECK_OK(test_queue_push_back(&queue_, i));
}
for (int i = 0; i < 8; ++i) {
test_queue_pop_front(&queue_, 1);
IREE_CHECK_OK(test_queue_push_back(&queue_, i + 4));
}
for (int i = 0; i < 4; ++i) {
EXPECT_EQ(test_queue_at(&queue_, i), i + 8);
}
EXPECT_EQ(queue_.element_count, 4);
}

TEST_F(IndexableDequeTest, allocate_twice) {
for (int i = 0; i < 8; ++i) {
IREE_CHECK_OK(test_queue_push_back(&queue_, i));
}
EXPECT_EQ(queue_.element_count, 8);
EXPECT_GT(queue_.capacity, 4);

for (int i = 8; i < 16; ++i) {
IREE_CHECK_OK(test_queue_push_back(&queue_, i));
}
EXPECT_EQ(queue_.element_count, 16);
EXPECT_GT(queue_.capacity, 8);
}

TEST_F(IndexableDequeTest, no_reallocation_when_capacity_sufficient) {
size_t initial_capacity = queue_.capacity;
for (int i = 0; i < initial_capacity; ++i) {
IREE_CHECK_OK(test_queue_push_back(&queue_, i));
}
EXPECT_EQ(queue_.capacity, initial_capacity);
}
1 change: 0 additions & 1 deletion runtime/src/iree/base/status_cc.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#include <type_traits>
#include <utility>

#include "iree/base/api.h"
#include "iree/base/attributes.h"
#include "iree/base/target_platform.h"

Expand Down

0 comments on commit aaa52bc

Please sign in to comment.