Skip to content

Commit

Permalink
Improve performance during refresh
Browse files Browse the repository at this point in the history
  • Loading branch information
blogh committed Oct 20, 2021
1 parent 7ff0dcf commit 86f338f
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 14 deletions.
6 changes: 3 additions & 3 deletions pgactivity/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def pg_get_activities(self, duration_mode: int = 1) -> List[RunningProcess]:
cur.execute(query, {"min_duration": self.min_duration})
ret = cur.fetchall()

return [RunningProcess(**row) for row in ret]
return [RunningProcess(**row, display=None) for row in ret]

def pg_get_waiting(self, duration_mode: int = 1) -> List[WaitingProcess]:
"""
Expand All @@ -274,7 +274,7 @@ def pg_get_waiting(self, duration_mode: int = 1) -> List[WaitingProcess]:
with self.pg_conn.cursor() as cur:
cur.execute(query, {"min_duration": self.min_duration})
ret = cur.fetchall()
return [WaitingProcess(**row) for row in ret]
return [WaitingProcess(**row, display=None) for row in ret]

def pg_get_blocking(self, duration_mode: int = 1) -> List[BlockingProcess]:
"""
Expand All @@ -293,7 +293,7 @@ def pg_get_blocking(self, duration_mode: int = 1) -> List[BlockingProcess]:
with self.pg_conn.cursor() as cur:
cur.execute(query, {"min_duration": self.min_duration})
ret = cur.fetchall()
return [BlockingProcess(**row) for row in ret]
return [BlockingProcess(**row, display=None) for row in ret]

def pg_is_local(self) -> bool:
"""
Expand Down
11 changes: 6 additions & 5 deletions pgactivity/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -693,17 +693,18 @@ class BaseProcess:
state: str
query: Optional[str]
is_parallel_worker: bool
display: Optional[str]


@attr.s(auto_attribs=True, frozen=True, slots=True)
@attr.s(auto_attribs=True, slots=True)
class RunningProcess(BaseProcess):
"""Process for a running query."""

wait: Union[bool, None, str]
is_parallel_worker: bool


@attr.s(auto_attribs=True, frozen=True, slots=True)
@attr.s(auto_attribs=True, slots=True)
class WaitingProcess(BaseProcess):
"""Process for a waiting query."""

Expand All @@ -717,7 +718,7 @@ class WaitingProcess(BaseProcess):
is_parallel_worker: bool = attr.ib(default=False, init=False)


@attr.s(auto_attribs=True, frozen=True, slots=True)
@attr.s(auto_attribs=True, slots=True)
class BlockingProcess(BaseProcess):
"""Process for a blocking query."""

Expand All @@ -732,7 +733,7 @@ class BlockingProcess(BaseProcess):
is_parallel_worker: bool = attr.ib(default=False, init=False)


@attr.s(auto_attribs=True, frozen=True, slots=True)
@attr.s(auto_attribs=True, slots=True)
class SystemProcess:
meminfo: Tuple[int, ...]
io_read: IOCounter
Expand All @@ -747,7 +748,7 @@ class SystemProcess:
psutil_proc: Optional[psutil.Process]


@attr.s(auto_attribs=True, frozen=True, slots=True)
@attr.s(auto_attribs=True, slots=True)
class LocalRunningProcess(RunningProcess):
cpu: float
mem: float
Expand Down
1 change: 1 addition & 0 deletions pgactivity/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ def main(
message=msg_pile.get(),
render_header=render_header,
render_footer=render_footer,
paused=ui.in_pause or ui.interactive(),
width=width,
)

Expand Down
158 changes: 152 additions & 6 deletions pgactivity/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,16 @@ def limit(func: Callable[..., Iterable[str]]) -> Callable[..., None]:
@functools.wraps(func)
def wrapper(term: Terminal, *args: Any, **kwargs: Any) -> None:
counter = kwargs.pop("lines_counter", None)
do_wrapping = kwargs.pop("do_wrapping", True)
width = kwargs.pop("width", None)
signature = inspect.signature(func)
if "width" in signature.parameters:
kwargs["width"] = width
for line in func(term, *args, **kwargs):
print(shorten(term, line, width) + term.clear_eol)
if do_wrapping:
print(shorten(term, line, width) + term.clear_eol)
else:
print(line)
if counter is not None and next(counter) == 1:
break

Expand Down Expand Up @@ -310,9 +314,8 @@ def format_query(query: str, is_parallel_worker: bool) -> str:
prefix = r"\_ " if is_parallel_worker else ""
return prefix + utils.clean_str(query)


@limit
def processes_rows(
def old_processes_rows(
term: Terminal,
ui: UI,
processes: SelectableProcesses,
Expand Down Expand Up @@ -405,6 +408,148 @@ def cell(
yield line


def processes_rows(
term: Terminal,
ui: UI,
processes: SelectableProcesses,
lines_counter: line_counter,
width: int,
paused: bool = False,
) -> None:
if not paused:
# generate the lines only the first time we pause
prepare_processes_rows(
term,
ui,
processes,
width=width,
)
# display the line and add the focus, selection on top as we go
display_processes_rows(
term,
ui,
processes,
lines_counter.value, # for display_process_rows()
lines_counter=lines_counter, # for @limit
width=width,
do_wrapping=False
)


def prepare_processes_rows(
term: Terminal,
ui: UI,
processes: SelectableProcesses,
width: Optional[int],
) -> None:
"""Display table rows with processes information."""

if width is None:
width = term.width

def text_append(value: str) -> None:
# We also restore 'normal' style so that the next item does not
# inherit previous one's style.
text.append(value + term.normal)

def cell(
value: Any,
column: Column,
) -> None:
# FIXME need to hangle colore properly
color = getattr(term, colors.FIELD_BY_MODE[column.color(value)]["default"])
text_append(f"{color}{column.render(value)}")

for process in processes:

text: List[str] = []
for column in ui.columns():
field = column.key
if field != "query":
cell(getattr(process, field), column)

indent = get_indent(ui) + " "
dif = width - len(indent)

query_display_mode = ui.query_display_mode
if dif < 0:
# Switch to wrap_noindent mode if terminal is too narrow.
query_display_mode = QueryDisplayMode.wrap_noindent

if process.query is not None:
query = format_query(process.query, process.is_parallel_worker)

if query_display_mode == QueryDisplayMode.truncate:
query_value = query[:dif]
else:
if query_display_mode == QueryDisplayMode.wrap_noindent:
if term.length(query.split(" ", 1)[0]) >= dif:
# Query too long to even start on the first line, wrap all
# lines.
query_lines = TextWrapper(width).wrap(query)
else:
# Only wrap subsequent lines.
wrapped_lines = TextWrapper(dif, drop_whitespace=False).wrap(
query
)
if wrapped_lines:
query_lines = [wrapped_lines[0]] + TextWrapper(width).wrap(
"".join(wrapped_lines[1:]).lstrip()
)
else:
query_lines = []
query_value = "\n".join(query_lines)
else:
assert (
query_display_mode == QueryDisplayMode.wrap
), f"unexpected mode {query_display_mode}"
wrapped_lines = TextWrapper(dif).wrap(query)
query_value = f"\n{indent}".join(wrapped_lines)

cell(query_value, ui.column("query"))

# FIXME there was a splitline() here
process.display = shorten(term, " ".join(text) + term.normal, width) + term.clear_eol


@limit
def display_processes_rows(
term: Terminal,
ui: UI,
processes: SelectableProcesses,
maxlines: int,
width: Optional[int],
) -> Iterator[str]:
"""Display table rows with processes information."""

focused, pinned = processes.focused, processes.pinned

# Scrolling is handeled here. we just have to manage the start position of the display.
# the length is managed by @limit. we try to have a 5 line leeway at the bottom of the
# page to increase readability.
position = processes.position()
start = 0
bottom = int(maxlines // 5)
if position is not None and position >= maxlines - bottom:
start = position - maxlines + 1 + bottom

for process in processes[start:]:
if process.display is None:
continue
line = process.display

# set the "special effects"
# FIXME use the proper colors later
if process.pid == focused:
line = term.on_red(line)
elif process.pid in pinned:
line = term.yellow(line)
else:
line = term.on_white(line)

yield line


def footer_message(term: Terminal, message: str, width: Optional[int] = None) -> None:
if width is None:
width = term.width
Expand Down Expand Up @@ -473,6 +618,7 @@ def screen(
message: Optional[str],
render_header: bool = True,
render_footer: bool = True,
paused: bool = False,
width: Optional[int] = None,
) -> None:
"""Display the screen."""
Expand Down Expand Up @@ -508,9 +654,9 @@ def screen(
term,
ui,
processes,
maxlines=lines_counter.value, # Used by process_rows
lines_counter=lines_counter, # Used by @limit
width=width,
lines_counter=lines_counter,
width=term.width,
paused=paused,
)

# Clear remaining lines in screen until footer (or EOS)
Expand Down

0 comments on commit 86f338f

Please sign in to comment.