[Skiboot] [PATCH] fast-reboot: parallel memory clearing

Stewart Smith stewart at linux.ibm.com
Tue Apr 17 18:46:07 AEST 2018


A real simple hack to split things up into 16GB jobs,
and name them as how far we are into zeroing, so we can
simply print progress out as XGB cleared as we wait for
the jobs to finish.

This seems to cut at least ~40% time from memory zeroing on
fast-reboot on a 256GB Boston system.

Signed-off-by: Stewart Smith <stewart at linux.ibm.com>
---
 core/mem_region.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 61 insertions(+), 2 deletions(-)

diff --git a/core/mem_region.c b/core/mem_region.c
index 8ae49bb790fd..a06e725db3ec 100644
--- a/core/mem_region.c
+++ b/core/mem_region.c
@@ -1206,19 +1206,47 @@ static void mem_clear_range(uint64_t s, uint64_t e)
 		return;
 	}
 
-	prlog(PR_NOTICE, "Clearing region %llx-%llx\n",
+	prlog(PR_DEBUG, "Clearing region %llx-%llx\n",
 	      (long long)s, (long long)e);
 	memset((void *)s, 0, e - s);
 }
 
+static void mem_region_clear_job(void *data)
+{
+	uint64_t *arg = (uint64_t*)data;
+	mem_clear_range(arg[0], arg[1]);
+}
+
+#define MEM_REGION_CLEAR_JOB_SIZE (16ULL*(1<<30))
+
 void mem_region_clear_unused(void)
 {
+	int njobs = 0;
+	struct cpu_job **jobs;
 	struct mem_region *r;
+	uint64_t *job_args;
+	uint64_t s,l;
+	uint64_t total = 0;
+	char **job_names;
+	int i;
 
 	lock(&mem_region_lock);
 	assert(mem_regions_finalised);
 
+	list_for_each(&regions, r, list) {
+		if (!(r->type == REGION_OS))
+			continue;
+		njobs++;
+		/* One job per 16GB */
+		njobs += r->len / MEM_REGION_CLEAR_JOB_SIZE;
+	}
+
+	jobs = malloc(njobs * sizeof(struct cpu_job*));
+	job_args = malloc(2*njobs*sizeof(uint64_t));
+	job_names = malloc(njobs*sizeof(char*));
+
 	prlog(PR_NOTICE, "Clearing unused memory:\n");
+	i = 0;
 	list_for_each(&regions, r, list) {
 		/* If it's not unused, ignore it. */
 		if (!(r->type == REGION_OS))
@@ -1226,9 +1254,40 @@ void mem_region_clear_unused(void)
 
 		assert(r != &skiboot_heap);
 
-		mem_clear_range(r->start, r->start + r->len);
+		s = r->start;
+		l = r->len;
+		while(l > MEM_REGION_CLEAR_JOB_SIZE) {
+			job_args[i*2] = s+l - MEM_REGION_CLEAR_JOB_SIZE;
+			job_args[i*2+1] = s+l;
+			l-=MEM_REGION_CLEAR_JOB_SIZE;
+			job_names[i] = malloc(sizeof(char)*40);
+			total+=MEM_REGION_CLEAR_JOB_SIZE;
+			snprintf(job_names[i], 40, "%lldGB cleared", total/(1<<30));
+			jobs[i] = cpu_queue_job(NULL, job_names[i],
+						mem_region_clear_job,
+						&job_args[i*2]);
+			i++;
+		}
+		job_args[i*2] = s;
+		job_args[i*2+1] = s+l;
+		job_names[i] = malloc(sizeof(char)*40);
+		total+=l;
+		snprintf(job_names[i], 40, "%lldGB cleared", total/(1<<30));
+		jobs[i] = cpu_queue_job(NULL, job_names[i],
+					mem_region_clear_job,
+					&job_args[i*2]);
+		i++;
+	}
+	cpu_process_local_jobs();
+	for(i=0; i < njobs; i++) {
+		cpu_wait_job(jobs[i], true);
+		printf("%s\n",job_names[i]);
+		free(job_names[i]);
 	}
 	unlock(&mem_region_lock);
+	free(jobs);
+	free(job_args);
+	free(job_names);
 }
 
 static void mem_region_add_dt_reserved_node(struct dt_node *parent,
-- 
2.14.3



More information about the Skiboot mailing list