server: refactor batch construction - #24843
Conversation
| t_prev = t_start; | ||
| SRV_INF("n_pre_decode = %" PRId64 "\n", n_pre_decode); | ||
| SRV_INF("avg t_pre_decode = %f ms\n", (double) t_pre_decode / n_pre_decode / 1000.0); | ||
| SRV_INF("avg t_decode = %f ms\n", (double) t_decode / n_decode / 1000.0); | ||
| SRV_INF("avg t_post_decode = %f ms\n", (double) t_post_decode / n_post_decode / 1000.0); | ||
| SRV_INF("avg t_sampl = %f ms\n", (double) t_sampl / n_sampl / 1000.0); | ||
| } |
There was a problem hiding this comment.
ok so I did a quick test on how the number of parallel requests affect the timings; turns out, t_post_decode grows proportionally. so probably worth making sampling multi-thread.
2 parallel requests:
0.22.465.968 I srv update_slots: n_pre_decode = 1427
0.22.465.971 I srv update_slots: avg t_pre_decode = 0.002619 ms
0.22.465.972 I srv update_slots: avg t_decode = 12.810192 ms
0.22.465.972 I srv update_slots: avg t_post_decode = 0.464135 ms
0.22.465.973 I srv update_slots: avg t_sampl = 0.230341 ms
10 parallel requests:
0.38.793.972 I srv update_slots: n_pre_decode = 207
0.38.793.986 I srv update_slots: avg t_pre_decode = 0.030816 ms
0.38.793.993 I srv update_slots: avg t_decode = 161.709222 ms
0.38.793.994 I srv update_slots: avg t_post_decode = 4.672478 ms
0.38.793.995 I srv update_slots: avg t_sampl = 0.466093 ms
|
@ggml-org/maintainers I'm trying to measure how sampling speed affects serving parallel requests on To test it:
Thanks in advanced! Tested on RTX 5060 Ti: Results2 requests: 10 requests: 10 requests with multi-threaded sampling (PoC): More: |
|
here my results on macbook air m3: |
|
@angt thanks but I forgot to mention that the timing log is on llama-server log (the script simply sends the requests, no timings info) could you please post the log lines in llama-server? like this: |
ggerganov
left a comment
There was a problem hiding this comment.
Here are timings on RTX 5090 with gpt-oss-20b:
==> Sending 1 parallel requests to http://localhost:8033/chat/completions
14.13.933.949 I srv update_slots: n_pre_decode = 1930
14.13.933.952 I srv update_slots: avg t_pre_decode = 0.000589 ms
14.13.933.952 I srv update_slots: avg t_decode = 2.484524 ms
14.13.933.953 I srv update_slots: avg t_post_decode = 0.104937 ms
14.13.933.953 I srv update_slots: avg t_sampl = 0.104513 ms
14.12.040.453 I slot print_timing: id 9 | task 0 | n_decoded = 1190, tg = 396.34 t/s, tg_3s = 396.34 t/s
==> Sending 2 parallel requests to http://localhost:8033/chat/completions
0.07.027.191 I srv update_slots: n_pre_decode = 991
0.07.027.195 I srv update_slots: avg t_pre_decode = 0.001558 ms
0.07.027.195 I srv update_slots: avg t_decode = 3.664242 ms
0.07.027.196 I srv update_slots: avg t_post_decode = 0.211232 ms
0.07.027.196 I srv update_slots: avg t_sampl = 0.105371 ms
0.09.292.503 I slot print_timing: id 8 | task 1 | n_decoded = 1583, tg = 263.52 t/s, tg_3s = 262.32 t/s
0.09.292.628 I slot print_timing: id 9 | task 0 | n_decoded = 1583, tg = 263.54 t/s, tg_3s = 262.32 t/s
==> Sending 10 parallel requests to http://localhost:8033/chat/completions
0.15.067.358 I slot print_timing: id 0 | task 4 | n_decoded = 1106, tg = 91.98 t/s, tg_3s = 92.40 t/s
0.15.067.466 I slot print_timing: id 1 | task 8 | n_decoded = 1106, tg = 91.98 t/s, tg_3s = 92.40 t/s
0.15.067.572 I slot print_timing: id 2 | task 7 | n_decoded = 1106, tg = 91.98 t/s, tg_3s = 92.40 t/s
0.15.067.679 I slot print_timing: id 3 | task 9 | n_decoded = 1106, tg = 91.99 t/s, tg_3s = 92.40 t/s
0.15.067.785 I slot print_timing: id 4 | task 3 | n_decoded = 1106, tg = 91.99 t/s, tg_3s = 92.40 t/s
0.15.067.892 I slot print_timing: id 5 | task 6 | n_decoded = 1106, tg = 91.99 t/s, tg_3s = 92.40 t/s
0.15.067.998 I slot print_timing: id 6 | task 0 | n_decoded = 1106, tg = 91.99 t/s, tg_3s = 92.40 t/s
0.15.068.103 I slot print_timing: id 7 | task 5 | n_decoded = 1106, tg = 92.00 t/s, tg_3s = 92.40 t/s
0.15.068.208 I slot print_timing: id 8 | task 2 | n_decoded = 1106, tg = 92.00 t/s, tg_3s = 92.40 t/s
0.15.068.319 I slot print_timing: id 9 | task 1 | n_decoded = 1106, tg = 92.00 t/s, tg_3s = 92.40 t/s
0.17.026.005 I srv update_slots: n_pre_decode = 1288
0.17.026.012 I srv update_slots: avg t_pre_decode = 0.006169 ms
0.17.026.013 I srv update_slots: avg t_decode = 9.931544 ms
0.17.026.013 I srv update_slots: avg t_post_decode = 1.049071 ms
0.17.026.013 I srv update_slots: avg t_sampl = 0.104443 ms
|
|
||
| struct server_batch { | ||
| llama_batch batch; | ||
| bool batch_rendered = false; |
| batch_rendered = true; | ||
| } | ||
|
|
||
| llama_batch get_view(int32_t off, int32_t n_tokens) { |
There was a problem hiding this comment.
| llama_batch get_view(int32_t off, int32_t n_tokens) { | |
| llama_batch get_view(int32_t off, int32_t n_tokens) const { |
|
@ggerganov Thanks for testing. If I calculate correctly, doing multi-threaded sampling with your hardware config (-np 10 case) will improve the tg from 92 -> 98 t/s. If possible could you also try this PoC? https://github.com/ggml-org/llama.cpp/tree/xsn/tmp_smpl_parallel Then I will let you decide if it worth adding (with a cleaner implementation) |
ggerganov
left a comment
There was a problem hiding this comment.
Yes, there is a ~5% improvement in this case using multi-threaded sampling:
0.15.705.360 I slot print_timing: id 0 | task 9 | n_decoded = 1156, tg = 96.16 t/s, tg_3s = 94.77 t/s
0.15.705.363 I slot print_timing: id 1 | task 4 | n_decoded = 1156, tg = 96.16 t/s, tg_3s = 94.77 t/s
0.15.705.364 I slot print_timing: id 2 | task 5 | n_decoded = 1156, tg = 96.16 t/s, tg_3s = 94.77 t/s
0.15.705.365 I slot print_timing: id 3 | task 7 | n_decoded = 1156, tg = 96.16 t/s, tg_3s = 94.77 t/s
0.15.705.366 I slot print_timing: id 4 | task 8 | n_decoded = 1156, tg = 96.16 t/s, tg_3s = 94.77 t/s
0.15.705.366 I slot print_timing: id 5 | task 6 | n_decoded = 1156, tg = 96.16 t/s, tg_3s = 94.77 t/s
0.15.705.367 I slot print_timing: id 6 | task 2 | n_decoded = 1156, tg = 96.16 t/s, tg_3s = 94.77 t/s
0.15.705.368 I slot print_timing: id 7 | task 3 | n_decoded = 1156, tg = 96.16 t/s, tg_3s = 94.77 t/s
0.15.705.369 I slot print_timing: id 8 | task 1 | n_decoded = 1156, tg = 96.16 t/s, tg_3s = 94.77 t/s
0.15.705.369 I slot print_timing: id 9 | task 0 | n_decoded = 1156, tg = 96.16 t/s, tg_3s = 94.77 t/s
0.17.119.197 I srv update_slots: n_pre_decode = 1293
0.17.119.201 I srv update_slots: avg t_pre_decode = 0.007119 ms
0.17.119.202 I srv update_slots: avg t_decode = 9.956678 ms
0.17.119.203 I srv update_slots: avg t_post_decode = 0.553848 ms
0.17.119.203 I srv update_slots: avg t_sampl = 0.545325 ms
I think it's worth it.
* server: refactor batch construction * wip * wip 2 * wip 3 * wip 4 * add abort_all_slots * handle batch full more carefully * fix assert * rm debug log * small nits * (debug) add timings * debug: force llama_synchronize for accurate timings * address comments * disable DEBUG_TIMINGS
* server: refactor batch construction * wip * wip 2 * wip 3 * wip 4 * add abort_all_slots * handle batch full more carefully * fix assert * rm debug log * small nits * (debug) add timings * debug: force llama_synchronize for accurate timings * address comments * disable DEBUG_TIMINGS
* server: refactor batch construction * wip * wip 2 * wip 3 * wip 4 * add abort_all_slots * handle batch full more carefully * fix assert * rm debug log * small nits * (debug) add timings * debug: force llama_synchronize for accurate timings * address comments * disable DEBUG_TIMINGS
Overview
Multiple motivations for this refactoring:
update_slots()into 3 separate steps pre-decode / decode / post-decodeupdate_slots()/slotsand/metricsendpoints to access slot data without being blocked by allama_decode()Additional information
The detailed implementation:
update_slots()now contains 3 steps: pre-decode / decode / post-decodeserver_batchis added to abstract out the construction ofllama_batchmetric updates are queued insideserver_batchand is applied once the batch decoding completeserver_batchLogic flow:
server_batchTODO:
queue metrics--> will be a dedicated PRRequirements