mirror of
https://github.com/acepanel/panel.git
synced 2026-02-04 05:31:44 +08:00
509 lines
11 KiB
Go
509 lines
11 KiB
Go
package service
|
||
|
||
import (
|
||
"bytes"
|
||
"compress/gzip"
|
||
"crypto/aes"
|
||
"crypto/cipher"
|
||
cryptorand "crypto/rand"
|
||
"encoding/json"
|
||
"fmt"
|
||
"image"
|
||
"image/color"
|
||
"io"
|
||
"math"
|
||
"math/big"
|
||
"math/rand/v2"
|
||
"net/http"
|
||
"os"
|
||
"path/filepath"
|
||
"regexp"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/leonelquinteros/gotext"
|
||
|
||
"github.com/acepanel/panel/internal/http/request"
|
||
"github.com/acepanel/panel/pkg/shell"
|
||
)
|
||
|
||
type ToolboxBenchmarkService struct {
|
||
t *gotext.Locale
|
||
}
|
||
|
||
func NewToolboxBenchmarkService(t *gotext.Locale) *ToolboxBenchmarkService {
|
||
return &ToolboxBenchmarkService{
|
||
t: t,
|
||
}
|
||
}
|
||
|
||
// Test 运行测试
|
||
func (s *ToolboxBenchmarkService) Test(w http.ResponseWriter, r *http.Request) {
|
||
req, err := Bind[request.ToolboxBenchmarkTest](r)
|
||
if err != nil {
|
||
Error(w, http.StatusUnprocessableEntity, "%v", err)
|
||
return
|
||
}
|
||
|
||
switch req.Name {
|
||
case "image":
|
||
result := s.imageProcessing()
|
||
Success(w, result)
|
||
case "machine":
|
||
result := s.machineLearning()
|
||
Success(w, result)
|
||
case "compile":
|
||
result := s.compileSimulationSingle()
|
||
Success(w, result)
|
||
case "encryption":
|
||
result := s.encryptionTest()
|
||
Success(w, result)
|
||
case "compression":
|
||
result := s.compressionTest()
|
||
Success(w, result)
|
||
case "physics":
|
||
result := s.physicsSimulation()
|
||
Success(w, result)
|
||
case "json":
|
||
result := s.jsonProcessing()
|
||
Success(w, result)
|
||
case "disk":
|
||
result := s.diskTestTask()
|
||
Success(w, result)
|
||
case "memory":
|
||
result := s.memoryTestTask()
|
||
Success(w, result)
|
||
default:
|
||
Error(w, http.StatusUnprocessableEntity, s.t.Get("unknown test type"))
|
||
}
|
||
}
|
||
|
||
// calculateCpuScore 计算CPU成绩
|
||
func (s *ToolboxBenchmarkService) calculateCpuScore(duration time.Duration) int {
|
||
score := int((10 / duration.Seconds()) * float64(3000))
|
||
|
||
if score < 0 {
|
||
score = 0
|
||
}
|
||
return score
|
||
}
|
||
|
||
// calculateScore 计算内存/硬盘成绩
|
||
func (s *ToolboxBenchmarkService) calculateScore(duration time.Duration) int {
|
||
score := int((20 / duration.Seconds()) * float64(30000))
|
||
|
||
if score < 0 {
|
||
score = 0
|
||
}
|
||
return score
|
||
}
|
||
|
||
// 图像处理
|
||
|
||
func (s *ToolboxBenchmarkService) imageProcessing() int {
|
||
start := time.Now()
|
||
if err := s.imageProcessingTask(); err != nil {
|
||
return 0
|
||
}
|
||
duration := time.Since(start)
|
||
return s.calculateCpuScore(duration)
|
||
}
|
||
|
||
func (s *ToolboxBenchmarkService) imageProcessingTask() error {
|
||
img := image.NewRGBA(image.Rect(0, 0, 4000, 4000))
|
||
for x := 0; x < 4000; x++ {
|
||
for y := 0; y < 4000; y++ {
|
||
img.Set(x, y, color.RGBA{R: uint8(x % 256), G: uint8(y % 256), A: 255})
|
||
}
|
||
}
|
||
|
||
dx := img.Bounds().Dx()
|
||
dy := img.Bounds().Dy()
|
||
|
||
for x := 1; x < dx-1; x++ {
|
||
for y := 1; y < dy-1; y++ {
|
||
// 卷积操作(模糊)
|
||
rTotal, gTotal, bTotal := 0, 0, 0
|
||
for k := -1; k <= 1; k++ {
|
||
for l := -1; l <= 1; l++ {
|
||
r, g, b, _ := img.At(x+k, y+l).RGBA()
|
||
rTotal += int(r)
|
||
gTotal += int(g)
|
||
bTotal += int(b)
|
||
}
|
||
}
|
||
rAvg := uint8(rTotal / 9 / 256)
|
||
gAvg := uint8(gTotal / 9 / 256)
|
||
bAvg := uint8(bTotal / 9 / 256)
|
||
img.Set(x, y, color.RGBA{R: rAvg, G: gAvg, B: bAvg, A: 255})
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// 机器学习(矩阵乘法)
|
||
|
||
func (s *ToolboxBenchmarkService) machineLearning() int {
|
||
start := time.Now()
|
||
s.machineLearningTask()
|
||
duration := time.Since(start)
|
||
return s.calculateCpuScore(duration)
|
||
}
|
||
|
||
func (s *ToolboxBenchmarkService) machineLearningTask() {
|
||
size := 900
|
||
a := make([][]float64, size)
|
||
b := make([][]float64, size)
|
||
for i := 0; i < size; i++ {
|
||
a[i] = make([]float64, size)
|
||
b[i] = make([]float64, size)
|
||
for j := 0; j < size; j++ {
|
||
a[i][j] = rand.Float64()
|
||
b[i][j] = rand.Float64()
|
||
}
|
||
}
|
||
|
||
c := make([][]float64, size)
|
||
for i := 0; i < size; i++ {
|
||
c[i] = make([]float64, size)
|
||
}
|
||
|
||
for i := 0; i < size; i++ {
|
||
for j := 0; j < size; j++ {
|
||
sum := 0.0
|
||
for l := 0; l < size; l++ {
|
||
sum += a[i][l] * b[l][j]
|
||
}
|
||
c[i][j] = sum
|
||
}
|
||
}
|
||
}
|
||
|
||
// 数学问题(计算斐波那契数)
|
||
|
||
func (s *ToolboxBenchmarkService) compileSimulationSingle() int {
|
||
start := time.Now()
|
||
totalCalculations := 1000
|
||
fibNumber := 20000
|
||
|
||
for j := 0; j < totalCalculations; j++ {
|
||
s.fib(fibNumber)
|
||
}
|
||
|
||
duration := time.Since(start)
|
||
return s.calculateCpuScore(duration)
|
||
}
|
||
|
||
// 斐波那契函数
|
||
func (s *ToolboxBenchmarkService) fib(n int) *big.Int {
|
||
if n < 2 {
|
||
return big.NewInt(int64(n))
|
||
}
|
||
a := big.NewInt(0)
|
||
b := big.NewInt(1)
|
||
temp := big.NewInt(0)
|
||
for i := 2; i <= n; i++ {
|
||
temp.Add(a, b)
|
||
a.Set(b)
|
||
b.Set(temp)
|
||
}
|
||
return b
|
||
}
|
||
|
||
// AES加密
|
||
|
||
func (s *ToolboxBenchmarkService) encryptionTest() int {
|
||
start := time.Now()
|
||
if err := s.encryptionTestTask(); err != nil {
|
||
return 0
|
||
}
|
||
duration := time.Since(start)
|
||
return s.calculateCpuScore(duration)
|
||
}
|
||
|
||
func (s *ToolboxBenchmarkService) encryptionTestTask() error {
|
||
key := []byte("abcdefghijklmnopqrstuvwxyz123456")
|
||
dataSize := 1024 * 1024 * 512 // 512 MB
|
||
plaintext := []byte(strings.Repeat("A", dataSize))
|
||
block, err := aes.NewCipher(key)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
aesGCM, err := cipher.NewGCM(block)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
nonce := make([]byte, aesGCM.NonceSize())
|
||
if _, err = cryptorand.Read(nonce); err != nil {
|
||
return err
|
||
}
|
||
|
||
aesGCM.Seal(nil, nonce, plaintext, nil)
|
||
return nil
|
||
}
|
||
|
||
// 压缩/解压缩
|
||
|
||
func (s *ToolboxBenchmarkService) compressionTest() int {
|
||
start := time.Now()
|
||
s.compressionTestTask()
|
||
duration := time.Since(start)
|
||
return s.calculateCpuScore(duration)
|
||
}
|
||
|
||
func (s *ToolboxBenchmarkService) compressionTestTask() {
|
||
data := []byte(strings.Repeat("AcePanel", 50000000))
|
||
|
||
// 压缩
|
||
var buf bytes.Buffer
|
||
w := gzip.NewWriter(&buf)
|
||
_, _ = w.Write(data)
|
||
_ = w.Close()
|
||
|
||
// 解压缩
|
||
r, err := gzip.NewReader(&buf)
|
||
if err != nil {
|
||
return
|
||
}
|
||
_, err = io.Copy(io.Discard, r)
|
||
if err != nil {
|
||
return
|
||
}
|
||
_ = r.Close()
|
||
}
|
||
|
||
// 物理仿真(N体问题)
|
||
|
||
func (s *ToolboxBenchmarkService) physicsSimulation() int {
|
||
start := time.Now()
|
||
s.physicsSimulationTask()
|
||
duration := time.Since(start)
|
||
return s.calculateCpuScore(duration)
|
||
}
|
||
|
||
func (s *ToolboxBenchmarkService) physicsSimulationTask() {
|
||
const (
|
||
numBodies = 4000
|
||
steps = 30
|
||
)
|
||
|
||
type Body struct {
|
||
x, y, z, vx, vy, vz float64
|
||
}
|
||
|
||
bodies := make([]Body, numBodies)
|
||
for i := 0; i < numBodies; i++ {
|
||
bodies[i] = Body{
|
||
x: rand.Float64(),
|
||
y: rand.Float64(),
|
||
z: rand.Float64(),
|
||
vx: rand.Float64(),
|
||
vy: rand.Float64(),
|
||
vz: rand.Float64(),
|
||
}
|
||
}
|
||
|
||
for step := 0; step < steps; step++ {
|
||
// 更新速度
|
||
for i := 0; i < numBodies; i++ {
|
||
bi := &bodies[i]
|
||
for j := 0; j < numBodies; j++ {
|
||
if i == j {
|
||
continue
|
||
}
|
||
bj := &bodies[j]
|
||
dx := bj.x - bi.x
|
||
dy := bj.y - bi.y
|
||
dz := bj.z - bi.z
|
||
dist := math.Sqrt(dx*dx + dy*dy + dz*dz)
|
||
if dist == 0 {
|
||
continue
|
||
}
|
||
force := 1 / (dist * dist)
|
||
bi.vx += force * dx / dist
|
||
bi.vy += force * dy / dist
|
||
bi.vz += force * dz / dist
|
||
}
|
||
}
|
||
|
||
// 更新位置
|
||
for i := 0; i < numBodies; i++ {
|
||
bi := &bodies[i]
|
||
bi.x += bi.vx
|
||
bi.y += bi.vy
|
||
bi.z += bi.vz
|
||
}
|
||
}
|
||
}
|
||
|
||
// JSON解析
|
||
|
||
func (s *ToolboxBenchmarkService) jsonProcessing() int {
|
||
start := time.Now()
|
||
s.jsonProcessingTask()
|
||
duration := time.Since(start)
|
||
return s.calculateCpuScore(duration)
|
||
}
|
||
|
||
func (s *ToolboxBenchmarkService) jsonProcessingTask() {
|
||
numElements := 500000
|
||
|
||
elements := make([]map[string]any, 0, numElements)
|
||
for j := 0; j < numElements; j++ {
|
||
elements = append(elements, map[string]any{
|
||
"id": j,
|
||
"value": fmt.Sprintf("Value%d", j),
|
||
})
|
||
}
|
||
|
||
encoded, err := json.Marshal(elements)
|
||
if err != nil {
|
||
return
|
||
}
|
||
|
||
var parsed []map[string]any
|
||
err = json.Unmarshal(encoded, &parsed)
|
||
if err != nil {
|
||
return
|
||
}
|
||
}
|
||
|
||
// 内存性能
|
||
|
||
func (s *ToolboxBenchmarkService) memoryTestTask() map[string]any {
|
||
results := make(map[string]any)
|
||
data := make([]byte, 100*1024*1024) // 100 MB
|
||
_, _ = cryptorand.Read(data)
|
||
|
||
start := time.Now()
|
||
// 内存读写速度
|
||
results["bandwidth"] = s.memoryBandwidthTest(data)
|
||
// 内存访问延迟
|
||
results["latency"] = s.memoryLatencyTest(data)
|
||
duration := time.Since(start)
|
||
results["score"] = s.calculateScore(duration)
|
||
|
||
return results
|
||
}
|
||
|
||
func (s *ToolboxBenchmarkService) memoryBandwidthTest(data []byte) string {
|
||
dataSize := len(data)
|
||
|
||
startTime := time.Now()
|
||
for i := 0; i < dataSize; i++ {
|
||
data[i] ^= 0xFF
|
||
}
|
||
|
||
duration := time.Since(startTime).Seconds()
|
||
if duration == 0 {
|
||
return "N/A"
|
||
}
|
||
speed := float64(dataSize) / duration / (1024 * 1024)
|
||
return fmt.Sprintf("%.2f MB/s", speed)
|
||
}
|
||
|
||
func (s *ToolboxBenchmarkService) memoryLatencyTest(data []byte) string {
|
||
dataSize := len(data)
|
||
indices := rand.Perm(dataSize)
|
||
|
||
startTime := time.Now()
|
||
sum := byte(0)
|
||
for _, idx := range indices {
|
||
sum ^= data[idx]
|
||
}
|
||
duration := time.Since(startTime).Seconds()
|
||
if duration == 0 {
|
||
return "N/A"
|
||
}
|
||
avgLatency := duration * 1e9 / float64(dataSize)
|
||
return fmt.Sprintf("%.2f ns", avgLatency)
|
||
}
|
||
|
||
// 硬盘IO
|
||
|
||
func (s *ToolboxBenchmarkService) diskTestTask() map[string]any {
|
||
results := make(map[string]any)
|
||
blockSizes := []int64{4 * 1024, 64 * 1024, 1 * 1024 * 1024} // 4K, 64K, 1M
|
||
|
||
tmpDir, err := os.MkdirTemp("", "disk_benchmark")
|
||
if err != nil {
|
||
return results
|
||
}
|
||
defer func(path string) {
|
||
_ = os.RemoveAll(path)
|
||
}(tmpDir)
|
||
|
||
testFile := filepath.Join(tmpDir, "testfile")
|
||
start := time.Now()
|
||
for _, blockSize := range blockSizes {
|
||
blockSizeKB := blockSize / 1024
|
||
result := s.diskIOTest(testFile, blockSize)
|
||
results[fmt.Sprintf("%d", blockSizeKB)] = result
|
||
}
|
||
duration := time.Since(start)
|
||
results["score"] = s.calculateScore(duration)
|
||
|
||
return results
|
||
}
|
||
|
||
func (s *ToolboxBenchmarkService) diskIOTest(testFile string, blockSize int64) map[string]any {
|
||
result := make(map[string]any)
|
||
|
||
// 确定测试参数
|
||
count := int64(3000)
|
||
if blockSize >= 64*1024 {
|
||
count = 2000
|
||
}
|
||
if blockSize >= 1*1024*1024 {
|
||
count = 500
|
||
}
|
||
|
||
// 写测试
|
||
result["write_speed"] = s.diskWriteTest(testFile, blockSize, count)
|
||
// 读测试
|
||
result["read_speed"] = s.diskReadTest(testFile, blockSize, count)
|
||
|
||
return result
|
||
}
|
||
|
||
func (s *ToolboxBenchmarkService) diskWriteTest(fileName string, blockSize int64, count int64) string {
|
||
var output string
|
||
var err error
|
||
|
||
blockSizeKB := blockSize / 1024
|
||
output, err = shell.Execf("dd if=/dev/zero of=%s bs=%dk count=%d oflag=direct 2>&1",
|
||
fileName, blockSizeKB, count)
|
||
|
||
if err != nil {
|
||
return ""
|
||
}
|
||
|
||
return s.parseCommandOutput(output)
|
||
}
|
||
|
||
func (s *ToolboxBenchmarkService) diskReadTest(fileName string, blockSize int64, count int64) string {
|
||
var output string
|
||
var err error
|
||
|
||
blockSizeKB := blockSize / 1024
|
||
output, err = shell.Execf("dd if=%s of=/dev/null bs=%dk count=%d iflag=direct 2>&1",
|
||
fileName, blockSizeKB, count)
|
||
if err != nil {
|
||
return ""
|
||
}
|
||
|
||
return s.parseCommandOutput(output)
|
||
}
|
||
|
||
func (s *ToolboxBenchmarkService) parseCommandOutput(output string) string {
|
||
speed := "N/A"
|
||
mbRegex := regexp.MustCompile(`(\d+\.?\d*)\s*[MG]B/s`)
|
||
if matches := mbRegex.FindStringSubmatch(output); len(matches) > 1 {
|
||
speed = strings.TrimSpace(matches[0])
|
||
}
|
||
|
||
return speed
|
||
}
|