Improve performance by multithreading the work to preserve and restore shmem pages. When preserving pages each thread saves non-overlapping ranges of a file to a pkram_obj until all pages are preserved. When restoring pages each thread loads pages using a local pkram_access. Signed-off-by: Anthony Yznaga <anthony.yznaga@xxxxxxxxxx> --- mm/shmem_pkram.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 5 deletions(-) diff --git a/mm/shmem_pkram.c b/mm/shmem_pkram.c index e52722b3a709..354c2b58962c 100644 --- a/mm/shmem_pkram.c +++ b/mm/shmem_pkram.c @@ -115,6 +115,7 @@ static int save_file_content_range(struct pkram_access *pa, } struct shmem_pkram_arg { + int *error; struct pkram_stream *ps; struct address_space *mapping; struct mm_struct *mm; @@ -137,6 +138,16 @@ static int get_save_range(unsigned long max, atomic64_t *next, unsigned long *st return 0; } +/* Completion tracking for save_file_content_thr() threads */ +static atomic_t pkram_save_n_undone; +static DECLARE_COMPLETION(pkram_save_all_done_comp); + +static inline void pkram_save_report_one_done(void) +{ + if (atomic_dec_and_test(&pkram_save_n_undone)) + complete(&pkram_save_all_done_comp); +} + static int do_save_file_content(struct pkram_stream *ps, struct address_space *mapping, atomic64_t *next) @@ -160,11 +171,40 @@ static int do_save_file_content(struct pkram_stream *ps, return ret; } -static int save_file_content(struct pkram_stream *ps, struct address_space *mapping) +static int save_file_content_thr(void *data) { - struct shmem_pkram_arg arg = { ps, mapping, NULL, ATOMIC64_INIT(0) }; - - return do_save_file_content(arg.ps, arg.mapping, &arg.next); + struct shmem_pkram_arg *arg = data; + int ret; + + ret = do_save_file_content(arg->ps, arg->mapping, &arg->next); + if (ret && !*arg->error) + *arg->error = ret; + + pkram_save_report_one_done(); + return 0; +} + +static int shmem_pkram_max_threads = 16; + +static int save_file_content(struct pkram_stream *ps, struct address_space *mapping) + { + int err = 0; + struct shmem_pkram_arg arg = { &err, ps, mapping, NULL, ATOMIC64_INIT(0) }; + unsigned int thr, nr_threads; + + nr_threads = num_online_cpus() - 1; + nr_threads = clamp_val(shmem_pkram_max_threads, 1, nr_threads); + + if (nr_threads == 1) + return do_save_file_content(arg.ps, arg.mapping, &arg.next); + + atomic_set(&pkram_save_n_undone, nr_threads); + for (thr = 0; thr < nr_threads; thr++) + kthread_run(save_file_content_thr, &arg, "pkram_save%d", thr); + + wait_for_completion(&pkram_save_all_done_comp); + + return err; } static int save_file(struct dentry *dentry, struct pkram_stream *ps) @@ -275,7 +315,17 @@ int shmem_save_pkram(struct super_block *sb) return err; } -static int load_file_content(struct pkram_stream *ps, struct address_space *mapping, struct mm_struct *mm) +/* Completion tracking for load_file_content_thr() threads */ +static atomic_t pkram_load_n_undone; +static DECLARE_COMPLETION(pkram_load_all_done_comp); + +static inline void pkram_load_report_one_done(void) +{ + if (atomic_dec_and_test(&pkram_load_n_undone)) + complete(&pkram_load_all_done_comp); +} + +static int do_load_file_content(struct pkram_stream *ps, struct address_space *mapping, struct mm_struct *mm) { PKRAM_ACCESS(pa, ps, pages); unsigned long index; @@ -296,6 +346,40 @@ static int load_file_content(struct pkram_stream *ps, struct address_space *mapp return err; } +static int load_file_content_thr(void *data) +{ + struct shmem_pkram_arg *arg = data; + int ret; + + ret = do_load_file_content(arg->ps, arg->mapping, arg->mm); + if (ret && !*arg->error) + *arg->error = ret; + + pkram_load_report_one_done(); + return 0; +} + +static int load_file_content(struct pkram_stream *ps, struct address_space *mapping, struct mm_struct *mm) +{ + int err = 0; + struct shmem_pkram_arg arg = { &err, ps, mapping, mm }; + unsigned int thr, nr_threads; + + nr_threads = num_online_cpus() - 1; + nr_threads = clamp_val(shmem_pkram_max_threads, 1, nr_threads); + + if (nr_threads == 1) + return do_load_file_content(ps, mapping, mm); + + atomic_set(&pkram_load_n_undone, nr_threads); + for (thr = 0; thr < nr_threads; thr++) + kthread_run(load_file_content_thr, &arg, "pkram_load%d", thr); + + wait_for_completion(&pkram_load_all_done_comp); + + return err; +} + static int load_file(struct dentry *parent, struct pkram_stream *ps, char *buf, size_t bufsize) { -- 1.8.3.1