@@ -525,6 +525,11 @@ def null_context(*args, **kwargs):
525525 "set_current_vllm_config" ,
526526 lambda * args , ** kwargs : null_context (),
527527 )
528+ monkeypatch .setattr (
529+ gpu_model_runner_v2 .current_platform ,
530+ "is_cuda" ,
531+ lambda : True ,
532+ )
528533
529534 def reserve_attention_workspace ():
530535 events .append ("reserve" )
@@ -534,14 +539,212 @@ def reserve_attention_workspace():
534539 runner ._reserve_attention_workspace_for_cudagraph_capture = (
535540 reserve_attention_workspace
536541 )
542+
543+ def profile_cudagraph_memory_graph_pool ():
544+ events .append ("graph_pool" )
545+ return 2048
546+
547+ runner ._profile_cudagraph_memory_graph_pool = profile_cudagraph_memory_graph_pool
537548 runner ._cleanup_profiling_kv_cache = lambda : events .append ("cleanup" )
538549
539550 estimate = runner .profile_cudagraph_memory ()
540551
541- assert estimate == 4096
552+ assert estimate == 6144
542553 assert runner .cudagraph_memory_persistent_estimate == 4096
554+ assert runner .cudagraph_memory_graph_pool_estimate == 2048
555+ assert events == ["init" , "reserve" , "graph_pool" , "cleanup" ]
556+
557+
558+ def test_v2_profile_is_noop_on_non_cuda (monkeypatch ):
559+ from vllm .v1 .worker .gpu import model_runner as gpu_model_runner_v2
560+ from vllm .v1 .worker .gpu .model_runner import GPUModelRunner
561+
562+ runner = GPUModelRunner .__new__ (GPUModelRunner )
563+
564+ monkeypatch .setattr (
565+ gpu_model_runner_v2 .current_platform ,
566+ "is_cuda" ,
567+ lambda : False ,
568+ )
569+ runner ._init_minimal_kv_cache_for_profiling = pytest .fail
570+
571+ assert runner .profile_cudagraph_memory () == 0
572+ assert runner .cudagraph_memory_persistent_estimate == 0
543573 assert runner .cudagraph_memory_graph_pool_estimate == 0
544- assert events == ["init" , "reserve" , "cleanup" ]
574+
575+
576+ def test_v2_cuda_graph_pool_sample_uses_peak (monkeypatch ):
577+ from vllm .v1 .worker .gpu import model_runner as gpu_model_runner_v2
578+ from vllm .v1 .worker .gpu .model_runner import GPUModelRunner
579+
580+ runner = GPUModelRunner .__new__ (GPUModelRunner )
581+ runner .device = torch .device ("cuda:0" )
582+ events = []
583+
584+ get_memory_info_values = iter ([(10_000 , 0 ), (9_950 , 0 )])
585+ monkeypatch .setattr (
586+ gpu_model_runner_v2 .torch .accelerator ,
587+ "synchronize" ,
588+ lambda : events .append ("sync" ),
589+ )
590+ monkeypatch .setattr (
591+ gpu_model_runner_v2 .torch .accelerator ,
592+ "empty_cache" ,
593+ lambda : events .append ("empty_cache" ),
594+ )
595+ monkeypatch .setattr (
596+ gpu_model_runner_v2 .torch .accelerator ,
597+ "get_memory_info" ,
598+ lambda : next (get_memory_info_values ),
599+ )
600+ monkeypatch .setattr (
601+ gpu_model_runner_v2 .torch .accelerator ,
602+ "memory_reserved" ,
603+ lambda device : 1_000 ,
604+ )
605+ monkeypatch .setattr (
606+ gpu_model_runner_v2 .torch .accelerator ,
607+ "memory_allocated" ,
608+ lambda device : 500 ,
609+ )
610+ monkeypatch .setattr (
611+ gpu_model_runner_v2 .torch .accelerator ,
612+ "reset_peak_memory_stats" ,
613+ lambda device : events .append ("reset_peak" ),
614+ )
615+ monkeypatch .setattr (
616+ gpu_model_runner_v2 .torch .accelerator ,
617+ "max_memory_reserved" ,
618+ lambda device : 1_120 ,
619+ )
620+ monkeypatch .setattr (
621+ gpu_model_runner_v2 .torch .accelerator ,
622+ "max_memory_allocated" ,
623+ lambda device : 530 ,
624+ )
625+
626+ assert (
627+ runner ._measure_cuda_graph_pool_sample (lambda : events .append ("capture" )) == 120
628+ )
629+ assert events == [
630+ "sync" ,
631+ "empty_cache" ,
632+ "reset_peak" ,
633+ "capture" ,
634+ "sync" ,
635+ ]
636+
637+
638+ def test_v2_graph_pool_profile_restores_capture_state (monkeypatch ):
639+ from vllm .v1 .worker .gpu import model_runner as gpu_model_runner_v2
640+ from vllm .v1 .worker .gpu .cudagraph_utils import BatchExecutionDescriptor
641+ from vllm .v1 .worker .gpu .model_runner import CUDAGraphMode , GPUModelRunner
642+
643+ piecewise_descs = [
644+ BatchExecutionDescriptor (CUDAGraphMode .PIECEWISE , 128 , None ),
645+ BatchExecutionDescriptor (CUDAGraphMode .PIECEWISE , 64 , None ),
646+ BatchExecutionDescriptor (CUDAGraphMode .PIECEWISE , 32 , None ),
647+ ]
648+ full_descs = [
649+ BatchExecutionDescriptor (CUDAGraphMode .FULL , 80 , 4 ),
650+ BatchExecutionDescriptor (CUDAGraphMode .FULL , 40 , 2 ),
651+ ]
652+ original_graph = object ()
653+ original_breakable_entry = object ()
654+ breakable_runner = SimpleNamespace (
655+ graph_pool = "breakable-original" ,
656+ entries = {"old" : original_breakable_entry },
657+ )
658+
659+ class FakeCudaGraphManager :
660+ def __init__ (self ):
661+ self .pool = "manager-original"
662+ self .graphs = {"old" : original_graph }
663+ self ._graphs_captured = False
664+ self .hidden_states = "hidden-original"
665+ self .aux_hidden_states = ["aux-original" ]
666+ self .intermediate_tensors = "intermediate-original"
667+ self .use_aux_hidden_state_outputs = False
668+ self .use_breakable_cg = True
669+ self .breakable_cg_runner = breakable_runner
670+
671+ def get_capture_descs (self ):
672+ return [
673+ (CUDAGraphMode .PIECEWISE , piecewise_descs ),
674+ (CUDAGraphMode .FULL , full_descs ),
675+ ]
676+
677+ def init_breakable_cg_runner (self , model ):
678+ assert model == "model"
679+
680+ runner = GPUModelRunner .__new__ (GPUModelRunner )
681+ runner .model = "model"
682+ runner .cudagraph_manager = FakeCudaGraphManager ()
683+ sample_values = iter ([1_000 , 2_000_000 , 800 , 3_000_000 ])
684+ capture_calls = []
685+
686+ monkeypatch .setattr (
687+ gpu_model_runner_v2 .current_platform ,
688+ "graph_pool_handle" ,
689+ lambda : "profile-pool" ,
690+ )
691+ empty_cache_calls = []
692+ monkeypatch .setattr (
693+ gpu_model_runner_v2 .torch .accelerator ,
694+ "empty_cache" ,
695+ lambda : empty_cache_calls .append ("empty_cache" ),
696+ )
697+ monkeypatch .setattr (
698+ gpu_model_runner_v2 .compilation_counter ,
699+ "num_cudagraph_captured" ,
700+ 11 ,
701+ )
702+ monkeypatch .setattr (
703+ runner ,
704+ "_measure_cuda_graph_pool_sample" ,
705+ lambda capture_fn : capture_fn () or next (sample_values ),
706+ )
707+
708+ def capture_model_cudagraphs (** kwargs ):
709+ capture_calls .append (kwargs )
710+ assert kwargs ["capture_speculator" ] is False
711+ assert runner .cudagraph_manager .pool == "profile-pool"
712+ assert breakable_runner .graph_pool == "profile-pool"
713+ runner .cudagraph_manager .graphs ["profile" ] = object ()
714+ runner .cudagraph_manager ._graphs_captured = True
715+ runner .cudagraph_manager .hidden_states = "hidden-profile"
716+ runner .cudagraph_manager .aux_hidden_states = ["aux-profile" ]
717+ runner .cudagraph_manager .intermediate_tensors = "intermediate-profile"
718+ runner .cudagraph_manager .use_aux_hidden_state_outputs = True
719+ breakable_runner .entries ["profile" ] = object ()
720+ gpu_model_runner_v2 .compilation_counter .num_cudagraph_captured = 99
721+
722+ monkeypatch .setattr (
723+ runner ,
724+ "_capture_model_cudagraphs" ,
725+ capture_model_cudagraphs ,
726+ )
727+
728+ estimate = runner ._profile_cudagraph_memory_graph_pool ()
729+
730+ assert estimate == 7_001_000
731+ assert [call ["capture_descs" ] for call in capture_calls ] == [
732+ {CUDAGraphMode .PIECEWISE : [piecewise_descs [0 ]]},
733+ {CUDAGraphMode .PIECEWISE : [piecewise_descs [1 ]]},
734+ {CUDAGraphMode .FULL : [full_descs [0 ]]},
735+ {CUDAGraphMode .FULL : [full_descs [1 ]]},
736+ ]
737+ assert runner .cudagraph_manager .pool == "manager-original"
738+ assert runner .cudagraph_manager .graphs == {"old" : original_graph }
739+ assert runner .cudagraph_manager ._graphs_captured is False
740+ assert runner .cudagraph_manager .hidden_states == "hidden-original"
741+ assert runner .cudagraph_manager .aux_hidden_states == ["aux-original" ]
742+ assert runner .cudagraph_manager .intermediate_tensors == "intermediate-original"
743+ assert runner .cudagraph_manager .use_aux_hidden_state_outputs is False
744+ assert breakable_runner .graph_pool == "breakable-original"
745+ assert breakable_runner .entries == {"old" : original_breakable_entry }
746+ assert gpu_model_runner_v2 .compilation_counter .num_cudagraph_captured == 11
747+ assert empty_cache_calls == ["empty_cache" ]
545748
546749
547750def test_v2_cleanup_profiling_kv_cache_releases_builder_refs (monkeypatch ):
0 commit comments