Comment by Cieric
1 day ago
On the technical details of mmap I agree (at least while single threaded which is how I believe I'm running it), but making it async does sound like an interesting method for speeding it up. My only goal with my testing was get as large of a model as possible running on a computer that "can't run it." I'm going to have to actually read through the code and figure out how it really works to really make any good optimizations, but as before this was just experiments with using and LLM (claude + codex) to just get it running. Since if they couldn't get it running I'm not sure if I would have wanted to spend time trying to get it working myself.
I also know I did some things that would actually make the perf worse to, like I believe I also had AI mmap the KV Cache to make sure to runs under any circumstance. For actual optimizations based on what I currently know, I'm probably going to try and get the llm running under my igpu on my laptop with persistent shader that has some kind of inbuilt request mechanism. That way the weights that are loaded can be used as fast as possible.
For the expert prediction, I assume I could use the medusa paper as kind of a kick off point for that since I'm already using it to try and predict the next 4 tokens. Doing verification on those 4 tokens is about as much as I can do though since it started to thrash on loading the experts. So some method of predicting even more tokens, but then batching together those with the same experts would probably yield slightly better results in this weird case.
Note: All of my tests have been around programming since that's the use case I'm interested in. I don't actually know if this would preform well in other cases (and anything more broad than that I assume would be slower.)
My recommendation if you are willing to push it further is to keep KV and always needed weights pinned in memory, so they do not get evicted. This is likely already the case, as they are touched on each token. mmap is slow on evicted pages, as it does not load the whole tensor, but only the touched pages. And it does this through a page fault, thus blocking your code. So it loads a page hands control back to you and the code goes on to touch another evicted page, repeating the loop. Now on an HDD that is not a big problem (yes reads can be coalesced, but a HDD is fundamentally serial in reading) while an SSD can overlay reads better and it is good to keep a few reads in flight at all times to keep its queue fed.
One option is locking the pages. But for that size you need extra privileges.
I experimented with some options. For example: one problem with io_uring is that it still reads to page cache so your reads gets copied in memory after they landed. Now if you pass O_DIRECT that does not happen, but it has its own can of worms.
For full transparency: I had opus write the io_uring layer into llama.cpp for me. And it yielded something slightly short of a 2x tok/s speedup vs simple mmaping. Also I noticed that disabling the warmup and initial test dramatically increases startup time.
The medusa paper looks interesting. My work was a few months ago, multi-token decoding was not a thing then.