145 lines
3.6 KiB
Go
145 lines
3.6 KiB
Go
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
|
|
}
|