Skip to content

Commit 8b5c8f8

Browse files
author
OutlyingWest
committed
BusySpinner() polishing
1 parent 8996680 commit 8b5c8f8

2 files changed

Lines changed: 23 additions & 29 deletions

File tree

src/jumper/kernel.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -802,10 +802,11 @@ async def scorep_execute(
802802
# e.g. tqdm for-loop progress bar
803803
self.cell_output("\0")
804804

805-
process_busy_spinner = BusySpinner()
805+
stdout_lock = threading.Lock()
806+
process_busy_spinner = BusySpinner(stdout_lock)
806807
process_busy_spinner.start('Process is running...')
807808

808-
multicellmode_timestamps = self.read_scorep_process_pipe(proc)
809+
multicellmode_timestamps = self.read_scorep_process_pipe(proc, stdout_lock)
809810

810811
process_busy_spinner.stop()
811812

@@ -962,11 +963,12 @@ async def scorep_execute(
962963
return self.standard_reply()
963964

964965

965-
def read_scorep_process_pipe(self, proc: subprocess.Popen[bytes]) -> list:
966+
def read_scorep_process_pipe(self, proc: subprocess.Popen[bytes], stdout_lock: threading.Lock) -> list:
966967
"""
967968
Reads and processes the output of a subprocess running with Score-P instrumentation.
968969
Args:
969970
proc (subprocess.Popen[bytes]): The subprocess whose output is being read.
971+
stdout_lock (threading.Lock): Lock to avoid output overlapping
970972
971973
Returns:
972974
list: A list of decoded strings containing "MCM_TS" timestamps.
@@ -977,6 +979,9 @@ def read_scorep_process_pipe(self, proc: subprocess.Popen[bytes]) -> list:
977979
sel.register(proc.stdout, selectors.EVENT_READ)
978980
sel.register(proc.stderr, selectors.EVENT_READ)
979981

982+
line_width = 50
983+
clear_line = "\r" + " " * line_width + "\r"
984+
980985
while True:
981986
# Select between stdout and stderr
982987
for key, val in sel.select():
@@ -988,11 +993,15 @@ def read_scorep_process_pipe(self, proc: subprocess.Popen[bytes]) -> list:
988993
decoded_line = line.decode(sys.getdefaultencoding(), errors='ignore')
989994

990995
if key.fileobj is proc.stderr:
991-
self.log.warning(f'{decoded_line.strip()}')
996+
with stdout_lock:
997+
self.log.warning(f'{decoded_line.strip()}')
992998
elif 'MCM_TS' in decoded_line:
993999
multicellmode_timestamps.append(decoded_line)
9941000
else:
995-
self.cell_output(decoded_line)
1001+
with stdout_lock:
1002+
sys.stdout.write(clear_line)
1003+
sys.stdout.flush()
1004+
self.cell_output(decoded_line)
9961005

9971006
# If both stdout and stderr empty -> out of loop
9981007
if not sel.get_map():

src/jumper/userpersistence.py

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def jupyter_dump(self):
121121
f"dump_variables({str(self.jupyter_variables)},globals(),"
122122
f"'{self.paths['jupyter']['var']}',"
123123
f"{self.marshaller})\n"
124-
"spinner.stop('Data is loaded!')\n"
124+
"spinner.stop('Data is loaded.')\n"
125125
)
126126

127127
return jupyter_dump_
@@ -390,26 +390,9 @@ def magics_cleanup(code):
390390
return scorep_env, nomagic_code
391391

392392

393-
def start_busy_spinner():
394-
pass
395-
396-
def stop_busy_spinner():
397-
pass
398-
399-
400-
def spinner_task(stop_event, message="Loading data..."):
401-
spinner = ['|', '/', '-', '\\']
402-
i = 0
403-
while not stop_event.is_set():
404-
sys.stdout.write(f'\r{message} {spinner[i % len(spinner)]}')
405-
sys.stdout.flush()
406-
time.sleep(0.1)
407-
i += 1
408-
sys.stdout.write('\rData is loaded to subprocess! \n')
409-
410-
411393
class BusySpinner:
412-
def __init__(self):
394+
def __init__(self, lock=None):
395+
self._lock = lock or threading.Lock()
413396
self._stop_event = threading.Event()
414397
self._thread = threading.Thread(target=self._spinner_task)
415398
self.working_message = ''
@@ -419,12 +402,14 @@ def _spinner_task(self):
419402
spinner_chars = "|/-\\"
420403
idx = 0
421404
while not self._stop_event.is_set():
422-
sys.stdout.write(f"\r{self.working_message} {spinner_chars[idx % len(spinner_chars)]}")
423-
sys.stdout.flush()
405+
with self._lock:
406+
sys.stdout.write(f"\r{self.working_message} {spinner_chars[idx % len(spinner_chars)]}")
407+
sys.stdout.flush()
424408
time.sleep(0.1)
425409
idx += 1
426-
sys.stdout.write(f"\r{self.done_message}")
427-
sys.stdout.flush()
410+
with self._lock:
411+
sys.stdout.write(f"\r{self.done_message}{' ' * len(self.working_message)}\n")
412+
sys.stdout.flush()
428413

429414
def start(self, working_message='Working...'):
430415
self.working_message = working_message

0 commit comments

Comments
 (0)