Skip to content

Conversation

georgeharker
Copy link

As per #352 I have modified pyinstrument to support multiple threads.

It does this by separating out both timing and frames for the different threads - as such it modifies a substantial amount of the data model (usually in the form of List[frames] -> Dict[str, List[Frames]] and the equivalents in typescript.

I don't do much typescript so it's possible there are prettier ways of doing the modifications on that side.

  • I've modified most of(but not all) of the renderers (I don't use / have speedscope so I'm not sure of the best fix there).
  • I'm sure the ux could be tidied, the threads come out in arbitrary order in the timeline view and it would ideally be possible to easily toggle various threads off etc).

I'd be interested in discussing how this looks to you

@lucamuscat
Copy link

Hey 👋

Good work!

It seems that you still need to insert the thread_start_times field in Session.from_json & Session.combine

Copy link
Owner

@joerick joerick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for sending this over. It's certainly ambitious! But it would be a good improvement to get this working. I'm still a bit confused about how this works. Do you have a sample script that illustrates how it's supposed to work?

@dataclass
class StackSamplerSubscriberTarget:
call_stack: SubscriberCallstackFn
event: SubscriberEventFn
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can combine this event and async_state change concepts into one interface. It seems that they're pretty similar to me.

Comment on lines +48 to +51
def record_thread_start(self, thread_id: str, time: float) -> None:
if not self.thread_start_times:
self.first_start_time = time
self.thread_start_times[thread_id] = time - self.first_start_time
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not store the raw start time in each, rather than the offset from the first_start_time? Generally I find it better to store truth over computed values.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially tried raw time but it had some complexity when trying to view the traces on the same view, i'd be happy to look at that again.

self._active_session.record_thread_start(thread_id, time)

# pylint: disable=W0613
def _sampler_saw_call_stack(
Copy link
Owner

@joerick joerick Jan 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused why this method _sampler_saw_call_stack doesn't need to change? Don't we need to separate out the storage of the different threads?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The frame records get a root thread id added which allows us to reconstruct what is separate - this is done in build_call_stack

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(different threads will never clash in the pythons code due to the GIL)

@georgeharker
Copy link
Author

Done!

Hey 👋

Good work!

It seems that you still need to insert the thread_start_times field in Session.from_json & Session.combine

Done!

@mjgp2
Copy link

mjgp2 commented Apr 8, 2025

Hi @lucamuscat 😄

Is there anything stopping this being merged?

@lucamuscat
Copy link

Hi @lucamuscat 😄

Is there anything stopping this being merged?

Hey 👋
I'm not a maintainer of this project, I had just left some comments as I was also looking at this PR and was hoping to help out in getting it merged.

@joerick is the right person to ask.

@georgeharker
Copy link
Author

There were some unresolved comments that I can help with (though a little snowed under work wise). I don't think it's super far off

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

Successfully merging this pull request may close these issues.

4 participants