bench.rs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. use std::{
  2. env, fs,
  3. path::{Path, PathBuf},
  4. process::{Command, ExitStatus},
  5. };
  6. use clap::Args;
  7. use crate::utils::cargo;
  8. #[derive(Debug, Args, Clone)]
  9. pub struct BenchArg {
  10. /// Package Prototyper and bench kernel into a single image
  11. #[clap(
  12. long,
  13. help = "Create a combined image with Prototyper and bench kernel"
  14. )]
  15. pub pack: bool,
  16. }
  17. const ARCH: &str = "riscv64imac-unknown-none-elf";
  18. const BENCH_KERNEL_NAME: &str = "rustsbi-bench-kernel";
  19. const PROTOTYPER_BIN: &str = "rustsbi-prototyper.bin";
  20. #[must_use]
  21. pub fn run(arg: &BenchArg) -> Option<ExitStatus> {
  22. let current_dir = env::current_dir().ok()?;
  23. let target_dir = get_target_dir(&current_dir);
  24. // Build the bench kernel
  25. info!("Building bench kernel");
  26. let build_status = build_bench_kernel()?;
  27. if !build_status.success() {
  28. error!("Failed to build bench kernel");
  29. return Some(build_status);
  30. }
  31. // Convert to binary format
  32. info!("Converting to binary format");
  33. let exit_status = convert_to_binary(&target_dir)?;
  34. if !exit_status.success() {
  35. error!("Failed to convert bench kernel to binary format");
  36. return Some(exit_status);
  37. }
  38. // Pack into image if requested
  39. if arg.pack {
  40. info!("Packing into image");
  41. match pack_image(&current_dir, &target_dir) {
  42. Ok(status) => {
  43. info!(
  44. "Output image created at: {}",
  45. target_dir
  46. .join(format!("{}.itb", BENCH_KERNEL_NAME))
  47. .display()
  48. );
  49. return Some(status);
  50. }
  51. Err(err_msg) => {
  52. error!("{}", err_msg);
  53. return Some(<ExitStatus as std::os::unix::process::ExitStatusExt>::from_raw(1));
  54. }
  55. }
  56. } else {
  57. info!(
  58. "Output binary created at: {}",
  59. target_dir
  60. .join(format!("{}.bin", BENCH_KERNEL_NAME))
  61. .display()
  62. );
  63. }
  64. Some(exit_status)
  65. }
  66. fn get_target_dir(current_dir: &Path) -> PathBuf {
  67. current_dir.join("target").join(ARCH).join("release")
  68. }
  69. fn build_bench_kernel() -> Option<ExitStatus> {
  70. cargo::Cargo::new("build")
  71. .package(BENCH_KERNEL_NAME)
  72. .target(ARCH)
  73. .release()
  74. .status()
  75. .ok()
  76. }
  77. fn convert_to_binary(target_dir: &Path) -> Option<ExitStatus> {
  78. let kernel_path = target_dir.join(BENCH_KERNEL_NAME);
  79. let bin_path = target_dir.join(format!("{}.bin", BENCH_KERNEL_NAME));
  80. Command::new("rust-objcopy")
  81. .args([
  82. "-O",
  83. "binary",
  84. "--binary-architecture=riscv64",
  85. &kernel_path.to_string_lossy(),
  86. &bin_path.to_string_lossy(),
  87. ])
  88. .status()
  89. .ok()
  90. }
  91. fn pack_image(current_dir: &Path, target_dir: &Path) -> Result<ExitStatus, String> {
  92. // Check if prototyper binary exists
  93. let prototyper_bin_path = target_dir.join(PROTOTYPER_BIN);
  94. if !prototyper_bin_path.exists() {
  95. return Err(format!(
  96. "Error: Prototyper binary not found at '{}'\n\
  97. Please run 'cargo prototyper' first to build the Prototyper binary.",
  98. prototyper_bin_path.display()
  99. ));
  100. }
  101. // Copy ITS file
  102. let its_source = current_dir
  103. .join("prototyper")
  104. .join("bench-kernel")
  105. .join("scripts")
  106. .join(format!("{}.its", BENCH_KERNEL_NAME));
  107. let its_dest = target_dir.join(format!("{}.its", BENCH_KERNEL_NAME));
  108. fs::copy(&its_source, &its_dest).map_err(|e| format!("Failed to copy ITS file: {}", e))?;
  109. // Change to target directory
  110. let original_dir =
  111. env::current_dir().map_err(|e| format!("Failed to get current directory: {}", e))?;
  112. env::set_current_dir(target_dir)
  113. .map_err(|e| format!("Failed to change directory to target: {}", e))?;
  114. // Create image
  115. let status = Command::new("mkimage")
  116. .args([
  117. "-f",
  118. &format!("{}.its", BENCH_KERNEL_NAME),
  119. &format!("{}.itb", BENCH_KERNEL_NAME),
  120. ])
  121. .status()
  122. .map_err(|e| format!("Failed to execute mkimage command: {}", e))?;
  123. // Clean up
  124. fs::remove_file(format!("{}.its", BENCH_KERNEL_NAME))
  125. .map_err(|e| format!("Failed to clean up ITS file: {}", e))?;
  126. // Restore original directory
  127. env::set_current_dir(original_dir)
  128. .map_err(|e| format!("Failed to restore original directory: {}", e))?;
  129. Ok(status)
  130. }