Bug 692057 - Ghostscript hangs at 300 dpi
Summary: Ghostscript hangs at 300 dpi
Status: NOTIFIED FIXED
Alias: None
Product: Ghostscript
Classification: Unclassified
Component: General (show other bugs)
Version: master
Hardware: PC All
: P1 normal
Assignee: Ray Johnston
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-03-11 16:03 UTC by Marcos H. Woehrmann
Modified: 2012-04-12 17:13 UTC (History)
2 users (show)

See Also:
Customer: 850
Word Size: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Marcos H. Woehrmann 2011-03-11 16:03:46 UTC
Created attachment 7359 [details]
58283.pdf

The customer reports I've verified that gs9.01 hangs when the attached file is ripped at 300dpi.  I've duplicated this with 9.01 and head (r12281).

The command line I'm using for testing:

  bin/gs -sDEVICE=tiff24nc -o test.tif -r300 ./58283.pdf
Comment 1 Marcos H. Woehrmann 2011-03-11 16:06:23 UTC
Further information from the customer:

When ripping the attached file with GS 9.01 the program works fine at e.g.
100 and 200 dpi but at 300 dpi or higher it hangs.
The effect can also be seen with Ghostview (version 4.9 with GS 9.01) when
zooming in enough; I could see *no* progress.
Strange is that in GS as well as Adobe Reader 9.4.2 there are quite large
rastered areas (grey/white and green/white) whereas in Foxit 4.3.1 these
aras are white.
Also, there are *no* callbacks (as specified in the init function of the
DLL) at the time GS hangs.

Most of the time seems to be used in the loop in gxacpath.c, function
accum_fill_rectangle, lines 476..477:
===
   /* Work backwards till we find the insertion point. */
   while (ye <= rptr->ymin)
     rptr = rptr->prev;
===

Parameters for gswin32c:
-P- -dBATCH -dNOPAUSE -Z: -r300x300 -sOUTPUTFILE=38028.tif
-sDEVICE=tiff24nc -dFirstPage=1 -dLastPage=1 -dNOCIE -dNOPSICC -dUseCropBox
-d.IgnoreNumCopies=true -c (58283.pdf) run

Famous last words:
===>
% Init started, instance 0x003F5F88, with args: -dDisplayFormat=198788
-dDisplayResolution=96 -P- -dBATCH -dNOPAUSE -Z: -r300x300
-sOUTPUTFILE=38028.tif -sDEVICE=tiff24nc -dFirstPage=1 -dLastPage=1 -dNOCIE
-dNOPSICC -dUseCropBox -d.IgnoreNumCopies=true -c (d:/58283.pdf) run
GPL Ghostscript 9.01 (2011-02-07)
Copyright (C) 2010 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
[:]width=2479, band_width=2479, band_height=456, nbands=8
[:]width=2479, band_width=2479, band_height=456, nbands=8
% Start time = 1.843, memory allocated = 1580512, used = 1425077
pdfpagecount=1
Processing pages 1 through 1.
Page 1
[:]width=16538, band_width=16538, band_height=68, nbands=158
[:]width=16538, band_width=16538, band_height=68, nbands=158
Can't find (or can't open) font file %rom%Resource/Font/ArialMT.
Can't find (or can't open) font file ArialMT.
Can't find (or can't open) font file %rom%Resource/Font/ArialMT.
Can't find (or can't open) font file ArialMT.
Querying operating system for font files...
Didn't find this font on the system!
Substituting font Helvetica for ArialMT.
Loading NimbusSanL-Regu font from %rom%Resource/Font/NimbusSanL-Regu...
2524896 1191873 1947640 650172 3 done.
Substituting font Helvetica-Narrow for ArialNarrow.
Loading NimbusSanL-ReguCond font from
%rom%Resource/Font/NimbusSanL-ReguCond... 2601872 1294323 2152620 848878 3
done.
[:]clist_end_page at cfile=10581, bfile=120
<===
Comment 2 Marcos H. Woehrmann 2011-03-11 16:23:07 UTC
This is a regression, the problem started with:

------------------------------------------------------------------------
r11579 | ray | 2010-07-30 17:37:07 -0700 (Fri, 30 Jul 2010) | 6 lines

Fix the calculation of the size of the pattern bitmap by correcting the
calculation of the effective depth (bits per pixel). PaintType 2 is the
uncolored (mask == 1 bit per pixel) mode, PaintType 1 is colored, thus
needs the full target device color_info.depth bits per pixel. Bug 691514
detected running the PDF 1.7 FTS for customer 532.

------------------------------------------------------------------------
Comment 3 Henry Stiles 2011-06-04 23:53:08 UTC
P1 for regression and hang.
Comment 4 Ray Johnston 2011-06-18 19:46:49 UTC
I am looking into this and have found an area of code that may be the root
cause.

As a temporary work around, the following halps.


The PDF contains:

%Resolving: [102 0]
%Pattern: << /PaintType 1 /XStep 128 /PaintProc {<< /XObject 
<< /Im2 {32 0 resolveR} >> /ExtGState << /GS1 {90 0 resolve R} >>
   /ColorSpace << /Cs10 {101 0 resolveR} /Cs6 {82 0 resolveR} >> 
   /ProcSet [/PDF /ImageC /ImageI] >> .pdfpaintproc} /Resources 
  {102 0 resolveR} /YStep 32 /.pattern_uses_transparency false 
  /PatternType 1 /Matrix [-2.13028193 0 0 -33.4684372 741.559387 1243.65186]
/Filter /FlateDecode /TilingType 1 /Type /Pattern /BBox [0 0 128 32] 
/Length 51 /File (...) 
>>

At 300 dpi, the pattern is 4463 by 1137 pixels so with a depth of 24 bits
this calculates (correctly) a bitmap size of 15,223,293 bytes which exceeds
the default MaxPatternBitmap of 8Mb.

Setting -dMaxPatternBitmap=32000000 this completes on my laptop in 58 seconds.
It takes 48 seconds to write the clist which is 114,407,724 Mb.

Note that adding -dBufferSpace=32000000 (so that only 20 bands are needed
instead of 158) completes in 51 seconds.

-----------------------
Comment 5 Ray Johnston 2011-06-19 21:40:22 UTC
The time is being spent turning a large mask (1143x4471 landscape) into
a clip list (ordered list of rectangles) which is started by 
gx_image_fill_masked_start detects that the pattern is a clist. This is so
that we don't play back the clist for each and every 'fill_masked' that happens
when the pattern is a tile.

For this landscape image 8 bit wide "swaths" of the image (full height) are
collected and then fed into the clip accumulator as 'copy_mono' calls. The
clip accumulator expects that it will be fed with y-ordered calls, so it
searches the list of rectangles from the tail back. This is fine for the
first swath that is painted with increasing y order, but for subsequent
swaths, it must search all the way back to the start of the list to insert
new rectangles. As more and more of the mask is turned into rectangles in the
clip list, this gets worse and worse, particularly since each group of
rectangles across x grows.

We need a smarter way of turning an image mask into the correct sequence of
rectangles. Ideas come to mind like collecting the list x-major (for this case)
then converting to y-major just once. or using a binary tree for the y list
and the list of rectangles in x order at each y entry.

Others may have code laying around we can apply, so I'll email tech and ask
for ideas.
Comment 6 Robin Watts 2011-06-20 10:28:44 UTC
This can be handled fairly simply.

Instead of holding a single sorted list into which we insert each new rectangle, instead, we hold 2 sorted lists. Let's call them master and temp. Whenever we get a new edge in, we check to see if it can be trivially inserted into the top or bottom of temp. If it can't, then we merge temp with master, and restart a new temp list that contains just the single rectangle.

This means that in the example given, most of our insertions are simple head/tail additions. The ones that aren't result in merges of 2 lists (an O(n) process).

This also copes nicely with the cases where the images are rotated by 180 degrees from the normal portrait/landscape cases, and the y ordering on incoming rectangles tends to be reversed.
Comment 7 Robin Watts 2011-06-20 18:44:07 UTC
Fixed in:

commit da1152191fb97516b82303ab187b08c971bfd360
Author: Robin Watts <Robin.Watts@artifex.com>
Date:   Mon Jun 20 17:57:46 2011 +0100

    Fix Bug 692057, 'hang' while converting mask->rectangle list.

    Previously the clip accumulator code would attempt to add a new
    rectangle would always search backwards from the tail of the
    list when looking for a new place to insert a rectangle.

    This works well when rectangles are coming in at (or near) the
    end of the list. For cases where this doesn't happen we quickly
    break down to O(n^2) operation.

    The example file on the bug shows one such circumstance, where
    we process a landscape image; this results in the masks coming
    in as '8 bit columns'. The first column accumulates nicely,
    subsequent ones do not.

    The fix here, as suggested by Chris Liddell, is to store the
    'last insert point', and to search from that. Locality of
    reference should pay off here and lead to much improved
    performance. Certainly tests with the example file show that we
    complete within 2.5 minutes on my machine, compared to 1.5 minutes
    with -dMaxPatternBitmap=32000000, and an unknown time over 5 minutes
    with the old code.

(Old code was tested on Rays machine and took over 2 hours before we gave up and killed it).