-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpsort.c
More file actions
executable file
·296 lines (248 loc) · 7.81 KB
/
Copy pathpsort.c
File metadata and controls
executable file
·296 lines (248 loc) · 7.81 KB
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
////////////////////////////////////////////////////////////////////////////////
// Main File: psort.c
// This File: psort.c
// Other Files: none
// Semester: CS 537 Spring 2023
// Instructor: Shivaram
//
// Author: Zelong Jiang, Dipaksi Attraya
// Email: zjiang287@wisc.edu, attraya@wisc.edu
// CS Login: zjiang, dipaksi
//
/////////////////////////// OTHER SOURCES OF HELP //////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/types.h>
#include <pthread.h>
#include <sys/time.h>
#define RECORD_SIZE 100
typedef struct{
int key;
int data[24];
}Record; // a structure that stores the key and value of the record
int num_records;
// swap two record elements
void swap(Record** a, Record** b) {
Record* t = *a;
*a = *b;
*b = t;
}
// partition the records from l to h (inclusive)
// the elements that are smaller than pivot are on the left side of the pivot
// the elements that are greater than or equal to pivot are on the right side of the pivot
int partition(Record** records, int l, int h) {
int pivot = records[h]->key;
//printf("pivot %d\n", pivot);
int i = (l - 1);
for (int j = l; j <= h - 1; j++) {
if (records[j]->key < pivot) {
i++;
swap(&records[i], &records[j]);
}
}
swap(&records[i + 1], &records[h]);
return (i + 1); // return the position of the pivot
}
// sort the record from l to h (inclusive)
void quicksort(Record** records, int l, int h) {
//printf("low: %d, high %d\n", l, h);
if (l < h) {
int pi = partition(records, l, h);
quicksort(records, l, pi - 1);
quicksort(records, pi + 1, h);
}
}
typedef struct{
Record** records;
int l;
int h;
}thread_data; //single thread sorting arguments
void *thread_function(void* args) // thread sorting function
{
thread_data * my_data = (thread_data *) args;
quicksort(my_data->records, my_data->l, my_data->h);
return NULL;
}
typedef struct{
Record** records;
int l1;
int l2;
int h;
}merge_thread_data; // thread merging function arguments
/*
* merge the records,
* the first half starts from l1
* the second half starts from l2, end at h (inclusive)
* */
void merge_in_thread(Record **records, int l1, int l2, int h)
{
int index = 0, left = l1, right = l2;
Record **temp_records = malloc((h - l1 + 1) * sizeof(Record*));
while(left < l2 && right <= h)
{
if(records[left]->key <= records[right]->key)
{
//printf("%d ", records[left].key);
temp_records[index++] = records[left++];
}
else
{
//printf("%d ", records[right].key);
temp_records[index++] = records[right++];
}
}
if(left == l2)
{
for(int i=0; i<index; i++)
records[i+l1] = temp_records[i];
}
else
{
int j = h;
for(int i=l2-1; i>=left; i--)
records[j--] = records[i];
for(int i=0; i<index; i++)
records[i+l1] = temp_records[i];
}
// printf("\n");
}
void *merge_thread_function(void*args) // thread merging function
{
merge_thread_data * my_data = (merge_thread_data *) args;
merge_in_thread(my_data->records, my_data->l1, my_data->l2, my_data->h);
return NULL;
}
/*
* create multiple threads to merge the data
* each thread has length chunklength (the last thread may have fewer length)
* */
void merge(Record **records, int chunklength)
{
// printf("merge %d\n", chunklength);
int numThreads = num_records / chunklength + 1;
pthread_t threads[numThreads];
merge_thread_data threads_args[numThreads];
int start = 0;
// create merge threads
for (int i = 0; i < numThreads; i++) {
if(start >= num_records)
{
numThreads--;
break;
}
threads_args[i].records = records;
threads_args[i].l1 = start;
if(start + chunklength / 2 >= num_records)
{
numThreads--;
break;
}
threads_args[i].l2 = start + chunklength / 2;
if(start + chunklength - 1 >= num_records)
threads_args[i].h = num_records - 1;
else
threads_args[i].h = start + chunklength - 1;
// printf("thread %d, l1: %d, l2: %d, h: %d\n", i,threads_args[i].l1, threads_args[i].l2, threads_args[i].h);
pthread_create(&threads[i], NULL, merge_thread_function, (void *)&threads_args[i]);
start += chunklength;
}
// wait for threads to finish
for (int i = 0; i < numThreads; i++) {
pthread_join(threads[i], NULL);
}
}
int main(int argc, char **argv)
{
if(argc != 4) // check the argument count
{
fprintf(stderr, "Usage: ./psort input output 4");
exit(1);
}
FILE *input_file = fopen(argv[1], "r"); // open the input file
if(input_file == NULL)
{
fprintf(stderr, "Can't open input file %s!\n", argv[1]);
exit(1);
}
// Get the size of the input file
fseek(input_file, 0, SEEK_END);
long file_size = ftell(input_file);
fseek(input_file, 0, SEEK_SET);
// Calculate the number of records in the file
num_records = file_size / RECORD_SIZE;
Record **records = malloc(num_records * sizeof(Record*));
int num;
// Read in each record from the input file
for (int i = 0; i < num_records; i++) {
records[i] = malloc(sizeof(Record));
num = fread(&records[i]->key, sizeof(int), 1, input_file);
if(!num)
{
fclose(input_file);
}
num = fread(records[i]->data, sizeof(int), 24, input_file);
if(!num)
{
fclose(input_file);
}
}
fclose(input_file);
int numThreads = atoi(argv[3]); // get the number of threads
if(numThreads > num_records)
numThreads = num_records;
int chunklength = num_records / numThreads; // divide the input records to chunks
pthread_t threads[numThreads];
thread_data threads_args[numThreads];
int start = 0;
// variables that calculate the time
struct timeval tv;
struct timeval start_tv;
gettimeofday(&start_tv, NULL); // start the timer
double elapsed = 0.0;
// create threads, within each thread, a chunk of records are sorted
for (int i = 0; i < numThreads; i++) {
threads_args[i].records = records;
threads_args[i].l = start;
if(i < numThreads - 1)
threads_args[i].h = start + chunklength - 1;
else // the last thread may have a bigger chunk
threads_args[i].h = num_records - 1;
start += chunklength;
pthread_create(&threads[i], NULL, thread_function, (void *)&threads_args[i]);
}
// wait for threads to finish
for (int i = 0; i < numThreads; i++) {
pthread_join(threads[i], NULL);
}
//gettimeofday(&start_tv, NULL);
chunklength *= 2;
// merge the data
while(chunklength < num_records * 2)
{
merge(records, chunklength);
chunklength *= 2;
}
gettimeofday(&tv, NULL); // end the timer
elapsed = (tv.tv_sec - start_tv.tv_sec) + (tv.tv_usec - start_tv.tv_usec) / 1000000.0;
printf("time elapsed: %f\n", elapsed);
// output the records into the output file
FILE *output_file = fopen(argv[2], "w"); // open the output file
if(output_file == NULL)
{
fprintf(stderr, "Can't open output file %s!\n", argv[2]);
exit(1);
}
// write each record to the output file
for (int i = 0; i < num_records; i++) {
fwrite(&records[i]->key, sizeof(int), 1, output_file);
fwrite(records[i]->data, sizeof(int), 24, output_file);
}
fsync(fileno(output_file));
fclose(output_file);
return 0;
}