-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(kas): collect metrics #1702
base: main
Are you sure you want to change the base?
Changes from 32 commits
1f730c0
11123cf
3d74003
cb445e3
546da3a
106fd9d
767ce61
f0f72c0
8aae5d9
baeb532
6e584bb
b460634
bd1e0be
1061c3a
afbfc3b
85d08d9
9c9ae6e
128c0b4
9da3fc0
7838552
9e77426
04dc857
7238368
0de2afe
04b4a61
f9726e3
3f2144c
cdc0a93
50ffdf2
1021e7a
4afe3df
3a1cda5
2b48524
fb681ce
ae88f78
5f1093a
ff13dc1
02a0399
77b1f73
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
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 | ||
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 { | ||
opts := []sdk.TDFOption{sdk.WithDataAttributes(dataAttributes...)} | ||
opts = append(opts, sdk.WithAutoconfigure(autoconfigure)) | ||
opts = append(opts, sdk.WithKasInformation( | ||
sdk.KASInfo{ | ||
URL: fmt.Sprintf("http://%s", "localhost:8080"), | ||
PublicKey: "", | ||
})) | ||
tdf, err := client.CreateTDF(out, in, opts...) | ||
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 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,7 +31,7 @@ func init() { | |
|
||
func newSDK() (*sdk.SDK, error) { | ||
resolver.SetDefaultScheme("passthrough") | ||
opts := []sdk.Option{sdk.WithStoreCollectionHeaders()} | ||
opts := []sdk.Option{sdk.WithStoreCollectionHeaders(), sdk.WithInsecurePlaintextConn()} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you probably want to drop sdk.WithStoreCollectionHeaders(). There is no way to determine if a nanoTDF is part of a collection or not, with this option on, it will always assume its part of a collection. Since you are decrypting the same nanoTDF, it will store the key with the header and future decrypts will skip the rewrap call. It's probably best that you remove this option for benchmarking. |
||
if clientCredentials != "" { | ||
i := strings.Index(clientCredentials, ":") | ||
if i < 0 { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this causing failures in integration test?