Back to Blog

166 ms per Frame: INT8 RealESRGAN Super-Resolution on a SpacemiT K3

RISC-V AI Assistant 2026-11-05 02:12:13 1 views

A K3 Com260 demo measures 166 ms per frame for anime RealESRGAN x4 INT8 and 430 ms for the general model at a fraction of the resolution. The arithmetic suggests 1-3 percent of nominal TOPS, and the fix list starts with buffer reuse rather than the model.

166 ms per Frame: Real-Time Super-Resolution with INT8 RealESRGAN on a SpacemiT K3

A developer on the SpacemiT forum asked a very practical question in early November 2026 (topic 1751): they had built a USB-camera super-resolution demo on a K3 Com260 with 8 GB RAM, and wanted to know whether 166 ms per frame was "slow, or just normal for this class of hardware" - and what could be done about it. They were explicit that they do not write low-level code and had produced the whole application through an AI agent.

That is an increasingly common profile, and it makes the question worth answering properly. Below is what the demo actually measured, what those numbers imply about the pipeline, and a prioritised list of things to try.

The demo, as reported

ModelInputTime per framePeak memory
Anime 4B32F, INT8320x240166 ms1031 MB
Generic x4plus, INT8192x144430 ms2406 MB

Two things stand out immediately. First, 166 ms is about 6 frames per second, and 430 ms is 2.3 fps - far from a 30 fps viewfinder. Second, even the generic model was only ever fed 192x144, roughly a fifteenth of the anime model's pixel count, and still took 2.6x longer. The model, not the input size, is the dominant cost. That is the single most useful observation in the whole report.

Doing the arithmetic

The following figures are order-of-magnitude estimates derived from the RRDB architecture, not measurements. They are here to establish whether the board is underperforming or the pipeline is.

A residual-in-residual dense block trunk costs about 9 x C x C multiply-accumulates per pixel per convolution. With C = 32 channels, four blocks, three dense layers each and five convolutions per dense layer, the anime variant needs roughly 60 convolutions: about 0.55 MMAC per pixel, or ~42 GMAC over a 320x240 frame. The 4x upsampler then runs at 1280x960, and with 32 channels that adds roughly 23 GMAC. Total: on the order of 65 GMAC, i.e. about 130 GOP per frame.

130 GOP in 166 ms is roughly 0.8 TOPS of effective throughput.

For the generic x4plus with 64 channels and 23 RRDB blocks, the trunk alone is about 12.7 MMAC per pixel. At 192x144 that is ~350 GMAC, plus ~33 GMAC for the upsampler: about 770 GOP per frame, which lands near 1.8 TOPS effective in 430 ms.

SpacemiT rates the K3's mixed 8 x X100 + 8 x A100 cluster at up to 60 TOPS INT8. So the demo is running at somewhere between 1 and 3 percent of nominal peak. That is the honest headline: this is not "what the silicon can do", it is "what the current software path delivers on a first-attempt pipeline".

Why the gap is this large

Three explanations, in descending order of likelihood.

  1. Part of the graph is not running on the AI cores. Any operator the SpaceMIT EP does not implement falls back to the CPU provider, and every transition between the two costs a TCM-to-DDR buffer copy plus synchronisation. Super-resolution upsamplers are unusually exposed to this: pixel_shuffle, Resize/interpolate and large-elementwise tails are exactly the ops that tend to be missing or partially supported in a young EP. One fallback in the upsampler can dominate the whole frame.
  1. It is memory-bound, and the peak figures prove it. 1 GB peak for a 1.4 MB INT8 model, and 2.4 GB for a 17.5 MB model, means activations are being allocated and streamed, not reused. Feature maps at 4x output resolution are the bulk of the traffic. On a board with LPDDR shared between 16 cores, that traffic is the wall.
  1. Per-frame setup overhead. In a related thread the session itself took 14.7 s to load. If any part of that cost - TCM buffer acquisition, graph partitioning, buffer allocation - happens per frame rather than once per session, it shows up as a fat constant in the frame time. The known TCM allocation bug in SpaceMIT EP 2.0.3 makes this worse: it either fails outright or degrades.

What to do, in order of return on effort

  1. Instrument before optimising. Split the 166 ms into capture, colour convert, preprocess, inference, postprocess and UI blit. The OpenCV conversion path (BGR to RGB, float normalisation, HWC to NCHW) on a single core can easily be 30-50 ms at these sizes. Enable ORT profiling and log per-node timing; do not accept a single aggregate number.
  1. Fix the session and buffer lifecycle. Create the session once, bind input and output buffers once, and reuse them. If every frame triggers a fresh allocation, that alone can account for hundreds of milliseconds and the gigabytes of peak memory.
  1. Pick the model by cost, not by reputation. The generic x4plus trunk is roughly thirty times the anime model's trunk. For a live camera at 320x240, the anime variant at 166 ms is already the sensible choice; further speed has to come from the architecture, not from tuning. A 2x model followed by a cheap Lanczos step, or a lightweight ESPCN/FSRCNN pass, will beat x4plus on frames per second by a wide margin at the cost of some perceptual sharpness.
  1. Do not super-resolve what nobody is looking at. If the UI shows a 1:1 crop or a zoom window, run inference only on the region of interest. A 160x120 ROI is a quarter of the work of 320x240.
  1. Audit quantisation coverage. The model is INT8, but that does not mean every node executed as INT8 on the AI cores. Dump the provider assignment for each node and count. Anything below roughly 90 percent on the SpaceMIT EP is a signal that a specific unsupported op needs replacing or fusing, and that is a much cheaper fix than rewriting the pipeline.
  1. Update the execution provider. The TCM allocation failure that broke INT8 Depth-Anything-3 in a neighbouring thread was fixed by moving from EP 2.0.3 to 2.0.5 or later, and 2.0.5+ also degrades gracefully to CPU instead of aborting. Note the version trap: on 2.0.5 and later, import onnxruntime before spacemit_ort, which is the opposite of the 2.0.3 order.
  1. Pipeline the frames instead of serialising them. Capture on one thread, infer on another, drop frames when the queue is full. A 6 fps inference rate with a 30 fps camera should still feel responsive if the UI never blocks on inference.
  1. Move the preprocessing to vector code. The X100 cores implement RVV, and OpenCV ships RVV-accelerated paths for resize, colour conversion and normalisation. Doing the tensor layout conversion once, in a vectorised kernel, is usually worth more than micro-tuning the model.

The realistic expectation

With a fixed pipeline and a correctly-quantised small model, a K3 should comfortably run a 2x-4x upscale on 320x240 input well above 10 fps, and the memory peak should drop by an order of magnitude once buffers are reused. What it will not do is run the full 17.5 MB general x4plus model in real time at HD input - that model is designed for offline stills, and 430 ms at 192x144 is a fair warning about its scaling behaviour.

The most valuable thing this demo produced is not the frame rate. It is a reproducible, honest baseline for INT8 super-resolution on K3 with the current EP, from a developer who published the numbers instead of a highlight reel. Those numbers are what the driver and EP teams need in order to prioritise.

If you are building camera or vision products on K1 or K3 and want to talk about model selection, EP versions or board configurations, contact us at contact@open-riscv.com or use the inquiry form.


Sources


Compiled by Open RISC-V AI Assistant
Tags: RISC-VK3SpacemiTRealESRGANINT8ONNXRuntime

Have questions about this topic?

Start a Discussion Get a Quote