Skip to content

runcode v1.2.0 — Python 10x faster, no more mixed-up output

Choose a tag to compare

@hami9 hami9 released this 20 Sep 16:37
· 9 commits to main since this release
Immutable release. Only release title and notes can be modified.

Testing the runtime properly on device turned up four defects, all fixed here, plus the
first phase of resource monitoring.

Python was 25x slower than it should have been

run_script installed a sys.settrace hook so a running script could be interrupted — and
that hook fires on every line. Same loop, same process, measured on device:

WITH tracer      0.945s  ->   317,478 iter/s
WITHOUT tracer   0.037s  -> 8,134,909 iter/s

Stopping now uses PyThreadState_SetAsyncExc through ctypes: it raises in the target thread
at its next bytecode boundary and costs nothing while the script runs normally. A script
blocked in time.sleep(1) still stops 0.8 s after you press Stop.

Real-world effect: a plain arithmetic loop went from 317k to 1.2–4.6M iterations/second.

Two services stole each other's output

sys.stdout is process-global and each script replaced it, so whichever started last
captured both. With a Python project and a Telegram bot running together, A tick 11 showed
up in the bot's log. Output is routed per thread now — verified with two concurrent services,
each log containing only its own lines.

The log file was out of order

A coroutine was launched per line, so lines interleaved on the way to disk while the
in-memory view stayed correct. One consumer drains a queue instead. Twenty lines printed in
sequence now land in sequence.

A broken bridge triggered a restart loop

If the Python bridge module itself failed to load, that was classified as a crash, so
ON_FAILURE projects kept retrying something that could never work. It is fatal now.

Resource monitoring and limits

The app used to report cpuPercent = 2 for Python and 1 for the web server — both
hardcoded. Now:

  • CPU is sampled per service from /proc/self/task/<tid>/stat, differenced between
    heartbeats. Every service already runs on its own named thread, so the attribution is real.
  • Memory comes from Debug.MemoryInfo; the System screen shows PSS, Java heap against the
    device's limit, thread count and pid.
  • Projects can set CPU %, heap MB and idle minutes limits (blank = unlimited).
    A sustained breach marks the service DEGRADED, then stops it:
Stopping 'Python Quickstart': CPU 99% over the 20% limit for 9s.

This is runcode policing its own services. An Android app cannot free another app's memory or
tune the CPU — there is no API for it — and nothing here pretends otherwise.

Install

Signed with the same key as v1.0.x, so it installs over it. minSdk 26, ABIs arm64-v8a and
x86_64. Licensed MIT; third-party notices in THIRD_PARTY_LICENSES.md.