Download c source code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "array_mutex.h"
#include "array_rwlock.h"

typedef struct
{
	size_t initial_element_count;
	size_t operation_count;
	double insertion_percent;
	double deletion_percent;
	double searching_percent;
	size_t worker_count;
	size_t tested_array;
	array_mutex_t* mutex_array;
	array_rwlock_t* rwlock_array;
} shared_t;

typedef struct
{
	size_t worker_id;
	shared_t* shared;
} thread_data_t;

void print_array(const char* name, array_mutex_t *array);
int test_arrays(shared_t* shared);
void* test_array(void* data);

static const char* const usage_text =
	"usage: array_thrsafe_perf #elements #operations %%insertions %%deletions %%searches #workers array\n";

int main(int argc, char* argv[])
{
	// All arguments are required
	if ( argc != 8 )
		return (void)printf(usage_text), 1;

	// Extract the arguments
	shared_t shared;
	shared.initial_element_count = strtoull(argv[1], NULL, 10);
	shared.operation_count = strtoull(argv[2], NULL, 10);
	shared.insertion_percent = strtod(argv[3], NULL);
	shared.deletion_percent = strtod(argv[4], NULL);
	shared.searching_percent = strtod(argv[5], NULL);
	shared.worker_count = strtoull(argv[6], NULL, 10);

	if ( strcmp(argv[7], "mutex") == 0 )
		shared.tested_array = 1;
	else if ( strcmp(argv[7], "rwlock") == 0 )
		shared.tested_array = 2;
	else
		return (void)fprintf(stderr, "error: unknown array: %s", argv[7]), 2;

	shared.mutex_array = NULL;
	shared.rwlock_array = NULL;

	// If we have to thes the mutex array
	if ( shared.tested_array == 1 )
	{
		//  Create the mutex array
		shared.mutex_array = array_mutex_create(shared.initial_element_count);

		// Append the intial elements
		for ( size_t current = 0; current < shared.initial_element_count; ++current )
			array_mutex_append( shared.mutex_array, (void*)(current) );
	}
	else
	{
		shared.rwlock_array = array_rwlock_create(shared.initial_element_count);
		for ( size_t current = 0; current < shared.initial_element_count; ++current )
			array_rwlock_append( shared.rwlock_array, (void*)(current) );
	}

	// Create and test the performance of the thread-safe arrays
	int result = test_arrays(&shared);

	// Destroy the arrays
	if ( shared.tested_array == 1 )
		array_mutex_destroy(shared.mutex_array);
	else
		array_rwlock_destroy(shared.rwlock_array);

	return result;
}

int test_arrays(shared_t* shared)
{
	// Init pseudo-random number generator
	srand( (unsigned)((unsigned)time(NULL) + (unsigned)clock()) );

	// Create threads and their data
	pthread_t* threads = (pthread_t*) malloc( shared->worker_count * sizeof(pthread_t) );
	thread_data_t* thread_data = (thread_data_t*) malloc( shared->worker_count * sizeof(thread_data_t) );

	// Start the asked number of threads
	for ( size_t current = 0; current < shared->worker_count; ++current )
	{
		thread_data[current].worker_id = current;
		thread_data[current].shared = shared;
		pthread_create( threads + current, NULL, test_array, thread_data + current );
	}

	// Wait for all threads to finish
	for ( size_t current = 0; current < shared->worker_count; ++current )
		pthread_join( threads[current], NULL );

	// Release threads and their data
	free(thread_data);
	free(threads);

//	print_array("array1", shared->mutex_array);
//	print_array("array2", shared->rwlock_array);

	return 0;
}

void* test_array(void* data)
{
	// Unpack the data
	thread_data_t* thread_data = (thread_data_t*)data;
	shared_t* shared = thread_data->shared;

	// Slice the operations among the threads
	size_t my_operations = shared->operation_count / shared->worker_count
		+ (thread_data->worker_id < shared->operation_count % shared->worker_count);

	// Execute the asked number of operations
	for ( size_t operation = 0; operation < my_operations; ++operation )
	{
		// Get a random number to insert, find, or delete from array
		size_t element = rand() % 100;

		// Get a random percent to choose the operation to execute
		size_t random_op = (size_t)rand() % shared->operation_count;

		// Execute the operation according to the percents
		if ( random_op < shared->insertion_percent * shared->operation_count )
		{
			// Insert an element into the tested array
			shared->tested_array == 1
				? array_mutex_append( shared->mutex_array, (void*)(element) )
				: array_rwlock_append( shared->rwlock_array, (void*)(element) );
		}
		else if ( random_op < shared->deletion_percent * shared->operation_count )
		{
			// Remove an element in the tested array
			shared->tested_array == 1
				? array_mutex_remove_first(shared->mutex_array, (void*)(element), 0)
				: array_rwlock_remove_first(shared->rwlock_array, (void*)(element), 0);
		}
		else
		{
			// Search an element in the tested array
			shared->tested_array == 1
				? array_mutex_find_first(shared->mutex_array, (void*)(element), 0)
				: array_rwlock_find_first(shared->rwlock_array, (void*)(element), 0);
		}
	}

	return NULL;
}

void print_array(const char* name, array_mutex_t* array)
{
	printf("%s: %zu elements\n", name, array_mutex_get_count(array));
	fflush(stdout);
}