Browse code

Replace k-way-merge with 2-way merge

John Hawthorn authored on 15/01/2017 05:46:55
Showing 1 changed files

... ...
@@ -140,6 +140,11 @@ size_t choices_available(choices_t *c) {
140 140
 
141 141
 #define BATCH_SIZE 512
142 142
 
143
+struct result_list {
144
+	struct scored_result *list;
145
+	size_t size;
146
+};
147
+
143 148
 struct search_job {
144 149
 	pthread_mutex_t lock;
145 150
 	choices_t *choices;
... ...
@@ -199,40 +204,57 @@ static void *choices_search_worker(void *data) {
199 204
 	return w;
200 205
 }
201 206
 
202
-static void merge_step(struct search_job *job, struct worker *all_workers) {
203
-	/* Merge our sorted partial-results */
204
-	choices_t *c = job->choices;
205
-	size_t worker_count = 0;
206
-	struct worker *workers[c->worker_count];
207
-	size_t indexes[c->worker_count];
207
+static struct result_list merge2(struct result_list list1, struct result_list list2) {
208
+	size_t result_index = 0, index1 = 0, index2 = 0;
208 209
 
209
-	for (unsigned int w = 0; w < c->worker_count; w++) {
210
-		indexes[w] = 0;
211
-		if (all_workers[w].available) {
212
-			workers[worker_count++] = &all_workers[w];
213
-		}
210
+	struct result_list result;
211
+	result.size = list1.size + list2.size;
212
+	result.list = malloc(result.size * sizeof(struct scored_result));
213
+	if (!result.list) {
214
+		fprintf(stderr, "Error: Can't allocate memory\n");
215
+		abort();
214 216
 	}
215 217
 
216
-	while (worker_count) {
217
-		/* Loop over each sorted block to find the lowest scoring result */
218
-		unsigned int min_w = 0;
219
-		for (unsigned int w = 0; w < worker_count; w++) {
220
-			if (cmpchoice(&workers[w]->results[indexes[w]], &workers[min_w]->results[indexes[min_w]]) < 0) {
221
-				min_w = w;
222
-			}
218
+	while(index1 < list1.size && index2 < list2.size) {
219
+		if (cmpchoice(&list1.list[index1], &list2.list[index2]) < 0) {
220
+			result.list[result_index++] = list1.list[index1++];
221
+		} else {
222
+			result.list[result_index++] = list2.list[index2++];
223 223
 		}
224
+	}
224 225
 
225
-		/* Move that result onto our global list */
226
-		c->results[c->available++] = workers[min_w]->results[indexes[min_w]++];
226
+	while(index1 < list1.size) {
227
+		result.list[result_index++] = list1.list[index1++];
228
+	}
229
+	while(index2 < list2.size) {
230
+		result.list[result_index++] = list2.list[index2++];
231
+	}
227 232
 
228
-		/* If we have merged all the results for this worker, shuffle it
229
-		 * out of our list */
230
-		if (indexes[min_w] == workers[min_w]->available) {
231
-			indexes[min_w] = indexes[worker_count - 1];
232
-			workers[min_w] = workers[worker_count - 1];
233
-			worker_count--;
234
-		}
233
+	free(list1.list);
234
+	free(list2.list);
235
+
236
+	return result;
237
+}
238
+
239
+static void merge_step(struct search_job *job, struct worker *workers) {
240
+	/* Merge our sorted partial-results */
241
+	choices_t *c = job->choices;
242
+
243
+	struct result_list result = {NULL, 0};
244
+
245
+	for (unsigned int w = 0; w < c->worker_count; w++) {
246
+		struct result_list new_result;
247
+		struct worker *worker = &workers[w];
248
+
249
+		struct result_list worker_result = {worker->results, worker->available};
250
+		new_result = merge2(result, worker_result);
251
+
252
+		free(result.list);
253
+		result = new_result;
235 254
 	}
255
+
256
+	c->results = result.list;
257
+	c->available = result.size;
236 258
 }
237 259
 
238 260
 void choices_search(choices_t *c, const char *search) {
... ...
@@ -246,13 +268,6 @@ void choices_search(choices_t *c, const char *search) {
246 268
 		abort();
247 269
 	}
248 270
 
249
-	/* allocate storage for our results */
250
-	c->results = malloc(c->size * sizeof(struct scored_result));
251
-	if (!c->results) {
252
-		fprintf(stderr, "Error: Can't allocate memory\n");
253
-		abort();
254
-	}
255
-
256 271
 	struct worker *workers = calloc(c->worker_count, sizeof(struct worker));
257 272
 	for (unsigned int i = 0; i < c->worker_count; i++) {
258 273
 		workers[i].job = job;