Skip to content

Commit

Permalink
Improved support for cooperative schedulers. Full support is not comp…
Browse files Browse the repository at this point in the history
…leted yet
  • Loading branch information
pzaino committed Nov 13, 2023
1 parent 655e53a commit 529c296
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 97 deletions.
140 changes: 81 additions & 59 deletions src/zvector.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,24 @@ struct ZVECT_PACKING p_vector
typedef struct p_vector * const ivector;
typedef struct p_vector * const cvector;

#if defined(ZVECT_COOPERATIVE)
// Struct used to store temporary range of the vector:
// when ZVector is used on CMT systems (like RISC OS or some embedded systems)
struct p_cmt_state_range {
int low;
int high;
};

// Struc used to store the state of the cooperative apply:
struct p_cmt_state {
zvect_index currentIndex;
cmt_state_range *stack;
int stackSize;
int stackCapacity;
bool isInitialized;
};
#endif

// Initialisation state:
static uint32_t p_init_state = 0;

Expand Down Expand Up @@ -2353,6 +2371,7 @@ void vect_rotate_right(ivector v, zvect_index i) {
p_throw_error(rval, NULL);
}

#if !defined(ZVECT_COOPERATIVE)
#ifdef TRADITIONAL_QSORT
static inline zvect_index
p_partition(vector v, zvect_index low, zvect_index high,
Expand Down Expand Up @@ -2383,7 +2402,7 @@ static void p_vect_qsort(vector v, zvect_index low, zvect_index high,
}
#endif // TRADITIONAL_QSORT

#if !defined(TRADITIONAL_QSORT) && !defined(COOPERATIVE_QSORT)
#if !defined(TRADITIONAL_QSORT)
// This is my much faster implementation of a quicksort algorithm
// it fundamentally uses the 3 ways partitioning adapted and improved
// to deal with arrays of pointers together with having a custom
Expand Down Expand Up @@ -2440,71 +2459,83 @@ static void p_vect_qsort(ivector v, zvect_index l, zvect_index r,
p_vect_qsort(v, i, r, compare_func);
}
#endif // ! TRADITIONAL_QSORT
#endif // ! ZVECT_COOPERATIVE

#ifdef COOPERATIVE_QSORT
typedef struct {
int low;
int high;
} cQSortRange;

// This struct is used to store the temporary state of the
// quicksort algorithm:
typedef struct {
cQSortRange* stack;
int stackSize;
// ... Other state variables as needed ...
} cQSortState;

void initQSortState(cQSortState* state, int initialCapacity) {
state->stack = malloc(initialCapacity * sizeof(cQSortRange));
#if defined(ZVECT_COOPERATIVE)
// Cooperative quicksort algorithm:
void initQSortState(cmt_state const state, int initialCapacity) {
state->stack = malloc(initialCapacity * sizeof(struct p_cmt_state_range));
state->stackSize = 0;
// ... Initialize other state variables ...
state->isInitialized = 1;
}

void freeQSortState(cQSortState* state) {
void freeQSortState(cmt_state const state) {
free(state->stack);
// ... Clean up other state resources ...
state->stackSize = 0;
state->stack = NULL;
}

void pushQSortRange(cQSortRange range, cQSortState* state) {
void pushQSortRange(struct p_cmt_state_range range, cmt_state const state) {
if (state->stackSize >= state->stackCapacity) {
// Resize the stack if needed
state->stackCapacity *= 2;
state->stack = realloc(state->stack, state->stackCapacity * sizeof(SortRange));
state->stack = realloc(state->stack, state->stackCapacity * sizeof(struct p_cmt_state_range));
}
state->stack[state->stackSize] = range;
state->stackSize++;
}

cQSortRange popQSortRange(cQSortState* state) {
struct p_cmt_state_range popQSortRange(cmt_state const state) {
if (state->stackSize == 0) {
// Handle error for empty stack or return a default value
cQSortRange empty = {0, 0};
struct p_cmt_state_range empty = {0, 0};
return empty;
}
state->stackSize--;
return state->stack[state->stackSize];
}

int p_qsort_is_empty(const cQSortState* state) {
int p_qsort_is_empty(cmt_state const state) {
return state->stackSize == 0;
}

zvect_index partition(ivector v,
zvect_index low, zvect_index high,
int (*compare_func)(const void *, const void *))
{
void* pivot = vect_get_at(v, high); // Pivot element
zvect_index i = (low - 1); // Index of smaller element

for (zvect_index j = low; j <= high - 1; j++) {
// If current element is smaller than or equal to pivot
if (compare_func(vect_get_at(v, j), pivot) <= 0) {
i++; // Increment index of smaller element
vect_swap(v, i, j); // Swap elements at i and j
}
}
vect_swap(v, i + 1, high); // Swap the pivot element with the element at i + 1
return (i + 1);
}


// Cooperative and iterative quicksort algorithm:
void p_vect_cqsort(ivector v, cQSortState* state,
void p_vect_cqsort(ivector v, cmt_state state,
int(*compare_func)(const void *, const void *),
zvect_index iterationLimit)
{
int iterations = 0;
zvect_index iterations = 0;
if (!state->isInitialized) {
initQSortState(state, p_vect_size(v) / iterationLimit );
}

while (!p_qsort_is_empty(state) && iterations < iterationLimit) {
cQSortRange range = popQSortRange(state);
cmt_state_range range = popQSortRange(state);

if (range.low < range.high) {
int pivot = partition(v, range.low, range.high, compare_func);
zvect_index pivot = partition(v, range.low, range.high, compare_func);

pushQSortRange((cQSortRange){range.low, pivot - 1}, state);
pushQSortRange((cQSortRange){pivot + 1, range.high}, state);
pushQSortRange((struct p_cmt_state_range){range.low, pivot - 1}, state);
pushQSortRange((struct p_cmt_state_range){pivot + 1, range.high}, state);

iterations++;
}
Expand All @@ -2525,9 +2556,9 @@ void p_vect_cqsort(ivector v, cQSortState* state,
// the cooperative quicksort
void vect_qsort(ivector v,
int (*compare_func)(const void *, const void *)
#ifdef COOPERATIVE_QSORT
#if defined(ZVECT_COOPERATIVE)
, struct p_cmt_state* const state
, zvect_index iterationLimit
, cQSortState* state
#endif
)
{
Expand All @@ -2548,21 +2579,20 @@ void vect_qsort(ivector v,
goto VECT_QSORT_DONE_PROCESSING;

// Process the vector:
#ifndef COOPERATIVE_QSORT
#ifndef ZVECT_COOPERATIVE
p_vect_qsort(v, 0, vsize - 1, compare_func);
#else
if (state == NULL) {
cQSortState state;
initQSortState(&state, 16);
}
if (iterationLimit == 0)
iterationLimit = vect_size(v);
if (iterationLimit > vect_size(v))
iterationLimit = vect_size(v);
cQSortRange range = {0, vsize - 1};
if (!state->isInitialized) {
initQSortState(state, vsize / iterationLimit );
}
struct p_cmt_state_range range = {0, vsize - 1};
pushQSortRange(range, state);
p_vect_cqsort(v, state, compare_func, iterationLimit);
freeQSortState(&state);
freeQSortState(state);
#endif

VECT_QSORT_DONE_PROCESSING:
Expand Down Expand Up @@ -2834,7 +2864,7 @@ bool vect_bsearch(ivector v, const void *key,

// Traditional Linear Search Algorithm,
// useful with non-sorted vectors:
#if defined(TRADITIONAL_LINEAR_SEARCH)
#if !defined(ZVECT_COOPERATIVE)
bool vect_lsearch(ivector v, const void *key,
int (*f1)(const void *, const void *),
zvect_index *item_index) {
Expand Down Expand Up @@ -2906,20 +2936,14 @@ bool vect_lsearch(ivector v, const void *key,
*item_index = 0;
return false;
}
#endif // TRADITIONAL_LINEAR_SEARCH || ADAPTIVE_LINEAR_SEARCH

#if defined(COOPERATIVE_LINEAR_SEARCH)
// Struc used to store the state of the cooperative linear search:
typedef struct {
zvect_index currentIndex;
bool isInitialized;
} LinearSearchState;
#endif // TRADITIONAL_LINEAR_SEARCH

#if defined(ZVECT_COOPERATIVE)
// Cooperative and iterative linear search algorithm:
bool vect_lsearch(ivector v, const void *key,
int (*f1)(const void *, const void *),
zvect_index *item_index,
LinearSearchState* state,
cmt_state const state,
zvect_index maxIterations)
{
// Check parameters:
Expand Down Expand Up @@ -3015,7 +3039,7 @@ bool vect_lsearch(ivector v, const void *key,
#ifdef ZVECT_SFMD_EXTENSIONS
// Single Function Call Multiple Data operations extensions:

#if !defined(COOPERATIVE_APPLY)
#if !defined(ZVECT_COOPERATIVE)
void vect_apply(ivector v, void (*f)(void *)) {
// Check Parameters:
if (f == NULL)
Expand Down Expand Up @@ -3057,16 +3081,10 @@ void vect_apply(ivector v, void (*f)(void *)) {
}
#endif

#if defined(COOPERATIVE_APPLY)
// Struc used to store the state of the cooperative apply:
typedef struct {
zvect_index currentIndex;
bool isInitialized;
} VectApplyState;

#if defined(ZVECT_COOPERATIVE)
void vect_apply(ivector v,
void (*f)(void *),
VectApplyState* state,
cmt_state const state,
zvect_index maxIterations)
{
// Check Parameters:
Expand All @@ -3079,6 +3097,10 @@ void vect_apply(ivector v,

zvect_index vsize = p_vect_size(v);
zvect_index iterations = 0;
if (!state->isInitialized) {
state->currentIndex = 0;
state->isInitialized = true;
}

if ((vsize & 3) == 0) {
// Unrolled loop
Expand Down
30 changes: 29 additions & 1 deletion src/zvector.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ extern "C" {
// Declare required structs:
typedef struct p_vector * vector;

#if defined(ZVECT_COOPERATIVE)
// Cooperative Scheduler support
typedef struct p_cmt_state * cmt_state;
typedef struct p_cmt_state_range cmt_state_range;
#endif


// Declare required enums:

Expand Down Expand Up @@ -474,7 +480,14 @@ void vect_rotate_right(vector const v, const zvect_index i);
* pointers to your datastructures stored in the vector.
*
*/
#if !defined(ZVECT_COOPERATIVE)
void vect_qsort(vector const v, int (*compare_func)(const void *, const void*));
#else
void vect_qsort(vector const v, int (*compare_func)(const void *, const void*),
cmt_state const state,
zvect_index maxIterations);
#endif


/*
* vect_bsearch is a function that allows to perform
Expand Down Expand Up @@ -515,9 +528,17 @@ bool vect_bsearch(vector const v, const void *key, int (*f1)(const void *, const
* int i = 5;
* vect_lsearch(v, &i, my_compare);
*/
bool vect_lsearch(vector v, const void *key,
#if !defined(ZVECT_COOPERATIVE)
bool vect_lsearch(vector const v, const void *key,
int (*f1)(const void *, const void *),
zvect_index *item_index);
#else
bool vect_lsearch(vector const v, const void *key,
int (*f1)(const void *, const void *),
zvect_index *item_index,
cmt_state state,
zvect_index maxIterations);
#endif

/*
* vect_add_ordered allows the insertion of new items in
Expand Down Expand Up @@ -557,7 +578,14 @@ void vect_add_ordered(vector const v, const void *value, int (*f1)(const void *,
* to deal with return values especially when you'll be
* using complex data structures as item of the vector.
*/
#if !defined(ZVECT_COOPERATIVE)
void vect_apply(vector const v, void (*f1)(void *));
#else
void vect_apply(vector const v,
void (*f)(void *),
cmt_state const state,
zvect_index maxIterations);
#endif

/*
* vect_apply_if is a function that will apply "f1" C function
Expand Down
42 changes: 5 additions & 37 deletions src/zvector_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,42 +81,10 @@ typedef int32_t zvect_retval;
// Enable/Disable SFMD Extensions:
#define ZVECT_SFMD_EXTENSIONS 1

// If you have enabled ZVector extensions
// you can choose to enable/disable
// which type of algorithms you want to use
// for some of the extensions:

// Linear search:
// Uncomment the following line to have
// traditional linear search (it's optimized)
// but it's still linear search.
// If you do not need linear search at all then
// comment all *_LINEAR_SEARCH defines.
#define TRADITIONAL_LINEAR_SEARCH
// Use cooperative ONLY on cooperative multitasking
// systems (like RISC OS or some embedded systems)
// If you use cooperative, please disable traditional
// #define COOPERATIVE_LINEAR_SEARCH

// Binary Search:
// Default is improved Adaptive Binary Search, but
// if you need traditional binary search then
// uncomment the following line:
// #define TRADITIONAL_BINARY_SEARCH
// Use cooperative ONLY on cooperative multitasking
// systems (like RISC OS or some embedded systems)
// If you use cooperative, please disable traditional
// #define COOPERATIVE_BINARY_SEARCH

// Quick Sort:
// Default is improved Quick Sort (3 ways partitioning),
// but if you need traditional quick sort then
// uncomment the following line:
//#define TRADITIONAL_QSORT
// uncomment the following line if you want
// cooperative quick sort (only on cooperative
// multitasking systems)
//#define COOPERATIVE_QSORT

// If you are using ZVector on a system
// that supports cooperative multitasking
// (like RISC OS or some embedded systems)
// then uncomment the following line:
//#define ZVECT_COOPERATIVE

#endif // SRC_ZVECTOR_CONFIG_H_

0 comments on commit 529c296

Please sign in to comment.