main.go 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // Package main provides a test client for the RDMA engine integration
  2. package main
  3. import (
  4. "context"
  5. "fmt"
  6. "os"
  7. "time"
  8. "seaweedfs-rdma-sidecar/pkg/rdma"
  9. "github.com/sirupsen/logrus"
  10. "github.com/spf13/cobra"
  11. )
  12. var (
  13. socketPath string
  14. debug bool
  15. timeout time.Duration
  16. volumeID uint32
  17. needleID uint64
  18. cookie uint32
  19. offset uint64
  20. size uint64
  21. )
  22. func main() {
  23. var rootCmd = &cobra.Command{
  24. Use: "test-rdma",
  25. Short: "Test client for SeaweedFS RDMA engine integration",
  26. Long: `Test client that demonstrates communication between Go sidecar and Rust RDMA engine.
  27. This tool allows you to test various RDMA operations including:
  28. - Engine connectivity and capabilities
  29. - RDMA read operations with mock data
  30. - Performance measurements
  31. - IPC protocol validation`,
  32. }
  33. // Global flags
  34. defaultSocketPath := os.Getenv("RDMA_SOCKET_PATH")
  35. if defaultSocketPath == "" {
  36. defaultSocketPath = "/tmp/rdma-engine.sock"
  37. }
  38. rootCmd.PersistentFlags().StringVarP(&socketPath, "socket", "s", defaultSocketPath, "Path to RDMA engine Unix socket (env: RDMA_SOCKET_PATH)")
  39. rootCmd.PersistentFlags().BoolVarP(&debug, "debug", "d", false, "Enable debug logging")
  40. rootCmd.PersistentFlags().DurationVarP(&timeout, "timeout", "t", 30*time.Second, "Operation timeout")
  41. // Subcommands
  42. rootCmd.AddCommand(pingCmd())
  43. rootCmd.AddCommand(capsCmd())
  44. rootCmd.AddCommand(readCmd())
  45. rootCmd.AddCommand(benchCmd())
  46. if err := rootCmd.Execute(); err != nil {
  47. fmt.Fprintf(os.Stderr, "Error: %v\n", err)
  48. os.Exit(1)
  49. }
  50. }
  51. func pingCmd() *cobra.Command {
  52. return &cobra.Command{
  53. Use: "ping",
  54. Short: "Test connectivity to RDMA engine",
  55. Long: "Send a ping message to the RDMA engine and measure latency",
  56. RunE: func(cmd *cobra.Command, args []string) error {
  57. client := createClient()
  58. defer client.Disconnect()
  59. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  60. defer cancel()
  61. fmt.Printf("🏓 Pinging RDMA engine at %s...\n", socketPath)
  62. if err := client.Connect(ctx); err != nil {
  63. return fmt.Errorf("failed to connect: %w", err)
  64. }
  65. latency, err := client.Ping(ctx)
  66. if err != nil {
  67. return fmt.Errorf("ping failed: %w", err)
  68. }
  69. fmt.Printf("✅ Ping successful! Latency: %v\n", latency)
  70. return nil
  71. },
  72. }
  73. }
  74. func capsCmd() *cobra.Command {
  75. return &cobra.Command{
  76. Use: "capabilities",
  77. Short: "Get RDMA engine capabilities",
  78. Long: "Query the RDMA engine for its current capabilities and status",
  79. RunE: func(cmd *cobra.Command, args []string) error {
  80. client := createClient()
  81. defer client.Disconnect()
  82. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  83. defer cancel()
  84. fmt.Printf("🔍 Querying RDMA engine capabilities...\n")
  85. if err := client.Connect(ctx); err != nil {
  86. return fmt.Errorf("failed to connect: %w", err)
  87. }
  88. caps := client.GetCapabilities()
  89. if caps == nil {
  90. return fmt.Errorf("no capabilities received")
  91. }
  92. fmt.Printf("\n📊 RDMA Engine Capabilities:\n")
  93. fmt.Printf(" Version: %s\n", caps.Version)
  94. fmt.Printf(" Max Sessions: %d\n", caps.MaxSessions)
  95. fmt.Printf(" Max Transfer Size: %d bytes (%.1f MB)\n", caps.MaxTransferSize, float64(caps.MaxTransferSize)/(1024*1024))
  96. fmt.Printf(" Active Sessions: %d\n", caps.ActiveSessions)
  97. fmt.Printf(" Real RDMA: %t\n", caps.RealRdma)
  98. fmt.Printf(" Port GID: %s\n", caps.PortGid)
  99. fmt.Printf(" Port LID: %d\n", caps.PortLid)
  100. fmt.Printf(" Supported Auth: %v\n", caps.SupportedAuth)
  101. if caps.RealRdma {
  102. fmt.Printf("🚀 Hardware RDMA enabled!\n")
  103. } else {
  104. fmt.Printf("🟡 Using mock RDMA (development mode)\n")
  105. }
  106. return nil
  107. },
  108. }
  109. }
  110. func readCmd() *cobra.Command {
  111. cmd := &cobra.Command{
  112. Use: "read",
  113. Short: "Test RDMA read operation",
  114. Long: "Perform a test RDMA read operation with specified parameters",
  115. RunE: func(cmd *cobra.Command, args []string) error {
  116. client := createClient()
  117. defer client.Disconnect()
  118. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  119. defer cancel()
  120. fmt.Printf("📖 Testing RDMA read operation...\n")
  121. fmt.Printf(" Volume ID: %d\n", volumeID)
  122. fmt.Printf(" Needle ID: %d\n", needleID)
  123. fmt.Printf(" Cookie: 0x%x\n", cookie)
  124. fmt.Printf(" Offset: %d\n", offset)
  125. fmt.Printf(" Size: %d bytes\n", size)
  126. if err := client.Connect(ctx); err != nil {
  127. return fmt.Errorf("failed to connect: %w", err)
  128. }
  129. start := time.Now()
  130. resp, err := client.ReadRange(ctx, volumeID, needleID, cookie, offset, size)
  131. if err != nil {
  132. return fmt.Errorf("read failed: %w", err)
  133. }
  134. duration := time.Since(start)
  135. fmt.Printf("\n✅ RDMA read completed successfully!\n")
  136. fmt.Printf(" Session ID: %s\n", resp.SessionID)
  137. fmt.Printf(" Bytes Read: %d\n", resp.BytesRead)
  138. fmt.Printf(" Duration: %v\n", duration)
  139. fmt.Printf(" Transfer Rate: %.2f MB/s\n", resp.TransferRate)
  140. fmt.Printf(" Success: %t\n", resp.Success)
  141. fmt.Printf(" Message: %s\n", resp.Message)
  142. // Show first few bytes of data for verification
  143. if len(resp.Data) > 0 {
  144. displayLen := 32
  145. if len(resp.Data) < displayLen {
  146. displayLen = len(resp.Data)
  147. }
  148. fmt.Printf(" Data (first %d bytes): %x\n", displayLen, resp.Data[:displayLen])
  149. }
  150. return nil
  151. },
  152. }
  153. cmd.Flags().Uint32VarP(&volumeID, "volume", "v", 1, "Volume ID")
  154. cmd.Flags().Uint64VarP(&needleID, "needle", "n", 100, "Needle ID")
  155. cmd.Flags().Uint32VarP(&cookie, "cookie", "c", 0x12345678, "Needle cookie")
  156. cmd.Flags().Uint64VarP(&offset, "offset", "o", 0, "Read offset")
  157. cmd.Flags().Uint64VarP(&size, "size", "z", 4096, "Read size in bytes")
  158. return cmd
  159. }
  160. func benchCmd() *cobra.Command {
  161. var (
  162. iterations int
  163. readSize uint64
  164. )
  165. cmd := &cobra.Command{
  166. Use: "bench",
  167. Short: "Benchmark RDMA read performance",
  168. Long: "Run multiple RDMA read operations and measure performance statistics",
  169. RunE: func(cmd *cobra.Command, args []string) error {
  170. client := createClient()
  171. defer client.Disconnect()
  172. ctx, cancel := context.WithTimeout(context.Background(), timeout)
  173. defer cancel()
  174. fmt.Printf("🏁 Starting RDMA read benchmark...\n")
  175. fmt.Printf(" Iterations: %d\n", iterations)
  176. fmt.Printf(" Read Size: %d bytes\n", readSize)
  177. fmt.Printf(" Socket: %s\n", socketPath)
  178. if err := client.Connect(ctx); err != nil {
  179. return fmt.Errorf("failed to connect: %w", err)
  180. }
  181. // Warmup
  182. fmt.Printf("🔥 Warming up...\n")
  183. for i := 0; i < 5; i++ {
  184. _, err := client.ReadRange(ctx, 1, uint64(i+1), 0x12345678, 0, readSize)
  185. if err != nil {
  186. return fmt.Errorf("warmup read %d failed: %w", i+1, err)
  187. }
  188. }
  189. // Benchmark
  190. fmt.Printf("📊 Running benchmark...\n")
  191. var totalDuration time.Duration
  192. var totalBytes uint64
  193. successful := 0
  194. startTime := time.Now()
  195. for i := 0; i < iterations; i++ {
  196. opStart := time.Now()
  197. resp, err := client.ReadRange(ctx, 1, uint64(i+1), 0x12345678, 0, readSize)
  198. opDuration := time.Since(opStart)
  199. if err != nil {
  200. fmt.Printf("❌ Read %d failed: %v\n", i+1, err)
  201. continue
  202. }
  203. totalDuration += opDuration
  204. totalBytes += resp.BytesRead
  205. successful++
  206. if (i+1)%10 == 0 || i == iterations-1 {
  207. fmt.Printf(" Completed %d/%d reads\n", i+1, iterations)
  208. }
  209. }
  210. benchDuration := time.Since(startTime)
  211. // Calculate statistics
  212. avgLatency := totalDuration / time.Duration(successful)
  213. throughputMBps := float64(totalBytes) / benchDuration.Seconds() / (1024 * 1024)
  214. opsPerSec := float64(successful) / benchDuration.Seconds()
  215. fmt.Printf("\n📈 Benchmark Results:\n")
  216. fmt.Printf(" Total Duration: %v\n", benchDuration)
  217. fmt.Printf(" Successful Operations: %d/%d (%.1f%%)\n", successful, iterations, float64(successful)/float64(iterations)*100)
  218. fmt.Printf(" Total Bytes Transferred: %d (%.1f MB)\n", totalBytes, float64(totalBytes)/(1024*1024))
  219. fmt.Printf(" Average Latency: %v\n", avgLatency)
  220. fmt.Printf(" Throughput: %.2f MB/s\n", throughputMBps)
  221. fmt.Printf(" Operations/sec: %.1f\n", opsPerSec)
  222. return nil
  223. },
  224. }
  225. cmd.Flags().IntVarP(&iterations, "iterations", "i", 100, "Number of read operations")
  226. cmd.Flags().Uint64VarP(&readSize, "read-size", "r", 4096, "Size of each read in bytes")
  227. return cmd
  228. }
  229. func createClient() *rdma.Client {
  230. logger := logrus.New()
  231. if debug {
  232. logger.SetLevel(logrus.DebugLevel)
  233. } else {
  234. logger.SetLevel(logrus.InfoLevel)
  235. }
  236. config := &rdma.Config{
  237. EngineSocketPath: socketPath,
  238. DefaultTimeout: timeout,
  239. Logger: logger,
  240. }
  241. return rdma.NewClient(config)
  242. }