summaryrefslogtreecommitdiff
path: root/source/tools/mudraw.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2016-05-04 11:28:18 +0100
committerRobin Watts <robin.watts@artifex.com>2016-05-09 16:50:38 +0100
commitecda9f94608188e414f6742ce7f0509b0bd893b5 (patch)
tree0825688970c0c89d153073ad0c41d3b1f233d093 /source/tools/mudraw.c
parent8b08ca2917b6230a88719cc516f791cbb6845180 (diff)
downloadmupdf-ecda9f94608188e414f6742ce7f0509b0bd893b5.tar.xz
First implementation of parallel rendering ("bgprint")
Add -P flag to mudraw to do 'parallel' rendering. We shift rendering onto a background thread, so that the main thread can continue interpreting page n+1 while page n is being rendered. To do this, we extract the core of the drawpage routine into 'dodrawpage', and either call it directly (in the normal case) or from a bgprint worker thread (in the parallel case). The threading construction exactly parallels that of the threaded band rendering. We have a semaphore to start the render process, a semaphore to indicate when the process has stopped, and the thread itself. The most complex thing here is the rejigging of the printfs required to ensure that we still get the timings displayed in a sane way.
Diffstat (limited to 'source/tools/mudraw.c')
-rw-r--r--source/tools/mudraw.c371
1 files changed, 266 insertions, 105 deletions
diff --git a/source/tools/mudraw.c b/source/tools/mudraw.c
index 52788aea..55c984c4 100644
--- a/source/tools/mudraw.c
+++ b/source/tools/mudraw.c
@@ -369,11 +369,29 @@ static int num_workers = 0;
static worker_t *workers;
static struct {
+ int active;
+ int started;
+ fz_context *ctx;
+ THREAD thread;
+ SEMAPHORE start;
+ SEMAPHORE stop;
+ int pagenum;
+ char *filename;
+ fz_display_list *list;
+ fz_page *page;
+} bgprint;
+
+static struct {
int count, total;
int min, max;
int minpage, maxpage;
char *minfilename;
char *maxfilename;
+ int render_count, render_total;
+ int render_min, render_max;
+ int render_minpage, render_maxpage;
+ char *render_minfilename;
+ char *render_maxfilename;
} timing;
static void usage(void)
@@ -419,6 +437,7 @@ static void usage(void)
"\t-D\tdisable use of display list\n"
"\t-i\tignore errors\n"
"\t-L\tlow memory mode (avoid caching, clear objects after each page)\n"
+ "\t-P\tparallel interpretation/rendering\n"
"\n"
"\tpages\tcomma separated list of page numbers and ranges\n"
);
@@ -555,91 +574,14 @@ static void drawband(fz_context *ctx, int savealpha, fz_page *page, fz_display_l
}
}
-static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
+static void dodrawpage(fz_context *ctx, fz_page *page, fz_display_list *list, int pagenum, fz_cookie *cookie, int start, char *filename, int bg)
{
- fz_page *page;
- fz_display_list *list = NULL;
- fz_device *dev = NULL;
- int start;
- fz_cookie cookie = { 0 };
fz_rect mediabox;
- int first_page = !output_append;
-
- fz_var(list);
- fz_var(dev);
-
- if (showtime)
- start = gettime();
-
- page = fz_load_page(ctx, doc, pagenum - 1);
+ fz_device *dev = NULL;
- if (showmd5 || showtime || showfeatures)
- fprintf(stderr, "page %s %d", filename, pagenum);
fz_bound_page(ctx, page, &mediabox);
- if (output_file_per_page)
- {
- char text_buffer[512];
-
- fz_drop_output(ctx, out);
- fz_snprintf(text_buffer, sizeof(text_buffer), output, pagenum);
- out = fz_new_output_with_path(ctx, text_buffer, output_append);
- output_append = 1;
- }
-
- /* Output any file level (as opposed to page level) headers. */
- if (first_page)
- file_level_headers(ctx);
-
- if (uselist)
- {
- fz_try(ctx)
- {
- list = fz_new_display_list(ctx);
- dev = fz_new_list_device(ctx, list);
- if (lowmemory)
- fz_enable_device_hints(ctx, dev, FZ_NO_CACHE);
- fz_run_page(ctx, page, dev, &fz_identity, &cookie);
- }
- fz_always(ctx)
- {
- fz_drop_device(ctx, dev);
- dev = NULL;
- }
- fz_catch(ctx)
- {
- fz_drop_display_list(ctx, list);
- fz_drop_page(ctx, page);
- fz_rethrow(ctx);
- }
- }
-
- if (showfeatures)
- {
- int iscolor;
- dev = fz_new_test_device(ctx, &iscolor, 0.02f);
- if (lowmemory)
- fz_enable_device_hints(ctx, dev, FZ_NO_CACHE);
- fz_try(ctx)
- {
- if (list)
- fz_run_display_list(ctx, list, dev, &fz_identity, &fz_infinite_rect, NULL);
- else
- fz_run_page(ctx, page, dev, &fz_identity, &cookie);
- }
- fz_always(ctx)
- {
- fz_drop_device(ctx, dev);
- dev = NULL;
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
- fprintf(stderr, " %s", iscolor ? "color" : "grayscale");
- }
-
if (output_format == OUT_TRACE)
{
fz_try(ctx)
@@ -650,9 +592,9 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
if (lowmemory)
fz_enable_device_hints(ctx, dev, FZ_NO_CACHE);
if (list)
- fz_run_display_list(ctx, list, dev, &fz_identity, &fz_infinite_rect, &cookie);
+ fz_run_display_list(ctx, list, dev, &fz_identity, &fz_infinite_rect, cookie);
else
- fz_run_page(ctx, page, dev, &fz_identity, &cookie);
+ fz_run_page(ctx, page, dev, &fz_identity, cookie);
fz_printf(ctx, out, "</page>\n");
}
fz_always(ctx)
@@ -683,9 +625,9 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
if (output_format == OUT_HTML)
fz_disable_device_hints(ctx, dev, FZ_IGNORE_IMAGE);
if (list)
- fz_run_display_list(ctx, list, dev, &fz_identity, &fz_infinite_rect, &cookie);
+ fz_run_display_list(ctx, list, dev, &fz_identity, &fz_infinite_rect, cookie);
else
- fz_run_page(ctx, page, dev, &fz_identity, &cookie);
+ fz_run_page(ctx, page, dev, &fz_identity, cookie);
fz_drop_device(ctx, dev);
dev = NULL;
if (output_format == OUT_STEXT)
@@ -728,9 +670,9 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
pdf_obj *page_obj;
if (list)
- fz_run_display_list(ctx, list, dev, &fz_identity, NULL, &cookie);
+ fz_run_display_list(ctx, list, dev, &fz_identity, NULL, cookie);
else
- fz_run_page(ctx, page, dev, &fz_identity, &cookie);
+ fz_run_page(ctx, page, dev, &fz_identity, cookie);
page_obj = pdf_add_page(ctx, pdfout, &mediabox, rotation, resources, contents);
pdf_insert_page(ctx, pdfout, -1, page_obj);
@@ -779,9 +721,9 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
if (lowmemory)
fz_enable_device_hints(ctx, dev, FZ_NO_CACHE);
if (list)
- fz_run_display_list(ctx, list, dev, &ctm, &tbounds, &cookie);
+ fz_run_display_list(ctx, list, dev, &ctm, &tbounds, cookie);
else
- fz_run_page(ctx, page, dev, &ctm, &cookie);
+ fz_run_page(ctx, page, dev, &ctm, cookie);
fz_drop_device(ctx, dev);
dev = NULL;
}
@@ -798,7 +740,6 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
fz_rethrow(ctx);
}
}
-
else
{
float zoom;
@@ -811,7 +752,9 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
fz_ps_output_context *psoc = NULL;
fz_mono_pcl_output_context *pmcoc = NULL;
fz_color_pcl_output_context *pccoc = NULL;
+ fz_device *dev = NULL;
+ fz_var(dev);
fz_var(pix);
fz_var(poc);
fz_var(psoc);
@@ -953,10 +896,10 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
DEBUG_THREADS(("Waiting for worker %d to complete band %d\n", w->num, band));
SEMAPHORE_WAIT(w->stop);
pix = w->pix;
- cookie.errors += w->cookie.errors;
+ cookie->errors += w->cookie.errors;
}
else
- drawband(ctx, savealpha, page, list, &ctm, &tbounds, &cookie, band, pix);
+ drawband(ctx, savealpha, page, list, &ctm, &tbounds, cookie, band, pix);
if (output)
{
@@ -1072,22 +1015,44 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
int end = gettime();
int diff = end - start;
- if (diff < timing.min)
+ if (bg)
{
- timing.min = diff;
- timing.minpage = pagenum;
- timing.minfilename = filename;
+ if (diff < timing.render_min)
+ {
+ timing.render_min = diff;
+ timing.render_minpage = pagenum;
+ timing.render_minfilename = filename;
+ }
+ if (diff > timing.render_max)
+ {
+ timing.render_max = diff;
+ timing.render_maxpage = pagenum;
+ timing.render_maxfilename = filename;
+ }
+ timing.render_total += diff;
+ timing.render_count ++;
+
+ fprintf(stderr, " %dms (rendering)", diff);
}
- if (diff > timing.max)
+ else
{
- timing.max = diff;
- timing.maxpage = pagenum;
- timing.maxfilename = filename;
- }
- timing.total += diff;
- timing.count ++;
+ if (diff < timing.min)
+ {
+ timing.min = diff;
+ timing.minpage = pagenum;
+ timing.minfilename = filename;
+ }
+ if (diff > timing.max)
+ {
+ timing.max = diff;
+ timing.maxpage = pagenum;
+ timing.maxfilename = filename;
+ }
+ timing.total += diff;
+ timing.count ++;
- fprintf(stderr, " %dms", diff);
+ fprintf(stderr, " %dms", diff);
+ }
}
if (showmd5 || showtime || showfeatures)
@@ -1105,10 +1070,143 @@ static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
fz_flush_warnings(ctx);
- if (cookie.errors)
+ if (cookie->errors)
errored = 1;
}
+static void bgprint_flush(void)
+{
+ if (!bgprint.active || !bgprint.started)
+ return;
+
+ SEMAPHORE_WAIT(bgprint.stop);
+ bgprint.started = 0;
+}
+
+static void drawpage(fz_context *ctx, fz_document *doc, int pagenum)
+{
+ fz_page *page;
+ fz_display_list *list = NULL;
+ fz_device *dev = NULL;
+ int start;
+ fz_cookie cookie = { 0 };
+ int first_page = !output_append;
+ int diff;
+
+ fz_var(list);
+ fz_var(dev);
+
+ start = (showtime ? gettime() : 0);
+
+ page = fz_load_page(ctx, doc, pagenum - 1);
+
+ /* Output any file level (as opposed to page level) headers. */
+ if (first_page)
+ file_level_headers(ctx);
+
+ if (uselist)
+ {
+ fz_try(ctx)
+ {
+ list = fz_new_display_list(ctx);
+ dev = fz_new_list_device(ctx, list);
+ if (lowmemory)
+ fz_enable_device_hints(ctx, dev, FZ_NO_CACHE);
+ fz_run_page(ctx, page, dev, &fz_identity, &cookie);
+ }
+ fz_always(ctx)
+ {
+ fz_drop_device(ctx, dev);
+ dev = NULL;
+ }
+ fz_catch(ctx)
+ {
+ fz_drop_display_list(ctx, list);
+ fz_drop_page(ctx, page);
+ fz_rethrow(ctx);
+ }
+
+ if (bgprint.active && showtime)
+ {
+ int end = gettime();
+ diff = end - start;
+
+ if (diff < timing.min)
+ {
+ timing.min = diff;
+ timing.minpage = pagenum;
+ timing.minfilename = filename;
+ }
+ if (diff > timing.max)
+ {
+ timing.max = diff;
+ timing.maxpage = pagenum;
+ timing.maxfilename = filename;
+ }
+ timing.total += diff;
+ timing.count ++;
+ }
+ }
+
+ if (showfeatures)
+ {
+ int iscolor;
+ dev = fz_new_test_device(ctx, &iscolor, 0.02f);
+ if (lowmemory)
+ fz_enable_device_hints(ctx, dev, FZ_NO_CACHE);
+ fz_try(ctx)
+ {
+ if (list)
+ fz_run_display_list(ctx, list, dev, &fz_identity, &fz_infinite_rect, NULL);
+ else
+ fz_run_page(ctx, page, dev, &fz_identity, &cookie);
+ }
+ fz_always(ctx)
+ {
+ fz_drop_device(ctx, dev);
+ dev = NULL;
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+ fprintf(stderr, " %s", iscolor ? "color" : "grayscale");
+ }
+
+ if (output_file_per_page)
+ {
+ char text_buffer[512];
+
+ bgprint_flush();
+ fz_drop_output(ctx, out);
+ fz_snprintf(text_buffer, sizeof(text_buffer), output, pagenum);
+ out = fz_new_output_with_path(ctx, text_buffer, output_append);
+ output_append = 1;
+ }
+
+ if (bgprint.active)
+ {
+ bgprint_flush();
+ if (bgprint.active && (showmd5 || showtime || showfeatures))
+ {
+ fprintf(stderr, "page %s %d", filename, pagenum);
+ if (showtime)
+ fprintf(stderr, " %dms (interpretation)", diff);
+ }
+
+ bgprint.started = 1;
+ bgprint.page = page;
+ bgprint.list = list;
+ bgprint.filename = filename;
+ bgprint.pagenum = pagenum;
+ SEMAPHORE_TRIGGER(bgprint.start);
+ }
+ else
+ {
+ dodrawpage(ctx, page, list, pagenum, &cookie, start, filename, 0);
+ }
+}
+
static void drawrange(fz_context *ctx, fz_document *doc, char *range)
{
int page, spage, epage, pagecount;
@@ -1241,6 +1339,29 @@ static THREAD_RETURN_TYPE worker_thread(void *arg)
while (me->band >= 0);
THREAD_RETURN();
}
+
+static THREAD_RETURN_TYPE bgprint_worker(void *arg)
+{
+ fz_cookie cookie = { 0 };
+ (void)arg;
+
+ do
+ {
+ DEBUG_THREADS(("BGPrint waiting\n"));
+ SEMAPHORE_WAIT(bgprint.start);
+ DEBUG_THREADS(("BGPrint woken for pagenum %d\n", bgprint.pagenum));
+ if (bgprint.pagenum >= 0)
+ {
+ int start = gettime();
+ memset(&cookie, 0, sizeof(cookie));
+ dodrawpage(bgprint.ctx, bgprint.page, bgprint.list, bgprint.pagenum, &cookie, start, bgprint.filename, 1);
+ }
+ DEBUG_THREADS(("BGPrint completed band %d\n", bgprint.pagenum));
+ SEMAPHORE_TRIGGER(bgprint.stop);
+ }
+ while (bgprint.pagenum >= 0);
+ THREAD_RETURN();
+}
#endif
#ifdef MUDRAW_STANDALONE
@@ -1257,7 +1378,7 @@ int mudraw_main(int argc, char **argv)
fz_var(doc);
- while ((c = fz_getopt(argc, argv, "p:o:F:R:r:w:h:fB:c:G:I:s:A:DiW:H:S:T:U:Lv")) != -1)
+ while ((c = fz_getopt(argc, argv, "p:o:F:R:r:w:h:fB:c:G:I:s:A:DiW:H:S:T:U:LvP")) != -1)
{
switch (c)
{
@@ -1313,6 +1434,7 @@ int mudraw_main(int argc, char **argv)
break;
#endif
case 'L': lowmemory = 1; break;
+ case 'P': bgprint.active = 1; break;
case 'v': fprintf(stderr, "mudraw version %s\n", FZ_VERSION); return 1;
}
@@ -1335,6 +1457,15 @@ int mudraw_main(int argc, char **argv)
}
}
+ if (bgprint.active)
+ {
+ if (uselist == 0)
+ {
+ fprintf(stderr, "cannot bgprint without using display list\n");
+ exit(1);
+ }
+ }
+
ctx = fz_new_context((showmemory == 0 ? NULL : &alloc_ctx), LOCKS_INIT(), (lowmemory ? 1 : FZ_STORE_DEFAULT));
if (!ctx)
{
@@ -1345,6 +1476,14 @@ int mudraw_main(int argc, char **argv)
fz_set_text_aa_level(ctx, alphabits_text);
fz_set_graphics_aa_level(ctx, alphabits_graphics);
+ if (bgprint.active)
+ {
+ bgprint.ctx = fz_clone_context(ctx);
+ SEMAPHORE_INIT(bgprint.start);
+ SEMAPHORE_INIT(bgprint.stop);
+ THREAD_INIT(bgprint.thread, bgprint_worker, NULL);
+ }
+
if (num_workers > 0)
{
workers = fz_calloc(ctx, num_workers, sizeof(*workers));
@@ -1494,6 +1633,14 @@ int mudraw_main(int argc, char **argv)
timing.maxpage = 0;
timing.minfilename = "";
timing.maxfilename = "";
+ timing.render_count = 0;
+ timing.render_total = 0;
+ timing.render_min = 1 << 30;
+ timing.render_max = 0;
+ timing.render_minpage = 0;
+ timing.render_maxpage = 0;
+ timing.render_minfilename = "";
+ timing.render_maxfilename = "";
fz_try(ctx)
{
@@ -1528,6 +1675,7 @@ int mudraw_main(int argc, char **argv)
drawrange(ctx, doc, argv[fz_optind++]);
}
+ bgprint_flush();
fz_drop_document(ctx, doc);
doc = NULL;
}
@@ -1536,6 +1684,7 @@ int mudraw_main(int argc, char **argv)
if (!ignore_errors)
fz_rethrow(ctx);
+ bgprint_flush();
fz_drop_document(ctx, doc);
doc = NULL;
fz_warn(ctx, "ignoring error in '%s'", filename);
@@ -1544,6 +1693,7 @@ int mudraw_main(int argc, char **argv)
}
fz_catch(ctx)
{
+ bgprint_flush();
fz_drop_document(ctx, doc);
fprintf(stderr, "error: cannot draw '%s'\n", filename);
errored = 1;
@@ -1596,12 +1746,23 @@ int mudraw_main(int argc, char **argv)
SEMAPHORE_WAIT(workers[i].stop);
SEMAPHORE_FIN(workers[i].start);
SEMAPHORE_FIN(workers[i].stop);
- fz_drop_context(workers[i].ctx);
THREAD_FIN(workers[i].thread);
+ fz_drop_context(workers[i].ctx);
}
fz_free(ctx, workers);
}
+ if (bgprint.active)
+ {
+ bgprint.pagenum = -1;
+ SEMAPHORE_TRIGGER(bgprint.start);
+ SEMAPHORE_WAIT(bgprint.stop);
+ SEMAPHORE_FIN(bgprint.start);
+ SEMAPHORE_FIN(bgprint.stop);
+ THREAD_FIN(bgprint.thread);
+ fz_drop_context(bgprint.ctx);
+ }
+
fz_drop_context(ctx);
LOCKS_FIN();