ref 9
This commit is contained in:
parent
456854246b
commit
b334b09efa
|
@ -2,7 +2,6 @@ package config
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -11,612 +10,6 @@ import (
|
|||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Original benchmarks
|
||||
func BenchmarkSmallConfig(b *testing.B) {
|
||||
// Small config with just a few key-value pairs
|
||||
smallConfig := `
|
||||
host "localhost"
|
||||
port 8080
|
||||
debug true
|
||||
timeout 30
|
||||
`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
reader := strings.NewReader(smallConfig)
|
||||
_, err := config.Load(reader)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse small config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMediumConfig(b *testing.B) {
|
||||
// Medium config with nested structures and arrays
|
||||
mediumConfig := `
|
||||
app {
|
||||
name "TestApp"
|
||||
version "1.0.0"
|
||||
enableLogging true
|
||||
}
|
||||
|
||||
database {
|
||||
host "db.example.com"
|
||||
port 5432
|
||||
credentials {
|
||||
username "admin"
|
||||
password "secure123"
|
||||
}
|
||||
}
|
||||
|
||||
features {
|
||||
"authentication"
|
||||
"authorization"
|
||||
"reporting"
|
||||
"analytics"
|
||||
}
|
||||
|
||||
timeouts {
|
||||
connect 5
|
||||
read 10
|
||||
write 10
|
||||
idle 60
|
||||
}
|
||||
|
||||
-- Comments to add some parsing overhead
|
||||
endpoints {
|
||||
api "/api/v1"
|
||||
web "/web"
|
||||
admin "/admin"
|
||||
health "/health"
|
||||
}
|
||||
`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
reader := strings.NewReader(mediumConfig)
|
||||
_, err := config.Load(reader)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse medium config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLargeConfig(b *testing.B) {
|
||||
// Simpler large config with careful bracket matching
|
||||
largeConfig := `
|
||||
application {
|
||||
name "EnterpriseApp"
|
||||
version "2.5.1"
|
||||
environment "production"
|
||||
debug false
|
||||
maxConnections 1000
|
||||
timeout 30
|
||||
retryCount 3
|
||||
logLevel "info"
|
||||
}
|
||||
|
||||
-- Database cluster configuration
|
||||
databases {
|
||||
primary {
|
||||
host "primary-db.example.com"
|
||||
port 5432
|
||||
maxConnections 100
|
||||
credentials {
|
||||
username "app_user"
|
||||
password "super_secret"
|
||||
ssl true
|
||||
timeout 5
|
||||
}
|
||||
}
|
||||
|
||||
replica {
|
||||
host "replica-db.example.com"
|
||||
port 5432
|
||||
maxConnections 200
|
||||
credentials {
|
||||
username "read_user"
|
||||
password "read_only_pw"
|
||||
ssl true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allowedIPs {
|
||||
"192.168.1.1"
|
||||
"192.168.1.2"
|
||||
"192.168.1.3"
|
||||
"192.168.1.4"
|
||||
"192.168.1.5"
|
||||
}
|
||||
|
||||
-- Add 50 numbered settings to make the config large
|
||||
settings {`
|
||||
|
||||
// Add many numbered settings
|
||||
var builder strings.Builder
|
||||
builder.WriteString(largeConfig)
|
||||
|
||||
for i := 1; i <= 50; i++ {
|
||||
builder.WriteString("\n\t\tsetting")
|
||||
builder.WriteString(strconv.Itoa(i))
|
||||
builder.WriteString(" ")
|
||||
builder.WriteString(strconv.Itoa(i * 10))
|
||||
}
|
||||
|
||||
// Close the settings block and add one more block
|
||||
builder.WriteString(`
|
||||
}
|
||||
|
||||
roles {
|
||||
admin {
|
||||
permissions {
|
||||
"read"
|
||||
"write"
|
||||
"delete"
|
||||
"admin"
|
||||
}
|
||||
}
|
||||
user {
|
||||
permissions {
|
||||
"read"
|
||||
"write"
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
largeConfig = builder.String()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
reader := strings.NewReader(largeConfig)
|
||||
_, err := config.Load(reader)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse large config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JSON Benchmarks
|
||||
func BenchmarkSmallConfigJSON(b *testing.B) {
|
||||
smallConfigJSON := `{
|
||||
"host": "localhost",
|
||||
"port": 8080,
|
||||
"debug": true,
|
||||
"timeout": 30
|
||||
}`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
reader := strings.NewReader(smallConfigJSON)
|
||||
var result map[string]interface{}
|
||||
decoder := json.NewDecoder(reader)
|
||||
err := decoder.Decode(&result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse small JSON config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMediumConfigJSON(b *testing.B) {
|
||||
mediumConfigJSON := `{
|
||||
"app": {
|
||||
"name": "TestApp",
|
||||
"version": "1.0.0",
|
||||
"enableLogging": true
|
||||
},
|
||||
"database": {
|
||||
"host": "db.example.com",
|
||||
"port": 5432,
|
||||
"credentials": {
|
||||
"username": "admin",
|
||||
"password": "secure123"
|
||||
}
|
||||
},
|
||||
"features": [
|
||||
"authentication",
|
||||
"authorization",
|
||||
"reporting",
|
||||
"analytics"
|
||||
],
|
||||
"timeouts": {
|
||||
"connect": 5,
|
||||
"read": 10,
|
||||
"write": 10,
|
||||
"idle": 60
|
||||
},
|
||||
"endpoints": {
|
||||
"api": "/api/v1",
|
||||
"web": "/web",
|
||||
"admin": "/admin",
|
||||
"health": "/health"
|
||||
}
|
||||
}`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
reader := strings.NewReader(mediumConfigJSON)
|
||||
var result map[string]interface{}
|
||||
decoder := json.NewDecoder(reader)
|
||||
err := decoder.Decode(&result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse medium JSON config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLargeConfigJSON(b *testing.B) {
|
||||
// Start building the large JSON config
|
||||
largeConfigJSON := `{
|
||||
"application": {
|
||||
"name": "EnterpriseApp",
|
||||
"version": "2.5.1",
|
||||
"environment": "production",
|
||||
"debug": false,
|
||||
"maxConnections": 1000,
|
||||
"timeout": 30,
|
||||
"retryCount": 3,
|
||||
"logLevel": "info"
|
||||
},
|
||||
"databases": {
|
||||
"primary": {
|
||||
"host": "primary-db.example.com",
|
||||
"port": 5432,
|
||||
"maxConnections": 100,
|
||||
"credentials": {
|
||||
"username": "app_user",
|
||||
"password": "super_secret",
|
||||
"ssl": true,
|
||||
"timeout": 5
|
||||
}
|
||||
},
|
||||
"replica": {
|
||||
"host": "replica-db.example.com",
|
||||
"port": 5432,
|
||||
"maxConnections": 200,
|
||||
"credentials": {
|
||||
"username": "read_user",
|
||||
"password": "read_only_pw",
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"allowedIPs": [
|
||||
"192.168.1.1",
|
||||
"192.168.1.2",
|
||||
"192.168.1.3",
|
||||
"192.168.1.4",
|
||||
"192.168.1.5"
|
||||
],
|
||||
"settings": {`
|
||||
|
||||
var builder strings.Builder
|
||||
builder.WriteString(largeConfigJSON)
|
||||
|
||||
// Add many numbered settings
|
||||
for i := 1; i <= 50; i++ {
|
||||
if i > 1 {
|
||||
builder.WriteString(",")
|
||||
}
|
||||
builder.WriteString("\n\t\t\t\"setting")
|
||||
builder.WriteString(strconv.Itoa(i))
|
||||
builder.WriteString("\": ")
|
||||
builder.WriteString(strconv.Itoa(i * 10))
|
||||
}
|
||||
|
||||
// Close the settings block and add roles
|
||||
builder.WriteString(`
|
||||
},
|
||||
"roles": {
|
||||
"admin": {
|
||||
"permissions": [
|
||||
"read",
|
||||
"write",
|
||||
"delete",
|
||||
"admin"
|
||||
]
|
||||
},
|
||||
"user": {
|
||||
"permissions": [
|
||||
"read",
|
||||
"write"
|
||||
]
|
||||
}
|
||||
}
|
||||
}`)
|
||||
|
||||
largeConfigJSONString := builder.String()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
reader := strings.NewReader(largeConfigJSONString)
|
||||
var result map[string]interface{}
|
||||
decoder := json.NewDecoder(reader)
|
||||
err := decoder.Decode(&result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse large JSON config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// YAML Benchmarks
|
||||
func BenchmarkSmallConfigYAML(b *testing.B) {
|
||||
smallConfigYAML := `
|
||||
host: localhost
|
||||
port: 8080
|
||||
debug: true
|
||||
timeout: 30
|
||||
`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var result map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(smallConfigYAML), &result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse small YAML config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMediumConfigYAML(b *testing.B) {
|
||||
mediumConfigYAML := `
|
||||
app:
|
||||
name: TestApp
|
||||
version: 1.0.0
|
||||
enableLogging: true
|
||||
database:
|
||||
host: db.example.com
|
||||
port: 5432
|
||||
credentials:
|
||||
username: admin
|
||||
password: secure123
|
||||
features:
|
||||
- authentication
|
||||
- authorization
|
||||
- reporting
|
||||
- analytics
|
||||
timeouts:
|
||||
connect: 5
|
||||
read: 10
|
||||
write: 10
|
||||
idle: 60
|
||||
# Comments to add some parsing overhead
|
||||
endpoints:
|
||||
api: /api/v1
|
||||
web: /web
|
||||
admin: /admin
|
||||
health: /health
|
||||
`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var result map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(mediumConfigYAML), &result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse medium YAML config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLargeConfigYAML(b *testing.B) {
|
||||
// Start building the large YAML config
|
||||
largeConfigYAML := `
|
||||
application:
|
||||
name: EnterpriseApp
|
||||
version: 2.5.1
|
||||
environment: production
|
||||
debug: false
|
||||
maxConnections: 1000
|
||||
timeout: 30
|
||||
retryCount: 3
|
||||
logLevel: info
|
||||
|
||||
# Database cluster configuration
|
||||
databases:
|
||||
primary:
|
||||
host: primary-db.example.com
|
||||
port: 5432
|
||||
maxConnections: 100
|
||||
credentials:
|
||||
username: app_user
|
||||
password: super_secret
|
||||
ssl: true
|
||||
timeout: 5
|
||||
replica:
|
||||
host: replica-db.example.com
|
||||
port: 5432
|
||||
maxConnections: 200
|
||||
credentials:
|
||||
username: read_user
|
||||
password: read_only_pw
|
||||
ssl: true
|
||||
|
||||
allowedIPs:
|
||||
- 192.168.1.1
|
||||
- 192.168.1.2
|
||||
- 192.168.1.3
|
||||
- 192.168.1.4
|
||||
- 192.168.1.5
|
||||
|
||||
# Add 50 numbered settings to make the config large
|
||||
settings:
|
||||
`
|
||||
|
||||
var builder strings.Builder
|
||||
builder.WriteString(largeConfigYAML)
|
||||
|
||||
// Add many numbered settings
|
||||
for i := 1; i <= 50; i++ {
|
||||
builder.WriteString(" setting")
|
||||
builder.WriteString(strconv.Itoa(i))
|
||||
builder.WriteString(": ")
|
||||
builder.WriteString(strconv.Itoa(i * 10))
|
||||
builder.WriteString("\n")
|
||||
}
|
||||
|
||||
// Add roles
|
||||
builder.WriteString(`
|
||||
roles:
|
||||
admin:
|
||||
permissions:
|
||||
- read
|
||||
- write
|
||||
- delete
|
||||
- admin
|
||||
user:
|
||||
permissions:
|
||||
- read
|
||||
- write
|
||||
`)
|
||||
|
||||
largeConfigYAMLString := builder.String()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var result map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(largeConfigYAMLString), &result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse large YAML config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TOML Benchmarks
|
||||
func BenchmarkSmallConfigTOML(b *testing.B) {
|
||||
smallConfigTOML := `
|
||||
host = "localhost"
|
||||
port = 8080
|
||||
debug = true
|
||||
timeout = 30
|
||||
`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var result map[string]interface{}
|
||||
err := toml.Unmarshal([]byte(smallConfigTOML), &result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse small TOML config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMediumConfigTOML(b *testing.B) {
|
||||
mediumConfigTOML := `
|
||||
[app]
|
||||
name = "TestApp"
|
||||
version = "1.0.0"
|
||||
enableLogging = true
|
||||
|
||||
[database]
|
||||
host = "db.example.com"
|
||||
port = 5432
|
||||
|
||||
[database.credentials]
|
||||
username = "admin"
|
||||
password = "secure123"
|
||||
|
||||
features = ["authentication", "authorization", "reporting", "analytics"]
|
||||
|
||||
[timeouts]
|
||||
connect = 5
|
||||
read = 10
|
||||
write = 10
|
||||
idle = 60
|
||||
|
||||
# Comments to add some parsing overhead
|
||||
[endpoints]
|
||||
api = "/api/v1"
|
||||
web = "/web"
|
||||
admin = "/admin"
|
||||
health = "/health"
|
||||
`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var result map[string]interface{}
|
||||
err := toml.Unmarshal([]byte(mediumConfigTOML), &result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse medium TOML config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLargeConfigTOML(b *testing.B) {
|
||||
// Start building the large TOML config
|
||||
largeConfigTOML := `
|
||||
[application]
|
||||
name = "EnterpriseApp"
|
||||
version = "2.5.1"
|
||||
environment = "production"
|
||||
debug = false
|
||||
maxConnections = 1000
|
||||
timeout = 30
|
||||
retryCount = 3
|
||||
logLevel = "info"
|
||||
|
||||
# Database cluster configuration
|
||||
[databases.primary]
|
||||
host = "primary-db.example.com"
|
||||
port = 5432
|
||||
maxConnections = 100
|
||||
|
||||
[databases.primary.credentials]
|
||||
username = "app_user"
|
||||
password = "super_secret"
|
||||
ssl = true
|
||||
timeout = 5
|
||||
|
||||
[databases.replica]
|
||||
host = "replica-db.example.com"
|
||||
port = 5432
|
||||
maxConnections = 200
|
||||
|
||||
[databases.replica.credentials]
|
||||
username = "read_user"
|
||||
password = "read_only_pw"
|
||||
ssl = true
|
||||
|
||||
allowedIPs = ["192.168.1.1", "192.168.1.2", "192.168.1.3", "192.168.1.4", "192.168.1.5"]
|
||||
|
||||
# Add 50 numbered settings to make the config large
|
||||
[settings]
|
||||
`
|
||||
|
||||
var builder strings.Builder
|
||||
builder.WriteString(largeConfigTOML)
|
||||
|
||||
// Add many numbered settings
|
||||
for i := 1; i <= 50; i++ {
|
||||
builder.WriteString("setting")
|
||||
builder.WriteString(strconv.Itoa(i))
|
||||
builder.WriteString(" = ")
|
||||
builder.WriteString(strconv.Itoa(i * 10))
|
||||
builder.WriteString("\n")
|
||||
}
|
||||
|
||||
// Add roles
|
||||
builder.WriteString(`
|
||||
[roles.admin]
|
||||
permissions = ["read", "write", "delete", "admin"]
|
||||
|
||||
[roles.user]
|
||||
permissions = ["read", "write"]
|
||||
`)
|
||||
|
||||
largeConfigTOMLString := builder.String()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var result map[string]interface{}
|
||||
err := toml.Unmarshal([]byte(largeConfigTOMLString), &result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse large TOML config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Value Retrieval Benchmarks for Custom Config Format
|
||||
func BenchmarkRetrieveSimpleValues(b *testing.B) {
|
||||
configData := `
|
||||
host "localhost"
|
617
bench/parse_test.go
Normal file
617
bench/parse_test.go
Normal file
|
@ -0,0 +1,617 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
config "git.sharkk.net/Go/Config"
|
||||
"github.com/BurntSushi/toml"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Original benchmarks
|
||||
func BenchmarkSmallConfig(b *testing.B) {
|
||||
// Small config with just a few key-value pairs
|
||||
smallConfig := `
|
||||
host "localhost"
|
||||
port 8080
|
||||
debug true
|
||||
timeout 30
|
||||
`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
reader := strings.NewReader(smallConfig)
|
||||
_, err := config.Load(reader)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse small config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMediumConfig(b *testing.B) {
|
||||
// Medium config with nested structures and arrays
|
||||
mediumConfig := `
|
||||
app {
|
||||
name "TestApp"
|
||||
version "1.0.0"
|
||||
enableLogging true
|
||||
}
|
||||
|
||||
database {
|
||||
host "db.example.com"
|
||||
port 5432
|
||||
credentials {
|
||||
username "admin"
|
||||
password "secure123"
|
||||
}
|
||||
}
|
||||
|
||||
features {
|
||||
"authentication"
|
||||
"authorization"
|
||||
"reporting"
|
||||
"analytics"
|
||||
}
|
||||
|
||||
timeouts {
|
||||
connect 5
|
||||
read 10
|
||||
write 10
|
||||
idle 60
|
||||
}
|
||||
|
||||
-- Comments to add some parsing overhead
|
||||
endpoints {
|
||||
api "/api/v1"
|
||||
web "/web"
|
||||
admin "/admin"
|
||||
health "/health"
|
||||
}
|
||||
`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
reader := strings.NewReader(mediumConfig)
|
||||
_, err := config.Load(reader)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse medium config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLargeConfig(b *testing.B) {
|
||||
// Simpler large config with careful bracket matching
|
||||
largeConfig := `
|
||||
application {
|
||||
name "EnterpriseApp"
|
||||
version "2.5.1"
|
||||
environment "production"
|
||||
debug false
|
||||
maxConnections 1000
|
||||
timeout 30
|
||||
retryCount 3
|
||||
logLevel "info"
|
||||
}
|
||||
|
||||
-- Database cluster configuration
|
||||
databases {
|
||||
primary {
|
||||
host "primary-db.example.com"
|
||||
port 5432
|
||||
maxConnections 100
|
||||
credentials {
|
||||
username "app_user"
|
||||
password "super_secret"
|
||||
ssl true
|
||||
timeout 5
|
||||
}
|
||||
}
|
||||
|
||||
replica {
|
||||
host "replica-db.example.com"
|
||||
port 5432
|
||||
maxConnections 200
|
||||
credentials {
|
||||
username "read_user"
|
||||
password "read_only_pw"
|
||||
ssl true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allowedIPs {
|
||||
"192.168.1.1"
|
||||
"192.168.1.2"
|
||||
"192.168.1.3"
|
||||
"192.168.1.4"
|
||||
"192.168.1.5"
|
||||
}
|
||||
|
||||
-- Add 50 numbered settings to make the config large
|
||||
settings {`
|
||||
|
||||
// Add many numbered settings
|
||||
var builder strings.Builder
|
||||
builder.WriteString(largeConfig)
|
||||
|
||||
for i := 1; i <= 50; i++ {
|
||||
builder.WriteString("\n\t\tsetting")
|
||||
builder.WriteString(strconv.Itoa(i))
|
||||
builder.WriteString(" ")
|
||||
builder.WriteString(strconv.Itoa(i * 10))
|
||||
}
|
||||
|
||||
// Close the settings block and add one more block
|
||||
builder.WriteString(`
|
||||
}
|
||||
|
||||
roles {
|
||||
admin {
|
||||
permissions {
|
||||
"read"
|
||||
"write"
|
||||
"delete"
|
||||
"admin"
|
||||
}
|
||||
}
|
||||
user {
|
||||
permissions {
|
||||
"read"
|
||||
"write"
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
largeConfig = builder.String()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
reader := strings.NewReader(largeConfig)
|
||||
_, err := config.Load(reader)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse large config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// JSON Benchmarks
|
||||
func BenchmarkSmallConfigJSON(b *testing.B) {
|
||||
smallConfigJSON := `{
|
||||
"host": "localhost",
|
||||
"port": 8080,
|
||||
"debug": true,
|
||||
"timeout": 30
|
||||
}`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
reader := strings.NewReader(smallConfigJSON)
|
||||
var result map[string]interface{}
|
||||
decoder := json.NewDecoder(reader)
|
||||
err := decoder.Decode(&result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse small JSON config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMediumConfigJSON(b *testing.B) {
|
||||
mediumConfigJSON := `{
|
||||
"app": {
|
||||
"name": "TestApp",
|
||||
"version": "1.0.0",
|
||||
"enableLogging": true
|
||||
},
|
||||
"database": {
|
||||
"host": "db.example.com",
|
||||
"port": 5432,
|
||||
"credentials": {
|
||||
"username": "admin",
|
||||
"password": "secure123"
|
||||
}
|
||||
},
|
||||
"features": [
|
||||
"authentication",
|
||||
"authorization",
|
||||
"reporting",
|
||||
"analytics"
|
||||
],
|
||||
"timeouts": {
|
||||
"connect": 5,
|
||||
"read": 10,
|
||||
"write": 10,
|
||||
"idle": 60
|
||||
},
|
||||
"endpoints": {
|
||||
"api": "/api/v1",
|
||||
"web": "/web",
|
||||
"admin": "/admin",
|
||||
"health": "/health"
|
||||
}
|
||||
}`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
reader := strings.NewReader(mediumConfigJSON)
|
||||
var result map[string]interface{}
|
||||
decoder := json.NewDecoder(reader)
|
||||
err := decoder.Decode(&result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse medium JSON config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLargeConfigJSON(b *testing.B) {
|
||||
// Start building the large JSON config
|
||||
largeConfigJSON := `{
|
||||
"application": {
|
||||
"name": "EnterpriseApp",
|
||||
"version": "2.5.1",
|
||||
"environment": "production",
|
||||
"debug": false,
|
||||
"maxConnections": 1000,
|
||||
"timeout": 30,
|
||||
"retryCount": 3,
|
||||
"logLevel": "info"
|
||||
},
|
||||
"databases": {
|
||||
"primary": {
|
||||
"host": "primary-db.example.com",
|
||||
"port": 5432,
|
||||
"maxConnections": 100,
|
||||
"credentials": {
|
||||
"username": "app_user",
|
||||
"password": "super_secret",
|
||||
"ssl": true,
|
||||
"timeout": 5
|
||||
}
|
||||
},
|
||||
"replica": {
|
||||
"host": "replica-db.example.com",
|
||||
"port": 5432,
|
||||
"maxConnections": 200,
|
||||
"credentials": {
|
||||
"username": "read_user",
|
||||
"password": "read_only_pw",
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"allowedIPs": [
|
||||
"192.168.1.1",
|
||||
"192.168.1.2",
|
||||
"192.168.1.3",
|
||||
"192.168.1.4",
|
||||
"192.168.1.5"
|
||||
],
|
||||
"settings": {`
|
||||
|
||||
var builder strings.Builder
|
||||
builder.WriteString(largeConfigJSON)
|
||||
|
||||
// Add many numbered settings
|
||||
for i := 1; i <= 50; i++ {
|
||||
if i > 1 {
|
||||
builder.WriteString(",")
|
||||
}
|
||||
builder.WriteString("\n\t\t\t\"setting")
|
||||
builder.WriteString(strconv.Itoa(i))
|
||||
builder.WriteString("\": ")
|
||||
builder.WriteString(strconv.Itoa(i * 10))
|
||||
}
|
||||
|
||||
// Close the settings block and add roles
|
||||
builder.WriteString(`
|
||||
},
|
||||
"roles": {
|
||||
"admin": {
|
||||
"permissions": [
|
||||
"read",
|
||||
"write",
|
||||
"delete",
|
||||
"admin"
|
||||
]
|
||||
},
|
||||
"user": {
|
||||
"permissions": [
|
||||
"read",
|
||||
"write"
|
||||
]
|
||||
}
|
||||
}
|
||||
}`)
|
||||
|
||||
largeConfigJSONString := builder.String()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
reader := strings.NewReader(largeConfigJSONString)
|
||||
var result map[string]interface{}
|
||||
decoder := json.NewDecoder(reader)
|
||||
err := decoder.Decode(&result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse large JSON config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// YAML Benchmarks
|
||||
func BenchmarkSmallConfigYAML(b *testing.B) {
|
||||
smallConfigYAML := `
|
||||
host: localhost
|
||||
port: 8080
|
||||
debug: true
|
||||
timeout: 30
|
||||
`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var result map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(smallConfigYAML), &result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse small YAML config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMediumConfigYAML(b *testing.B) {
|
||||
mediumConfigYAML := `
|
||||
app:
|
||||
name: TestApp
|
||||
version: 1.0.0
|
||||
enableLogging: true
|
||||
database:
|
||||
host: db.example.com
|
||||
port: 5432
|
||||
credentials:
|
||||
username: admin
|
||||
password: secure123
|
||||
features:
|
||||
- authentication
|
||||
- authorization
|
||||
- reporting
|
||||
- analytics
|
||||
timeouts:
|
||||
connect: 5
|
||||
read: 10
|
||||
write: 10
|
||||
idle: 60
|
||||
# Comments to add some parsing overhead
|
||||
endpoints:
|
||||
api: /api/v1
|
||||
web: /web
|
||||
admin: /admin
|
||||
health: /health
|
||||
`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var result map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(mediumConfigYAML), &result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse medium YAML config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLargeConfigYAML(b *testing.B) {
|
||||
// Start building the large YAML config
|
||||
largeConfigYAML := `
|
||||
application:
|
||||
name: EnterpriseApp
|
||||
version: 2.5.1
|
||||
environment: production
|
||||
debug: false
|
||||
maxConnections: 1000
|
||||
timeout: 30
|
||||
retryCount: 3
|
||||
logLevel: info
|
||||
|
||||
# Database cluster configuration
|
||||
databases:
|
||||
primary:
|
||||
host: primary-db.example.com
|
||||
port: 5432
|
||||
maxConnections: 100
|
||||
credentials:
|
||||
username: app_user
|
||||
password: super_secret
|
||||
ssl: true
|
||||
timeout: 5
|
||||
replica:
|
||||
host: replica-db.example.com
|
||||
port: 5432
|
||||
maxConnections: 200
|
||||
credentials:
|
||||
username: read_user
|
||||
password: read_only_pw
|
||||
ssl: true
|
||||
|
||||
allowedIPs:
|
||||
- 192.168.1.1
|
||||
- 192.168.1.2
|
||||
- 192.168.1.3
|
||||
- 192.168.1.4
|
||||
- 192.168.1.5
|
||||
|
||||
# Add 50 numbered settings to make the config large
|
||||
settings:
|
||||
`
|
||||
|
||||
var builder strings.Builder
|
||||
builder.WriteString(largeConfigYAML)
|
||||
|
||||
// Add many numbered settings
|
||||
for i := 1; i <= 50; i++ {
|
||||
builder.WriteString(" setting")
|
||||
builder.WriteString(strconv.Itoa(i))
|
||||
builder.WriteString(": ")
|
||||
builder.WriteString(strconv.Itoa(i * 10))
|
||||
builder.WriteString("\n")
|
||||
}
|
||||
|
||||
// Add roles
|
||||
builder.WriteString(`
|
||||
roles:
|
||||
admin:
|
||||
permissions:
|
||||
- read
|
||||
- write
|
||||
- delete
|
||||
- admin
|
||||
user:
|
||||
permissions:
|
||||
- read
|
||||
- write
|
||||
`)
|
||||
|
||||
largeConfigYAMLString := builder.String()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var result map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(largeConfigYAMLString), &result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse large YAML config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TOML Benchmarks
|
||||
func BenchmarkSmallConfigTOML(b *testing.B) {
|
||||
smallConfigTOML := `
|
||||
host = "localhost"
|
||||
port = 8080
|
||||
debug = true
|
||||
timeout = 30
|
||||
`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var result map[string]interface{}
|
||||
err := toml.Unmarshal([]byte(smallConfigTOML), &result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse small TOML config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMediumConfigTOML(b *testing.B) {
|
||||
mediumConfigTOML := `
|
||||
[app]
|
||||
name = "TestApp"
|
||||
version = "1.0.0"
|
||||
enableLogging = true
|
||||
|
||||
[database]
|
||||
host = "db.example.com"
|
||||
port = 5432
|
||||
|
||||
[database.credentials]
|
||||
username = "admin"
|
||||
password = "secure123"
|
||||
|
||||
features = ["authentication", "authorization", "reporting", "analytics"]
|
||||
|
||||
[timeouts]
|
||||
connect = 5
|
||||
read = 10
|
||||
write = 10
|
||||
idle = 60
|
||||
|
||||
# Comments to add some parsing overhead
|
||||
[endpoints]
|
||||
api = "/api/v1"
|
||||
web = "/web"
|
||||
admin = "/admin"
|
||||
health = "/health"
|
||||
`
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var result map[string]interface{}
|
||||
err := toml.Unmarshal([]byte(mediumConfigTOML), &result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse medium TOML config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLargeConfigTOML(b *testing.B) {
|
||||
// Start building the large TOML config
|
||||
largeConfigTOML := `
|
||||
[application]
|
||||
name = "EnterpriseApp"
|
||||
version = "2.5.1"
|
||||
environment = "production"
|
||||
debug = false
|
||||
maxConnections = 1000
|
||||
timeout = 30
|
||||
retryCount = 3
|
||||
logLevel = "info"
|
||||
|
||||
# Database cluster configuration
|
||||
[databases.primary]
|
||||
host = "primary-db.example.com"
|
||||
port = 5432
|
||||
maxConnections = 100
|
||||
|
||||
[databases.primary.credentials]
|
||||
username = "app_user"
|
||||
password = "super_secret"
|
||||
ssl = true
|
||||
timeout = 5
|
||||
|
||||
[databases.replica]
|
||||
host = "replica-db.example.com"
|
||||
port = 5432
|
||||
maxConnections = 200
|
||||
|
||||
[databases.replica.credentials]
|
||||
username = "read_user"
|
||||
password = "read_only_pw"
|
||||
ssl = true
|
||||
|
||||
allowedIPs = ["192.168.1.1", "192.168.1.2", "192.168.1.3", "192.168.1.4", "192.168.1.5"]
|
||||
|
||||
# Add 50 numbered settings to make the config large
|
||||
[settings]
|
||||
`
|
||||
|
||||
var builder strings.Builder
|
||||
builder.WriteString(largeConfigTOML)
|
||||
|
||||
// Add many numbered settings
|
||||
for i := 1; i <= 50; i++ {
|
||||
builder.WriteString("setting")
|
||||
builder.WriteString(strconv.Itoa(i))
|
||||
builder.WriteString(" = ")
|
||||
builder.WriteString(strconv.Itoa(i * 10))
|
||||
builder.WriteString("\n")
|
||||
}
|
||||
|
||||
// Add roles
|
||||
builder.WriteString(`
|
||||
[roles.admin]
|
||||
permissions = ["read", "write", "delete", "admin"]
|
||||
|
||||
[roles.user]
|
||||
permissions = ["read", "write"]
|
||||
`)
|
||||
|
||||
largeConfigTOMLString := builder.String()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
var result map[string]interface{}
|
||||
err := toml.Unmarshal([]byte(largeConfigTOMLString), &result)
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to parse large TOML config: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
12
pool.go
12
pool.go
|
@ -6,8 +6,8 @@ import (
|
|||
|
||||
// byteSlicePool helps reuse byte slices
|
||||
var byteSlicePool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
b := make([]byte, 0, 128)
|
||||
New: func() any {
|
||||
b := make([]byte, 0, 64)
|
||||
return &b
|
||||
},
|
||||
}
|
||||
|
@ -27,8 +27,8 @@ func PutByteSlice(b *[]byte) {
|
|||
|
||||
// mapPool helps reuse maps for config objects
|
||||
var mapPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
m := make(map[string]any, 16)
|
||||
New: func() any {
|
||||
m := make(map[string]any, 8)
|
||||
return &m
|
||||
},
|
||||
}
|
||||
|
@ -51,8 +51,8 @@ func PutMap(m *map[string]any) {
|
|||
|
||||
// arrayPool helps reuse slices
|
||||
var arrayPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
a := make([]any, 0, 8)
|
||||
New: func() any {
|
||||
a := make([]any, 0, 4)
|
||||
return &a
|
||||
},
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ type Scanner struct {
|
|||
|
||||
// scannerPool helps reuse scanner objects
|
||||
var scannerPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
New: func() any {
|
||||
bufferRef := GetByteSlice()
|
||||
return &Scanner{
|
||||
line: 1,
|
||||
|
@ -43,7 +43,7 @@ var scannerPool = sync.Pool{
|
|||
// NewScanner creates a new scanner from a pool
|
||||
func NewScanner(r io.Reader) *Scanner {
|
||||
s := scannerPool.Get().(*Scanner)
|
||||
s.reader = bufio.NewReader(r)
|
||||
s.reader = bufio.NewReaderSize(r, 1024)
|
||||
s.line = 1
|
||||
s.col = 0
|
||||
s.buffer = (*s.bufferRef)[:0]
|
||||
|
|
Loading…
Reference in New Issue
Block a user