Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Doc/library/curses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,14 @@ The module :mod:`!curses` defines the following functions:
appearance of the screen.


.. function:: term_attrs()

Like :func:`termattrs`, but return the attributes as :ref:`WA_*
<curses-wa-constants>` values rather than ``A_*`` values.

.. versionadded:: next


.. function:: termname()

Return the value of the environment variable :envvar:`TERM`, as a bytes object,
Expand Down
8 changes: 8 additions & 0 deletions Doc/library/itertools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ loops that truncate the stream.
for iterable in iterables:
yield from iterable

Note that :pep:`798` unpacking syntax provides similar functionality
so that ``list(chain(p, q))`` could be written as
``[*s for s in (p, q)]``.


.. classmethod:: chain.from_iterable(iterable)

Expand All @@ -208,6 +212,10 @@ loops that truncate the stream.
for iterable in iterables:
yield from iterable

Note that :pep:`798` unpacking syntax provides similar functionality
so that ``list(chain.from_iterable(iterables))`` could be written as
``[*s for s in iterables]``.


.. function:: combinations(iterable, r)

Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ curses
:func:`~curses.scr_set`, which dump the whole screen to a file and restore it.
(Contributed by Serhiy Storchaka in :gh:`152260`.)

* Add the :func:`curses.term_attrs` function, which returns the supported
video attributes as :ref:`WA_* <curses-wa-constants>` values, the
counterpart of :func:`curses.termattrs`.
(Contributed by Serhiy Storchaka in :gh:`152332`.)

* Add the :mod:`curses` key-management functions :func:`~curses.define_key`,
:func:`~curses.key_defined` and :func:`~curses.keyok`, available when built
against an ncurses with ``NCURSES_EXT_FUNCS``.
Expand Down
81 changes: 53 additions & 28 deletions Lib/profiling/sampling/gecko_collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,25 @@ def collect(self, stack_frames, timestamps_us=None):
self.interval = (times[-1] - self.last_sample_time) / self.sample_count
self.last_sample_time = times[-1]

# Process async tasks
if stack_frames and hasattr(stack_frames[0], "awaited_by"):
for frames, thread_id, _ in self._iter_async_frames(stack_frames):
frames = filter_internal_frames(frames)
if not frames:
continue

if thread_id not in self.threads:
self.threads[thread_id] = self._create_thread(
thread_id, False
)

self._record_stack_sample(
self.threads[thread_id], frames, thread_id, times, first_time
)

self.sample_count += len(times)
return

# Process threads
for interpreter_info in stack_frames:
for thread_info in interpreter_info.threads:
Expand Down Expand Up @@ -333,37 +352,43 @@ def collect(self, stack_frames, timestamps_us=None):
if not frames:
continue

# Process stack once to get stack_index
stack_index = self._process_stack(thread_data, frames)

# Add samples with timestamps
thread_spill = thread_data["_spill"]
for t in times:
thread_spill.append_sample(stack_index, t)

# Handle opcodes
if self.opcodes_enabled and frames:
leaf_frame = frames[0]
filename, location, funcname, opcode = leaf_frame
if isinstance(location, tuple):
lineno, _, col_offset, _ = location
else:
lineno = location
col_offset = -1

current_state = (opcode, lineno, col_offset, funcname, filename)

if tid not in self.opcode_state:
self.opcode_state[tid] = (*current_state, first_time)
elif self.opcode_state[tid][:5] != current_state:
prev_opcode, prev_lineno, prev_col, prev_funcname, prev_filename, prev_start = self.opcode_state[tid]
self._add_opcode_interval_marker(
tid, prev_opcode, prev_lineno, prev_col, prev_funcname, prev_start, first_time
)
self.opcode_state[tid] = (*current_state, first_time)
self._record_stack_sample(
thread_data, frames, tid, times, first_time
)

self.sample_count += len(times)

def _record_stack_sample(self, thread_data, frames, tid, times, first_time):
stack_index = self._process_stack(thread_data, frames)

thread_spill = thread_data["_spill"]
for t in times:
thread_spill.append_sample(stack_index, t)

if self.opcodes_enabled and frames:
leaf_frame = frames[0]
filename, location, funcname, opcode = leaf_frame
if isinstance(location, tuple):
lineno, _, col_offset, _ = location
else:
lineno = location
col_offset = -1

current_state = (opcode, lineno, col_offset, funcname, filename)

if tid not in self.opcode_state:
self.opcode_state[tid] = (*current_state, first_time)
elif self.opcode_state[tid][:5] != current_state:
(
prev_opcode, prev_lineno, prev_col, prev_funcname,
prev_filename, prev_start
) = self.opcode_state[tid]
self._add_opcode_interval_marker(
tid, prev_opcode, prev_lineno, prev_col, prev_funcname,
prev_start, first_time
)
self.opcode_state[tid] = (*current_state, first_time)

def _create_thread(self, tid, is_main_thread):
"""Create a new thread structure with processed profile format."""
if self.spill_dir is None:
Expand Down
Loading
Loading