If you look at the picture above, you can see that RenderStepped blocks the execution of any further steps until it yields. It runs before all the Rendering / Network Replicate / wait() resume / Humanoid / Stepped / Physics / Heartbeat. So if you stick all of your code in there, it means that all that code has to execute before the rest can begin. In that same image, everything after RenderStepped does run in parallel. So there are two pipelines there, and the top one (Rendering) will run in parallel with the bottom pipeline (all the other stuff). The bottom pipeline doesn’t block the rendering of the next frame.
Now imagine that in the situation where you run all your code in RenderStepped, the RenderStepped cycle takes 10ms, the top pipeline takes 10ms, and the bottom pipeline takes 1ms. Since the top pipeline runs in parallel with the bottom one, the two combined will run for max(10ms, 1ms) = 10ms. RenderStepped needs to be executed before that, so the whole cycle takes 10ms + 10ms = 20ms.
In an alternative case, suppose that you move your non-camera code to Heartbeat instead of RenderStepped. The RenderStepped cycle now takes 1ms, the top pipeline takes 10ms still, and the bottom pipeline now takes 10ms. Again, the two pipelines together run in parallel so that’s 10 ms. However, since your RenderStepped call only takes 1ms now, the total cycle time will be 1ms + 10ms = 11ms.
This means you get a performance increase when sticking non-rendering related code in Heartbeat due to parallelism and the fact that Heartbeat doesn’t interfere with the rendering of the current frame.