# ----------------------------------------------------------------------------
# Copyright (c) 2021-2026 DexForce Technology Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ----------------------------------------------------------------------------
"""Unified benchmark CLI.
Usage examples::
embodichain benchmark rl --tasks push_cube --algorithms ppo --suite default
embodichain benchmark rl --rebuild-report-only
embodichain benchmark robotics-kinematic-solver -s pytorch
embodichain benchmark motion-generation --suite motion_panda_free_space_smoke
embodichain benchmark motion-generation --suite atomic_franka_pgi_smoke
embodichain benchmark atomic-action-profile --smoke
embodichain benchmark grasp-pose-generator --device cuda
embodichain benchmark workspace-analyzer
embodichain benchmark rendering --camera-count 2 --resolution 1280x720
"""
from __future__ import annotations
import argparse
import sys
from collections.abc import Sequence
def _run_robotics_kinematic_solver_cli(args: argparse.Namespace) -> None:
"""Run robotics kinematic solver benchmark with forwarded CLI args."""
from scripts.benchmark.robotics.kinematic_solver.run_benchmark import (
run_all_benchmarks,
)
run_all_benchmarks(selected_solvers=args.solvers)
def _run_rl_cli(_: argparse.Namespace) -> None:
"""Run RL benchmark CLI entrypoint."""
from scripts.benchmark.rl.run_benchmark import main as rl_main
rl_main()
def _run_motion_generation_cli(args: argparse.Namespace) -> None:
"""Run the shared Motion Planning and Atomic Skills benchmark."""
from embodichain_benchmarks.motion_generation.cli import run_from_args
run_from_args(args)
def _run_atomic_action_profile_cli(_: argparse.Namespace) -> None:
"""Run individual atomic action profiling over preset scenes."""
from scripts.benchmark.atomic_action.run_benchmark import main as atomic_main
atomic_main()
def _run_grasp_pose_generator_cli(_: argparse.Namespace) -> None:
"""Run grasp pose generator benchmark CLI entrypoint."""
from scripts.benchmark.grasp_pose_generator.run_benchmark import main
main()
def _run_workspace_analyzer_cli(_: argparse.Namespace) -> None:
"""Run workspace analyzer benchmarks."""
from scripts.benchmark.workspace_analyzer.benchmark_workspace_analyzer import (
run_all_benchmarks,
)
run_all_benchmarks()
def _run_rendering_cli(_: argparse.Namespace) -> None:
"""Run the configurable rendering benchmark entrypoint."""
from scripts.benchmark.rendering.offscreen_denoising import main as rendering_main
rendering_main()
[docs]
def main(argv: Sequence[str] | None = None) -> None:
"""Dispatch to the appropriate benchmark sub-command CLI."""
arguments = list(sys.argv[1:] if argv is None else argv)
parser = argparse.ArgumentParser(
prog="embodichain benchmark",
description="EmbodiChain benchmark command-line interface.",
)
subparsers = parser.add_subparsers(dest="command")
# -- rl ------------------------------------------------------------------
rl_parser = subparsers.add_parser(
"rl",
add_help=False,
help="Run RL benchmark: train, evaluate, aggregate, and report results.",
)
rl_parser.set_defaults(func=_run_rl_cli)
# -- robotics-kinematic-solver -------------------------------------------
robotics_ks_parser = subparsers.add_parser(
"robotics-kinematic-solver",
help="Benchmark the OPW kinematic solver (FK/IK accuracy and speed).",
)
robotics_ks_parser.add_argument(
"--solvers",
"-s",
nargs="+",
choices=("opw", "pytorch", "all"),
default=["all"],
help="Solvers to benchmark. Use one or more of: opw, pytorch, all.",
)
robotics_ks_parser.set_defaults(func=_run_robotics_kinematic_solver_cli)
# -- motion-generation ---------------------------------------------------
motion_generation_parser = subparsers.add_parser(
"motion-generation",
help="Compare planners with Motion Planning or Atomic Skills suites.",
description=(
"Compare planners with Motion Planning or Atomic Skills suites. "
"Use --suite to select the cases and robot."
),
)
if arguments and arguments[0] == "motion-generation":
from embodichain_benchmarks.motion_generation.cli import add_parser_arguments
add_parser_arguments(motion_generation_parser)
motion_generation_parser.set_defaults(func=_run_motion_generation_cli)
# -- atomic-action-profile -----------------------------------------------
atomic_action_profile_parser = subparsers.add_parser(
"atomic-action-profile",
add_help=False,
help="Profile individual atomic actions over object presets and positions.",
)
atomic_action_profile_parser.set_defaults(func=_run_atomic_action_profile_cli)
# -- grasp-pose-generator -----------------------------------------------
grasp_pose_parser = subparsers.add_parser(
"grasp-pose-generator",
add_help=False,
help="Benchmark grasp sampling and pose selection.",
)
grasp_pose_parser.set_defaults(func=_run_grasp_pose_generator_cli)
# -- workspace-analyzer -------------------------------------------------
workspace_parser = subparsers.add_parser(
"workspace-analyzer",
help="Benchmark workspace analysis operations.",
)
workspace_parser.set_defaults(func=_run_workspace_analyzer_cli)
# -- rendering -----------------------------------------------------------
rendering_parser = subparsers.add_parser(
"rendering",
add_help=False,
help="Benchmark configurable offscreen rendering and denoising.",
)
rendering_parser.set_defaults(func=_run_rendering_cli)
# -- Parse ---------------------------------------------------------------
# If no sub-command is given, print help and exit.
if not arguments or arguments[0] in ("-h", "--help"):
parser.print_help()
return
# Determine which sub-command was selected, then reconstruct argv so
# that each sub-command's entry point can call ``parse_args()`` normally.
delegated_commands = {
"rl",
"atomic-action-profile",
"grasp-pose-generator",
"rendering",
}
if arguments[0] in delegated_commands:
known, _ = parser.parse_known_args(arguments)
else:
known = parser.parse_args(arguments)
if hasattr(known, "func"):
# Rewrite sys.argv so the sub-command's argparse sees only its own args.
subcommand_argv = [
f"embodichain benchmark {arguments[0]}",
*arguments[1:],
]
original_argv = sys.argv
sys.argv = subcommand_argv
try:
known.func(known)
finally:
sys.argv = original_argv
else:
parser.print_help()
sys.exit(1)
if __name__ == "__main__":
main()
__all__ = ["main"]