
But that was with injectors, and the factory code had a per-injector offset that made it easy to cut off one at a time... and I'm guessing the same spark dwell is used on all 8 cylinders.
I wonder if it would work to make the dwell nonzero but small, right on the edge of being insufficient. So basically you'd be introducing random misfires. The amount of dwell, and thus the frequency of misfires, would vary with how close actual RPM is to the target RPM. But it might be hard to find a dwell value that works well for this, and to be honest there might not even be a dwell value that works for this, because I'm just making this shit up as I go along...

Another option would be to randomly set the dwell to the default or to zero when RPM is near the target. For example set it to zero 25% of the time when RPM is 4000, set it to zero 50% of the time when RPM is 4100, 75% of the time at 4200, 100% at 4300 and above. Depending on how many ignition events there are between calls to your dwell-hacking function, this might turn out OK. Or more to the point, if there are more than 8 ignition events per invocation then this won't help at all. But if your code is getting invoked roughly once per ignition event, or faster, then I think this would work well.
Do you know how many times per second your code is getting called? If not you could have it increment a simple counter in memory, and data-log that memory location, and measure how quickly the counter increases.
A simple random number generator in C using 16-bit values:
https://codebase64.org/doku.php?id=base ... _generator
This might need some explaining:
x ^= x << 7;
In English:
shift the value of x 7 bits to the left, then XOR the result with the original value of x, then store the result in x
The random number generator does that in different directions and with different amounts of shift, and the result is a mostly-random number.
The result isn't truly random but it should be random enough. 16-bit values range from 0 to 65535. 65535 divided by 4 is 16384. So...
The result should be less than 16384 about 25% of the time.
The result should be less than 32768 about 50% of the time.
The result should be less than 49152 about 75% of the time.