@@ -1,68 +1,171 @@
|
|
1 |
#include <pthread.h>
|
2 |
#include <stdio.h>
|
3 |
#include <stdlib.h>
|
|
|
4 |
#include <time.h>
|
5 |
|
6 |
-
#include "
|
|
|
7 |
|
8 |
-
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
void* test_array(void* data);
|
11 |
|
12 |
-
|
13 |
-
|
14 |
-
array_t* array1 = array_create(100);
|
15 |
-
array_t* array2 = array_create(100);
|
16 |
|
17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
-
|
20 |
-
|
21 |
|
22 |
-
|
23 |
-
|
|
|
|
|
|
|
24 |
|
25 |
-
|
|
|
|
|
26 |
}
|
27 |
-
|
28 |
-
void print_array(const char* name, array_t* array)
|
29 |
{
|
30 |
-
|
31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
}
|
33 |
|
34 |
-
|
35 |
{
|
|
|
36 |
srand( (unsigned)((unsigned)time(NULL) + (unsigned)clock()) );
|
37 |
|
38 |
-
|
39 |
-
pthread_t* threads = (pthread_t*) malloc(
|
|
|
40 |
|
41 |
-
|
42 |
-
|
|
|
|
|
|
|
|
|
|
|
43 |
|
44 |
-
|
|
|
45 |
pthread_join( threads[current], NULL );
|
46 |
|
|
|
|
|
47 |
free(threads);
|
|
|
|
|
|
|
|
|
|
|
48 |
}
|
49 |
|
50 |
void* test_array(void* data)
|
51 |
{
|
52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
|
54 |
-
|
|
|
55 |
{
|
56 |
-
|
57 |
-
|
58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
else
|
60 |
{
|
61 |
-
|
62 |
-
|
63 |
-
|
|
|
64 |
}
|
65 |
}
|
66 |
|
67 |
return NULL;
|
68 |
}
|
|
|
|
|
|
|
|
|
|
|
|
1 |
#include <pthread.h>
|
2 |
#include <stdio.h>
|
3 |
#include <stdlib.h>
|
4 |
+
#include <string.h>
|
5 |
#include <time.h>
|
6 |
|
7 |
+
#include "array_mutex.h"
|
8 |
+
#include "array_rwlock.h"
|
9 |
|
10 |
+
typedef struct
|
11 |
+
{
|
12 |
+
size_t initial_element_count;
|
13 |
+
size_t operation_count;
|
14 |
+
double insertion_percent;
|
15 |
+
double deletion_percent;
|
16 |
+
double searching_percent;
|
17 |
+
size_t worker_count;
|
18 |
+
size_t tested_array;
|
19 |
+
array_mutex_t* mutex_array;
|
20 |
+
array_rwlock_t* rwlock_array;
|
21 |
+
} shared_t;
|
22 |
+
|
23 |
+
typedef struct
|
24 |
+
{
|
25 |
+
size_t worker_id;
|
26 |
+
shared_t* shared;
|
27 |
+
} thread_data_t;
|
28 |
+
|
29 |
+
void print_array(const char* name, array_mutex_t *array);
|
30 |
+
int test_arrays(shared_t* shared);
|
31 |
void* test_array(void* data);
|
32 |
|
33 |
+
static const char* const usage_text =
|
34 |
+
"usage: array_thrsafe_perf #elements #operations %%insertions %%deletions %%searches #workers array\n";
|
|
|
|
|
35 |
|
36 |
+
int main(int argc, char* argv[])
|
37 |
+
{
|
38 |
+
// All arguments are required
|
39 |
+
if ( argc != 8 )
|
40 |
+
return (void)printf(usage_text), 1;
|
41 |
+
|
42 |
+
// Extract the arguments
|
43 |
+
shared_t shared;
|
44 |
+
shared.initial_element_count = strtoull(argv[1], NULL, 10);
|
45 |
+
shared.operation_count = strtoull(argv[2], NULL, 10);
|
46 |
+
shared.insertion_percent = strtod(argv[3], NULL);
|
47 |
+
shared.deletion_percent = strtod(argv[4], NULL);
|
48 |
+
shared.searching_percent = strtod(argv[5], NULL);
|
49 |
+
shared.worker_count = strtoull(argv[6], NULL, 10);
|
50 |
+
|
51 |
+
if ( strcmp(argv[7], "mutex") == 0 )
|
52 |
+
shared.tested_array = 1;
|
53 |
+
else if ( strcmp(argv[7], "rwlock") == 0 )
|
54 |
+
shared.tested_array = 2;
|
55 |
+
else
|
56 |
+
return (void)fprintf(stderr, "error: unknown array: %s", argv[7]), 2;
|
57 |
|
58 |
+
shared.mutex_array = NULL;
|
59 |
+
shared.rwlock_array = NULL;
|
60 |
|
61 |
+
// If we have to thes the mutex array
|
62 |
+
if ( shared.tested_array == 1 )
|
63 |
+
{
|
64 |
+
// Create the mutex array
|
65 |
+
shared.mutex_array = array_mutex_create(shared.initial_element_count);
|
66 |
|
67 |
+
// Append the intial elements
|
68 |
+
for ( size_t current = 0; current < shared.initial_element_count; ++current )
|
69 |
+
array_mutex_append( shared.mutex_array, (void*)(current) );
|
70 |
}
|
71 |
+
else
|
|
|
72 |
{
|
73 |
+
shared.rwlock_array = array_rwlock_create(shared.initial_element_count);
|
74 |
+
for ( size_t current = 0; current < shared.initial_element_count; ++current )
|
75 |
+
array_rwlock_append( shared.rwlock_array, (void*)(current) );
|
76 |
+
}
|
77 |
+
|
78 |
+
// Create and test the performance of the thread-safe arrays
|
79 |
+
int result = test_arrays(&shared);
|
80 |
+
|
81 |
+
// Destroy the arrays
|
82 |
+
if ( shared.tested_array == 1 )
|
83 |
+
array_mutex_destroy(shared.mutex_array);
|
84 |
+
else
|
85 |
+
array_rwlock_destroy(shared.rwlock_array);
|
86 |
+
|
87 |
+
return result;
|
88 |
}
|
89 |
|
90 |
+
int test_arrays(shared_t* shared)
|
91 |
{
|
92 |
+
// Init pseudo-random number generator
|
93 |
srand( (unsigned)((unsigned)time(NULL) + (unsigned)clock()) );
|
94 |
|
95 |
+
// Create threads and their data
|
96 |
+
pthread_t* threads = (pthread_t*) malloc( shared->worker_count * sizeof(pthread_t) );
|
97 |
+
thread_data_t* thread_data = (thread_data_t*) malloc( shared->worker_count * sizeof(thread_data_t) );
|
98 |
|
99 |
+
// Start the asked number of threads
|
100 |
+
for ( size_t current = 0; current < shared->worker_count; ++current )
|
101 |
+
{
|
102 |
+
thread_data[current].worker_id = current;
|
103 |
+
thread_data[current].shared = shared;
|
104 |
+
pthread_create( threads + current, NULL, test_array, thread_data + current );
|
105 |
+
}
|
106 |
|
107 |
+
// Wait for all threads to finish
|
108 |
+
for ( size_t current = 0; current < shared->worker_count; ++current )
|
109 |
pthread_join( threads[current], NULL );
|
110 |
|
111 |
+
// Release threads and their data
|
112 |
+
free(thread_data);
|
113 |
free(threads);
|
114 |
+
|
115 |
+
// print_array("array1", shared->mutex_array);
|
116 |
+
// print_array("array2", shared->rwlock_array);
|
117 |
+
|
118 |
+
return 0;
|
119 |
}
|
120 |
|
121 |
void* test_array(void* data)
|
122 |
{
|
123 |
+
// Unpack the data
|
124 |
+
thread_data_t* thread_data = (thread_data_t*)data;
|
125 |
+
shared_t* shared = thread_data->shared;
|
126 |
+
|
127 |
+
// Slice the operations among the threads
|
128 |
+
size_t my_operations = shared->operation_count / shared->worker_count
|
129 |
+
+ (thread_data->worker_id < shared->operation_count % shared->worker_count);
|
130 |
+
|
131 |
+
// Execute the asked number of operations
|
132 |
+
for ( size_t operation = 0; operation < my_operations; ++operation )
|
133 |
+
{
|
134 |
+
// Get a random number to insert, find, or delete from array
|
135 |
+
size_t element = rand() % 100;
|
136 |
+
|
137 |
+
// Get a random percent to choose the operation to execute
|
138 |
+
size_t random_op = (size_t)rand() % shared->operation_count;
|
139 |
|
140 |
+
// Execute the operation according to the percents
|
141 |
+
if ( random_op < shared->insertion_percent * shared->operation_count )
|
142 |
{
|
143 |
+
// Insert an element into the tested array
|
144 |
+
shared->tested_array == 1
|
145 |
+
? array_mutex_append( shared->mutex_array, (void*)(element) )
|
146 |
+
: array_rwlock_append( shared->rwlock_array, (void*)(element) );
|
147 |
+
}
|
148 |
+
else if ( random_op < shared->deletion_percent * shared->operation_count )
|
149 |
+
{
|
150 |
+
// Remove an element in the tested array
|
151 |
+
shared->tested_array == 1
|
152 |
+
? array_mutex_remove_first(shared->mutex_array, (void*)(element), 0)
|
153 |
+
: array_rwlock_remove_first(shared->rwlock_array, (void*)(element), 0);
|
154 |
+
}
|
155 |
else
|
156 |
{
|
157 |
+
// Search an element in the tested array
|
158 |
+
shared->tested_array == 1
|
159 |
+
? array_mutex_find_first(shared->mutex_array, (void*)(element), 0)
|
160 |
+
: array_rwlock_find_first(shared->rwlock_array, (void*)(element), 0);
|
161 |
}
|
162 |
}
|
163 |
|
164 |
return NULL;
|
165 |
}
|
166 |
+
|
167 |
+
void print_array(const char* name, array_mutex_t* array)
|
168 |
+
{
|
169 |
+
printf("%s: %zu elements\n", name, array_mutex_get_count(array));
|
170 |
+
fflush(stdout);
|
171 |
+
}
|