watir-screenshot-stitch icon indicating copy to clipboard operation
watir-screenshot-stitch copied to clipboard

Added Multithreaded image magic and file write execution.

Open deibele1 opened this issue 3 years ago • 7 comments

Ruby is thread locked so typically you wont see much improvement from multithreading unless ruby is waiting on an external resource. Image Magick and writing to the drive can run while their ruby thread sleeps and the main thread continues for a dramatic performance improvement.

deibele1 avatar May 06 '21 18:05 deibele1

@deibele1 Thanks for this. It makes a lot of sense, as this stitch is lengthy. However, I think we need to update our tests – not just because they are failing with this change, but because we should also use them to teach people (including me :] ) how best to wait for the file to be written.

$ bundle _1.16.0_ exec rspec spec/watir-screenshot-stitch_spec.rb:25
Run options: include {:locations=>{"./spec/watir-screenshot-stitch_spec.rb"=>[25]}}

Watir::Screenshot
  driving firefox
    saves stitched-together color screenshot (FAILED - 1)

Failures:

  1) Watir::Screenshot driving firefox saves stitched-together color screenshot
     Failure/Error: expect(image.colorspace).not_to match(/gray/i)

       expected "DirectClass Gray Alpha" not to match /gray/i
       Diff:
       @@ -1 +1 @@
       -/gray/i
       +"DirectClass Gray Alpha"

     # ./spec/watir-screenshot-stitch_spec.rb:45:in `block (3 levels) in <top (required)>'

Finished in 11.12 seconds (files took 0.4652 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/watir-screenshot-stitch_spec.rb:25 # Watir::Screenshot driving firefox saves stitched-together color screenshot

samnissen avatar May 14 '21 09:05 samnissen

One way make sure the action is completed for the sake of testing would be return the thread and join it before starting your test. I'll push some changes for you to try.

On Fri, May 14, 2021 at 5:10 AM Sam @.***> wrote:

@deibele1 https://github.com/deibele1 Thanks for this. It makes a lot of sense, as this stitch is lengthy. However, I think we need to update our tests – not just because they are failing with this change, but because we should also use them to teach people (including me :] ) how best to wait for the file to be written.

$ bundle 1.16.0 exec rspec spec/watir-screenshot-stitch_spec.rb:25

Run options: include {:locations=>{"./spec/watir-screenshot-stitch_spec.rb"=>[25]}}

Watir::Screenshot

driving firefox

saves stitched-together color screenshot (FAILED - 1)

Failures:

  1. Watir::Screenshot driving firefox saves stitched-together color screenshot

    Failure/Error: expect(image.colorspace).not_to match(/gray/i)

    expected "DirectClass Gray Alpha" not to match /gray/i

    Diff:

    @@ -1 +1 @@

    -/gray/i

    +"DirectClass Gray Alpha"

    ./spec/watir-screenshot-stitch_spec.rb:45:in `block (3 levels) in <top (required)>'

Finished in 11.12 seconds (files took 0.4652 seconds to load)

1 example, 1 failure

Failed examples:

rspec ./spec/watir-screenshot-stitch_spec.rb:25 # Watir::Screenshot driving firefox saves stitched-together color screenshot

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/samnissen/watir-screenshot-stitch/pull/64#issuecomment-841119346, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOST6N2FWPL4V2PFQ5QXEHLTNTSHFANCNFSM44HVPATA .

deibele1 avatar May 14 '21 13:05 deibele1

Another approach would be to let a parameter determine whether to run the stitch concurrently or synchronously.

On Fri, May 14, 2021 at 9:45 AM Aaron Deibele @.***> wrote:

One way make sure the action is completed for the sake of testing would be return the thread and join it before starting your test. I'll push some changes for you to try.

On Fri, May 14, 2021 at 5:10 AM Sam @.***> wrote:

@deibele1 https://github.com/deibele1 Thanks for this. It makes a lot of sense, as this stitch is lengthy. However, I think we need to update our tests – not just because they are failing with this change, but because we should also use them to teach people (including me :] ) how best to wait for the file to be written.

$ bundle 1.16.0 exec rspec spec/watir-screenshot-stitch_spec.rb:25

Run options: include {:locations=>{"./spec/watir-screenshot-stitch_spec.rb"=>[25]}}

Watir::Screenshot

driving firefox

saves stitched-together color screenshot (FAILED - 1)

Failures:

  1. Watir::Screenshot driving firefox saves stitched-together color screenshot

    Failure/Error: expect(image.colorspace).not_to match(/gray/i)

    expected "DirectClass Gray Alpha" not to match /gray/i

    Diff:

    @@ -1 +1 @@

    -/gray/i

    +"DirectClass Gray Alpha"

    ./spec/watir-screenshot-stitch_spec.rb:45:in `block (3 levels) in <top (required)>'

Finished in 11.12 seconds (files took 0.4652 seconds to load)

1 example, 1 failure

Failed examples:

rspec ./spec/watir-screenshot-stitch_spec.rb:25 # Watir::Screenshot driving firefox saves stitched-together color screenshot

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/samnissen/watir-screenshot-stitch/pull/64#issuecomment-841119346, or unsubscribe https://github.com/notifications/unsubscribe-auth/AOST6N2FWPL4V2PFQ5QXEHLTNTSHFANCNFSM44HVPATA .

deibele1 avatar May 14 '21 14:05 deibele1

@deibele1 I still like this, but what the test changes show me is that this would break existing implementation, which I'm not in favor of. Could we break out the threading via a default-false option, like

opts = { thread_image_stitching: true }
thread = @browser.screenshot.save_stitch(file_path, opts)
# -or-
@browser.screenshot.save_stitch(file_path, {}) #=> no thread returned

Internally I'm imagining tidying up save_stitch a bit in a way that might allow us to reuse the threading in other places one day:

def save_stitch(path, opts = {})
  return @browser.screenshot.save(path) if base64_capable?

  @options = opts
  @path = path

  calculate_dimensions
  return self.save(@path) if (one_shot? || bug_shot?)

  build_canvas
  gather_slices

  if opts[: thread_image_stitching]
    return thread { do stitching }
  else
    do_stitching
  end
end

# ...
def thread(&block)
  stitch = Thread.new do
    isolator.synchronize do
      block.call
    end
  end
  at_exit { stitch.join }
  stitch
end

def do_stitching
  stitch_together
  @combined_screenshot.write @path
end

Let me know what you think

samnissen avatar Jun 09 '21 15:06 samnissen

It looks like a good approach. I think you missed and underscore in "return thread { do stitching }" and I would name the thread method something like exclusive_thread to better distinguish it from Thread.

deibele1 avatar Jun 09 '21 16:06 deibele1

This looks good to me @deibele1, though it is definitely far outside my area of expertise. @sandeepnagra Can you please also review?

samnissen avatar Jun 16 '21 19:06 samnissen

This looks good to me @deibele1, though it is definitely far outside my area of expertise. @sandeepnagra Can you please also review?

Yes, I can take a look at it later today.

sandeepnagra avatar Jun 17 '21 14:06 sandeepnagra