Files
golib/ioutils/fileDescriptor/benchmark_test.go
nabbar 3837f0b2bb Improvements, test & documentatons (2025-12 #1)
[file/bandwidth]
- ADD documentation: add enhanced README and TESTING guidelines
- ADD tests: complete test suites with benchmarks, concurrency, and edge cases

[file/perm]
- ADD documentation: add enhanced README and TESTING guidelines
- ADD tests: complete test suites with benchmarks, concurrency, and edge cases
- ADD function to parse form "rwx-wxr-x" or "-rwx-w-r-x"
- ADD function to ParseFileMode to convert os.FileMode to file.Perm

[file/progress]
- ADD documentation: add enhanced README and TESTING guidelines
- ADD tests: complete test suites with benchmarks, concurrency, and edge cases

[ioutils/...]
- UPDATE documentation: update enhanced README and TESTING guidelines
- UPDATE tests: complete test suites with benchmarks, concurrency, and edge cases

[logger/...]
- UPDATE documentation: update enhanced README and TESTING guidelines
- ADD documentation: add enhanced README and TESTING guidelines for sub
  packages
- UPDATE tests: complete test suites with benchmarks, concurrency, and edge cases
- UPDATE config: remove FileBufferSize from OptionFile (rework hookfile)
- UPDATE fields: expose Store function in interface
- REWORK hookfile: rework package, use aggregator to allow multi write and
  single file
- FIX hookstderr: fix bug with NonColorable
- FIX hookstdout: fix bug with NonColorable
- FIX hookwriter: fix bug with NonColorable

[network/protocol]
- ADD function IsTCP, IsUDP, IsUnixLike to check type of protocol

[runner]
- FIX typo

[socket]
- UPDATE documentation: update enhanced README and TESTING guidelines
- ADD documentation: add enhanced README and TESTING guidelines for sub
  packages
- UPDATE tests: complete test suites with benchmarks, concurrency, and edge cases
- REWORK server: use context compatible io.reader, io.writer, io.closer
  instead of reader / writer
- REWORK server: simplify, optimize server
- REMOVE reader, writer type
- ADD context: add new interface in root socket interface to expose
  context interface that extend context, io reader/writer/closer,
dediacted function to server (IsConnected, ...)
2025-12-02 02:56:20 +01:00

189 lines
5.3 KiB
Go

/*
* MIT License
*
* Copyright (c) 2019 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package fileDescriptor_test
import (
"testing"
"github.com/nabbar/golib/ioutils/fileDescriptor"
)
// Standard Go benchmarks for SystemFileDescriptor.
// Run with: go test -bench . -benchmem
//
// Expected results:
// - Query: ~500 ns/op, 0 allocs/op
// - Very consistent timing (low variance)
// - Zero memory allocations
// BenchmarkQuery measures the performance of querying file descriptor limits.
// This is the most common operation and should be extremely fast.
func BenchmarkQuery(b *testing.B) {
// Warmup
fileDescriptor.SystemFileDescriptor(0)
b.ResetTimer()
for i := 0; i < b.N; i++ {
fileDescriptor.SystemFileDescriptor(0)
}
}
// BenchmarkQueryParallel measures query performance under concurrent load.
// Should scale well as operations are independent and kernel-synchronized.
func BenchmarkQueryParallel(b *testing.B) {
// Warmup
fileDescriptor.SystemFileDescriptor(0)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
fileDescriptor.SystemFileDescriptor(0)
}
})
}
// BenchmarkQueryWithErrorCheck measures query with full error handling.
// Should have negligible overhead compared to BenchmarkQuery.
func BenchmarkQueryWithErrorCheck(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
current, max, err := fileDescriptor.SystemFileDescriptor(0)
if err != nil {
b.Fatal(err)
}
if current <= 0 || max < current {
b.Fatalf("Invalid result: current=%d, max=%d", current, max)
}
}
}
// BenchmarkIncrease measures the performance of limit increase operations.
// Note: May fail due to permissions, which is acceptable.
func BenchmarkIncrease(b *testing.B) {
initial, max, err := fileDescriptor.SystemFileDescriptor(0)
if err != nil {
b.Skip("Cannot query initial limits")
}
target := initial + 10
if target > max {
b.Skip("Cannot test increase: already at maximum")
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _, _ = fileDescriptor.SystemFileDescriptor(target)
// Ignore errors (may be permission denied)
}
}
// BenchmarkSequentialCalls measures overhead of sequential calls.
// Useful for comparing with concurrent access patterns.
func BenchmarkSequentialCalls(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
// Query twice in sequence
fileDescriptor.SystemFileDescriptor(0)
fileDescriptor.SystemFileDescriptor(0)
}
}
// BenchmarkAlternatingOperations measures mixed query/increase pattern.
// Simulates a realistic usage pattern where checks alternate with increases.
func BenchmarkAlternatingOperations(b *testing.B) {
initial, max, err := fileDescriptor.SystemFileDescriptor(0)
if err != nil {
b.Skip("Cannot query initial limits")
}
target := initial + 5
if target > max {
target = initial
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if i%2 == 0 {
fileDescriptor.SystemFileDescriptor(0)
} else {
fileDescriptor.SystemFileDescriptor(target)
}
}
}
// BenchmarkValueExtraction measures the cost of extracting return values.
// Verifies that return value handling doesn't add significant overhead.
func BenchmarkValueExtraction(b *testing.B) {
var current, max int
var err error
b.ResetTimer()
for i := 0; i < b.N; i++ {
current, max, err = fileDescriptor.SystemFileDescriptor(0)
// Use values to prevent optimization
_ = current
_ = max
_ = err
}
}
// BenchmarkCompareWithReset measures impact of resetting to same value.
// Useful for understanding no-op cost.
func BenchmarkCompareWithReset(b *testing.B) {
current, _, err := fileDescriptor.SystemFileDescriptor(0)
if err != nil {
b.Skip("Cannot query limits")
}
b.Run("Query", func(b *testing.B) {
for i := 0; i < b.N; i++ {
fileDescriptor.SystemFileDescriptor(0)
}
})
b.Run("SetSameValue", func(b *testing.B) {
for i := 0; i < b.N; i++ {
fileDescriptor.SystemFileDescriptor(current)
}
})
}
// BenchmarkCacheMiss measures the cost when values might not be cached.
// Varies the requested value to test different code paths.
func BenchmarkCacheMiss(b *testing.B) {
initial, _, _ := fileDescriptor.SystemFileDescriptor(0)
values := []int{0, -1, initial, initial + 1, initial + 100}
for _, val := range values {
b.Run(b.Name(), func(b *testing.B) {
for i := 0; i < b.N; i++ {
fileDescriptor.SystemFileDescriptor(val)
}
})
}
}