Skip to content

Commit b74e3a1

Browse files
authored
Fix limited buffer size when using pty (#107)
`bpftrace` outputs are sometimes truncated when too long, but everything after ^c is still there. It's just too fragile. Let's use Popen for now.
1 parent 3c94d4c commit b74e3a1

File tree

4 files changed

+26
-28
lines changed

4 files changed

+26
-28
lines changed

docs/src/changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212

1313
### Security
1414

15+
## [`v0.3.8` (2023-02-21)](https://github.com/anupli/running-ng/releases/tag/v0.3.8)
16+
### Changed
17+
#### Commands
18+
- `runbms`: companion programs are now expected to self-terminate.
19+
1520
## [`v0.3.7` (2023-02-14)](https://github.com/anupli/running-ng/releases/tag/v0.3.7)
1621
### Fixed
1722
#### Commands

docs/src/references/suite.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,18 @@ Second, a dictionary of strings with shell-like syntax to specify possibly diffe
6767
If a benchmark doesn't have a wrapper in the dictionary, it is treated as `null`.
6868

6969
`companion` (preview ⚠️): the syntax is similar to `wrapper`.
70-
The companion program will start before the main program and run in a separate terminal.
70+
The companion program will start before the main program.
7171
The main program will start two seconds after the companion program to make sure the companion is fully initialized.
72-
Once the main program finishes, `^C` is sent to the terminal to stop the companion program.
72+
Once the main program finishes, we will wait for the companion program to finish.
73+
Therefore, companion programs should have appropriate timeouts or detect when main program finishes.
7374
Here is an example of using `companion` to launch `bpftrace` in the background to count the system calls.
7475
```yaml
7576
includes:
7677
- "$RUNNING_NG_PACKAGE_DATA/base/runbms.yml"
7778
7879
overrides:
7980
"suites.dacapo2006.timing_iteration": 1
80-
"suites.dacapo2006.companion": "sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @syscall[args->id] = count(); @process[comm] = count();} END { printf(\"Goodbye world!\\n\"); }'"
81+
"suites.dacapo2006.companion": "sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @syscall[args->id] = count(); @process[comm] = count();} interval:s:10 { printf(\"Goodbye world!\\n\"); exit(); }'"
8182
"invocations": 1
8283
8384
benchmarks:

src/running/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
VERSION = (0, 3, 7)
1+
VERSION = (0, 3, 8)
22
__VERSION__ = '.'.join(map(str, VERSION))

src/running/benchmark.py

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,10 @@ def run(self, runtime: Runtime, cwd: Optional[Path] = None) -> Tuple[bytes, byte
9595
companion_out = b""
9696
stdout: Optional[bytes]
9797
if self.companion:
98-
pid, fd = pty.fork()
99-
if pid == 0:
100-
os.execvp(self.companion[0], self.companion)
98+
companion_p = subprocess.Popen(
99+
self.companion, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
100+
sleep(COMPANION_WAIT_START)
101101
try:
102-
if self.companion:
103-
# Wait for the companion program to start
104-
sleep(COMPANION_WAIT_START)
105102
p = subprocess.run(
106103
cmd,
107104
env=env_args,
@@ -120,25 +117,20 @@ def run(self, runtime: Runtime, cwd: Optional[Path] = None) -> Tuple[bytes, byte
120117
stdout = e.stdout
121118
finally:
122119
if self.companion:
123-
# send ^C to the companion's controlling terminal
124-
# this is so that we can terminal setuid programs like sudo
125-
os.write(fd, b"\x03")
126-
while True:
127-
try:
128-
output = os.read(fd, 1024)
129-
if not output:
130-
break
131-
companion_out += output
132-
except OSError as e:
133-
if e.errno == errno.EIO:
134-
break
135-
pid_wait, status = os.waitpid(pid, 0)
136-
assert pid_wait == pid
137-
exitcode = os.waitstatus_to_exitcode(status)
138-
if exitcode != 0:
120+
try:
121+
companion_stdout, _ = companion_p.communicate(
122+
timeout=10)
123+
companion_out += companion_stdout
124+
except subprocess.TimeoutExpired:
139125
logging.warning(
140-
"Exit code {} for the companion process".format(exitcode))
141-
os.close(fd)
126+
"Companion program not exited after 10 seconds timeout. Trying to kill ...")
127+
try:
128+
companion_p.kill()
129+
except PermissionError:
130+
logging.warning("Failed to kill.")
131+
companion_stdout, _ = companion_p.communicate()
132+
companion_out += companion_stdout
133+
142134
return stdout if stdout else b"", companion_out, subprocess_exit
143135

144136

0 commit comments

Comments
 (0)