package syscheck import ( "context" "crypto/rand" "fmt" "time" "golang.org/x/sys/unix" ) // GetMemorySpace returns total physical memory (RAM) in bytes, excluding swap func GetMemorySpace(ctx context.Context) (int64, error) { var info unix.Sysinfo_t if err := unix.Sysinfo(&info); err != nil { return 0, fmt.Errorf("failed to get memory info: %w", err) } // Total physical RAM (excluding swap) // info.Totalram is in memory unit size (info.Unit) totalMemory := int64(info.Totalram) * int64(info.Unit) return totalMemory, nil } // GetMemorySpeed measures memory read/write speed by allocating and accessing memory // Returns read speed and write speed in bytes per second func GetMemorySpeed(ctx context.Context) (int64, int64, error) { const ( testSize = 512 * 1024 * 1024 // 512MB test size iterations = 5 // Number of iterations for averaging ) // Test write speed writeSpeed, err := measureMemoryWriteSpeed(ctx, testSize, iterations) if err != nil { return 0, 0, fmt.Errorf("failed to measure memory write speed: %w", err) } // Test read speed readSpeed, err := measureMemoryReadSpeed(ctx, testSize, iterations) if err != nil { return 0, 0, fmt.Errorf("failed to measure memory read speed: %w", err) } return readSpeed, writeSpeed, nil } // measureMemoryWriteSpeed measures memory write speed func measureMemoryWriteSpeed(ctx context.Context, size int64, iterations int) (int64, error) { var totalDuration time.Duration for i := 0; i < iterations; i++ { // Check context cancellation select { case <-ctx.Done(): return 0, ctx.Err() default: } // Allocate memory buffer buffer := make([]byte, size) // Generate random data source := make([]byte, 1024*1024) // 1MB source buffer if _, err := rand.Read(source); err != nil { return 0, fmt.Errorf("failed to generate random data: %w", err) } // Start timing startTime := time.Now() // Write data to memory buffer for offset := int64(0); offset < size; offset += int64(len(source)) { remaining := size - offset if remaining < int64(len(source)) { copy(buffer[offset:], source[:remaining]) } else { copy(buffer[offset:offset+int64(len(source))], source) } } // Stop timing duration := time.Since(startTime) totalDuration += duration // Force the buffer to be used to prevent optimization _ = buffer[0] } // Calculate average speed avgDuration := totalDuration / time.Duration(iterations) speed := int64(float64(size) / avgDuration.Seconds()) return speed, nil } // measureMemoryReadSpeed measures memory read speed func measureMemoryReadSpeed(ctx context.Context, size int64, iterations int) (int64, error) { var totalDuration time.Duration // Pre-allocate and fill buffer buffer := make([]byte, size) if _, err := rand.Read(buffer); err != nil { return 0, fmt.Errorf("failed to initialize buffer: %w", err) } for i := 0; i < iterations; i++ { // Check context cancellation select { case <-ctx.Done(): return 0, ctx.Err() default: } // Start timing startTime := time.Now() // Read data from memory buffer var sum int64 for offset := int64(0); offset < size; offset += 1024 { // Read in chunks to simulate real access patterns end := offset + 1024 if end > size { end = size } for j := offset; j < end; j++ { sum += int64(buffer[j]) } } // Stop timing duration := time.Since(startTime) totalDuration += duration // Use sum to prevent optimization _ = sum } // Calculate average speed avgDuration := totalDuration / time.Duration(iterations) speed := int64(float64(size) / avgDuration.Seconds()) return speed, nil }