[PATCH v2] Improve the performance of --num-threads -d 31

Minoru Usui min-usui at ti.jp.nec.com
Tue Feb 23 00:00:24 PST 2016


 Hi,

> -----Original Message-----
> From: "Zhou, Wenjian/周文?" [mailto:zhouwj-fnst at cn.fujitsu.com]
> Sent: Tuesday, February 23, 2016 12:45 PM
> To: Usui Minoru(碓井 成) <min-usui at ti.jp.nec.com>; kexec at lists.infradead.org
> Subject: Re: [PATCH v2] Improve the performance of --num-threads -d 31
> 
> Hello Usui,
> 
> On 02/23/2016 09:32 AM, Minoru Usui wrote:
> > Hello, Zhou
> >
> > Thank you for reflecting my comments.
> > I have other comments.
> >
> > See below.
> >
> >> -----Original Message-----
> >> From: kexec [mailto:kexec-bounces at lists.infradead.org] On Behalf Of Zhou Wenjian
> >> Sent: Wednesday, February 17, 2016 4:06 PM
> >> To: kexec at lists.infradead.org
> >> Subject: [PATCH v2] Improve the performance of --num-threads -d 31
> >>
> >> v2:
> >>          1. address Minoru Usui's comments about magic number and error message
> >>          2. fix a bug in cyclic mode caused by optimizing
> >>
> >> v1:
> >>          1. change page_flag.ready's value to enum
> >>          2. change the patch description
> >>          3. cleanup some codes
> >>          4. fix a bug in cyclic mode
> >>
> >> multi-threads implementation will introduce extra cost when handling
> >> each page. The origin implementation will also do the extra work for
> >> filtered pages. So there is a big performance degradation in
> >> --num-threads -d 31.
> >> The new implementation won't do the extra work for filtered pages any
> >> more. So the performance of -d 31 is close to that of serial processing.
> >>
> >> The new implementation is just like the following:
> >>          * The basic idea is producer producing page and consumer writing page.
> >>          * Each producer have a page_flag_buf list which is used for storing
> >>            page's description.
> >>          * The size of page_flag_buf is little so it won't take too much memory.
> >>          * And all producers will share a page_data_buf array which is
> >>            used for storing page's compressed data.
> >>          * The main thread is the consumer. It will find the next pfn and write
> >>            it into file.
> >>          * The next pfn is smallest pfn in all page_flag_buf.
> >>
> >> Signed-off-by: Zhou Wenjian <zhouwj-fnst at cn.fujitsu.com>
> >> ---
> >>   makedumpfile.c | 266 ++++++++++++++++++++++++++++++++++++++-------------------
> >>   makedumpfile.h |  31 ++++---
> >>   2 files changed, 200 insertions(+), 97 deletions(-)
> >>
> >> diff --git a/makedumpfile.c b/makedumpfile.c
> >> index fa0b779..31329b5 100644
> >> --- a/makedumpfile.c
> >> +++ b/makedumpfile.c
> >> @@ -3483,7 +3483,8 @@ initial_for_parallel()
> >>   	unsigned long page_data_buf_size;
> >>   	unsigned long limit_size;
> >>   	int page_data_num;
> >> -	int i;
> >> +	struct page_flag *current;
> >> +	int i, j;
> >>
> >>   	len_buf_out = calculate_len_buf_out(info->page_size);
> >>
> >> @@ -3562,8 +3563,10 @@ initial_for_parallel()
> >>   		      - MAP_REGION * info->num_threads) * 0.6;
> >>
> >>   	page_data_num = limit_size / page_data_buf_size;
> >> +	info->num_buffers = 3 * info->num_threads;
> >>
> >> -	info->num_buffers = MIN(NUM_BUFFERS, page_data_num);
> >> +	info->num_buffers = MAX(info->num_buffers, NUM_BUFFERS);
> >> +	info->num_buffers = MIN(info->num_buffers, page_data_num);
> >>
> >>   	DEBUG_MSG("Number of struct page_data for produce/consume: %d\n",
> >>   			info->num_buffers);
> >> @@ -3588,6 +3591,36 @@ initial_for_parallel()
> >>   	}
> >>
> >>   	/*
> >> +	 * initial page_flag for each thread
> >> +	 */
> >> +	if ((info->page_flag_buf = malloc(sizeof(void *) * info->num_threads))
> >> +	    == NULL) {
> >> +		MSG("Can't allocate memory for page_flag_buf. %s\n",
> >> +				strerror(errno));
> >> +		return FALSE;
> >> +	}
> >> +	memset(info->page_flag_buf, 0, sizeof(void *) * info->num_threads);
> >> +
> >> +	for (i = 0; i < info->num_threads; i++) {
> >> +		if ((info->page_flag_buf[i] = calloc(1, sizeof(struct page_flag))) == NULL) {
> >> +			MSG("Can't allocate memory for page_flag. %s\n",
> >> +				strerror(errno));
> >> +			return FALSE;
> >> +		}
> >> +		current = info->page_flag_buf[i];
> >> +
> >> +		for (j = 1; j < NUM_BUFFERS; j++) {
> >> +			if ((current->next = calloc(1, sizeof(struct page_flag))) == NULL) {
> >> +				MSG("Can't allocate memory for page_flag. %s\n",
> >> +					strerror(errno));
> >> +				return FALSE;
> >> +			}
> >> +			current = current->next;
> >> +		}
> >> +		current->next = info->page_flag_buf[i];
> >> +	}
> >> +
> >> +	/*
> >>   	 * initial fd_memory for threads
> >>   	 */
> >>   	for (i = 0; i < info->num_threads; i++) {
> >> @@ -3612,7 +3645,8 @@ initial_for_parallel()
> >>   void
> >>   free_for_parallel()
> >>   {
> >> -	int i;
> >> +	int i, j;
> >> +	struct page_flag *current;
> >>
> >>   	if (info->threads != NULL) {
> >>   		for (i = 0; i < info->num_threads; i++) {
> >> @@ -3655,6 +3689,19 @@ free_for_parallel()
> >>   		free(info->page_data_buf);
> >>   	}
> >>
> >> +	if (info->page_flag_buf != NULL) {
> >> +		for (i = 0; i < info->num_threads; i++) {
> >> +			for (j = 0; j < NUM_BUFFERS; j++) {
> >> +				if (info->page_flag_buf[i] != NULL) {
> >> +					current = info->page_flag_buf[i];
> >> +					info->page_flag_buf[i] = current->next;
> >> +					free(current);
> >> +				}
> >> +			}
> >> +		}
> >> +		free(info->page_flag_buf);
> >> +	}
> >> +
> >>   	if (info->parallel_info == NULL)
> >>   		return;
> >>
> >> @@ -7076,10 +7123,10 @@ kdump_thread_function_cyclic(void *arg) {
> >>   	void *retval = PTHREAD_FAIL;
> >>   	struct thread_args *kdump_thread_args = (struct thread_args *)arg;
> >>   	struct page_data *page_data_buf = kdump_thread_args->page_data_buf;
> >> +	struct page_flag *page_flag_buf = kdump_thread_args->page_flag_buf;
> >>   	struct cycle *cycle = kdump_thread_args->cycle;
> >> -	int page_data_num = kdump_thread_args->page_data_num;
> >> -	mdf_pfn_t pfn;
> >> -	int index;
> >> +	mdf_pfn_t pfn = cycle->start_pfn;
> >> +	int index = kdump_thread_args->thread_num;
> >>   	int buf_ready;
> >>   	int dumpable;
> >>   	int fd_memory = 0;
> >> @@ -7125,47 +7172,46 @@ kdump_thread_function_cyclic(void *arg) {
> >>   						kdump_thread_args->thread_num);
> >>   	}
> >>
> >> -	while (1) {
> >> -		/* get next pfn */
> >> -		pthread_mutex_lock(&info->current_pfn_mutex);
> >> -		pfn = info->current_pfn;
> >> -		info->current_pfn++;
> >> -		pthread_mutex_unlock(&info->current_pfn_mutex);
> >> +	/*
> >> +	 * filtered page won't take anything
> >> +	 * unfiltered zero page will only take a page_flag_buf
> >> +	 * unfiltered non-zero page will take a page_flag_buf and a page_data_buf
> >> +	 */
> >> +	while (pfn < kdump_thread_args->end_pfn) {
> >> +		buf_ready = FALSE;
> >>
> >> -		if (pfn >= kdump_thread_args->end_pfn)
> >> -			break;
> >> +		while (page_data_buf[index].used != FALSE ||
> >> +				pthread_mutex_trylock(&page_data_buf[index].mutex) != 0)
> >> +			index = (index + 1) % info->num_buffers;
> >> -		index = -1;
> >> -		buf_ready = FALSE;
> >> +		page_data_buf[index].used = TRUE;
> >>
> >>   		while (buf_ready == FALSE) {
> >>   			pthread_testcancel();
> >> -
> >> -			index = pfn % page_data_num;
> >> -
> >> -			if (pfn - info->consumed_pfn > info->num_buffers)
> >> -				continue;
> >> -
> >> -			if (page_data_buf[index].ready != 0)
> >> +			if (page_flag_buf->ready == FLAG_READY)
> >>   				continue;
> >>
> >> -			pthread_mutex_lock(&page_data_buf[index].mutex);
> >> -
> >> -			if (page_data_buf[index].ready != 0)
> >> -				goto unlock;
> >> +			/* get next pfn */
> >> +			pthread_mutex_lock(&info->current_pfn_mutex);
> >> +			pfn = info->current_pfn;
> >> +			info->current_pfn++;
> >> +			page_flag_buf->ready = FLAG_FILLING;
> >> +			pthread_mutex_unlock(&info->current_pfn_mutex);
> >>
> >> -			buf_ready = TRUE;
> >> +			page_flag_buf->pfn = pfn;
> >>
> >> -			page_data_buf[index].pfn = pfn;
> >> -			page_data_buf[index].ready = 1;
> >> +			if (pfn >= kdump_thread_args->end_pfn) {
> >> +				page_data_buf[index].used = FALSE;
> >> +				page_flag_buf->ready = FLAG_READY;
> >> +				break;
> >> +			}
> >>
> >>   			dumpable = is_dumpable(
> >>   				info->fd_bitmap ? &bitmap_parallel : info->bitmap2,
> >>   				pfn,
> >>   				cycle);
> >> -			page_data_buf[index].dumpable = dumpable;
> >>   			if (!dumpable)
> >> -				goto unlock;
> >> +				continue;
> >>
> >>   			if (!read_pfn_parallel(fd_memory, pfn, buf,
> >>   					       &bitmap_memory_parallel,
> >> @@ -7178,11 +7224,11 @@ kdump_thread_function_cyclic(void *arg) {
> >>
> >>   			if ((info->dump_level & DL_EXCLUDE_ZERO)
> >>   			    && is_zero_page(buf, info->page_size)) {
> >> -				page_data_buf[index].zero = TRUE;
> >> -				goto unlock;
> >> +				page_flag_buf->zero = TRUE;
> >> +				goto next;
> >>   			}
> >>
> >> -			page_data_buf[index].zero = FALSE;
> >> +			page_flag_buf->zero = FALSE;
> >>
> >>   			/*
> >>   			 * Compress the page data.
> >> @@ -7232,12 +7278,16 @@ kdump_thread_function_cyclic(void *arg) {
> >>   				page_data_buf[index].size  = info->page_size;
> >>   				memcpy(page_data_buf[index].buf, buf, info->page_size);
> >>   			}
> >> -unlock:
> >> -			pthread_mutex_unlock(&page_data_buf[index].mutex);
> >> +			page_flag_buf->index = index;
> >> +			buf_ready = TRUE;
> >> +next:
> >> +			page_flag_buf->ready = FLAG_READY;
> >> +			page_flag_buf = page_flag_buf->next;
> >>
> >>   		}
> >> -	}
> >>
> >> +		pthread_mutex_unlock(&page_data_buf[index].mutex);
> >> +	}
> >>   	retval = NULL;
> >>
> >>   fail:
> >> @@ -7265,14 +7315,15 @@ write_kdump_pages_parallel_cyclic(struct cache_data *cd_header,
> >>   	struct page_desc pd;
> >>   	struct timeval tv_start;
> >>   	struct timeval last, new;
> >> -	unsigned long long consuming_pfn;
> >>   	pthread_t **threads = NULL;
> >>   	struct thread_args *kdump_thread_args = NULL;
> >>   	void *thread_result;
> >> -	int page_data_num;
> >> +	int page_buf_num;
> >>   	struct page_data *page_data_buf = NULL;
> >>   	int i;
> >>   	int index;
> >> +	int end_count, consuming, check_count;
> >> +	mdf_pfn_t current_pfn, temp_pfn;
> >>
> >>   	if (info->flag_elf_dumpfile)
> >>   		return FALSE;
> >> @@ -7319,16 +7370,11 @@ write_kdump_pages_parallel_cyclic(struct cache_data *cd_header,
> >>   	threads = info->threads;
> >>   	kdump_thread_args = info->kdump_thread_args;
> >>
> >> -	page_data_num = info->num_buffers;
> >> +	page_buf_num = info->num_buffers;
> >>   	page_data_buf = info->page_data_buf;
> >>
> >> -	for (i = 0; i < page_data_num; i++) {
> >> -		/*
> >> -		 * producer will use pfn in page_data_buf to decide the
> >> -		 * consumed pfn
> >> -		 */
> >> -		page_data_buf[i].pfn = start_pfn - 1;
> >> -		page_data_buf[i].ready = 0;
> >> +	for (i = 0; i < page_buf_num; i++) {
> >> +		page_data_buf[i].used = FALSE;
> >>   		res = pthread_mutex_init(&page_data_buf[i].mutex, NULL);
> >>   		if (res != 0) {
> >>   			ERRMSG("Can't initialize mutex of page_data_buf. %s\n",
> >> @@ -7342,8 +7388,9 @@ write_kdump_pages_parallel_cyclic(struct cache_data *cd_header,
> >>   		kdump_thread_args[i].len_buf_out = len_buf_out;
> >>   		kdump_thread_args[i].start_pfn = start_pfn;
> >>   		kdump_thread_args[i].end_pfn = end_pfn;
> >> -		kdump_thread_args[i].page_data_num = page_data_num;
> >> +		kdump_thread_args[i].page_buf_num = page_buf_num;
> >>   		kdump_thread_args[i].page_data_buf = page_data_buf;
> >> +		kdump_thread_args[i].page_flag_buf = info->page_flag_buf[i];
> >>   		kdump_thread_args[i].cycle = cycle;
> >>
> >>   		res = pthread_create(threads[i], NULL,
> >> @@ -7356,55 +7403,101 @@ write_kdump_pages_parallel_cyclic(struct cache_data *cd_header,
> >>   		}
> >>   	}
> >>
> >> -	consuming_pfn = start_pfn;
> >> -	index = -1;
> >> +	end_count = 0;
> >> +	while (1) {
> >> +		consuming = 0;
> >> +		check_count = 0;
> >>
> >> -	gettimeofday(&last, NULL);
> >> +		/*
> >> +		 * The basic idea is producer producing page and consumer writing page.
> >> +		 * Each producer have a page_flag_buf list which is used for storing page's description.
> >> +		 * The size of page_flag_buf is little so it won't take too much memory.
> >> +		 * And all producers will share a page_data_buf array which is used for storing page's compressed data.
> >> +		 * The main thread is the consumer. It will find the next pfn and write it into file.
> >> +		 * The next pfn is smallest pfn in all page_flag_buf.
> >> +		 */
> >> +		gettimeofday(&last, NULL);
> >> +		while (1) {
> >> +			current_pfn = end_pfn;
> >>
> >> -	while (consuming_pfn < end_pfn) {
> >> -		index = consuming_pfn % page_data_num;
> >> +			/*
> >> +			 * page_flag_buf is in circular linked list.
> >> +			 * The array info->page_flag_buf[] records the current page_flag_buf in each thread's
> >> +			 * page_flag_buf list.
> >> +			 * consuming is used for recording in which thread the pfn is the smallest.
> >> +			 * current_pfn is used for recording the value of pfn when checking the pfn.
> >> +			 */
> >> +			for (i = 0; i < info->num_threads; i++) {
> >> +				if (info->page_flag_buf[i]->ready == FLAG_UNUSED)
> >> +					continue;
> >> +				temp_pfn = info->page_flag_buf[i]->pfn;
> >>
> >> -		gettimeofday(&new, NULL);
> >> -		if (new.tv_sec - last.tv_sec > WAIT_TIME) {
> >> -			ERRMSG("Can't get data of pfn %llx.\n", consuming_pfn);
> >> -			goto out;
> >> -		}
> >> +				/*
> >> +				 * count how many threads have reached the end.
> >> +				 */
> >> +				if (temp_pfn >= end_pfn) {
> >> +					/*
> >> +					 * prevent setting FLAG_UNUSED being optimized.
> >> +					 */
> >> +					MSG("-");
> >
> > Why does this line need?
> > Please clarify why FLAG_UNUSED is optimized.
> >
> 
> I tried but still can't figure out the reason or get better solution.
> I will be so happy if you can help me.
> 
> In gdb, I run it by step.
> The code "info->page_flag_buf[i]->ready = FLAG_UNUSED;" can never be reached.
> If a breakpoint is set here, the code will never be skipped.

On my environment, RHEL7.2, gdb stops at this line even if MSG("-") is deleted.
See below.

===
[root at ark crash]# gdb makedumpfile-code-3d32567394bac85ee3247780bfa41072b0d9bfe9/makedumpfile
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-80.el7                                           
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /work/crash/makedumpfile-code-3d32567394bac85ee3247780bfa41072b0d9bfe9/makedumpfile...done.
(gdb) set args -l -d0 --num-threads=2 ./vmcore ./vmcore.new.2                                 
(gdb) l 7780                                                                                  
7775                                    if (info->page_flag_buf[i]->ready == FLAG_UNUSED)
7776                                            continue;
7777                                    temp_pfn = info->page_flag_buf[i]->pfn;
7778    
7779                                    /*
7780                                     * count how many threads have reached the end.
7781                                     */
7782                                    if (temp_pfn >= end_pfn) {
7783                                            info->page_flag_buf[i]->ready = FLAG_UNUSED;
7784    
(gdb) b 7783
Breakpoint 1 at 0x433778: file makedumpfile.c, line 7783.
(gdb)
(gdb) run
Starting program: /work/crash/makedumpfile-code-3d32567394bac85ee3247780bfa41072b0d9bfe9/makedumpfile -l -d0 --num-threads=2 ./vmcore ./vmcore.new.2
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
The kernel version is not supported.
The makedumpfile operation may be incomplete.
Checking for memory holes          : [100.0 %] |[New Thread 0x7ffff6530700 (LWP 32123)]
[New Thread 0x7ffff5d2f700 (LWP 32124)]
Copying data                       : [ 98.8 %] |
Breakpoint 1, write_kdump_pages_parallel_cyclic (cd_header=<optimized out>, 
    cd_page=<optimized out>, pd_zero=<optimized out>, offset_data=<optimized out>, 
    cycle=<optimized out>) at makedumpfile.c:7783
7783                                            info->page_flag_buf[i]->ready = FLAG_UNUSED;
Missing separate debuginfos, use: debuginfo-install bzip2-libs-1.0.6-13.el7.x86_64 elfutils-libelf-0.163-3.el7.x86_64 elfutils-libs-0.163-3.el7.x86_64 glibc-2.17-105.el7.x86_64 lzo-2.06-8.el7.x86_64 xz-libs-5.1.2-12alpha.el7.x86_64 zlib-1.2.7-15.el7.x86_64
(gdb) bt
#0  write_kdump_pages_parallel_cyclic (cd_header=<optimized out>, cd_page=<optimized out>, 
    pd_zero=<optimized out>, offset_data=<optimized out>, cycle=<optimized out>)
    at makedumpfile.c:7783
#1  0x0000000000439a15 in write_kdump_pages_and_bitmap_cyclic (
    cd_header=cd_header at entry=0x7fffffffe2d0, cd_page=cd_page at entry=0x7fffffffe300)
    at makedumpfile.c:8501
#2  0x000000000043a918 in writeout_dumpfile () at makedumpfile.c:9497
#3  0x000000000044181c in create_dumpfile () at makedumpfile.c:9724
#4  0x00000000004086df in main (argc=<optimized out>, argv=0x7fffffffe468)
    at makedumpfile.c:11159
(gdb)
===

> >>
> >> -		/*
> >> -		 * check pfn first without mutex locked to reduce the time
> >> -		 * trying to lock the mutex
> >> -		 */
> >> -		if (page_data_buf[index].pfn != consuming_pfn)
> >> -			continue;
> >> +					info->page_flag_buf[i]->ready = FLAG_UNUSED;
> >>
> >> -		if (pthread_mutex_trylock(&page_data_buf[index].mutex) != 0)
> >> -			continue;
> >> +					info->current_pfn = end_pfn;
> >
> > This part doesn't get info->current_pfn_mutex.
> > It becomes bigger than end_pfn at the end of producer thread in following case.
> >
> > ===
> >    producer                   Consumer
> > ---------------------------------------------------------
> >    pthread_mutex_lock()
> >    pfn = info->current_pfn
> >                               info->current_pfn = end_pfn
> >    info->current_pfn++
> >      -> end_pfn + 1
> >    pthread_mutex_unlock()
> > ===
> >
> > But I know, if this race is happened, processing other producer thread and consumer thread works well
> > in current cycle.
> > Because each thread checks whether info->current_pfn >= end_pfn.
> >
> > On the other hand, info->current_pfn is initialized to cycle->start_pfn before pthread_create()
> > in write_kdump_pages_parallel_cyclic().
> > This means it does not cause a problem in next cycle, too.
> >
> > In other words, my point is following.
> >
> >    a) When info->current_pfn changes, you have to get info->current_pfn_mutex.
> >    b) If you allow info->current_pfn is bigger than end_pfn at the end of each cycle,
> >       "info->current_pfn = end_pfn;" is unnecessary.
> >
> > Honestly, I don't like approach b).
> 
> You're right. Some thing I thought is wrong.
> But I don't like lock if I have other choice.
> I will set info->current_pfn before returning.
> How about it?

If you mean you set info->current_pfn by producer side, 
this race will occur between producer A and producer B.

I think you can't avoid getting mutex lock, if you will change info->current_pfn.

Thanks,
Minoru Usui


> --
> Thanks
> Zhou
> 
> >
> > Thanks,
> > Minoru Usui
> >
> >> +					end_count++;
> >> +					continue;
> >> +				}
> >> +
> >> +				if (current_pfn < temp_pfn)
> >> +					continue;
> >>
> >> -		/* check whether the found one is ready to be consumed */
> >> -		if (page_data_buf[index].pfn != consuming_pfn ||
> >> -		    page_data_buf[index].ready != 1) {
> >> -			goto unlock;
> >> +				check_count++;
> >> +				consuming = i;
> >> +				current_pfn = temp_pfn;
> >> +			}
> >> +
> >> +			/*
> >> +			 * If all the threads have reached the end, we will finish writing.
> >> +			 */
> >> +			if (end_count >= info->num_threads)
> >> +				goto finish;
> >> +
> >> +			/*
> >> +			 * Since it has the probabilty that there is no page_flag_buf being ready,
> >> +			 * we should recheck if it happens.
> >> +			 */
> >> +			if (check_count == 0)
> >> +				continue;
> >> +
> >> +			/*
> >> +			 * If the page_flag_buf is not ready, the pfn recorded may be changed.
> >> +			 * So we should recheck.
> >> +			 */
> >> +			if (info->page_flag_buf[consuming]->ready != FLAG_READY) {
> >> +				gettimeofday(&new, NULL);
> >> +				if (new.tv_sec - last.tv_sec > WAIT_TIME) {
> >> +					ERRMSG("Can't get data of pfn.\n");
> >> +					goto out;
> >> +				}
> >> +				continue;
> >> +			}
> >> +
> >> +			if (current_pfn == info->page_flag_buf[consuming]->pfn)
> >> +				break;
> >>   		}
> >>
> >>   		if ((num_dumped % per) == 0)
> >>   			print_progress(PROGRESS_COPY, num_dumped, info->num_dumpable);
> >>
> >> -		/* next pfn is found, refresh last here */
> >> -		last = new;
> >> -		consuming_pfn++;
> >> -		info->consumed_pfn++;
> >> -		page_data_buf[index].ready = 0;
> >> -
> >> -		if (page_data_buf[index].dumpable == FALSE)
> >> -			goto unlock;
> >> -
> >>   		num_dumped++;
> >>
> >> -		if (page_data_buf[index].zero == TRUE) {
> >> +
> >> +		if (info->page_flag_buf[consuming]->zero == TRUE) {
> >>   			if (!write_cache(cd_header, pd_zero, sizeof(page_desc_t)))
> >>   				goto out;
> >>   			pfn_zero++;
> >>   		} else {
> >> +			index = info->page_flag_buf[consuming]->index;
> >>   			pd.flags      = page_data_buf[index].flags;
> >>   			pd.size       = page_data_buf[index].size;
> >>   			pd.page_flags = 0;
> >> @@ -7420,12 +7513,12 @@ write_kdump_pages_parallel_cyclic(struct cache_data *cd_header,
> >>   			 */
> >>   			if (!write_cache(cd_page, page_data_buf[index].buf, pd.size))
> >>   				goto out;
> >> -
> >> +			page_data_buf[index].used = FALSE;
> >>   		}
> >> -unlock:
> >> -		pthread_mutex_unlock(&page_data_buf[index].mutex);
> >> +		info->page_flag_buf[consuming]->ready = FLAG_UNUSED;
> >> +		info->page_flag_buf[consuming] = info->page_flag_buf[consuming]->next;
> >>   	}
> >> -
> >> +finish:
> >>   	ret = TRUE;
> >>   	/*
> >>   	 * print [100 %]
> >> @@ -7464,7 +7557,7 @@ out:
> >>   	}
> >>
> >>   	if (page_data_buf != NULL) {
> >> -		for (i = 0; i < page_data_num; i++) {
> >> +		for (i = 0; i < page_buf_num; i++) {
> >>   			pthread_mutex_destroy(&page_data_buf[i].mutex);
> >>   		}
> >>   	}
> >> @@ -7564,6 +7657,7 @@ write_kdump_pages_cyclic(struct cache_data *cd_header, struct cache_data *cd_pag
> >>   		num_dumped++;
> >>   		if (!read_pfn(pfn, buf))
> >>   			goto out;
> >> +
> >>   		filter_data_buffer(buf, pfn_to_paddr(pfn), info->page_size);
> >>
> >>   		/*
> >> diff --git a/makedumpfile.h b/makedumpfile.h
> >> index e0b5bbf..8a9a5b2 100644
> >> --- a/makedumpfile.h
> >> +++ b/makedumpfile.h
> >> @@ -977,7 +977,7 @@ typedef unsigned long long int ulonglong;
> >>   #define PAGE_DATA_NUM	(50)
> >>   #define WAIT_TIME	(60 * 10)
> >>   #define PTHREAD_FAIL	((void *)-2)
> >> -#define NUM_BUFFERS	(50)
> >> +#define NUM_BUFFERS	(20)
> >>
> >>   struct mmap_cache {
> >>   	char	*mmap_buf;
> >> @@ -985,28 +985,36 @@ struct mmap_cache {
> >>   	off_t   mmap_end_offset;
> >>   };
> >>
> >> +enum {
> >> +	FLAG_UNUSED,
> >> +	FLAG_READY,
> >> +	FLAG_FILLING
> >> +};
> >> +struct page_flag {
> >> +	mdf_pfn_t pfn;
> >> +	char zero;
> >> +	char ready;
> >> +	short index;
> >> +	struct page_flag *next;
> >> +};
> >> +
> >>   struct page_data
> >>   {
> >> -	mdf_pfn_t pfn;
> >> -	int dumpable;
> >> -	int zero;
> >> -	unsigned int flags;
> >> +	pthread_mutex_t mutex;
> >>   	long size;
> >>   	unsigned char *buf;
> >> -	pthread_mutex_t mutex;
> >> -	/*
> >> -	 * whether the page_data is ready to be consumed
> >> -	 */
> >> -	int ready;
> >> +	int flags;
> >> +	int used;
> >>   };
> >>
> >>   struct thread_args {
> >>   	int thread_num;
> >>   	unsigned long len_buf_out;
> >>   	mdf_pfn_t start_pfn, end_pfn;
> >> -	int page_data_num;
> >> +	int page_buf_num;
> >>   	struct cycle *cycle;
> >>   	struct page_data *page_data_buf;
> >> +	struct page_flag *page_flag_buf;
> >>   };
> >>
> >>   /*
> >> @@ -1295,6 +1303,7 @@ struct DumpInfo {
> >>   	pthread_t **threads;
> >>   	struct thread_args *kdump_thread_args;
> >>   	struct page_data *page_data_buf;
> >> +	struct page_flag **page_flag_buf;
> >>   	pthread_rwlock_t usemmap_rwlock;
> >>   	mdf_pfn_t current_pfn;
> >>   	pthread_mutex_t current_pfn_mutex;
> >> --
> >> 1.8.3.1
> >>
> >>
> >>
> >>
> >> _______________________________________________
> >> kexec mailing list
> >> kexec at lists.infradead.org
> >> http://lists.infradead.org/mailman/listinfo/kexec
> 
> 




More information about the kexec mailing list