class_docstr: Greedy Partitioner
  
  Args:
      sort_by (SortBy): Sort sharding options by storage or perf in
          descending order (i.e., large tables will be placed first).
      balance_modules (bool): Whether to sort by modules first, where
          smaller modules will be sorted first. In effect, this will place
          tables in each module in a balanced way.
code: def _uniform_partition(
      sharding_options: List[ShardingOption],
      devices: List[DeviceHardware],
  ) -> None:
      for sharding_option in sharding_options:
          if sharding_option.num_shards != len(devices):
              raise RuntimeError(
                  f"For a uniform partition, the number of shards ({sharding_option.num_shards}) must equal the number of devices ({len(devices)})"
              )
          for i in range(len(devices)):
              storage_needed = cast(
                  Storage, sharding_option.shards[i].storage
              )
              if not storage_needed.fits_in(devices[i].storage):
                  raise PlannerError(
                      error_type=PlannerErrorType.PARTITION,
                      message=f"Shard of size {storage_needed} bytes does not fit on any rank. Device memory cap: {devices[i].storage}.",
                  )
              else:
                  sharding_option.shards[i].rank = devices[i].rank
                  devices[i].storage -= storage_needed
                  devices[i].perf += cast(
                      Perf, sharding_option.shards[i].perf
                  )
  
imports: import copy
  import heapq
  import logging
  from dataclasses import dataclass
  from enum import Enum
  from typing import cast, Dict, List, Optional
  from torchrec.distributed.planner.perf_models import NoopPerfModel
  from torchrec.distributed.planner.types import DeviceHardware, PartitionByType, Partitioner, Perf, PerfModel, PlannerError, PlannerErrorType, ShardingOption, Storage, Topology
  from torchrec.distributed.planner.utils import bytes_to_gb, reset_shard_rank
  from torchrec.distributed.types import ShardingType
label_desc: Use image node_id 7 for calling the GreedyPerfPartitioner obj's underlying member method code with example usage: obj._uniform_partition(sharding_options, devices) without return types