-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Adds [otel](https://opentelemetry.io/) based tracing to kas methods: publicKey and rewrap - adds `trace` top level config to viper config, including `trace.enabled` (boolean) for enabling otel tracer, and `trace.folder` for setting the folder to store the `trace.log` file - Adds new `examples benchmark` command to run encrypt/decrypt and rewrap benchmarks - Also adds a job to the checks.yaml to run it, but it is pretty bare-bones for now, and doesn't have any checks against performance regressions or anything. - Variety of small linter fixes ``` tdf3: Benchmark Results: Total Requests: 5000 Successful Requests: 5000 Failed Requests: 0 Concurrent Requests: 50 Total Time: 1m7.704277611s Average Latency: 673.018399ms Throughput: 73.85 requests/second nano: Benchmark Results: Total Requests: 5000 Successful Requests: 4992 Failed Requests: 8 Concurrent Requests: 50 Total Time: 57.72426082s Average Latency: 575.422342ms Throughput: 86.48 requests/second Error Summary: ReadNanoTDF error: readSeeker.Seek failed: error making nano rewrap request to kas: error making rewrap request: rpc error: code = PermissionDenied desc = request error rpc error: code = PermissionDenied desc = forbidden: 8 occurrences Trace Statistics: publickey: Total Requests: 2 Average Duration: 0.073 ms (72.647 µs, 72647 ns) Min Duration: 0.030 ms (2[9](https://github.com/opentdf/platform/actions/runs/12053261131/job/33608512613?pr=1702#step:17:10).937 µs, 29937 ns) Max Duration: 0.[11](https://github.com/opentdf/platform/actions/runs/12053261131/job/33608512613?pr=1702#step:17:12)5 ms (115.357 µs, 115357 ns) rewrap-tdf3: Total Requests: 5000 Average Duration: 316.499 ms (316498.907 µs, 316498907 ns) Min Duration: 23.608 ms (23607.787 µs, 23607787 ns) Max Duration: 979.418 ms (979417.815 µs, 979417815 ns) rewrap-nanotdf: Total Requests: 4776 Average Duration: 320.718 ms (320717.904 µs, 320717904 ns) Min Duration: 22.802 ms (22801.981 µs, 22801981 ns) Max Duration: 874.830 ms (874829.7[13](https://github.com/opentdf/platform/actions/runs/12053261131/job/33608512613?pr=1702#step:17:14) µs, 874829713 ns) ``` --------- Co-authored-by: Dave Mihalcik <dmihalcik@virtru.com>
- Loading branch information
1 parent
c34251e
commit def28d1
Showing
31 changed files
with
821 additions
and
228 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,3 +45,4 @@ sensitive.txt.tdf | |
keys/ | ||
/examples/sensitive.txt.ntdf | ||
sensitive.txt.ntdf | ||
traces/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
package cmd | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"os" | ||
"strings" | ||
"sync" | ||
"time" | ||
|
||
"github.com/opentdf/platform/sdk" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
type TDFFormat string | ||
|
||
const ( | ||
TDF3 TDFFormat = "tdf3" | ||
NanoTDF TDFFormat = "nanotdf" | ||
) | ||
|
||
func (f *TDFFormat) String() string { | ||
return string(*f) | ||
} | ||
|
||
func (f *TDFFormat) Set(value string) error { | ||
switch value { | ||
case "tdf3", "nanotdf": | ||
*f = TDFFormat(value) | ||
return nil | ||
default: | ||
return errors.New("invalid TDF format") | ||
} | ||
} | ||
|
||
func (f *TDFFormat) Type() string { | ||
return "TDFFormat" | ||
} | ||
|
||
type BenchmarkConfig struct { | ||
TDFFormat TDFFormat | ||
ConcurrentRequests int | ||
RequestCount int | ||
RequestsPerSecond int | ||
TimeoutSeconds int | ||
} | ||
|
||
var config BenchmarkConfig | ||
|
||
func init() { | ||
benchmarkCmd := &cobra.Command{ | ||
Use: "benchmark", | ||
Short: "OpenTDF benchmark tool", | ||
Long: `A OpenTDF benchmark tool to measure throughput and latency with configurable concurrency.`, | ||
RunE: runBenchmark, | ||
} | ||
|
||
benchmarkCmd.Flags().IntVar(&config.ConcurrentRequests, "concurrent", 10, "Number of concurrent requests") | ||
benchmarkCmd.Flags().IntVar(&config.RequestCount, "count", 100, "Total number of requests") | ||
benchmarkCmd.Flags().IntVar(&config.RequestsPerSecond, "rps", 50, "Requests per second limit") | ||
benchmarkCmd.Flags().IntVar(&config.TimeoutSeconds, "timeout", 30, "Timeout in seconds") | ||
benchmarkCmd.Flags().Var(&config.TDFFormat, "tdf", "TDF format (tdf3 or nanotdf)") | ||
ExamplesCmd.AddCommand(benchmarkCmd) | ||
} | ||
|
||
func runBenchmark(cmd *cobra.Command, args []string) error { | ||
in := strings.NewReader("Hello, World!") | ||
|
||
// Create new offline client | ||
client, err := newSDK() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
out := os.Stdout | ||
if outputName != "-" { | ||
out, err = os.Create("sensitive.txt.tdf") | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
defer func() { | ||
if outputName != "-" { | ||
out.Close() | ||
} | ||
}() | ||
|
||
var dataAttributes = []string{"https://example.com/attr/attr1/value/value1"} | ||
if config.TDFFormat == NanoTDF { | ||
nanoTDFConfig, err := client.NewNanoTDFConfig() | ||
if err != nil { | ||
return err | ||
} | ||
nanoTDFConfig.SetAttributes(dataAttributes) | ||
nanoTDFConfig.EnableECDSAPolicyBinding() | ||
err = nanoTDFConfig.SetKasURL(fmt.Sprintf("http://%s/kas", "localhost:8080")) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
_, err = client.CreateNanoTDF(out, in, *nanoTDFConfig) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if outputName != "-" { | ||
err = cat(cmd, outputName) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
} else { | ||
tdf, err := | ||
client.CreateTDF( | ||
out, in, | ||
sdk.WithDataAttributes(dataAttributes...), | ||
sdk.WithKasInformation( | ||
sdk.KASInfo{ | ||
URL: fmt.Sprintf("http://%s", "localhost:8080"), | ||
PublicKey: "", | ||
}), | ||
sdk.WithAutoconfigure(false)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
manifestJSON, err := json.MarshalIndent(tdf.Manifest(), "", " ") | ||
if err != nil { | ||
return err | ||
} | ||
cmd.Println(string(manifestJSON)) | ||
} | ||
|
||
var wg sync.WaitGroup | ||
requests := make(chan struct{}, config.ConcurrentRequests) | ||
results := make(chan time.Duration, config.RequestCount) | ||
errors := make(chan error, config.RequestCount) | ||
|
||
// Function to perform the operation | ||
operation := func() { | ||
defer wg.Done() | ||
start := time.Now() | ||
|
||
file, err := os.Open("sensitive.txt.tdf") | ||
if err != nil { | ||
errors <- fmt.Errorf("file open error: %v", err) | ||
return | ||
} | ||
defer file.Close() | ||
|
||
if config.TDFFormat == NanoTDF { | ||
_, err = client.ReadNanoTDF(io.Discard, file) | ||
if err != nil { | ||
errors <- fmt.Errorf("ReadNanoTDF error: %v", err) | ||
return | ||
} | ||
} else { | ||
tdfreader, err := client.LoadTDF(file) | ||
if err != nil { | ||
errors <- fmt.Errorf("LoadTDF error: %v", err) | ||
return | ||
} | ||
|
||
_, err = io.Copy(io.Discard, tdfreader) | ||
if err != nil && err != io.EOF { | ||
errors <- fmt.Errorf("read error: %v", err) | ||
return | ||
} | ||
} | ||
|
||
results <- time.Since(start) | ||
} | ||
|
||
// Start the benchmark | ||
startTime := time.Now() | ||
for i := 0; i < config.RequestCount; i++ { | ||
wg.Add(1) | ||
requests <- struct{}{} | ||
go func() { | ||
defer func() { <-requests }() | ||
operation() | ||
}() | ||
} | ||
|
||
wg.Wait() | ||
close(results) | ||
close(errors) | ||
|
||
// Count errors and collect error messages | ||
errorCount := 0 | ||
errorMsgs := make(map[string]int) | ||
for err := range errors { | ||
errorCount++ | ||
errorMsgs[err.Error()]++ | ||
} | ||
|
||
successCount := 0 | ||
var totalDuration time.Duration | ||
for result := range results { | ||
successCount++ | ||
totalDuration += result | ||
} | ||
|
||
totalTime := time.Since(startTime) | ||
averageLatency := totalDuration / time.Duration(successCount) | ||
throughput := float64(successCount) / totalTime.Seconds() | ||
|
||
// Print results | ||
cmd.Printf("\nBenchmark Results:\n") | ||
cmd.Printf("Total Requests: %d\n", config.RequestCount) | ||
cmd.Printf("Successful Requests: %d\n", successCount) | ||
cmd.Printf("Failed Requests: %d\n", errorCount) | ||
cmd.Printf("Concurrent Requests: %d\n", config.ConcurrentRequests) | ||
cmd.Printf("Total Time: %s\n", totalTime) | ||
cmd.Printf("Average Latency: %s\n", averageLatency) | ||
cmd.Printf("Throughput: %.2f requests/second\n", throughput) | ||
|
||
if errorCount > 0 { | ||
cmd.Printf("\nError Summary:\n") | ||
for errMsg, count := range errorMsgs { | ||
cmd.Printf("%s: %d occurrences\n", errMsg, count) | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.