@@ -455,36 +455,37 @@ def _export_kineto_trace(
455455 logging .info (f"backward: fbgemm { time * 1e3 :.3f} ms{ ref_str } " )
456456
457457
458- def _gen_group_inputs (
459- row_size : int ,
460- batch_size : int ,
461- unique_batch_size : int ,
458+ def _gen_group_inputs_uniform (
459+ num_cols : int ,
460+ num_rows : int ,
461+ num_indices : int ,
462+ num_unique_indices : int ,
462463 num_groups : int ,
463464 dtype : torch .dtype ,
464465 sort_indices : bool ,
465466 device : str ,
466467) -> tuple [list [torch .Tensor ], list [torch .Tensor ]]:
467468 """Generate homogeneous synthetic inputs for group_index_select_2d_bench.
468469
469- Every group shares the same shape: a ``(batch_size, row_size )`` slice of a
470- single ``(num_groups * batch_size, row_size )`` tensor, with ``batch_size ``
471- indices drawn from ``unique_batch_size `` distinct rows. Used by
470+ Every group shares the same shape: a ``(num_rows, num_cols )`` slice of a
471+ single ``(num_groups * num_rows, num_cols )`` tensor, with ``num_indices ``
472+ indices drawn from ``num_unique_indices `` distinct rows. Used by
472473 ``group-index-select-2d-bench`` when ``--input-dims`` is NOT provided.
473474 """
474475
475- def gen_inverse_index (curr_size : int , final_size : int ) -> np .ndarray :
476- inverse_index = list (range (curr_size ))
476+ def gen_inverse_index (num_unique : int , num_indices : int ) -> np .ndarray :
477+ inverse_index = list (range (num_unique ))
477478 np_arr = np .array (inverse_index )
478- for _ in range (final_size - curr_size ):
479- inverse_index .append (np .random .randint (0 , curr_size ))
479+ for _ in range (num_indices - num_unique ):
480+ inverse_index .append (np .random .randint (0 , num_unique ))
480481 np_arr = np .array (inverse_index )
481482 np .random .shuffle (np_arr )
482483 return np_arr
483484
484485 indices_group = []
485486 for _ in range (num_groups ):
486487 indices = torch .tensor (
487- gen_inverse_index (unique_batch_size , batch_size ),
488+ gen_inverse_index (num_unique_indices , num_indices ),
488489 dtype = torch .int32 ,
489490 device = device ,
490491 )
@@ -493,28 +494,28 @@ def gen_inverse_index(curr_size: int, final_size: int) -> np.ndarray:
493494 indices_group .append (indices )
494495
495496 input = torch .rand (
496- num_groups * batch_size ,
497- row_size ,
497+ num_groups * num_rows ,
498+ num_cols ,
498499 dtype = dtype ,
499500 device = device ,
500501 )
501502 input .requires_grad = True
502- input_group = list (input .split (batch_size , 0 ))
503+ input_group = list (input .split (num_rows , 0 ))
503504 return input_group , indices_group
504505
505506
506- def _gen_group_inputs_with_spec (
507+ def _gen_group_inputs_jagged (
507508 input_dims : str ,
508509 input_strides : str | None ,
509- index_dim : int ,
510+ num_indices : int ,
510511 dtype : torch .dtype ,
511512 sort_indices : bool ,
512513 device : str ,
513514) -> tuple [list [torch .Tensor ], list [torch .Tensor ]]:
514- """Generate ragged inputs from explicit per-group shapes.
515+ """Generate jagged inputs from explicit per-group shapes.
515516
516- Each group gets its own ``[num_rows, row_size ]`` tensor (groups may differ
517- in both row count and column width) with ``index_dim `` indices each, matching
517+ Each group gets its own ``[num_rows, num_cols ]`` tensor (groups may differ
518+ in both row count and column width) with ``num_indices `` indices each, matching
518519 real-world / production shapes. Used by ``group-index-select-2d-bench`` when
519520 ``--input-dims`` is provided; ``--input-strides`` is optional and defaults to
520521 contiguous strides per group.
@@ -523,7 +524,7 @@ def _gen_group_inputs_with_spec(
523524 if input_strides is not None and input_strides .strip () != "" :
524525 strides = json .loads (input_strides )
525526 else :
526- strides = [[rs , 1 ] for (_ , rs ) in dims ]
527+ strides = [[num_cols , 1 ] for (_ , num_cols ) in dims ]
527528 if len (strides ) != len (dims ):
528529 raise ValueError (
529530 f"--input-strides length ({ len (strides )} ) must match "
@@ -541,7 +542,7 @@ def _gen_group_inputs_with_spec(
541542 idx = torch .randint (
542543 low = 0 ,
543544 high = dim [0 ],
544- size = (index_dim ,),
545+ size = (num_indices ,),
545546 dtype = torch .int32 ,
546547 device = device ,
547548 )
@@ -553,12 +554,12 @@ def _gen_group_inputs_with_spec(
553554
554555
555556@cli .command ()
556- @click .option ("--row-size " , default = 512 )
557- @click .option ("--batch-size " , default = 4096 )
558- @click .option ("--unique-batch-size " , default = 1024 )
557+ @click .option ("--num-cols " , type = int , default = None )
558+ @click .option ("--num-rows " , type = int , default = None )
559+ @click .option ("--num- unique-indices " , type = int , default = None )
559560@click .option ("--input-precision" , type = str , default = "fp32" )
560561@click .option ("--sort-indices" , type = bool , default = True )
561- @click .option ("--num-groups" , default = 32 )
562+ @click .option ("--num-groups" , type = int , default = None )
562563@click .option (
563564 "--device" ,
564565 type = str ,
@@ -580,8 +581,8 @@ def _gen_group_inputs_with_spec(
580581 "--input-dims" ,
581582 type = str ,
582583 default = None ,
583- help = "JSON list of [num_rows, row_size ] per group, e.g. '[[27330,96],[4914,96]]'. "
584- "When provided, --row-size , --batch-size , --unique-batch-size , and --num-groups are ignored." ,
584+ help = "JSON list of [num_rows, num_cols ] per group, e.g. '[[27330,96],[4914,96]]'. "
585+ "When provided, --num-cols , --num-rows , --num- unique-indices , and --num-groups are ignored." ,
585586)
586587@click .option (
587588 "--input-strides" ,
@@ -590,35 +591,31 @@ def _gen_group_inputs_with_spec(
590591 help = "JSON list of [stride0, stride1] per group. Defaults to contiguous strides if not provided." ,
591592)
592593@click .option (
593- "--index-dim" , type = int , default = None , help = "Number of indices per group."
594+ "--num-indices" ,
595+ type = int ,
596+ default = None ,
597+ help = "Number of indices per group (= output rows / effective batch L)." ,
594598)
595599@click .option (
596600 "--manual-seed/--skip-manual-seed" ,
597601 default = True ,
598602 help = "Use manual seed for reproduction." ,
599603)
600604def group_index_select_2d_bench (
601- row_size : int ,
602- batch_size : int ,
603- unique_batch_size : int ,
605+ num_cols : int | None ,
606+ num_rows : int | None ,
607+ num_unique_indices : int | None ,
604608 input_precision : str ,
605609 sort_indices : bool ,
606- num_groups : int ,
610+ num_groups : int | None ,
607611 device : str ,
608612 export_trace : bool ,
609613 trace_url : str ,
610614 input_dims : str | None ,
611615 input_strides : str | None ,
612- index_dim : int | None ,
616+ num_indices : int | None ,
613617 manual_seed : bool ,
614618) -> None :
615- # Input validation (backported from tritonbench implementation)
616- if unique_batch_size > batch_size :
617- raise ValueError (
618- f"unique_batch_size ({ unique_batch_size } ) must be <= batch_size "
619- f"({ batch_size } )"
620- )
621-
622619 # set manual seed for reproducibility
623620 if manual_seed :
624621 torch .manual_seed (42 )
@@ -632,34 +629,56 @@ def group_index_select_2d_bench(
632629 else :
633630 raise RuntimeError (f"Does not support data type { input_precision } " )
634631
635- bench_kwargs = {"num_warmups" : 10 , "iters" : 100 }
636-
637- def _kineto_trace_handler (p : profile , phase : str ) -> None :
638- p .export_chrome_trace (trace_url .format (phase = phase , ospid = os .getpid ()))
639-
640- # pyre-ignore[3]
641- def context_factory (on_trace_ready : Callable [[profile ], None ]):
642- return profile (on_trace_ready = on_trace_ready ) if export_trace else nullcontext ()
643-
644- # An empty/whitespace --input-dims is treated as NOT provided, so it falls
645- # back to the synthetic path. Checking input_dims directly (rather than via a
646- # bool) lets the type checker narrow it to a non-None str inside the branch.
632+ # Two mutually-exclusive shape-specification modes:
633+ # uniform (synthetic): --num-groups + --num-rows + --num-cols
634+ # jagged (prod/real): --input-dims + --input-strides
635+ # --num-indices / --num-unique-indices / --input-precision / --sort-indices
636+ # apply to both. The uniform scalar flags default to None so we can detect
637+ # which mode the user selected and reject mixing the two. Checking input_dims
638+ # directly (rather than via a bool) lets the type checker narrow it.
647639 if input_dims is not None and input_dims .strip () != "" :
648- if index_dim is None :
649- raise ValueError ("--index-dim is required when --input-dims is provided" )
650- input_group , indices_group = _gen_group_inputs_with_spec (
651- input_dims , input_strides , index_dim , dtype , sort_indices , device
640+ for name , val in [
641+ ("--num-groups" , num_groups ),
642+ ("--num-rows" , num_rows ),
643+ ("--num-cols" , num_cols ),
644+ ("--num-unique-indices" , num_unique_indices ),
645+ ]:
646+ if val is not None :
647+ raise ValueError (
648+ f"{ name } cannot be combined with --input-dims (jagged mode)"
649+ )
650+ if num_indices is None :
651+ raise ValueError (
652+ "--num-indices is required with --input-dims (jagged mode)"
653+ )
654+ input_group , indices_group = _gen_group_inputs_jagged (
655+ input_dims , input_strides , num_indices , dtype , sort_indices , device
652656 )
653657 logging .info (
654- f"ragged : { len (input_group )} groups, "
658+ f"jagged : { len (input_group )} groups, "
655659 f"cols={ [t .shape [1 ] for t in input_group ]} , "
656- f"index_dim= { index_dim } , sort_indices={ sort_indices } "
660+ f"num_indices= { num_indices } , sort_indices={ sort_indices } "
657661 )
658662 else :
659- input_group , indices_group = _gen_group_inputs (
660- row_size ,
661- batch_size ,
662- unique_batch_size ,
663+ if input_strides is not None and input_strides .strip () != "" :
664+ raise ValueError ("--input-strides requires --input-dims (jagged mode)" )
665+ # Apply uniform-mode effective defaults (preserve today's numbers).
666+ num_groups = 32 if num_groups is None else num_groups
667+ num_rows = 4096 if num_rows is None else num_rows
668+ num_cols = 512 if num_cols is None else num_cols
669+ num_unique_indices = 1024 if num_unique_indices is None else num_unique_indices
670+ # Decoupled default: indices count falls back to the row count.
671+ num_indices = num_rows if num_indices is None else num_indices
672+ if num_unique_indices > min (num_rows , num_indices ):
673+ raise ValueError (
674+ f"num_unique_indices ({ num_unique_indices } ) must be <= "
675+ f"min(num_rows={ num_rows } , num_indices={ num_indices } )"
676+ )
677+ input_group , indices_group = _gen_group_inputs_uniform (
678+ num_cols ,
679+ num_rows ,
680+ num_indices ,
681+ num_unique_indices ,
663682 num_groups ,
664683 dtype ,
665684 sort_indices ,
@@ -670,9 +689,18 @@ def context_factory(on_trace_ready: Callable[[profile], None]):
670689 # reference fwd/bwd below to compare torch.index_select vs fbgemm.
671690 # input = torch.cat(input_group, dim=0)
672691 # offset_indices = torch.cat(
673- # [idx + batch_size * i for i, idx in enumerate(indices_group)]
692+ # [idx + num_rows * i for i, idx in enumerate(indices_group)]
674693 # )
675- # num_bytes = 2 * batch_size * row_size * input.element_size() * num_groups
694+ # num_bytes = 2 * num_rows * num_cols * input.element_size() * num_groups
695+
696+ bench_kwargs = {"num_warmups" : 10 , "iters" : 100 }
697+
698+ def _kineto_trace_handler (p : profile , phase : str ) -> None :
699+ p .export_chrome_trace (trace_url .format (phase = phase , ospid = os .getpid ()))
700+
701+ # pyre-ignore[3]
702+ def context_factory (on_trace_ready : Callable [[profile ], None ]):
703+ return profile (on_trace_ready = on_trace_ready ) if export_trace else nullcontext ()
676704
677705 # Benchmark forward
678706 with context_factory (lambda p : _kineto_trace_handler (p , "fwd" )):
0 commit comments