The mystery of the fifteen-millisecond breakpoint instruction
21–30 of 50 posts
Re: The mystery of the fifteen-millisecond breakpoint instruction
#22Earlier quoted context omitted.
Just read the second comment on the link you provided and you have the answer.
> Nowaday’s fast Class 10 cards achieve their high read and write speeds only by buffering in advance, assuming that the subsequent blocks will be read or written next. That means they inevitably sacrifice random read and write speeds. This effect is in the order of several magnitudes. For instance, a card with sequential read and write speeds of 10 MB/s might collapse to just 0.01 MB/s for random access. Yow. Yet an…
No meta data or other interaction required? Surely the sequential writes benefit from larger buffers? Not to mention that the flash block is way larger than the appended message. You would need TRIM to not make that an extremely wasteful operation, not sure if the typical Pi installations make use of it but a quick google seems to indicate that it at least has been a problem. So writing that 1 kbit now means reading a whole block, edit the content of it, and writing that whole block back - which is hardly sequential either. 1 Mbit/s is starting to seem pretty fast.
The only pathological case here is the "not optimal sequential write case", which sure is enough to kill any random USB-thumbdrive or SD-card. Just copying two files two a thumdrive at once can kill performance by an order of magnitude compared to doing them one after another.
Re: The mystery of the fifteen-millisecond breakpoint instruction
#23Wait... It takes ~1ms to write a line to a log file?
It's better to be slow than unreliable in this case.
Re: The mystery of the fifteen-millisecond breakpoint instruction
#24> Think about the common debugging scenario where the user sets a conditional breakpoint: "break if x > y". Testing that condition is going to take 15ms each time.
Wouldn't the implementation of a software breakpoint look like:
if x > y: bkpt
so it'd only be slow on the case where it needed to break? I guess I can imagine you could implement it the other way (always break, check the condition after breaking, resume if the condition isn't met) but it's not obvious to me why you'd do it that way.Just guessing, but if you're just patching the binary to insert the breakpoint you might not have enough space? But you need space for the "bkpt" instruction too...
Re: The mystery of the fifteen-millisecond breakpoint instruction
#25He wrote: > Think about the common debugging scenario where the user sets a conditional breakpoint: "break if x > y". Testing that condition is going to take 15ms each time. Wouldn't the implementation of a software breakpoint look like: if x > y: bkpt so it'd only be slow on the case where it needed to break? I guess I can imagine you could implement it the other way (always break, check the condition after breaking…
I often go back, edit the code to add something like
if (condition) {
foo = foo;
}
recompile, restart the debugger, and break on the foo = foo line. Even with all of those steps, that's still faster than using a conditional breakpoint most of the time.Re: The mystery of the fifteen-millisecond breakpoint instruction
#26Earlier quoted context omitted.
> Nowaday’s fast Class 10 cards achieve their high read and write speeds only by buffering in advance, assuming that the subsequent blocks will be read or written next. That means they inevitably sacrifice random read and write speeds. This effect is in the order of several magnitudes. For instance, a card with sequential read and write speeds of 10 MB/s might collapse to just 0.01 MB/s for random access. Yow. Yet an…
This is much closer to random access than sequential access. Counter question: How is appending to a log file repeatedly sequential access? No meta data or other interaction required? Surely the sequential writes benefit from larger buffers? Not to mention that the flash block is way larger than the appended message. You would need TRIM to not make that an extremely wasteful operation, not sure if the typical Pi inst…
Unfortunately, it seems like both the controller and file system are brain-dead on the RPi.
Namely, you have a cache that detects this sort of (relatively-common) append-only operation, and buffers it until it makes sense to actually write it (either because the disk is otherwise unoccupied or because you are close to the limits of your power buffer).
Alternatively, you have a file system that actually knows the advantages and limitations of flash. You can do append-only files efficiently on flash (without doing all of the read + write dance). "All" you need to do is take advantage of a bit of scratch space and knowing how flash works. Namely that you don't necessarily need to flash a block to write to it, as long as you are only turning zeros to ones (or vice versa, depending on how physical bits are mapped to logical bits. Multilevel flash is a little more complex, but still doable). (For instance, instead of having one filestamp, you have space for 16 filestamps, with two bytes at the beginning, all initially set to all zeros. You check the last bit set and use that filestamp. Congratulations, you now can update the file 16 times before needing to reflash the block. If that's not enough, you can extend it arbitrarily (note that you can do this dynamically for files only when they are updated enough to warrant it!) And metadata/etc can be done in the same way. For something like a log file, you have, say, 16 slots for how much of the block is occupied, and a pointer to the next block (or null). You append the content of the new log line to the file and add the new content. One write, no blocks being flashed. (Two writes if/when you run out of space in the block.)
See, for instance, https://github.com/bnahill/FLogFS/ or https://en.wikipedia.org/wiki/F2FS/
Re: The mystery of the fifteen-millisecond breakpoint instruction
#27Wait... It takes ~1ms to write a line to a log file?
Since it's a debug log from the kernel, it makes sense to take the time to make sure it gets all the way to the disk. For many other purposes, it's fine to be quick and just do the best effort. But the kernel log is a vital resource for doing post mortem analysis if everything goes wrong and the kernel panics. It's better to be slow than unreliable in this case.
It seems that both the file system and flash controller punt the relatively common (and relatively simple) case of a file being repeatedly appended to by small amounts.
Re: The mystery of the fifteen-millisecond breakpoint instruction
#28He wrote: > Think about the common debugging scenario where the user sets a conditional breakpoint: "break if x > y". Testing that condition is going to take 15ms each time. Wouldn't the implementation of a software breakpoint look like: if x > y: bkpt so it'd only be slow on the case where it needed to break? I guess I can imagine you could implement it the other way (always break, check the condition after breaking…
The issue of space is actually a bit subtle. Imagine you have something like (assuming 4 byte fixed width instructions, which is the case on ARM):
0000 instruction 1
0004 instruction 2
0008 instruction 3
000c jmp 0004
Breakpoint instructions are generally designed so that they only take up one instruction's worth of space. On x86, the opcode is just "0xCC". Once you start adding in more complex code, you will necessarily use more instructions. Now, suppose your new breakpoint takes up two instructions (bytes 0-8). When the jump at 000c takes place, it will jump into the second of your two instructions, which will probably not do anything good (on x86 this is even worse because you may jump into the middle of an instruction!)There's also the practical issue – if you put the conditional test in the patched code, you would need to basically bundle a compiler with gdb so that it could compile the conditional testing code in order to create the patch.
Re: The mystery of the fifteen-millisecond breakpoint instruction
#29Wait... It takes ~1ms to write a line to a log file?
Re: The mystery of the fifteen-millisecond breakpoint instruction
#30Wait... It takes ~1ms to write a line to a log file?
My theory is that it's also being written to the RPi's serial port console, which runs at 115200 baud by default, so 11520 characters/second or ~7ms to write 80 characters.