[PATCH 3/5] [RFC] Introduce multi-thread to string search

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



search_chars is different from search_ulong, search_uint and search_ushort.
The latter ones don't need to handle the page crossing, while search_chars
deals with string search, the strings can be longer than ulong/uint/ushort,
so page crossing should be handled in this case.

For the original single thread version of search_chars, at the end of each
pagebuf string match, a hit record with chars location is kept, and will be
used for string match at the start of next pagebuf processing. Since it only
handles the page crossing between 2 pages, one cross_match struct is enough
for the work.

For the multithread version of search_chars, the situation is a bit more
complex. e.g. we have 4 search_chars threads, and 100 pagebufs per zone.
Threads 1 handles page 1~25, thread 2 handles page 26~50, thread 3 handles page
51~75, thread 4 handles page 76~100. For each thread, the page crossing is
handled as usual, and a copy of the first page is kept as reserved page.

The cases which should be handled specifically are 25~26, 50~51, 75~76, 100~101
page crossing. The last finished thread is responsible to use the final hit
record of thread 1, aka page 25, against the reserved page of thread 2, aka
page 26. Same as 50~51 and 75~76 page crossing. Then the final hit record of
thread 4, aka page 100, is copied to thread 1, which will later be used against
page 101 of next zone processing. In this case, 4 cross_match_para struct is
used for 4 threads page crossing.

Signed-off-by: Tao Liu <ltao@xxxxxxxxxx>
---
 memory.c | 334 ++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 243 insertions(+), 91 deletions(-)

diff --git a/memory.c b/memory.c
index 75112d7..024eccc 100644
--- a/memory.c
+++ b/memory.c
@@ -249,11 +249,11 @@ static void display_with_pre_and_post(void *, ulonglong, struct searchinfo *);
 static ulong search_ulong(ulong *, ulong, int, struct searchinfo *, struct searchinfo *, void *);
 static ulong search_uint(ulong *, ulong, int, struct searchinfo *, struct searchinfo *, void *);
 static ulong search_ushort(ulong *, ulong, int, struct searchinfo *, struct searchinfo *, void *);
-static ulong search_chars(ulong *, ulong, int, struct searchinfo *);
+static ulong search_chars(ulong *, ulong, int, struct searchinfo *, void *);
 static ulonglong search_ulong_p(ulong *, ulonglong, int, struct searchinfo *, void *);
 static ulonglong search_uint_p(ulong *, ulonglong, int, struct searchinfo *, void *);
 static ulonglong search_ushort_p(ulong *, ulonglong, int, struct searchinfo *, void *);
-static ulonglong search_chars_p(ulong *, ulonglong, int, struct searchinfo *);
+static ulonglong search_chars_p(ulong *, ulonglong, int, struct searchinfo *, void *);
 static void search_virtual(struct searchinfo *);
 static void search_physical(struct searchinfo *);
 static int next_upage(struct task_context *, ulong, ulong *);
@@ -328,6 +328,8 @@ static void dump_hstates(void);
 static void freelist_ptr_init(void);
 static ulong freelist_ptr(struct meminfo *, ulong, ulong);
 static ulong handle_each_vm_area(struct handle_each_vm_area_args *);
+static void clean_cross_para(int);
+static void cross_para_handle(ulong *, struct searchinfo *, int, char **, int *, int *);
 
 /*
  *  Memory display modes specific to this file.
@@ -15316,188 +15318,285 @@ typedef struct thread_data {
 	int thread_index;
 } thread_data_t;
 
+typedef struct cross_match_para {
+	struct search_arg {
+		int cnt;
+		ulong addr;
+		ulonglong addr_p;
+		char hit[BUFSIZE];
+	} search_arg[MAXARGS];
+	char *reserve_buf;
+	ulonglong reserve_buf_addr_p;
+	ulonglong cross_match_next_addr_p;
+	int thread_start_flag;
+} cross_para_t;
+cross_para_t *cross_para;
+
 static void
-report_match(struct searchinfo *si, ulong addr, char *ptr1, int len1, char *ptr2, int len2)
+report_match(struct searchinfo *si, ulong addr, char *ptr1, int len1,
+	     char *ptr2, int len2, char **out_buf, int *out_buf_size,
+	     int *out_buf_offset)
 {
 	int i;
+	char *tmp;
+	cache_output_t co = {
+		.output_buf = out_buf,
+		.output_buf_offset = out_buf_offset,
+		.output_buf_size = out_buf_size,
+	};
+
+	if (*out_buf_offset > (*out_buf_size >> 1)) {
+		tmp = *out_buf;
+		*out_buf_size <<= 1;
+		if ((*out_buf = malloc(*out_buf_size)) == NULL) {
+			error(FATAL, "cannot malloc more output buffer");
+		}
+		memcpy(*out_buf, tmp, *out_buf_offset);
+		free(tmp);
+	}
 
 	if (si->do_task_header) {
-		print_task_header(fp, si->task_context, si->tasks_found);
+		print_task_header_para(si->task_context, si->tasks_found, &co);
 		si->do_task_header = FALSE;
 		si->tasks_found++;
 	}
 
-	fprintf(fp, "%lx: ", addr);
+	*out_buf_offset += snprintf(*out_buf + *out_buf_offset,
+				*out_buf_size - *out_buf_offset, "%lx: ", addr);
 	for (i = 0; i < len1; i++) {
 		if (isprint(ptr1[i]))
-			fprintf(fp, "%c", ptr1[i]);
+			*out_buf_offset += snprintf(*out_buf + *out_buf_offset,
+						*out_buf_size - *out_buf_offset,
+						"%c", ptr1[i]);
 		else
-			fprintf(fp, ".");
+			*out_buf_offset += snprintf(*out_buf + *out_buf_offset,
+						*out_buf_size - *out_buf_offset,
+						".");
 	}
 	for (i = 0; i < len2; i++) {
 		if (isprint(ptr2[i]))
-			fprintf(fp, "%c", ptr2[i]);
+			*out_buf_offset += snprintf(*out_buf + *out_buf_offset,
+						*out_buf_size - *out_buf_offset,
+						"%c", ptr2[i]);
 		else
-			fprintf(fp, ".");
+			*out_buf_offset += snprintf(*out_buf + *out_buf_offset,
+						*out_buf_size - *out_buf_offset,
+						".");
 	}
-	fprintf(fp, "\n");	
+	*out_buf_offset += snprintf(*out_buf + *out_buf_offset,
+				*out_buf_size - *out_buf_offset, "\n");
 }
 	
 static ulong
-search_chars(ulong *bufptr, ulong addr, int longcnt, struct searchinfo *si)
+search_chars(ulong *bufptr, ulong addr, int longcnt,
+	     struct searchinfo *si, void *priv)
 {
 	int i, j;
 	int len;
 	char *target;
 	int charcnt = longcnt * sizeof(long);
 	char *ptr = (char *)bufptr;
+	thread_data_t *td = (thread_data_t *)priv;
+	int thread_index = td->thread_index;
 
-	/* is this the first page of this search? */
-	if (si->s_parms.s_chars.started_flag == 0) {
-		for (j = 0; j < si->vcnt; j++) {
-			cross[j].cnt = 0;   /* no hits */
-		}
-		cross_match_next_addr = (ulong)-1; /* no page match for first page */
-		si->s_parms.s_chars.started_flag++;
+	if ((cross_para[thread_index].cross_match_next_addr_p) == addr) {
+		cross_para_handle(bufptr, si, thread_index, &td->output_buf,
+				&td->output_buf_size, &td->output_buf_offset);
 	}
 
-	if (cross_match_next_addr == addr) {
-		for (j = 0; j < si->vcnt; j++) {
-			if (cross[j].cnt) {
-				target = si->s_parms.s_chars.value[j];
-				len = si->s_parms.s_chars.len[j];
-				for (i = 0; i < len - 1; i++) {
-					if (cross[j].hit[i] &&
-						!strncmp(&target[len - 1 - i], ptr, i + 1)) 
-							report_match(si, cross[j].addr + i, 
-									target, len,
-									&ptr[i+1], 
-									CHARS_CTX - len);
-				}
-			}
-		}
+	if (cross_para[thread_index].thread_start_flag) {
+		cross_para[thread_index].thread_start_flag = 0;
+		cross_para[thread_index].reserve_buf = ptr;
+		cross_para[thread_index].reserve_buf_addr_p = addr;
 	}
 
-	/* set up for possible cross matches on this page */
-	cross_match_next_addr = addr + charcnt;
+	// reset hit status
 	for (j = 0; j < si->vcnt; j++) {
 		len = si->s_parms.s_chars.len[j];
-		cross[j].cnt = 0;
-		cross[j].addr = addr + longcnt * sizeof(long) - (len - 1);
-		for (i = 0; i < len - 1; i++) 
-			cross[j].hit[i] = 0;
+		cross_para[thread_index].search_arg[j].cnt = 0;
+		cross_para[thread_index].search_arg[j].addr_p =
+			addr + longcnt * sizeof(long) - (len - 1);
+		for (i = 0; i < len - 1; i++)
+			cross_para[thread_index].search_arg[j].hit[i] = 0;
 	}
-	
-	for (i = 0; i < charcnt; i++, ptr++, addr++) {
+
+	for (i = 0; i < charcnt; i++, ptr++) {
 		for (j = 0; j < si->vcnt; j++) {
 			target = si->s_parms.s_chars.value[j];
 			len = si->s_parms.s_chars.len[j];
 			if ((i + len) > charcnt) {
 				/* check for cross match */
 				if (!strncmp(target, ptr, charcnt - i)) {
-					cross[j].hit[len + i - charcnt - 1] = 1;
-					cross[j].cnt++;
-				} 
+					cross_para[thread_index].search_arg[j]
+						.hit[len + i - charcnt - 1] = 1;
+					cross_para[thread_index].search_arg[j].cnt++;
+				}
 			} else {
 				if (!strncmp(target, ptr, len)) {
 					int slen = CHARS_CTX;
 					if ((i + CHARS_CTX) > charcnt) 
 						slen = charcnt - i;
-					report_match(si, addr, ptr, slen, (char *)0, 0);
+					report_match(si,
+						addr + i, ptr, slen, NULL, 0,
+						&td->output_buf,
+						&td->output_buf_size,
+						&td->output_buf_offset
+					);
 				}
 			}
 		}
 	}
-	return addr;
+	cross_para[thread_index].cross_match_next_addr_p = addr + charcnt;
+	return addr + charcnt;
 }
 						
 
 static void
-report_match_p(ulonglong addr, char *ptr1, int len1, char *ptr2, int len2)
+report_match_p(ulonglong addr, char *ptr1, int len1, char *ptr2,
+		int len2, char **out_buf, int *out_buf_size,
+		int *out_buf_offset)
 {
 	int i;
-	fprintf(fp, "%llx: ", addr);
+	char *tmp;
+
+	if (*out_buf_offset > (*out_buf_size >> 1)) {
+		tmp = *out_buf;
+		*out_buf_size <<= 1;
+		if ((*out_buf = malloc(*out_buf_size)) == NULL) {
+			error(FATAL, "cannot malloc more output buffer");
+		}
+		memcpy(*out_buf, tmp, *out_buf_offset);
+		free(tmp);
+	}
+
+	*out_buf_offset += snprintf(*out_buf + *out_buf_offset,
+				*out_buf_size - *out_buf_offset, "%llx: ", addr);
 	for (i = 0; i < len1; i++) {
 		if (isprint(ptr1[i]))
-			fprintf(fp, "%c", ptr1[i]);
+			*out_buf_offset += snprintf(*out_buf + *out_buf_offset,
+						*out_buf_size - *out_buf_offset,
+						"%c", ptr1[i]);
 		else
-			fprintf(fp, ".");
+			*out_buf_offset += snprintf(*out_buf + *out_buf_offset,
+						*out_buf_size - *out_buf_offset,
+						".");
 	}
 	for (i = 0; i < len2; i++) {
 		if (isprint(ptr2[i]))
-			fprintf(fp, "%c", ptr2[i]);
+			*out_buf_offset += snprintf(*out_buf + *out_buf_offset,
+						*out_buf_size - *out_buf_offset,
+						"%c", ptr2[i]);
 		else
-			fprintf(fp, ".");
+			*out_buf_offset += snprintf(*out_buf + *out_buf_offset,
+						*out_buf_size - *out_buf_offset,
+						".");
+	}
+	*out_buf_offset += snprintf(*out_buf + *out_buf_offset,
+				*out_buf_size - *out_buf_offset, "\n");
+}
+
+static void
+cross_para_handle(ulong *bufptr, struct searchinfo *si,
+		int thread_index, char **output_buf,
+		int *output_buf_size, int *output_buf_offset)
+{
+	int i, j;
+	int len;
+	char *target;
+	char *ptr = (char *)bufptr;
+
+	for (j = 0; j < si->vcnt; j++) {
+		if (cross_para[thread_index].search_arg[j].cnt) {
+			target = si->s_parms.s_chars.value[j];
+			len = si->s_parms.s_chars.len[j];
+			for (i = 0; i < len - 1; i++) {
+				if (cross_para[thread_index].search_arg[j].hit[i] &&
+					!strncmp(&target[len - 1 - i], ptr, i + 1))
+						report_match_p(
+						    cross_para[thread_index]
+							.search_arg[j].addr_p + i,
+						    target, len,
+						    &ptr[i + 1], CHARS_CTX - len,
+						    output_buf,
+						    output_buf_size,
+						    output_buf_offset);
+			}
+		}
 	}
-	fprintf(fp, "\n");	
 }
 
 static ulonglong
-search_chars_p(ulong *bufptr, ulonglong addr_p, int longcnt, struct searchinfo *si)
+search_chars_p(ulong *bufptr, ulonglong addr_p, int longcnt,
+		struct searchinfo *si, void *priv)
 {
 	int i, j;
 	int len;
 	char *target;
 	int charcnt = longcnt * sizeof(long);
 	char *ptr = (char *)bufptr;
+	thread_data_t *td = (thread_data_t *)priv;
+	int thread_index = td->thread_index;
 
-	/* is this the first page of this search? */
-	if (si->s_parms.s_chars.started_flag == 0) {
-		for (j = 0; j < si->vcnt; j++) {
-			cross[j].cnt = 0;   /* no hits */
-		}
-		cross_match_next_addr_p = (ulonglong)-1; /* no page match for first page */
-		si->s_parms.s_chars.started_flag++;
+	if ((cross_para[thread_index].cross_match_next_addr_p) == addr_p) {
+		cross_para_handle(bufptr, si, thread_index,
+				&td->output_buf, &td->output_buf_size,
+				&td->output_buf_offset);
 	}
 
-	if (cross_match_next_addr_p == addr_p) {
-		for (j = 0; j < si->vcnt; j++) {
-			if (cross[j].cnt) {
-				target = si->s_parms.s_chars.value[j];
-				len = si->s_parms.s_chars.len[j];
-				for (i = 0; i < len - 1; i++) {
-					if (cross[j].hit[i] &&
-						!strncmp(&target[len - 1 - i], ptr, i + 1)) 
-							report_match_p(cross[j].addr_p + i, 
-									target, len,
-									&ptr[i+1], 
-									CHARS_CTX - len);
-				}
-			}
-		}
+	if (cross_para[thread_index].thread_start_flag) {
+		cross_para[thread_index].thread_start_flag = 0;
+		cross_para[thread_index].reserve_buf = ptr;
+		cross_para[thread_index].reserve_buf_addr_p = addr_p;
 	}
 
-	/* set up for possible cross matches on this page */
-	cross_match_next_addr_p = addr_p + charcnt;
+	// reset hit status
 	for (j = 0; j < si->vcnt; j++) {
 		len = si->s_parms.s_chars.len[j];
-		cross[j].cnt = 0;
-		cross[j].addr_p = addr_p + longcnt * sizeof(long) - (len - 1);
-		for (i = 0; i < len - 1; i++) 
-			cross[j].hit[i] = 0;
+		cross_para[thread_index].search_arg[j].cnt = 0;
+		cross_para[thread_index].search_arg[j].addr_p =
+			addr_p + longcnt * sizeof(long) - (len - 1);
+		for (i = 0; i < len - 1; i++)
+			cross_para[thread_index].search_arg[j].hit[i] = 0;
 	}
-	
-	for (i = 0; i < charcnt; i++, ptr++, addr_p++) {
+
+	for (i = 0; i < charcnt; i++, ptr++) {
 		for (j = 0; j < si->vcnt; j++) {
 			target = si->s_parms.s_chars.value[j];
 			len = si->s_parms.s_chars.len[j];
 			if ((i + len) > charcnt) {
 				/* check for cross match */
 				if (!strncmp(target, ptr, charcnt - i)) {
-					cross[j].hit[len + i - charcnt - 1] = 1;
-					cross[j].cnt++;
-				} 
+					cross_para[thread_index].search_arg[j]
+						.hit[len + i - charcnt - 1] = 1;
+					cross_para[thread_index].search_arg[j].cnt++;
+				}
 			} else {
 				if (!strncmp(target, ptr, len)) {
 					int slen = CHARS_CTX;
 					if ((i + CHARS_CTX) > charcnt) 
 						slen = charcnt - i;
-					report_match_p(addr_p, ptr, slen, (char *)0, 0);
+					report_match_p(
+						addr_p + i, ptr, slen, NULL, 0,
+						&td->output_buf,
+						&td->output_buf_size,
+						&td->output_buf_offset
+					);
 				}
 			}
 		}
 	}
-	return addr_p;
+	cross_para[thread_index].cross_match_next_addr_p = addr_p + charcnt;
+	return addr_p + charcnt;
+}
+
+static void
+clean_cross_para(int i)
+{
+	memset(&cross_para[i].search_arg[0], 0,
+		sizeof(cross_para[i].search_arg));
+	cross_para[i].reserve_buf_addr_p = (ulonglong)-1;
+	cross_para[i].cross_match_next_addr_p = (ulonglong)-1;
+	cross_para[i].thread_start_flag = 1;
 }
 
 static void *
@@ -15558,7 +15657,8 @@ do_search_virtual(void *args)
 						     &si, td->si, &cache_output);
 				break;
 			case SEARCH_CHARS:
-				next = search_chars(ubp, next, wordcnt, si);
+				next = search_chars(ubp, next, wordcnt,
+						    &si, td);
 				break;
 			default:
 				/* unimplemented search type */
@@ -15569,6 +15669,28 @@ do_search_virtual(void *args)
 		pthread_mutex_lock(td->finished_thread_count_mutex);
 		if (++(*td->finished_thread_count) == si.thread_num) {
 			pthread_mutex_unlock(td->finished_thread_count_mutex);
+			if (td->si->mode == SEARCH_CHARS) {
+				for (i = 0; i < si.thread_num - 1; i++) {
+					if (cross_para[i].cross_match_next_addr_p ==
+					    cross_para[i + 1].reserve_buf_addr_p) {
+						cross_para_handle(
+							(ulong *)cross_para[i + 1].reserve_buf,
+							&si, i, &(td->td + i)->output_buf,
+							&(td->td + i)->output_buf_size,
+							&(td->td + i)->output_buf_offset
+						);
+					}
+					clean_cross_para(i);
+				}
+				memcpy(&cross_para[0].search_arg[0],
+					&cross_para[i].search_arg[0],
+					sizeof(cross_para[i].search_arg));
+				cross_para[0].cross_match_next_addr_p =
+					cross_para[i].cross_match_next_addr_p;
+				cross_para[0].thread_start_flag = 1;
+				if (i > 0)
+					clean_cross_para(i);
+			}
 			for (i = 0; i < si.thread_num; i++) {
 				fprintf(fp, "%s", (td->td + i)->output_buf);
 				*((td->td + i)->output_buf) = '\0';
@@ -15620,6 +15742,7 @@ search_virtual(struct searchinfo *si)
 	// Alloc buffers
 	page_buf = (page_buf_t *)GETBUF(sizeof(page_buf_t) *
 		si->page_buf_zone_num * page_buf_num_per_zone);
+	cross_para = (cross_para_t *)GETBUF(sizeof(cross_para_t) * thread_num);
 	threads = (pthread_t *)GETBUF(sizeof(pthread_t) * thread_num);
 	td = (thread_data_t *)GETBUF(sizeof(thread_data_t) * thread_num);
 	memset(threads, 0, sizeof(sizeof(pthread_t) * thread_num));
@@ -15660,6 +15783,7 @@ search_virtual(struct searchinfo *si)
 		memset(td[i].start, 0, sizeof(int) * si->page_buf_zone_num * 3);
 
 		td[i].thread_index = i;
+		clean_cross_para(i);
 
 		pthread_create(&threads[i], NULL, do_search_virtual, &td[i]);
 	}
@@ -15759,6 +15883,7 @@ done:
 		free(td[i].output_buf);
 		FREEBUF(td[i].start);
 	}
+	FREEBUF(cross_para);
 	for (i = 0; i < si->page_buf_zone_num * page_buf_num_per_zone; i++) {
 		FREEBUF(((struct page_buf *)page_buf + i)->pagebuf);
 	}
@@ -15834,7 +15959,8 @@ do_search_physical(void *args)
 							&si, &cache_output);
 				break;
 			case SEARCH_CHARS:
-				pnext = search_chars_p(ubp, pnext, wordcnt, si);
+				pnext = search_chars_p(ubp, pnext, wordcnt,
+							&si, td);
 				break;
 			default:
 				/* unimplemented search type */
@@ -15846,6 +15972,29 @@ do_search_physical(void *args)
 		if (++(*td->finished_thread_count) == si.thread_num) {
 			pthread_mutex_unlock(td->finished_thread_count_mutex);
 
+			if (td->si->mode == SEARCH_CHARS) {
+				for (i = 0; i < si.thread_num - 1; i++) {
+					if (cross_para[i].cross_match_next_addr_p ==
+					    cross_para[i + 1].reserve_buf_addr_p) {
+						cross_para_handle(
+							(ulong *)cross_para[i + 1].reserve_buf,
+							&si, i, &(td->td + i)->output_buf,
+							&(td->td + i)->output_buf_size,
+							&(td->td + i)->output_buf_offset
+						);
+					}
+					clean_cross_para(i);
+				}
+				memcpy(&cross_para[0].search_arg[0],
+					&cross_para[i].search_arg[0],
+					sizeof(cross_para[i].search_arg));
+				cross_para[0].cross_match_next_addr_p =
+					cross_para[i].cross_match_next_addr_p;
+				cross_para[0].thread_start_flag = 1;
+				if (i > 0)
+					clean_cross_para(i);
+			}
+
 			for (i = 0; i < si.thread_num; i++) {
 				fprintf(fp, "%s", (td->td + i)->output_buf);
 				*((td->td + i)->output_buf) = '\0';
@@ -15896,6 +16045,7 @@ search_physical(struct searchinfo *si)
 	// Alloc buffers
 	page_buf = (page_buf_t *)GETBUF(sizeof(page_buf_t) *
 		si->page_buf_zone_num * page_buf_num_per_zone);
+	cross_para = (cross_para_t *)GETBUF(sizeof(cross_para_t) * thread_num);
 	threads = (pthread_t *)GETBUF(sizeof(pthread_t) * thread_num);
 	td = (thread_data_t *)GETBUF(sizeof(thread_data_t) * thread_num);
 	memset(td, 0, sizeof(thread_data_t) * thread_num);
@@ -15936,6 +16086,7 @@ search_physical(struct searchinfo *si)
 		memset(td[i].start, 0, sizeof(int) * si->page_buf_zone_num * 3);
 
 		td[i].thread_index = i;
+		clean_cross_para(i);
 
 		pthread_create(&threads[i], NULL, do_search_physical, &td[i]);
 	}
@@ -16000,6 +16151,7 @@ search_physical(struct searchinfo *si)
 		free(td[i].output_buf);
 		FREEBUF(td[i].start);
 	}
+	FREEBUF(cross_para);
 	for (i = 0; i < si->page_buf_zone_num * page_buf_num_per_zone; i++) {
 		FREEBUF(((struct page_buf *)page_buf + i)->pagebuf);
 	}
-- 
2.33.1

--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://listman.redhat.com/mailman/listinfo/crash-utility
Contribution Guidelines: https://github.com/crash-utility/crash/wiki




[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux