Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Threaded vs. Interrupt Approach #91

Closed
jlfwong opened this issue Nov 28, 2017 · 10 comments
Closed

Threaded vs. Interrupt Approach #91

jlfwong opened this issue Nov 28, 2017 · 10 comments

Comments

@jlfwong
Copy link
Collaborator

jlfwong commented Nov 28, 2017

Today I tried enabling https://github.com/jlfwong/rack-mini-profiler for developers at Figma, but had to turn it off almost immediately because we discovered that the sampling profiler causes interrupts to fire in the middle of network requests to S3, causing those S3 requests to fail. I suspect this is because the system calls underlying those network requests return early with an error code if they're interrupted.

I believe other approaches to sampled profiling involve creating a separate thread to sample periodically. This will have significantly more performance overhead, but overcomes the obstacles with network request failure.

Is it possible to use such an approach in Ruby? If so, is this something you would want to support as part of stackprof? Or would that be better suited for an entirely different project?

@tmm1
Copy link
Owner

tmm1 commented Nov 28, 2017

I've run stackprof on large scale production traffic sites (like this one) without issue. Sounds like there may be a bug in the s3 library you're using, where it doesn't handle EINTR correctly and retry.

Although iirc we are using SA_RESTART so interruptions shouldn't even bubble up in the first place.

@jlfwong
Copy link
Collaborator Author

jlfwong commented Nov 28, 2017

Based on http://man7.org/linux/man-pages/man7/signal.7.html, it sounds like there a variety of functions that are never restarted, regardless of the use of SA_RESTART. These methods include recv and send, which are presumably used under the hood by the S3 library.

@tmm1
Copy link
Owner

tmm1 commented Nov 28, 2017

What library is it?

Networking code generally loops around EINTR for this reason.

@jlfwong
Copy link
Collaborator Author

jlfwong commented Nov 28, 2017

https://github.com/aws/aws-sdk-ruby, specifically version 2.8.7

@tmm1
Copy link
Owner

tmm1 commented Nov 28, 2017

Do you have a stack trace of the failure?

@tmm1
Copy link
Owner

tmm1 commented Nov 28, 2017

The approach in stackprof was copied from gperftools, which google also uses extensively internally. If a library doesn't react well to signal interruption, it's a bug in that library.

Sampling via a thread is an interesting idea. You could do that for wall time profiling, but I'm not sure how cpu profiling would work with a thread. Either way, probably best to implement something like that in a separate project? You could do it with a ruby thread, and there might be something like that already implemented in ruby-prof or other profiler.

@jlfwong
Copy link
Collaborator Author

jlfwong commented Nov 28, 2017

Thanks for the really fast responses, as always :) You're a very helpful maintainer.

I'll try to dig up a stack trace later, and see if I can identify a bug in the S3 library.

If that ends up being a rabbit hole, I'll investigate other profiling libraries.

@jlfwong
Copy link
Collaborator Author

jlfwong commented Dec 8, 2017

Okay, I dug a little further, and on second look, I don't think it has anything to do with S3.

It seems like an interaction with the thread pool being used by https://github.com/chadrem/workers (we parallelize S3 uploads using that library).

require 'workers'
require 'stackprof'

group = Workers::TaskGroup.new
group.add { sleep(1) }
StackProf.run(mode: :wall, interval: 500, raw: true) do
  puts group.run
end
puts group.tasks[0].state

I would expect this to output:

true
suceeded

What it actually outputs is

false
running

If I remove the Stackprof.Run (so the resulting script is just this):

require 'workers'
require 'stackprof'

group = Workers::TaskGroup.new
group.add { sleep(1) }
puts group.run
puts group.tasks[0].state

Then the result is indeed

true
succeeded

I recognize that this is likely a bug with the workers library, and not with stackprof, but just figured I'd post here in case I'm wrong about that, or if you have any insights about the potential cause.

@jlfwong
Copy link
Collaborator Author

jlfwong commented Dec 8, 2017

Found a fix: chadrem/workers#8 (comment)

Closing this now, since this ended up having nothing to do with stackprof :)

@jlfwong jlfwong closed this as completed Dec 8, 2017
@tmm1
Copy link
Owner

tmm1 commented Dec 8, 2017

Nice find. May be worth reporting up to ruby-core too, as it seems CondVar#wait should have more sane behavior here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants