Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
1094 lines (897 loc) · 53.5 KB
/
Copy pathMakefile
File metadata and controls
1094 lines (897 loc) · 53.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# yllm 构建 (Linux / macOS / Windows/MinGW)
#
# make 标量版本
# make avx2 x86_64 上的 AVX2 版本(其他架构退化为标量)
# make cuda AVX2 + CUDA 后端(产物在 build/avx2-cuda/, 与 avx2 隔离)
# make vulkan 标量 + Vulkan 后端(产物在 build/vulkan/, 无 AVX2)
# make vulkan-avx2 AVX2 + Vulkan(产物在 build/avx2-vulkan/)
# make android NDK arm64 + Vulkan (platform/android → build/android)
# make android-cpu 同上但不编 Vulkan
# make gen-cuda / chat-cuda 用 --device cuda 冒烟
# make gen-vulkan / chat-vulkan / chat-*-avx2-vulkan
# make chat-* MTP=1 追加 --mtp 1(投机解码; 模型需带 nextn 权重, 默认无)
# make chat-* KV=q8 追加 --kv q8(KV int8 量化, 仅 CPU, 默认无; server 目标透传 hub)
# make test 运行测试
# make clean
#
# 跨平台打包见 platform/{android,ios,pc,web}/ 与 docs/design-mobile.md
# Windows 下请在 MSYS2 / MinGW 环境执行本 Makefile;
# 若使用 MSVC, 请改用 CMake:
# cmake -S . -B build-msvc && cmake --build build-msvc --config Release
CC ?= cc
LDFLAGS ?=
LIBS :=
# 公共头: inference/include; 后端私有头: cuda/ vulkan/
INFER_INC := -Iinference/include -Iinference/cuda -Iinference/vulkan -Iinference/vision
HDR_PUBLIC := inference/include/yllm.h inference/include/llf.h inference/include/convert.h \
inference/include/matvec.h inference/include/dist.h inference/include/device.h \
inference/include/arch.h inference/include/log.h inference/include/cache.h \
inference/include/vision.h
SRC := \
inference/core/platform.c inference/core/log.c inference/core/llf.c \
inference/convert/convert.c inference/convert/convert_safetensors.c inference/convert/convert_gguf.c \
inference/convert/dump.c \
inference/core/tokenizer.c inference/core/matvec.c inference/core/engine.c \
inference/arch/arch.c inference/arch/llama.c inference/arch/qwen.c \
inference/arch/gemma4.c inference/arch/qwen35.c \
inference/vision/minicpmv.c inference/vision/qwen3vl.c inference/vision/gemma4v.c inference/vision/vision.c \
inference/core/cache.c inference/core/dist.c inference/device/device_cpu.c
TEST_ENGINE_CORE := \
inference/core/platform.c inference/core/log.c inference/core/llf.c \
inference/convert/convert.c inference/convert/convert_safetensors.c inference/convert/convert_gguf.c \
inference/convert/dump.c \
inference/core/tokenizer.c inference/core/matvec.c inference/core/engine.c \
inference/arch/arch.c inference/arch/llama.c inference/arch/qwen.c \
inference/arch/gemma4.c inference/arch/qwen35.c \
inference/vision/minicpmv.c inference/vision/qwen3vl.c inference/vision/gemma4v.c inference/vision/vision.c \
inference/device/device_cpu.c
# ---- CUDA 后端(可选) ----
# make cuda # 推荐: 独立目录 build/avx2-cuda
# make gen-cuda / chat-cuda # 构建并 --device cuda 跑 TinyLlama
# make avx2 YLLM_CUDA=1 # 旧写法(写入 build/avx2, 易与纯 CPU 产物混用)
# make cuda YLLM_CUDA_HOST=1 # 无 toolkit / 强制 host-shim
# make cuda YLLM_CUDA_HOST=0 # 强制真 CUDA runtime(需 libcudart)
YLLM_CUDA ?= 0
YLLM_CUDA_HOST ?=
YLLM_VULKAN ?= 0
GPU ?= 0
GPU_WEIGHTS ?= auto
NVCC ?= $(shell command -v nvcc 2>/dev/null)
ifeq ($(YLLM_CUDA),1)
SRC += inference/device/device_cuda.c inference/cuda/cuda_fwd.c
TEST_ENGINE_CORE += inference/device/device_cuda.c inference/cuda/cuda_fwd.c
ifeq ($(YLLM_CUDA_HOST),)
ifeq ($(NVCC),)
YLLM_CUDA_HOST := 1
else
YLLM_CUDA_HOST := 0
endif
endif
endif
ifeq ($(YLLM_VULKAN),1)
SRC += inference/device/device_vulkan.c inference/vulkan/vulkan_load.c \
inference/vulkan/vulkan_fwd.c inference/vulkan/vulkan_compute.c
TEST_ENGINE_CORE += inference/device/device_vulkan.c inference/vulkan/vulkan_load.c \
inference/vulkan/vulkan_fwd.c inference/vulkan/vulkan_compute.c
endif
# 真 CUDA 时由 nvcc 编译的 .cu(host-shim 不编)
CUDA_CU_OBJ :=
CUDA_CU_OBJ_AVX2 :=
ifeq ($(YLLM_CUDA),1)
ifneq ($(YLLM_CUDA_HOST),1)
CUDA_CU_SRC := inference/cuda/cuda_kernels.cu
endif
endif
# ---- OS 检测 (Windows: MSYS2/MinGW 的 uname 会带 MINGW/MSYS, 也归为 Windows) ----
ifneq ($(OS),Windows_NT)
UNAME_S := $(shell uname -s 2>/dev/null)
else
UNAME_S := Windows
endif
ifneq ($(findstring MINGW,$(UNAME_S)),)
UNAME_S := Windows
endif
ifneq ($(findstring MSYS,$(UNAME_S)),)
UNAME_S := Windows
endif
# ---- 架构检测 (AVX2 仅 x86_64) ----
ifneq ($(OS),Windows_NT)
ARCH := $(shell uname -m 2>/dev/null)
else
ARCH := x86_64
endif
# ---- 平台相关: 可执行后缀 / feature macros / 链接库 ----
ifeq ($(UNAME_S),Windows)
EXE := .exe
PLATDEF :=
PLATLIBS := -lm -lws2_32
OMPFLAG := -fopenmp
else ifeq ($(UNAME_S),Darwin)
EXE :=
PLATDEF := -D_DARWIN_C_SOURCE
PLATLIBS := -lm -pthread
OMPFLAG :=
else
EXE :=
PLATDEF := -D_DEFAULT_SOURCE
PLATLIBS := -lm -pthread
# Linux 默认启用 OpenMP 多核加速(可用 make OMPFLAG= 关闭)
OMPFLAG := -fopenmp
endif
LIBS += $(PLATLIBS)
# ---- 标量版本(默认) ----
# 批量 prefill(编译期开关): 默认开启, 用 make BATCH_PREFILL=0 关闭
BATCH_PREFILL ?= 1
# 会话数据包调试: make YLLM_SESS_DEBUG=1 开启(0 默认关闭)
YLLM_SESS_DEBUG ?= 0
CFLAGS_BASE := -O3 -std=c99 -Wall -Wextra -DYLLM_BATCH_PREFILL=$(BATCH_PREFILL) -DYLLM_SESS_DEBUG=$(YLLM_SESS_DEBUG) $(PLATDEF) $(OMPFLAG)
ifeq ($(YLLM_CUDA),1)
ifeq ($(YLLM_CUDA_HOST),1)
CFLAGS_BASE += -DYLLM_CUDA=1 -DYLLM_CUDA_HOST=1
else
CFLAGS_BASE += -DYLLM_CUDA=1
LIBS += -lcudart -lcublas
endif
endif
ifeq ($(YLLM_VULKAN),1)
CFLAGS_BASE += -DYLLM_VULKAN=1
ifeq ($(YLLM_VULKAN_HOST),1)
CFLAGS_BASE += -DYLLM_VULKAN_HOST=1
endif
# 头文件: VULKAN_SDK 或系统路径; 运行时动态加载 loader(无需链 vulkan-1.lib)
ifneq ($(VULKAN_SDK),)
CFLAGS_BASE += -I"$(VULKAN_SDK)/Include"
endif
ifneq ($(UNAME_S),Windows)
LIBS += -ldl
endif
endif
OBJDIR := build
BIN := build/yllm$(EXE)
OBJ := $(SRC:inference/%.c=$(OBJDIR)/%.o) $(OBJDIR)/main.o $(OBJDIR)/rank.o $(OBJDIR)/server.o $(OBJDIR)/router.o $(OBJDIR)/supervisor.o $(OBJDIR)/hub.o $(OBJDIR)/router_http.o $(OBJDIR)/status.o $(OBJDIR)/ctl.o $(OBJDIR)/sync.o
ifneq ($(CUDA_CU_SRC),)
CUDA_CU_OBJ := $(CUDA_CU_SRC:inference/%.cu=$(OBJDIR)/%.o)
OBJ += $(CUDA_CU_OBJ)
endif
OBJ := $(sort $(OBJ))
# ---- AVX2 版本(仅 x86_64; 其余架构退化为标量, 保持 target 可用) ----
CFLAGS_AVX2 := $(CFLAGS_BASE)
LDFLAGS_AVX2 :=
OBJDIR_AVX2 := build/avx2
BIN_AVX2 := build/avx2/yllm$(EXE)
OBJ_AVX2 := $(SRC:inference/%.c=$(OBJDIR_AVX2)/%.o) $(OBJDIR_AVX2)/main.o $(OBJDIR_AVX2)/rank.o $(OBJDIR_AVX2)/server.o $(OBJDIR_AVX2)/router.o $(OBJDIR_AVX2)/supervisor.o $(OBJDIR_AVX2)/hub.o $(OBJDIR_AVX2)/router_http.o $(OBJDIR_AVX2)/status.o $(OBJDIR_AVX2)/ctl.o $(OBJDIR_AVX2)/sync.o
ifneq ($(CUDA_CU_SRC),)
CUDA_CU_OBJ_AVX2 := $(CUDA_CU_SRC:inference/%.cu=$(OBJDIR_AVX2)/%.o)
OBJ_AVX2 += $(CUDA_CU_OBJ_AVX2)
endif
OBJ_AVX2 := $(sort $(OBJ_AVX2))
ifeq ($(ARCH),x86_64)
CFLAGS_AVX2 := $(CFLAGS_BASE) -mavx2 -mfma -mf16c
endif
# CUDA 独立产物(与 build/avx2 隔离, 避免 CPU/CUDA 目标混用同一 .o)
OBJDIR_CUDA := build/avx2-cuda
BIN_CUDA := $(OBJDIR_CUDA)/yllm$(EXE)
OBJDIR_VULKAN := build/vulkan
BIN_VULKAN := $(OBJDIR_VULKAN)/yllm$(EXE)
OBJDIR_VULKAN_AVX2 := build/avx2-vulkan
BIN_VULKAN_AVX2 := $(OBJDIR_VULKAN_AVX2)/yllm$(EXE)
all: $(BIN)
avx2: $(BIN_AVX2)
$(BIN): $(OBJ)
$(CC) $(CFLAGS_BASE) -o $@ $(OBJ) $(LDFLAGS) $(LIBS)
$(BIN_AVX2): $(OBJ_AVX2)
$(CC) $(CFLAGS_AVX2) -o $@ $(OBJ_AVX2) $(LDFLAGS) $(LDFLAGS_AVX2) $(LIBS)
$(OBJDIR)/%.o: inference/%.c $(HDR_PUBLIC) | $(OBJDIR)
@mkdir -p $(dir $@)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -c -o $@ $<
ifneq ($(CUDA_CU_SRC),)
$(OBJDIR)/%.o: inference/%.cu inference/cuda/cuda_kernels.h | $(OBJDIR)
@mkdir -p $(dir $@)
$(NVCC) -O2 -std=c++14 -Xcompiler -fPIC $(INFER_INC) -c -o $@ $<
endif
$(OBJDIR)/main.o: main.c $(HDR_PUBLIC) serve/rank.h | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR)/rank.o: serve/rank.c serve/protocol.h serve/rank.h serve/sock.h serve/frame.h serve/node.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR)/server.o: serve/server.c serve/protocol.h serve/server.h serve/sock.h serve/frame.h serve/node.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR)/router.o: serve/router.c serve/protocol.h serve/router.h serve/sock.h serve/frame.h serve/node.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR)/supervisor.o: serve/supervisor.c serve/protocol.h serve/supervisor.h serve/sock.h serve/frame.h serve/node.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR)/hub.o: serve/hub.c serve/hub.h serve/supervisor.h serve/router.h serve/server.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR)/status.o: serve/status.c serve/status.h serve/protocol.h serve/frame.h serve/sock.h serve/node.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR)/ctl.o: serve/ctl.c serve/ctl.h serve/protocol.h serve/frame.h serve/sock.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR)/sync.o: serve/sync.c serve/sync.h serve/frame.h serve/sock.h $(HDR_PUBLIC) | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR)/router_http.o: serve/router_http.c serve/router_http.h serve/router.h serve/json.h serve/http.h serve/sock.h $(HDR_PUBLIC) | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR_AVX2)/%.o: inference/%.c $(HDR_PUBLIC) | $(OBJDIR_AVX2)
@mkdir -p $(dir $@)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -c -o $@ $<
ifneq ($(CUDA_CU_SRC),)
$(OBJDIR_AVX2)/%.o: inference/%.cu inference/cuda/cuda_kernels.h | $(OBJDIR_AVX2)
@mkdir -p $(dir $@)
$(NVCC) -O2 -std=c++14 -Xcompiler "-fPIC $(filter -mavx2 -mfma -mf16c,$(CFLAGS_AVX2))" $(INFER_INC) -c -o $@ $<
endif
$(OBJDIR_AVX2)/main.o: main.c $(HDR_PUBLIC) serve/rank.h | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR_AVX2)/rank.o: serve/rank.c serve/protocol.h serve/rank.h serve/sock.h serve/frame.h serve/node.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR_AVX2)/server.o: serve/server.c serve/protocol.h serve/server.h serve/sock.h serve/frame.h serve/node.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR_AVX2)/router.o: serve/router.c serve/protocol.h serve/router.h serve/sock.h serve/frame.h serve/node.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR_AVX2)/supervisor.o: serve/supervisor.c serve/protocol.h serve/supervisor.h serve/sock.h serve/frame.h serve/node.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR_AVX2)/hub.o: serve/hub.c serve/hub.h serve/supervisor.h serve/router.h serve/server.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR_AVX2)/status.o: serve/status.c serve/status.h serve/protocol.h serve/frame.h serve/sock.h serve/node.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR_AVX2)/ctl.o: serve/ctl.c serve/ctl.h serve/protocol.h serve/frame.h serve/sock.h serve/config.h $(HDR_PUBLIC) | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR_AVX2)/sync.o: serve/sync.c serve/sync.h serve/frame.h serve/sock.h $(HDR_PUBLIC) | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -Iserve -c -o $@ $<
$(OBJDIR_AVX2)/router_http.o: serve/router_http.c serve/router_http.h serve/router.h serve/json.h serve/http.h serve/sock.h $(HDR_PUBLIC) | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -Iserve -c -o $@ $<
# ---- 测试(标量 + AVX2 两套) ----
TEST_SRC := tests/test_matvec.c tests/test_tokenizer.c tests/test_llf.c tests/test_engine.c tests/test_prefill_batch.c tests/test_cache.c
$(OBJDIR)/test_matvec.exe: tests/test_matvec.c tests/ref_data.h inference/core/platform.c inference/core/llf.c inference/core/matvec.c inference/core/log.c | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -Itests -o $@ $< inference/core/platform.c inference/core/llf.c inference/core/matvec.c inference/core/log.c $(LDFLAGS) $(LIBS)
$(OBJDIR)/test_tokenizer.exe: tests/test_tokenizer.c inference/core/platform.c inference/core/llf.c inference/core/tokenizer.c inference/core/log.c | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -o $@ $^ $(LDFLAGS) $(LIBS)
$(OBJDIR)/test_llf.exe: tests/test_llf.c $(TEST_ENGINE_CORE) | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -o $@ $^ $(LDFLAGS) $(LIBS)
$(OBJDIR)/test_engine.exe: tests/test_engine.c $(TEST_ENGINE_CORE) | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -o $@ $^ $(LDFLAGS) $(LIBS)
$(OBJDIR_AVX2)/test_matvec.exe: tests/test_matvec.c tests/ref_data.h inference/core/platform.c inference/core/llf.c inference/core/matvec.c inference/core/log.c | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -Itests -o $@ $< inference/core/platform.c inference/core/llf.c inference/core/matvec.c inference/core/log.c $(LDFLAGS) $(LDFLAGS_AVX2) $(LIBS)
$(OBJDIR_AVX2)/test_tokenizer.exe: tests/test_tokenizer.c inference/core/platform.c inference/core/llf.c inference/core/tokenizer.c inference/core/log.c | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -o $@ $^ $(LDFLAGS) $(LDFLAGS_AVX2) $(LIBS)
$(OBJDIR_AVX2)/test_llf.exe: tests/test_llf.c $(TEST_ENGINE_CORE) | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -o $@ $^ $(LDFLAGS) $(LDFLAGS_AVX2) $(LIBS)
$(OBJDIR_AVX2)/test_engine.exe: tests/test_engine.c $(TEST_ENGINE_CORE) | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -o $@ $^ $(LDFLAGS) $(LDFLAGS_AVX2) $(LIBS)
$(OBJDIR)/test_prefill_batch.exe: tests/test_prefill_batch.c $(TEST_ENGINE_CORE) | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -o $@ $^ $(LDFLAGS) $(LIBS)
$(OBJDIR)/test_cache.exe: tests/test_cache.c inference/core/cache.c inference/core/platform.c inference/core/log.c | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -o $@ $^ $(LDFLAGS) $(LIBS)
$(OBJDIR_AVX2)/test_prefill_batch.exe: tests/test_prefill_batch.c $(TEST_ENGINE_CORE) | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -o $@ $^ $(LDFLAGS) $(LDFLAGS_AVX2) $(LIBS)
$(OBJDIR_AVX2)/test_cache.exe: tests/test_cache.c inference/core/cache.c inference/core/platform.c inference/core/log.c | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -o $@ $^ $(LDFLAGS) $(LDFLAGS_AVX2) $(LIBS)
$(OBJDIR)/test_long_chat.exe: tests/test_long_chat.c $(TEST_ENGINE_CORE) | $(OBJDIR)
$(CC) $(CFLAGS_BASE) $(INFER_INC) -o $@ $^ $(LDFLAGS) $(LIBS)
$(OBJDIR_AVX2)/test_long_chat.exe: tests/test_long_chat.c $(TEST_ENGINE_CORE) | $(OBJDIR_AVX2)
$(CC) $(CFLAGS_AVX2) $(INFER_INC) -o $@ $^ $(LDFLAGS) $(LDFLAGS_AVX2) $(LIBS)
TEST_BIN := $(TEST_SRC:tests/%.c=$(OBJDIR)/%.exe)
TEST_BIN_AVX := $(TEST_SRC:tests/%.c=$(OBJDIR_AVX2)/%.exe)
# 默认 test 用 AVX2 版本(生产构建; golden 与 SIMD/fma 结果一致)。
# 标量版可用 make test-base 运行(其数值因无 fma 与 golden 存在预期差异)。
test: $(TEST_BIN_AVX)
@echo "=== test_matvec (avx2) ==="
./$(OBJDIR_AVX2)/test_matvec.exe
@echo "=== test_tokenizer (avx2) ==="
./$(OBJDIR_AVX2)/test_tokenizer.exe
@echo "=== test_llf (avx2) ==="
./$(OBJDIR_AVX2)/test_llf.exe
@echo "=== test_engine (avx2) ==="
./$(OBJDIR_AVX2)/test_engine.exe
@echo "=== test_prefill_batch (avx2) ==="
./$(OBJDIR_AVX2)/test_prefill_batch.exe
@echo "=== test_cache (avx2) ==="
./$(OBJDIR_AVX2)/test_cache.exe
test-avx2: test
test-base: $(TEST_BIN)
@echo "=== test_matvec (scalar) ==="
./$(OBJDIR)/test_matvec.exe
@echo "=== test_tokenizer (scalar) ==="
./$(OBJDIR)/test_tokenizer.exe
@echo "=== test_llf (scalar) ==="
./$(OBJDIR)/test_llf.exe
@echo "=== test_engine (scalar, golden 差异预期) ==="
./$(OBJDIR)/test_engine.exe
@echo "=== test_prefill_batch (scalar) ==="
./$(OBJDIR)/test_prefill_batch.exe
@echo "=== test_cache (scalar) ==="
./$(OBJDIR)/test_cache.exe
# ---- PP 会话缓存集成测试(2 段) ----
# tools/test_pp_sess.sh: 临时 ranks:2 → 启动 → tests/test_pp_sess.py → 恢复 serve.yaml
test-pp-sess: $(BIN_AVX2) $(MODEL_LLF)
@bash tools/test_pp_sess.sh $(BIN_AVX2)
# ---- 集成: 转换模型 + 运行 chat/gen ----
MODEL_GGUF ?= models/tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf
MODEL_LLF ?= models/tinyllama-1.1b-chat-v1.0.Q4_K_M.llf
MODEL_VOCAB ?= models/tinyllama.vocab.txt
CHAT_PROMPT ?= "Once upon a time"
CHAT_TOKENS ?= 30
# 推理线程数(OpenMP)。默认物理核数(lscpu; SMT 超订阅会拖慢 decode), 可用 NTHREADS=N 覆盖。
NTHREADS ?= $(shell n=`lscpu -p=CORE 2>/dev/null | grep -v '^#' | sort -u | wc -l`; if [ -z "$$n" ] || [ "$$n" = 0 ]; then n=`nproc 2>/dev/null || echo 4`; fi; echo $$n)
# 运行参数(默认无): MTP=1 开投机解码(模型需带 MTP/nextn 权重); KV=q8 开 KV int8 量化(仅 CPU, 内存减半)
# make chat-avx2 MTP=1 / make gen-avx2 KV=q8
# make chat-minicpm5-2b-avx2 MTP=1 KV=q8
# server 目标: KV=q8 会透传给 hub(→ rank); MTP 仅 serve.yaml 模型条目 mtp: 1 支持
MTP ?= 0
KV ?= f16
RUNARGS = $(if $(filter 1,$(MTP)),--mtp 1,) $(if $(filter q8,$(KV)),--kv q8,)
# serve/hub 透传(hub/supervisor → rank): --kv q8 全模型生效; --mtp 为全局默认(serve.yaml 模型条目 mtp 优先)
HUBKV = $(if $(filter q8,$(KV)),--kv q8,) $(if $(filter 1,$(MTP)),--mtp 1,)
RUN = OMP_NUM_THREADS=$(NTHREADS) $(BIN)
RUN_AVX2 = OMP_NUM_THREADS=$(NTHREADS) $(BIN_AVX2)
# llf 转换规则: 仅当 gguf 比 llf 新才转换(bin 用 order-only 依赖, 不触发重转)
$(MODEL_LLF): $(MODEL_GGUF) | $(BIN)
@mkdir -p $(dir $@)
$(BIN) convert --gguf $(MODEL_GGUF) --out $(MODEL_LLF) --vocab $(MODEL_VOCAB) --seq 2048
chat: $(BIN) $(MODEL_LLF)
$(RUN) chat --model $(MODEL_LLF) --vocab $(MODEL_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
gen: $(BIN) $(MODEL_LLF)
$(RUN) gen --model $(MODEL_LLF) --vocab $(MODEL_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
chat-avx2: $(BIN_AVX2) $(MODEL_LLF)
$(RUN_AVX2) chat --model $(MODEL_LLF) --vocab $(MODEL_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
gen-avx2: $(BIN_AVX2) $(MODEL_LLF)
$(RUN_AVX2) gen --model $(MODEL_LLF) --vocab $(MODEL_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
# ---- CUDA: 独立目录构建 + 设备冒烟 ----
# 有 nvcc → FP16 权 + cublas decode; 无 nvcc → host-shim
cuda:
$(MAKE) avx2 YLLM_CUDA=1 OBJDIR_AVX2=$(OBJDIR_CUDA) BIN_AVX2=$(BIN_CUDA)
RUN_CUDA = OMP_NUM_THREADS=$(NTHREADS) $(BIN_CUDA)
gen-cuda: cuda $(MODEL_LLF)
$(RUN_CUDA) gen --model $(MODEL_LLF) --vocab $(MODEL_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) --device cuda --gpu $(GPU) --gpu-weights $(GPU_WEIGHTS) $(RUNARGS)
chat-cuda: cuda $(MODEL_LLF)
$(RUN_CUDA) chat --model $(MODEL_LLF) --vocab $(MODEL_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) --device cuda --gpu $(GPU) --gpu-weights $(GPU_WEIGHTS) $(RUNARGS)
chat-gemma4-e2b-cuda: cuda $(G4_E2B_LLF)
$(RUN_CUDA) chat --model $(G4_E2B_LLF) --vocab $(G4_E2B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device cuda --gpu $(GPU) --gpu-weights $(GPU_WEIGHTS) \
$(if $(IMAGE),--mmproj $(G4_E2B_MMPROJ) --image $(IMAGE),)
chat-gemma4-e4b-cuda: cuda $(G4_E4B_LLF)
$(RUN_CUDA) chat --model $(G4_E4B_LLF) --vocab $(G4_E4B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device cuda --gpu $(GPU) --gpu-weights $(GPU_WEIGHTS) \
$(if $(IMAGE),--mmproj $(G4_E4B_MMPROJ) --image $(IMAGE),)
# ---- Vulkan: 独立目录; 默认尝试原生 VkDevice, YLLM_VULKAN_HOST=1 强制 shim ----
# make vulkan = 标量 CPU fallback + Vulkan(无 -mavx2)
vulkan:
$(MAKE) all YLLM_VULKAN=1 OBJDIR=$(OBJDIR_VULKAN) BIN=$(BIN_VULKAN)
vulkan-avx2:
$(MAKE) avx2 YLLM_VULKAN=1 OBJDIR_AVX2=$(OBJDIR_VULKAN_AVX2) BIN_AVX2=$(BIN_VULKAN_AVX2)
RUN_VULKAN = OMP_NUM_THREADS=$(NTHREADS) $(BIN_VULKAN)
RUN_VULKAN_AVX2 = OMP_NUM_THREADS=$(NTHREADS) $(BIN_VULKAN_AVX2)
gen-vulkan: vulkan $(MODEL_LLF)
$(RUN_VULKAN) gen --model $(MODEL_LLF) --vocab $(MODEL_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) --device vulkan --gpu $(GPU) $(RUNARGS)
chat-vulkan: vulkan $(MODEL_LLF)
$(RUN_VULKAN) chat --model $(MODEL_LLF) --vocab $(MODEL_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) --temp 0 --no-template 1 --device vulkan --gpu $(GPU) $(RUNARGS)
# AVX2 CPU fallback + Vulkan(产物 build/avx2-vulkan)
chat-avx2-vulkan: vulkan-avx2 $(MODEL_LLF)
$(RUN_VULKAN_AVX2) chat --model $(MODEL_LLF) --vocab $(MODEL_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) --temp 0 --no-template 1 --device vulkan --gpu $(GPU) $(RUNARGS)
gen-avx2-vulkan: vulkan-avx2 $(MODEL_LLF)
$(RUN_VULKAN_AVX2) gen --model $(MODEL_LLF) --vocab $(MODEL_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) --device vulkan --gpu $(GPU) $(RUNARGS)
# ---- Android: platform/android CMake + NDK (arm64-v8a) ----
# make android Vulkan ON → build/android/yllm + libyllm.so
# make android-cpu Vulkan OFF → build/android-cpu/
# 环境: ANDROID_NDK / ANDROID_SDK; 未设则扫 E:/soft/android-ndk-* 与 %LOCALAPPDATA%/Android/Sdk
ANDROID_ABI ?= arm64-v8a
ANDROID_PLATFORM ?= android-28
ANDROID_BUILD ?= build/android
ANDROID_BUILD_CPU ?= build/android-cpu
ANDROID_SDK_CAND := $(subst \,/,$(LOCALAPPDATA))/Android/Sdk \
$(subst \,/,$(ANDROID_HOME)) \
E:/soft/Android/Sdk \
$(HOME)/Android/Sdk
ifeq ($(strip $(ANDROID_SDK)),)
ANDROID_SDK := $(firstword $(wildcard $(ANDROID_SDK_CAND)))
endif
ANDROID_NDK_CAND := $(subst \,/,$(ANDROID_NDK_ROOT)) \
E:/soft/android-ndk-r27d \
E:/soft/android-ndk-r27 \
$(ANDROID_SDK)/ndk-bundle
ifeq ($(strip $(ANDROID_NDK)),)
ANDROID_NDK := $(firstword $(wildcard $(ANDROID_NDK_CAND)))
endif
ifeq ($(strip $(ANDROID_NDK)),)
ifneq ($(strip $(ANDROID_SDK)),)
ANDROID_NDK := $(lastword $(sort $(wildcard $(ANDROID_SDK)/ndk/*)))
endif
endif
ifeq ($(strip $(ANDROID_CMAKE)),)
ANDROID_CMAKE := $(firstword $(wildcard \
$(ANDROID_SDK)/cmake/3.22.1/bin/cmake.exe \
$(ANDROID_SDK)/cmake/3.22.1/bin/cmake \
$(ANDROID_SDK)/cmake/3.18.1/bin/cmake.exe \
$(ANDROID_SDK)/cmake/3.18.1/bin/cmake))
endif
ifeq ($(strip $(ANDROID_CMAKE)),)
ANDROID_CMAKE := cmake
endif
ifeq ($(strip $(ANDROID_NINJA)),)
ANDROID_NINJA := $(firstword $(wildcard \
$(ANDROID_SDK)/cmake/3.22.1/bin/ninja.exe \
$(ANDROID_SDK)/cmake/3.22.1/bin/ninja \
$(ANDROID_SDK)/cmake/3.18.1/bin/ninja.exe \
$(ANDROID_SDK)/cmake/3.18.1/bin/ninja))
endif
ifeq ($(strip $(ANDROID_NINJA)),)
ANDROID_NINJA := ninja
endif
ANDROID_TOOLCHAIN = $(ANDROID_NDK)/build/cmake/android.toolchain.cmake
define ANDROID_CMAKE_CFG
@if [ -z "$(ANDROID_NDK)" ] || [ ! -f "$(ANDROID_TOOLCHAIN)" ]; then \
echo "android: set ANDROID_NDK (cmake toolchain not found)"; exit 1; \
fi
$(ANDROID_CMAKE) -G Ninja -S platform/android -B $(1) \
-DANDROID_ABI=$(ANDROID_ABI) \
-DANDROID_PLATFORM=$(ANDROID_PLATFORM) \
-DANDROID_NDK=$(ANDROID_NDK) \
-DCMAKE_TOOLCHAIN_FILE=$(ANDROID_TOOLCHAIN) \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_MAKE_PROGRAM=$(ANDROID_NINJA) \
-DYLLM_VULKAN=$(2)
$(ANDROID_CMAKE) --build $(1) -j
endef
android android-vulkan:
$(call ANDROID_CMAKE_CFG,$(ANDROID_BUILD),ON)
@echo "android: $(ANDROID_BUILD)/yllm $(ANDROID_BUILD)/libyllm.so"
android-cpu:
$(call ANDROID_CMAKE_CFG,$(ANDROID_BUILD_CPU),OFF)
@echo "android-cpu: $(ANDROID_BUILD_CPU)/yllm $(ANDROID_BUILD_CPU)/libyllm.so"
# ---- 指定模型的 chat 快捷目标(gemma4) ----
G4_E2B_GGUF ?= models/gemma-4-E2B-it-Q4_K_M.gguf
G4_E2B_LLF ?= models/gemma-4-E2B-it-Q4_K_M.llf
G4_E2B_VOCAB ?= models/gemma4.vocab.txt
G4_E2B_MMPROJ ?= models/mmproj-gemma-4-E2B-F16.gguf
G4_E4B_GGUF ?= models/gemma-4-E4B-it-Q4_K_M.gguf
G4_E4B_LLF ?= models/gemma-4-E4B-it-Q4_K_M.llf
G4_E4B_VOCAB ?= models/gemma4.vocab.txt
G4_E4B_MMPROJ ?= models/mmproj-gemma-4-E4B-f16.gguf
IMAGE ?=
$(G4_E2B_LLF): $(G4_E2B_GGUF) | $(BIN)
$(BIN) convert --gguf $(G4_E2B_GGUF) --out $(G4_E2B_LLF) --vocab $(G4_E2B_VOCAB) --seq 8192
$(G4_E4B_LLF): $(G4_E4B_GGUF) | $(BIN)
$(BIN) convert --gguf $(G4_E4B_GGUF) --out $(G4_E4B_LLF) --vocab $(G4_E4B_VOCAB) --seq 8192
chat-gemma4-e2b: $(BIN) $(G4_E2B_LLF)
$(RUN) chat --model $(G4_E2B_LLF) --vocab $(G4_E2B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS) \
$(if $(IMAGE),--mmproj $(G4_E2B_MMPROJ) --image $(IMAGE),)
chat-gemma4-e2b-avx2: $(BIN_AVX2) $(G4_E2B_LLF)
$(RUN_AVX2) chat --model $(G4_E2B_LLF) --vocab $(G4_E2B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS) \
$(if $(IMAGE),--mmproj $(G4_E2B_MMPROJ) --image $(IMAGE),) \
$(if $(OPT),--opt $(OPT),)
chat-gemma4-e2b-vulkan: vulkan $(G4_E2B_LLF)
$(RUN_VULKAN) chat --model $(G4_E2B_LLF) --vocab $(G4_E2B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU) \
$(if $(IMAGE),--mmproj $(G4_E2B_MMPROJ) --image $(IMAGE),)
# 长序列 chat 吞吐(不进 make test)
# make test-long-chat
# make test-long-chat LONG_N=14,512,2048,4096 LONG_DECODE=16
LONG_N ?= 14,512
LONG_DECODE ?= 16
test-long-chat: $(OBJDIR_AVX2)/test_long_chat.exe $(G4_E2B_LLF)
OMP_NUM_THREADS=$(NTHREADS) ./$(OBJDIR_AVX2)/test_long_chat.exe --model $(G4_E2B_LLF) --vocab $(G4_E2B_VOCAB) --n $(LONG_N) --tokens $(LONG_DECODE)
test-long-chat-avx2: test-long-chat
chat-gemma4-e2b-avx2-vulkan: vulkan-avx2 $(G4_E2B_LLF)
$(RUN_VULKAN_AVX2) chat --model $(G4_E2B_LLF) --vocab $(G4_E2B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU) \
$(if $(IMAGE),--mmproj $(G4_E2B_MMPROJ) --image $(IMAGE),)
chat-gemma4-e4b: $(BIN) $(G4_E4B_LLF)
$(RUN) chat --model $(G4_E4B_LLF) --vocab $(G4_E4B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS) \
$(if $(IMAGE),--mmproj $(G4_E4B_MMPROJ) --image $(IMAGE),)
chat-gemma4-e4b-avx2: $(BIN_AVX2) $(G4_E4B_LLF)
$(RUN_AVX2) chat --model $(G4_E4B_LLF) --vocab $(G4_E4B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS) \
$(if $(IMAGE),--mmproj $(G4_E4B_MMPROJ) --image $(IMAGE),)
chat-gemma4-e4b-avx2-vulkan: vulkan-avx2 $(G4_E4B_LLF)
$(RUN_VULKAN_AVX2) chat --model $(G4_E4B_LLF) --vocab $(G4_E4B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU) \
$(if $(IMAGE),--mmproj $(G4_E4B_MMPROJ) --image $(IMAGE),)
# ---- 指定模型的 chat 快捷目标(qwen2.5 / qwen3) ----
Q25_GGUF ?= models/qwen2.5-1.5b-instruct-q4_k_m.gguf
Q25_LLF ?= models/qwen2.5-1.5b.llf
Q25_VOCAB ?= models/qwen2.5.vocab.txt
Q25_7B_GGUF ?= models/qwen2.5-7b-instruct-q4_k_m.gguf
Q25_7B_LLF ?= models/qwen2.5-7b.llf
Q25_7B_VOCAB ?= models/qwen2.5-7b.vocab.txt
Q3_8B_GGUF ?= models/Qwen3-8B-Q4_K_M.gguf
Q3_8B_LLF ?= models/qwen3-8b.llf
Q3_8B_VOCAB ?= models/qwen3-8b.vocab.txt
$(Q25_LLF): $(Q25_GGUF) | $(BIN)
@mkdir -p $(dir $@)
$(BIN) convert --gguf $(Q25_GGUF) --out $(Q25_LLF) --vocab $(Q25_VOCAB) --seq 2048
$(Q25_7B_LLF): $(Q25_7B_GGUF) | $(BIN)
@mkdir -p $(dir $@)
$(BIN) convert --gguf $(Q25_7B_GGUF) --out $(Q25_7B_LLF) --vocab $(Q25_7B_VOCAB) --seq 4096
$(Q3_8B_LLF): $(Q3_8B_GGUF) | $(BIN)
@mkdir -p $(dir $@)
$(BIN) convert --gguf $(Q3_8B_GGUF) --out $(Q3_8B_LLF) --vocab $(Q3_8B_VOCAB) --seq 2048
chat-qwen2.5-1.5b: $(BIN) $(Q25_LLF)
$(RUN) chat --model $(Q25_LLF) --vocab $(Q25_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
chat-qwen2.5-1.5b-avx2: $(BIN_AVX2) $(Q25_LLF)
$(RUN_AVX2) chat --model $(Q25_LLF) --vocab $(Q25_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
chat-qwen2.5-1.5b-vulkan: vulkan $(Q25_LLF)
$(RUN_VULKAN) chat --model $(Q25_LLF) --vocab $(Q25_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU)
chat-qwen2.5-1.5b-avx2-vulkan: vulkan-avx2 $(Q25_LLF)
$(RUN_VULKAN_AVX2) chat --model $(Q25_LLF) --vocab $(Q25_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU)
chat-qwen2.5-7b: $(BIN) $(Q25_7B_LLF)
$(RUN) chat --model $(Q25_7B_LLF) --vocab $(Q25_7B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
chat-qwen2.5-7b-avx2: $(BIN_AVX2) $(Q25_7B_LLF)
$(RUN_AVX2) chat --model $(Q25_7B_LLF) --vocab $(Q25_7B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
chat-qwen2.5-7b-vulkan: vulkan $(Q25_7B_LLF)
$(RUN_VULKAN) chat --model $(Q25_7B_LLF) --vocab $(Q25_7B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU)
chat-qwen2.5-7b-avx2-vulkan: vulkan-avx2 $(Q25_7B_LLF)
$(RUN_VULKAN_AVX2) chat --model $(Q25_7B_LLF) --vocab $(Q25_7B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU)
chat-qwen3-8b: $(BIN) $(Q3_8B_LLF)
$(RUN) chat --model $(Q3_8B_LLF) --vocab $(Q3_8B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
chat-qwen3-8b-avx2: $(BIN_AVX2) $(Q3_8B_LLF)
$(RUN_AVX2) chat --model $(Q3_8B_LLF) --vocab $(Q3_8B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
chat-qwen3-8b-vulkan: vulkan $(Q3_8B_LLF)
$(RUN_VULKAN) chat --model $(Q3_8B_LLF) --vocab $(Q3_8B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU)
chat-qwen3-8b-avx2-vulkan: vulkan-avx2 $(Q3_8B_LLF)
$(RUN_VULKAN_AVX2) chat --model $(Q3_8B_LLF) --vocab $(Q3_8B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU)
# ---- qwen3-vl-2b(文本 + 可选 mmproj 视觉; GGUF arch=qwen3vl) ----
Q3VL_2B_GGUF ?= models/Qwen3-VL-2B-Instruct-Q4_K_M.gguf
Q3VL_2B_LLF ?= models/qwen3-vl-2b.llf
Q3VL_2B_VOCAB ?= models/qwen3-vl-2b.vocab.txt
Q3VL_2B_MMPROJ ?= models/mmproj-Qwen3VL-2B-Instruct-Q8_0.gguf
$(Q3VL_2B_LLF): $(Q3VL_2B_GGUF) | $(BIN)
@mkdir -p $(dir $@)
$(BIN) convert --gguf $(Q3VL_2B_GGUF) --out $(Q3VL_2B_LLF) --vocab $(Q3VL_2B_VOCAB) --seq 4096
chat-qwen3-vl-2b: $(BIN) $(Q3VL_2B_LLF)
$(RUN) chat --model $(Q3VL_2B_LLF) --vocab $(Q3VL_2B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS) \
$(if $(IMAGE),--mmproj $(Q3VL_2B_MMPROJ) --image $(IMAGE),)
chat-qwen3-vl-2b-avx2: $(BIN_AVX2) $(Q3VL_2B_LLF)
$(RUN_AVX2) chat --model $(Q3VL_2B_LLF) --vocab $(Q3VL_2B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS) \
$(if $(IMAGE),--mmproj $(Q3VL_2B_MMPROJ) --image $(IMAGE),)
chat-qwen3-vl-2b-vulkan: vulkan $(Q3VL_2B_LLF)
$(RUN_VULKAN) chat --model $(Q3VL_2B_LLF) --vocab $(Q3VL_2B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU) \
$(if $(IMAGE),--mmproj $(Q3VL_2B_MMPROJ) --image $(IMAGE),)
chat-qwen3-vl-2b-avx2-vulkan: vulkan-avx2 $(Q3VL_2B_LLF)
$(RUN_VULKAN_AVX2) chat --model $(Q3VL_2B_LLF) --vocab $(Q3VL_2B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU) \
$(if $(IMAGE),--mmproj $(Q3VL_2B_MMPROJ) --image $(IMAGE),)
# ---- qwen3.8-27b(Gated Attention + GDN 混合架构) ----
Q3_27B_GGUF ?= models/Qwen3.8-27B-Q4_K_M.gguf
Q3_27B_LLF ?= models/qwen3.8-27b.llf
Q3_27B_VOCAB ?= models/qwen3.vocab.txt
$(Q3_27B_LLF): $(Q3_27B_GGUF) | $(BIN)
@mkdir -p $(dir $@)
$(BIN) convert --gguf $(Q3_27B_GGUF) --out $(Q3_27B_LLF) --vocab $(Q3_27B_VOCAB) --seq 2048
gen-qwen3.8-27b: $(BIN) $(Q3_27B_LLF)
$(RUN) gen --model $(Q3_27B_LLF) --vocab $(Q3_27B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
gen-qwen3.8-27b-avx2: $(BIN_AVX2) $(Q3_27B_LLF)
$(RUN_AVX2) gen --model $(Q3_27B_LLF) --vocab $(Q3_27B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
gen-qwen3.8-27b-avx2-vulkan: vulkan-avx2 $(Q3_27B_LLF)
$(RUN_VULKAN_AVX2) gen --model $(Q3_27B_LLF) --vocab $(Q3_27B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU)
chat-qwen3.8-27b: $(BIN) $(Q3_27B_LLF)
$(RUN) chat --model $(Q3_27B_LLF) --vocab $(Q3_27B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
chat-qwen3.8-27b-avx2: $(BIN_AVX2) $(Q3_27B_LLF)
$(RUN_AVX2) chat --model $(Q3_27B_LLF) --vocab $(Q3_27B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
chat-qwen3.8-27b-avx2-vulkan: vulkan-avx2 $(Q3_27B_LLF)
$(RUN_VULKAN_AVX2) chat --model $(Q3_27B_LLF) --vocab $(Q3_27B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU)
# qwen35 gpu_fused=0: 现阶段 CUDA 只加载权重, transformer 仍走 CPU(日志 cuda: skip GPU transformer)
chat-qwen3.8-27b-cuda: cuda $(Q3_27B_LLF)
$(RUN_CUDA) chat --model $(Q3_27B_LLF) --vocab $(Q3_27B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) --device cuda --gpu $(GPU) --gpu-weights $(GPU_WEIGHTS) $(RUNARGS)
# ---- qwen3.5-0.8b(qwen35 架构, 小模型; 内存/CPU 友好) ----
# 模型文件默认放 models/ 下, 名字不一样就覆盖变量:
# make chat-qwen3.5-0.8b-avx2 Q35_08B_GGUF=models/xxx.gguf
Q35_08B_GGUF ?= models/Qwen_Qwen3.5-0.8B-Q4_K_M.gguf
Q35_08B_LLF ?= models/qwen3.5-0.8b.llf
Q35_08B_VOCAB ?= models/qwen3.5-0.8b.vocab.txt
$(Q35_08B_LLF): $(Q35_08B_GGUF) | $(BIN)
@mkdir -p $(dir $@)
$(BIN) convert --gguf $(Q35_08B_GGUF) --out $(Q35_08B_LLF) --vocab $(Q35_08B_VOCAB) --seq 2048
gen-qwen3.5-0.8b: $(BIN) $(Q35_08B_LLF)
$(RUN) gen --model $(Q35_08B_LLF) --vocab $(Q35_08B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
gen-qwen3.5-0.8b-avx2: $(BIN_AVX2) $(Q35_08B_LLF)
$(RUN_AVX2) gen --model $(Q35_08B_LLF) --vocab $(Q35_08B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
chat-qwen3.5-0.8b: $(BIN) $(Q35_08B_LLF)
$(RUN) chat --model $(Q35_08B_LLF) --vocab $(Q35_08B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
chat-qwen3.5-0.8b-avx2: $(BIN_AVX2) $(Q35_08B_LLF)
$(RUN_AVX2) chat --model $(Q35_08B_LLF) --vocab $(Q35_08B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
# 目标名大小写别名: 模型名写 0.8B, 直接 make chat-qwen3.5-0.8B 也能用
chat-qwen3.5-0.8B: chat-qwen3.5-0.8b
chat-qwen3.5-0.8B-avx2: chat-qwen3.5-0.8b-avx2
# ---- minicpm-v-4.6(qwen35 文本塔 + clip mmproj 视觉; 无 --image 则纯文本) ----
MCPM_V46_GGUF ?= models/MiniCPM-V-4_6-Q4_K_M.gguf
MCPM_V46_LLF ?= models/minicpm-v-4.6.llf
MCPM_V46_VOCAB ?= models/minicpm-v-4.6.vocab.txt
MCPM_V46_MMPROJ ?= models/mmproj-model-f16.gguf
IMAGE ?=
$(MCPM_V46_LLF): $(MCPM_V46_GGUF) | $(BIN)
@mkdir -p $(dir $@)
$(BIN) convert --gguf $(MCPM_V46_GGUF) --out $(MCPM_V46_LLF) --vocab $(MCPM_V46_VOCAB) --seq 2048
chat-minicpm-v-4.6: $(BIN) $(MCPM_V46_LLF)
$(RUN) chat --model $(MCPM_V46_LLF) --vocab $(MCPM_V46_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS) \
$(if $(IMAGE),--mmproj $(MCPM_V46_MMPROJ) --image $(IMAGE),) \
$(if $(OPT),--opt $(OPT),)
# make chat-minicpm-v-4.6-avx2 IMAGE=models/test_red.ppm CHAT_TOKENS=16'
chat-minicpm-v-4.6-avx2: $(BIN_AVX2) $(MCPM_V46_LLF)
$(RUN_AVX2) chat --model $(MCPM_V46_LLF) --vocab $(MCPM_V46_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS) \
$(if $(IMAGE),--mmproj $(MCPM_V46_MMPROJ) --image $(IMAGE),) \
$(if $(OPT),--opt $(OPT),)
chat-minicpm-v-4.6-vulkan: vulkan $(MCPM_V46_LLF)
$(RUN_VULKAN) chat --model $(MCPM_V46_LLF) --vocab $(MCPM_V46_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU) \
$(if $(IMAGE),--mmproj $(MCPM_V46_MMPROJ) --image $(IMAGE),) \
$(if $(OPT),--opt $(OPT),)
chat-minicpm-v-4.6-avx2-vulkan: vulkan-avx2 $(MCPM_V46_LLF)
$(RUN_VULKAN_AVX2) chat --model $(MCPM_V46_LLF) --vocab $(MCPM_V46_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU) \
$(if $(IMAGE),--mmproj $(MCPM_V46_MMPROJ) --image $(IMAGE),) \
$(if $(OPT),--opt $(OPT),)
# ---- minicpm5-2b(纯文本; GGUF: MiniCPM5-2B-Q4_K_M.gguf) ----
# make chat-minicpm5-2b / gen-minicpm5-2b
# make chat-minicpm5-2b-avx2 / gen-minicpm5-2b-avx2
# make chat-minicpm5-2b-vulkan / chat-minicpm5-2b-avx2-vulkan
# make server-minicpm5-2b → make infer-minicpm5-2b
# MTP/KV 用全局参数: make chat-minicpm5-2b-avx2 MTP=1 KV=q8
# (MTP 仅当 GGUF 含 nextn. 张量才生效, 普通 Q4_K_M 量化没有 → 警告并回退)
MCPM5_2B_GGUF ?= models/MiniCPM5-2B-Q4_K_M.gguf
MCPM5_2B_LLF ?= models/minicpm5-2b.llf
MCPM5_2B_VOCAB ?= models/minicpm5-2b.vocab.txt
$(MCPM5_2B_LLF): $(MCPM5_2B_GGUF) | $(BIN)
@mkdir -p $(dir $@)
$(BIN) convert --gguf $(MCPM5_2B_GGUF) --out $(MCPM5_2B_LLF) --vocab $(MCPM5_2B_VOCAB) --seq 4096
chat-minicpm5-2b: $(BIN) $(MCPM5_2B_LLF)
$(RUN) chat --model $(MCPM5_2B_LLF) --vocab $(MCPM5_2B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
gen-minicpm5-2b: $(BIN) $(MCPM5_2B_LLF)
$(RUN) gen --model $(MCPM5_2B_LLF) --vocab $(MCPM5_2B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
chat-minicpm5-2b-avx2: $(BIN_AVX2) $(MCPM5_2B_LLF)
$(RUN_AVX2) chat --model $(MCPM5_2B_LLF) --vocab $(MCPM5_2B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
gen-minicpm5-2b-avx2: $(BIN_AVX2) $(MCPM5_2B_LLF)
$(RUN_AVX2) gen --model $(MCPM5_2B_LLF) --vocab $(MCPM5_2B_VOCAB) --prompt $(CHAT_PROMPT) --tokens $(CHAT_TOKENS) $(RUNARGS)
chat-minicpm5-2b-vulkan: vulkan $(MCPM5_2B_LLF)
$(RUN_VULKAN) chat --model $(MCPM5_2B_LLF) --vocab $(MCPM5_2B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU)
chat-minicpm5-2b-avx2-vulkan: vulkan-avx2 $(MCPM5_2B_LLF)
$(RUN_VULKAN_AVX2) chat --model $(MCPM5_2B_LLF) --vocab $(MCPM5_2B_VOCAB) --prompt $(CHAT_PROMPT) \
--tokens $(CHAT_TOKENS) $(RUNARGS) --device vulkan --gpu $(GPU)
# ---- 指定模型的 serve 快捷目标(serve.yaml 多模型, 用 --model <名字> 只拉起对应模型) ----
# make server-<name> / make infer-<name> 与 chat-* 一一对应
# make server-qwen38 兼容旧名(= server-qwen3.8-27b, yaml name=qwen3.8)
server-tinyllama: $(BIN_AVX2) $(MODEL_LLF)
@mkdir -p $(SERVE_LOGDIR)
@nohup env OMP_NUM_THREADS=$(NTHREADS) YLLM_SRV_TIMEOUT=$(YLLM_SRV_TIMEOUT) $(BIN_AVX2) hub --config serve.yaml --model tinyllama $(HUBKV) > $(SERVE_LOGDIR)/hub.out 2>&1 &
@echo "hub started (serve.yaml, model=tinyllama); 用 make infer-tinyllama 发请求 (HTTP 127.0.0.1:8000)"
server-qwen2.5-1.5b: $(BIN_AVX2) $(Q25_LLF)
@mkdir -p $(SERVE_LOGDIR)
@nohup env OMP_NUM_THREADS=$(NTHREADS) YLLM_SRV_TIMEOUT=$(YLLM_SRV_TIMEOUT) $(BIN_AVX2) hub --config serve.yaml --model qwen2.5-1.5b $(HUBKV) > $(SERVE_LOGDIR)/hub.out 2>&1 &
@echo "hub started (serve.yaml, model=qwen2.5-1.5b); 用 make infer-qwen2.5-1.5b 发请求 (HTTP 127.0.0.1:8000)"
server-qwen2.5-7b: $(BIN_AVX2) $(Q25_7B_LLF)
@mkdir -p $(SERVE_LOGDIR)
@nohup env OMP_NUM_THREADS=$(NTHREADS) YLLM_SRV_TIMEOUT=$(YLLM_SRV_TIMEOUT) $(BIN_AVX2) hub --config serve.yaml --model qwen2.5 $(HUBKV) > $(SERVE_LOGDIR)/hub.out 2>&1 &
@echo "hub started (serve.yaml, model=qwen2.5); 用 make infer-qwen2.5-7b 发请求 (HTTP 127.0.0.1:8000)"
server-qwen3-8b: $(BIN_AVX2) $(Q3_8B_LLF)
@mkdir -p $(SERVE_LOGDIR)
@nohup env OMP_NUM_THREADS=$(NTHREADS) YLLM_SRV_TIMEOUT=$(YLLM_SRV_TIMEOUT) $(BIN_AVX2) hub --config serve.yaml --model qwen3-8b $(HUBKV) > $(SERVE_LOGDIR)/hub.out 2>&1 &
@echo "hub started (serve.yaml, model=qwen3-8b); 用 make infer-qwen3-8b 发请求 (HTTP 127.0.0.1:8000)"
server-qwen3-vl-2b: $(BIN_AVX2) $(Q3VL_2B_LLF)
@mkdir -p $(SERVE_LOGDIR)
@nohup env OMP_NUM_THREADS=$(NTHREADS) YLLM_SRV_TIMEOUT=$(YLLM_SRV_TIMEOUT) $(BIN_AVX2) hub --config serve.yaml --model qwen3-vl-2b $(HUBKV) > $(SERVE_LOGDIR)/hub.out 2>&1 &
@echo "hub started (serve.yaml, model=qwen3-vl-2b); 用 make infer-qwen3-vl-2b 发请求 (HTTP 127.0.0.1:8000)"
server-qwen3.8-27b: $(BIN_AVX2) $(Q3_27B_LLF)
@mkdir -p $(SERVE_LOGDIR)
@nohup env OMP_NUM_THREADS=$(NTHREADS) YLLM_SRV_TIMEOUT=$(YLLM_SRV_TIMEOUT) $(BIN_AVX2) hub --config serve.yaml --model qwen3.8 $(HUBKV) > $(SERVE_LOGDIR)/hub.out 2>&1 &
@echo "hub started (serve.yaml, model=qwen3.8); 用 make infer-qwen3.8-27b 发请求 (HTTP 127.0.0.1:8000)"
server-qwen38: server-qwen3.8-27b
server-gemma4-e2b: $(BIN_AVX2) $(G4_E2B_LLF)
@mkdir -p $(SERVE_LOGDIR)
@nohup env OMP_NUM_THREADS=$(NTHREADS) YLLM_SRV_TIMEOUT=$(YLLM_SRV_TIMEOUT) $(BIN_AVX2) hub --config serve.yaml --model gemma4-e2b $(HUBKV) > $(SERVE_LOGDIR)/hub.out 2>&1 &
@echo "hub started (gemma4-e2b ranks=2 local=1 → 本机 rank0 :9410, timeout=$(YLLM_SRV_TIMEOUT)s)"
@echo "远端 rank1(无需 --peers), 见 docs/serve-cli.md, 例:"
@echo " LD_LIBRARY_PATH=. ./yllm rank --model gemma-4-E2B-it-Q4_K_M.llf --vocab gemma4.vocab.txt \\"
@echo " --model-name gemma4-e2b --port 9411 --rank 1 --ranks 2 \\"
@echo " --supervisor 192.168.1.161:9500 --id rank-1 --budget 1024MB"
@echo "然后: make infer-gemma4-e2b"
server-gemma4-e4b: $(BIN_AVX2) $(G4_E4B_LLF)
@mkdir -p $(SERVE_LOGDIR)
@nohup env OMP_NUM_THREADS=$(NTHREADS) YLLM_SRV_TIMEOUT=$(YLLM_SRV_TIMEOUT) $(BIN_AVX2) hub --config serve.yaml --model gemma4-e4b $(HUBKV) > $(SERVE_LOGDIR)/hub.out 2>&1 &
@echo "hub started (serve.yaml, model=gemma4-e4b, timeout=$(YLLM_SRV_TIMEOUT)s); 用 make infer-gemma4-e4b 发请求 (HTTP 127.0.0.1:8000)"
server-minicpm5-2b: $(BIN_AVX2) $(MCPM5_2B_LLF)
@mkdir -p $(SERVE_LOGDIR)
@nohup env OMP_NUM_THREADS=$(NTHREADS) YLLM_SRV_TIMEOUT=$(YLLM_SRV_TIMEOUT) $(BIN_AVX2) hub --config serve.yaml --model minicpm5-2b $(HUBKV) > $(SERVE_LOGDIR)/hub.out 2>&1 &
@echo "hub started (serve.yaml, model=minicpm5-2b, timeout=$(YLLM_SRV_TIMEOUT)s); 用 make infer-minicpm5-2b 发请求 (HTTP 127.0.0.1:8000)"
# 对应模型的 infer 快捷目标(模型名需匹配 serve.yaml 的 name)
infer-tinyllama: $(BIN)
$(BIN) router --config serve.yaml --send "tinyllama $(CHAT_TOKENS) $(SERVE_PROMPT)"
infer-qwen2.5-1.5b: $(BIN)
$(BIN) router --config serve.yaml --send "qwen2.5-1.5b $(CHAT_TOKENS) $(SERVE_PROMPT)"
infer-qwen2.5-7b: $(BIN)
$(BIN) router --config serve.yaml --send "qwen2.5 $(CHAT_TOKENS) $(SERVE_PROMPT)"
infer-qwen3-8b: $(BIN)
$(BIN) router --config serve.yaml --send "qwen3-8b $(CHAT_TOKENS) $(SERVE_PROMPT)"
infer-qwen3-vl-2b: $(BIN)
$(BIN) router --config serve.yaml --send "qwen3-vl-2b $(CHAT_TOKENS) $(SERVE_PROMPT)"
infer-qwen3.8-27b: $(BIN)
$(BIN) router --config serve.yaml --send "qwen3.8 $(CHAT_TOKENS) $(SERVE_PROMPT)"
infer-qwen38: infer-qwen3.8-27b
infer-gemma4-e2b: $(BIN)
$(BIN) router --config serve.yaml --send "gemma4-e2b $(CHAT_TOKENS) $(SERVE_PROMPT)"
infer-gemma4-e4b: $(BIN)
$(BIN) router --config serve.yaml --send "gemma4-e4b $(CHAT_TOKENS) $(SERVE_PROMPT)"
infer-minicpm5-2b: $(BIN)
$(BIN) router --config serve.yaml --send "minicpm5-2b $(CHAT_TOKENS) $(SERVE_PROMPT)"
# ---- 常驻推理服务(serve 层) ----
# 统一配置: serve.yaml(所有角色共用)
# 用法:
# make serve # supervisor --config serve.yaml 一键拉起 rank+server
# make hub # 合并模式: supervisor+router+server 同进程(推荐)
# make hub SERVER_MODEL=gemma4-e2b # 只拉起指定模型(serve.yaml name)
# make serve-avx2 # 同上, avx2 版本
# make serve-stop # 停掉 serve 相关进程
# make infer # 客户端经 router 发请求(SERVER_MODEL=...)
# 分开模式(各自独立进程, 同一份 config):
# make supervisor / make router / make server / make rank
SERVE_CONFIG ?= serve.yaml
SERVE_LOGDIR ?= logs
# server→rank 读超时(秒); 大 prompt/视觉 prefill 常 >60s, 默认放宽
YLLM_SRV_TIMEOUT ?= 300
# 模型名须匹配 serve.yaml 的 name; hub/infer 共用
SERVER_MODEL ?= tinyllama
SERVE_PROMPT ?= Once upon a time
serve: $(BIN) $(MODEL_LLF)
@mkdir -p $(SERVE_LOGDIR)
@echo "== supervisor --config $(SERVE_CONFIG) =="
@nohup $(BIN) supervisor --config $(SERVE_CONFIG) $(HUBKV) > $(SERVE_LOGDIR)/serve.out 2>&1 &
@echo "serve started (supervisor auto-spawns rank+server)"
serve-avx2: $(BIN_AVX2) $(MODEL_LLF)
@mkdir -p $(SERVE_LOGDIR)
@echo "== supervisor --config $(SERVE_CONFIG) (avx2) =="
@nohup $(BIN_AVX2) supervisor --config $(SERVE_CONFIG) $(HUBKV) > $(SERVE_LOGDIR)/serve.out 2>&1 &
@echo "serve started (avx2)"
# 合并模式: supervisor+router+server 同进程, 自动拉起 rank; 之后 make infer 即可
# make hub # 默认 SERVER_MODEL=tinyllama
# make hub SERVER_MODEL=gemma4-e2b # 只拉起指定模型(= yllm hub --model ...)
# make hub SERVER_MODEL= # 不传 --model, 拉起 yaml 全部本机模型(慎用)
hub: $(BIN_AVX2)
@mkdir -p $(SERVE_LOGDIR)
@echo "== hub --config $(SERVE_CONFIG)$(if $(SERVER_MODEL), --model $(SERVER_MODEL),) (avx2) =="
@nohup env OMP_NUM_THREADS=$(NTHREADS) YLLM_SRV_TIMEOUT=$(YLLM_SRV_TIMEOUT) $(BIN_AVX2) hub --config $(SERVE_CONFIG) \
$(if $(SERVER_MODEL),--model $(SERVER_MODEL),) $(HUBKV) > $(SERVE_LOGDIR)/hub.out 2>&1 &
@echo "hub started$(if $(SERVER_MODEL), (model=$(SERVER_MODEL)),) timeout=$(YLLM_SRV_TIMEOUT)s; 用 make infer 发请求"
# 分开模式(独立进程, 同一份 config)
supervisor: $(BIN)
@mkdir -p $(SERVE_LOGDIR)
@nohup $(BIN) supervisor --config $(SERVE_CONFIG) > $(SERVE_LOGDIR)/supervisor.out 2>&1 &
@echo "supervisor started (--config $(SERVE_CONFIG))"
router: $(BIN)
@mkdir -p $(SERVE_LOGDIR)
@nohup $(BIN) router --config $(SERVE_CONFIG) > $(SERVE_LOGDIR)/router.out 2>&1 &
@echo "router started (--config $(SERVE_CONFIG))"
server: $(BIN)
@mkdir -p $(SERVE_LOGDIR)
@nohup $(BIN) server --config $(SERVE_CONFIG) > $(SERVE_LOGDIR)/server.out 2>&1 &
@echo "server started (--config $(SERVE_CONFIG))"
rank: $(BIN) $(MODEL_LLF)
@mkdir -p $(SERVE_LOGDIR)
@nohup $(BIN) rank --config $(SERVE_CONFIG) > $(SERVE_LOGDIR)/rank.out 2>&1 &
@echo "rank started (--config $(SERVE_CONFIG))"
# 客户端: 经 router 发请求(prompt 不含引号)
# SERVER_MODEL / SERVE_PROMPT 见上方 SERVE_* 节
# 支持 `make infer hello world` 把多余参数当 prompt
ifneq ($(filter-out infer,$(MAKECMDGOALS)),)
SERVE_PROMPT := $(filter-out infer,$(MAKECMDGOALS))
endif
status: $(BIN_AVX2)
$(BIN_AVX2) ctl --config $(SERVE_CONFIG) status
# 管理命令: make ctl <target> <cmd> [need] (目标用短别名, 避免与 make 目标名冲突)
# r0=rank-0 s0=server-0 sv=supervisor rt=router
# 例: make ctl status # 完整状态查看
# make ctl r0 PING / r0 STAT / r0 DRAIN / r0 QUIT
# make ctl sv SCALE 2 # 扩一组 rank
# make ctl sv QUERY_SERVERS
# make ctl s0 DRAIN # server 优雅下线
# make ctl stop # 只发 DRAIN/QUIT(落盘), 不强杀
# make ctl exit # 先 stop, 再强杀残留
CTL_GOALS := $(filter-out ctl,$(MAKECMDGOALS))
CTL_T0 := $(word 1,$(CTL_GOALS))
CTL_TGT := $(if $(filter r0,$(CTL_T0)),rank-0,$(if $(filter s0,$(CTL_T0)),server-0,$(if $(filter sv,$(CTL_T0)),supervisor,$(if $(filter rt,$(CTL_T0)),router,$(CTL_T0)))))
ifeq ($(words $(CTL_GOALS)),1)
CTL_ARGS := --cmd $(CTL_GOALS)
else ifeq ($(words $(CTL_GOALS)),3)
CTL_ARGS := --target $(CTL_TGT) --cmd $(word 2,$(CTL_GOALS)) --need-groups $(word 3,$(CTL_GOALS))
else
CTL_ARGS := --target $(CTL_TGT) --cmd $(word 2,$(CTL_GOALS))
endif
ctl: $(BIN_AVX2)
$(BIN_AVX2) ctl --config $(SERVE_CONFIG) $(CTL_ARGS)
# 文件分发: 接收端 make sync-serve PORT=9600; 发送端 make sync-push FILE=... TO=host:9600 DEST=...
sync-serve: $(BIN)
$(BIN) sync --serve --port $(SYNC_PORT) --dir $(SYNC_DIR)
sync-push: $(BIN)
$(BIN) sync --push $(SYNC_FILE) --to $(SYNC_TO) --dest $(SYNC_DEST)
infer: $(BIN)
$(BIN) router --config $(SERVE_CONFIG) --send "$(SERVER_MODEL) $(CHAT_TOKENS) $(SERVE_PROMPT)"
# 捕获 `make infer <prompt...>` 的多余目标词, 避免 "没有规则" 报错