Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

MicroPython for Microcontrollers Module 7

Memory limits, speed, native and viper code interview questions

Interview questions on memory limits, speed, native and viper code: warm-ups, then what each harder question tests and how a good answer starts.

17 questions: 3 warm-ups and 14 with model answers · Levels: Fresher to staff

Warm-up questions

Short questions with short answers, each answered in full.

  1. Fresher

    Why does gc.mem_free() not go up after del buf?

    Answered in the lesson The heap, the garbage collector and mem_info

  2. Fresher

    Why use time.ticks_diff() instead of subtracting two ticks_us() values?

    Answered in the lesson Measuring and improving speed

  3. Fresher

    What is the difference between @micropython.native and @micropython.viper?

    Answered in the lesson @micropython.native and @micropython.viper

Questions with model answers

What each question tests, the first step of a good answer and the follow-ups to expect.

  1. Fresher to mid

    A Pico samples a sensor every millisecond and logs gc.mem_free() once a second. The log falls by about 16,000 bytes a second, from 180,000 to 20,000, jumps back to 180,000 and repeats, and a few samples go missing at every jump. What does the log show, and how would you stop the missed samples?

    What it tests
    Reading a falling and jumping mem_free as garbage made and then collected, linking the jump to a collection pause, and choosing between less garbage, a threshold and collecting at a chosen moment.
    First step
    Read the curve before touching code. The slope is the rate of garbage: 16,000 bytes a second is 16 bytes, one block, per sample, a float or a small object made on every pass. Each jump is an automatic collection when a request found no room, about every ten seconds, and its pause lands wherever the loop happens to be. Then find what the sampling path allocates.
    Follow-ups

    From the lesson The heap, the garbage collector and mem_info

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.

    Opening the model answers with your pass…

    Model answers open with any MySmartCoPilot pass.

    • Pro pass · 1 week₹79$2.99
    • 30 days₹179$5.99
    • 1 year₹1,699$45

    One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

    It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  2. Mid to senior

    You are starting a Pico W product that keeps 12 KB of sensor buffers and uploads a batch over HTTPS every five minutes. Before the app is written, how do you budget its RAM, and what do you measure on the first prototype?

    What it tests
    Pricing buffers in 16-byte blocks, knowing that TLS memory comes from the heap on the rp2 port and needs one long run, measuring imports on the board, and planning the order of allocations.
    First step
    List what lives for the whole run and price it in blocks: each buffer rounded up, plus its 16-byte object. Then the TLS connection, whose buffers come from the MicroPython heap on the rp2 port and need one run of at least 1,026 blocks for the incoming records. Plan to measure gc.mem_free() after the imports and max free sz before every upload on the prototype.
    Follow-ups

    From the lesson The heap, the garbage collector and mem_info

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  3. Fresher to mid

    A Pico logger has run for two days when bytearray(1024) fails with "memory allocation failed, allocating 1024 bytes". A gc.mem_free() call just before it returned 7,488. How can that be, and what do you change?

    What it tests
    That an allocation needs one free run, that collections never move live objects, reading max free sz, and fixing the order of allocations.
    First step
    Log micropython.mem_info() right before the failing line. The GC line gives the free total, and max free sz the longest free run in blocks. If it is below 64, the 1,024 bytes of items fit nowhere, however much is free. Then look at what the program keeps between runs, because those objects decide where the holes are.
    Follow-ups

    From the lesson Fragmentation and zero-allocation loops

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes
  4. Mid to senior

    To keep room for an upload buffer, a teammate makes reserve = bytearray(1100) at start-up, deletes it right before each upload and makes it again right after. Uploads fail with MemoryError from the second one on. How do you find out why, and what do you change?

    What it tests
    Debugging allocation order on a first-fit heap, reading block positions in mem_info(1), and knowing what a collection does and does not do.
    First step
    Measure instead of guessing: print max free sz after the reserve is deleted, after the upload and after the reserve is made again, and the block map of mem_info(1) at each point. The question is whether the run the reserve held is still in one piece when the next request arrives, and if not, which object split it.
    Follow-ups

    From the lesson Fragmentation and zero-allocation loops

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  5. Mid to senior

    Your parser for a 1 kHz sensor stream must never allocate. How do you prove that it does not, and what can a passing proof still miss?

    What it tests
    Using heap_lock() as a test, covering every branch, reading code for allocating constructs, and knowing what a locked run cannot show.
    First step
    Turn the claim into a test: run the parser under micropython.heap_lock(), on the unix port or the board, and make sure the heap is unlocked again however the run ends. Then decide which inputs the test must feed it: good packets, damaged ones and every edge case the protocol allows.
    Follow-ups

    From the lesson Fragmentation and zero-allocation loops

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  6. Fresher to mid

    A colleague timed a filter function at 40 µs on their laptop and planned a 10 kHz control loop on a Pico around that number. What is wrong with the plan, and how would you measure the function properly?

    What it tests
    That a timing belongs to its interpreter and machine, how to time on the board with ticks_us(), ticks_diff() and several runs, and what the budget of a 10 kHz loop is.
    First step
    Start from the budget: 10 kHz leaves 100 µs per pass for everything, the filter and the rest. Then time the filter where it will run: on the Pico, with ticks_us() and ticks_diff(), gc.collect() before each of several runs, the best and the slowest run reported. The laptop's 40 µs comes from CPython on a different processor.
    Follow-ups

    From the lesson Measuring and improving speed

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  7. Mid to senior

    A Pico's 1 kHz loop needs 1,200 µs per sample, and the budget is 1,000. Walk through how you would make it fit, in order, and say what you would measure at each step.

    What it tests
    Measuring before changing code, using the hot spot's share to choose the work, and ordering the changes: less work per sample, no allocation, integer maths, local names, const(), then machine code.
    First step
    Measure before touching anything: time one sample on the board with the best of several runs, then time its parts, so you know what share the slowest part takes. The share decides what any speed-up of that part can win for the whole loop, and whether the plan can reach 1,000 µs at all.
    Follow-ups

    From the lesson Measuring and improving speed

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  8. Mid to senior

    A driver module defines 60 register addresses as REG_NAME = const(0x..). A teammate says the constants waste RAM. Is that right, how much is it, and what do you change without breaking the modules that use the driver?

    What it tests
    What const() puts into the bytecode, what a public name still costs in the module's globals, private names, and keeping an API stable while saving RAM.
    First step
    Separate the two effects of const(). Every use of a constant is folded into the bytecode, so reads cost nothing in any case. What the teammate means is the name itself: a public const name stays in the module's globals so other modules can read it. Count which of the 60 names other modules actually use.
    Follow-ups

    From the lesson Measuring and improving speed

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes
  9. Mid to senior

    A viper checksum over a file's bytes matches the CPython reference in every unit test, yet a Pico reports a different value for large files. What is the likely cause, how do you confirm it, and how do you make the tests catch it?

    What it tests
    That viper integers are machine words that wrap, why tests on CPython or a 64-bit build cannot see it, and how to fix the algorithm and the tests.
    First step
    Suspect the word size before the code. Viper integers are 32-bit words on the RP2040, while CPython's never wrap, so a sum that passes 2³¹ − 1 differs only on the board. Confirm it by computing the reference result and checking whether it fits a signed 32-bit word, for the file sizes that fail.
    Follow-ups

    From the lesson @micropython.native and @micropython.viper

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes
  10. Mid to senior

    Your CI runs MicroPython's unix port on an Apple Silicon runner, and every module with a viper function fails at import with SyntaxError: invalid micropython decorator. What is going on, and how do you test viper code in CI?

    What it tests
    Which builds have native emitters, why the error comes at compile time, and a test plan that covers both the logic and the board's word size.
    First step
    Read the error as a fact about the build, not the code: decorators are handled by the compiler, and the unix port has no native emitter for 64-bit ARM, so the module cannot compile there at all. The fix belongs in CI: a build with an emitter, or tests that do not need one.
    Follow-ups

    From the lesson @micropython.native and @micropython.viper

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes
  11. Senior to staff

    A Pico must checksum each 64 KB block it reads from flash within 20 ms, and the bytecode version takes 60 ms. How do you choose between native, viper and the inline assembler, and what evidence do you collect before you decide?

    What it tests
    Measuring on the board, the hot spot's share, what each emitter gains and costs, viper's word-size risks, and when assembler is worth its maintenance.
    First step
    Measure first: time the checksum alone and the whole block on the board with the best of several runs, so you know whether the checksum is most of the 60 ms. Then try the cheapest change that could reach 20 ms, measure again, and move to a harder one only if the numbers say so.
    Follow-ups

    From the lesson @micropython.native and @micropython.viper

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  12. Mid to senior

    An inline assembler routine that ran on a Pyboard fails on a Pico at import with SyntaxError: unsupported Thumb instruction 'movwt' with 2 arguments. Why, and how do you port it?

    What it tests
    The difference between the ARMv7-M and ARMv6-M instruction sets, why the error comes at compile time, and the usual rewrites of constants, division, bit counting and conditional blocks.
    First step
    Read the error as a statement about the processor. The Pyboard's chip runs the full Thumb-2 set of ARMv7-M, while the RP2040's Cortex-M0+ implements ARMv6-M, and MicroPython's assembler refuses ARMv7-M instructions when it builds for the Pico. List every instruction of the routine that is ARMv7-M only before changing any.
    Follow-ups

    From the lesson Inline assembler: asm_thumb and asm_rv32

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 3 minutes
  13. Senior to staff

    A teammate wants to rewrite a viper filter in inline assembler for a 20 % gain on the filter. How do you decide, and what must come with the change if you accept it?

    What it tests
    Turning a local gain into a whole-program gain, weighing maintenance and portability, and the tests, fallbacks and measurements that make assembler safe to keep.
    First step
    Ask for the numbers first: the filter's share of the loop and the loop's target, both measured on the board. A 20 % gain on a part that takes a third of the time saves under 7 % of the whole, so the change is worth considering only if that closes a gap the product actually has.
    Follow-ups

    From the lesson Inline assembler: asm_thumb and asm_rv32

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes
  14. Mid to senior

    Estimate how long a Thumb loop that sums 64 KB of bytes takes on a Pico at its default clock, and say what the estimate leaves out.

    What it tests
    Counting instructions and cycles from the datasheet's table, using the clock rate, and knowing why a cycle count is a floor rather than a measurement.
    First step
    Write the loop down and count one pass: a byte load, an addition, a pointer step, a count down and a branch back. Take each instruction's cycles from the RP2040 datasheet's table, multiply by 65,536 bytes, and divide by the rp2 port's default 125 MHz.
    Follow-ups

    From the lesson Inline assembler: asm_thumb and asm_rv32

    Model answer, Pro.

    In the answer:

    • Model answer
    • Follow-up answers
    • Common mistakes
    • Rubric
    • Variants
    • about 2 minutes

All MicroPython for Microcontrollers interview questions · The MicroPython for Microcontrollers track

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.