Print this page
9694 Parallel dump hangs
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: John Levon <levon@movementarian.org>
*** 20,29 ****
--- 20,30 ----
*/
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2018 Joyent, Inc.
+ * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
*** 69,78 ****
--- 70,80 ----
#include <vm/pvn.h>
#include <vm/seg.h>
#include <vm/seg_kmem.h>
#include <sys/clock_impl.h>
#include <sys/hold_page.h>
+ #include <sys/cpu.h>
#include <bzip2/bzlib.h>
#define ONE_GIG (1024 * 1024 * 1024UL)
*** 438,447 ****
--- 440,458 ----
} dumpbuf_t;
dumpbuf_t dumpbuf; /* I/O buffer */
/*
+ * For parallel dump, defines maximum time main task thread will wait
+ * for at least one helper to register in dumpcfg.helpermap, before
+ * assuming there are no helpers and falling back to serial mode.
+ * Value is chosen arbitrary and provides *really* long wait for any
+ * available helper to register.
+ */
+ #define DUMP_HELPER_MAX_WAIT 1000 /* millisec */
+
+ /*
* The dump I/O buffer must be at least one page, at most xfer_size
* bytes, and should scale with physmem in between. The transfer size
* passed in will either represent a global default (maxphys) or the
* best size for the device. The size of the dumpbuf I/O buffer is
* limited by dumpbuf_limit (8MB by default) because the dump
*** 2299,2331 ****
pgcnt_t pagenum = 0, bitnum = 0, hibitnum;
dumpmlw_t mlw;
cbuf_t *cp;
pgcnt_t baseoff, pfnoff;
pfn_t base, pfn;
! int i, dumpserial;
/*
* Fall back to serial mode if there are no helpers.
* dump_plat_mincpu can be set to 0 at any time.
* dumpcfg.helpermap must contain at least one member.
*/
! dumpserial = 1;
!
if (dump_plat_mincpu != 0 && dumpcfg.clevel != 0) {
for (i = 0; i < BT_BITOUL(NCPU); ++i) {
if (dumpcfg.helpermap[i] != 0) {
! dumpserial = 0;
break;
}
}
}
if (dumpserial) {
dumpcfg.clevel = 0;
! if (dumpcfg.helper[0].lzbuf == NULL)
! dumpcfg.helper[0].lzbuf = dumpcfg.helper[1].page;
}
dump_init_memlist_walker(&mlw);
for (;;) {
int sec = (gethrtime() - ds->start) / NANOSEC;
--- 2310,2360 ----
pgcnt_t pagenum = 0, bitnum = 0, hibitnum;
dumpmlw_t mlw;
cbuf_t *cp;
pgcnt_t baseoff, pfnoff;
pfn_t base, pfn;
! boolean_t dumpserial;
! int i;
/*
* Fall back to serial mode if there are no helpers.
* dump_plat_mincpu can be set to 0 at any time.
* dumpcfg.helpermap must contain at least one member.
+ *
+ * It is possible that the helpers haven't registered
+ * in helpermap yet; wait up to DUMP_HELPER_MAX_WAIT for
+ * at least one helper to register.
*/
! dumpserial = B_TRUE;
if (dump_plat_mincpu != 0 && dumpcfg.clevel != 0) {
+ hrtime_t hrtmax = MSEC2NSEC(DUMP_HELPER_MAX_WAIT);
+ hrtime_t hrtstart = gethrtime();
+
+ for (;;) {
for (i = 0; i < BT_BITOUL(NCPU); ++i) {
if (dumpcfg.helpermap[i] != 0) {
! dumpserial = B_FALSE;
break;
}
}
+
+ if ((!dumpserial) ||
+ ((gethrtime() - hrtstart) >= hrtmax)) {
+ break;
}
+ SMT_PAUSE();
+ }
+
if (dumpserial) {
dumpcfg.clevel = 0;
! if (dumpcfg.helper[0].lzbuf == NULL) {
! dumpcfg.helper[0].lzbuf =
! dumpcfg.helper[1].page;
}
+ }
+ }
dump_init_memlist_walker(&mlw);
for (;;) {
int sec = (gethrtime() - ds->start) / NANOSEC;
*** 2465,2479 ****
* If there are no helpers the main task does
* non-streams lzjb compress.
*/
if (dumpserial) {
dumpsys_lzjb_page(dumpcfg.helper, cp);
! break;
! }
!
/* pass mapped pages to a helper */
CQ_PUT(helperq, cp, CBUF_INREADY);
/* the last page was done */
if (bitnum >= dumpcfg.bitmapsize)
CQ_CLOSE(helperq);
--- 2494,2507 ----
* If there are no helpers the main task does
* non-streams lzjb compress.
*/
if (dumpserial) {
dumpsys_lzjb_page(dumpcfg.helper, cp);
! } else {
/* pass mapped pages to a helper */
CQ_PUT(helperq, cp, CBUF_INREADY);
+ }
/* the last page was done */
if (bitnum >= dumpcfg.bitmapsize)
CQ_CLOSE(helperq);
*** 2575,2586 ****
P("Found %ldM ranges,%ld\n", (CBUF_MAPSIZE / DUMP_1MB), cfg->found4m);
P("Found small pages,%ld\n", cfg->foundsm);
P("Compression level,%d\n", cfg->clevel);
! P("Compression type,%s %s\n", cfg->clevel == 0 ? "serial" : "parallel",
cfg->clevel >= DUMP_CLEVEL_BZIP2 ? "bzip2" : "lzjb");
P("Compression ratio,%d.%02d\n", compress_ratio / 100, compress_ratio %
100);
P("nhelper_used,%d\n", cfg->nhelper_used);
P("Dump I/O rate MBS,%d.%02d\n", iorate / 100, iorate % 100);
--- 2603,2618 ----
P("Found %ldM ranges,%ld\n", (CBUF_MAPSIZE / DUMP_1MB), cfg->found4m);
P("Found small pages,%ld\n", cfg->foundsm);
P("Compression level,%d\n", cfg->clevel);
! P("Compression type,%s %s", cfg->clevel == 0 ? "serial" : "parallel",
cfg->clevel >= DUMP_CLEVEL_BZIP2 ? "bzip2" : "lzjb");
+ if (cfg->clevel >= DUMP_CLEVEL_BZIP2)
+ P(" (level %d)\n", dump_bzip2_level);
+ else
+ P("\n");
P("Compression ratio,%d.%02d\n", compress_ratio / 100, compress_ratio %
100);
P("nhelper_used,%d\n", cfg->nhelper_used);
P("Dump I/O rate MBS,%d.%02d\n", iorate / 100, iorate % 100);