From 94f1951430f9f78ccf84609ef8df1cbefdae31cd Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Thu, 17 Oct 2024 09:39:19 -0700 Subject: [PATCH] Fix detailed output when single hostname and multiple clients (#341) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #327 Output after fix: ``` λ warp analyze -analyze.v -analyze.limit=1000000 -analyze.out="out.csv" 100Ksize-1Mcount-GET-noinflux.csv.zst 1000000 operations loaded... Done! ---------------------------------------- Operation: GET (1000000). Ran 16s. Size: 100000 bytes. Concurrency: 640. Warp Instances: 8. Requests considered: 994817: * Avg: 11ms, 50%: 8ms, 90%: 19ms, 99%: 40ms, Fastest: 1ms, Slowest: 133ms, StdDev: 7ms * TTFB: Avg: 10ms, Best: 1ms, 25th: 6ms, Median: 8ms, 75th: 13ms, 90th: 19ms, 99th: 39ms, Worst: 133ms StdDev: 7ms * First Access: Avg: 11ms, 50%: 9ms, 90%: 21ms, 99%: 44ms, Fastest: 1ms, Slowest: 116ms, StdDev: 8ms * First Access TTFB: Avg: 11ms, Best: 1ms, 25th: 6ms, Median: 8ms, 75th: 14ms, 90th: 21ms, 99th: 44ms, Worst: 116ms StdDev: 8ms * Last Access: Avg: 10ms, 50%: 8ms, 90%: 17ms, 99%: 35ms, Fastest: 1ms, Slowest: 94ms, StdDev: 7ms * Last Access TTFB: Avg: 10ms, Best: 1ms, 25th: 6ms, Median: 8ms, 75th: 12ms, 90th: 17ms, 99th: 35ms, Worst: 93ms StdDev: 6ms Requests by host: * Client_a - 123837 requests: - Avg: 11ms Fastest: 1ms Slowest: 133ms 50%: 9ms 90%: 19ms StdDev: 7ms - First Byte: Avg: 11ms, Best: 1ms, 25th: 6ms, Median: 8ms, 75th: 13ms, 90th: 19ms, 99th: 40ms, Worst: 133ms StdDev: 7ms * Client_b - 123001 requests: - Avg: 11ms Fastest: 1ms Slowest: 101ms 50%: 9ms 90%: 19ms StdDev: 7ms - First Byte: Avg: 11ms, Best: 1ms, 25th: 6ms, Median: 8ms, 75th: 13ms, 90th: 19ms, 99th: 40ms, Worst: 101ms StdDev: 7ms * Client_c - 125151 requests: - Avg: 11ms Fastest: 1ms Slowest: 114ms 50%: 8ms 90%: 19ms StdDev: 7ms - First Byte: Avg: 10ms, Best: 1ms, 25th: 6ms, Median: 8ms, 75th: 13ms, 90th: 19ms, 99th: 40ms, Worst: 114ms StdDev: 7ms * Client_d - 125577 requests: - Avg: 11ms Fastest: 1ms Slowest: 117ms 50%: 8ms 90%: 19ms StdDev: 8ms - First Byte: Avg: 10ms, Best: 1ms, 25th: 6ms, Median: 8ms, 75th: 13ms, 90th: 19ms, 99th: 40ms, Worst: 117ms StdDev: 8ms * Client_e - 125571 requests: - Avg: 11ms Fastest: 1ms Slowest: 111ms 50%: 8ms 90%: 19ms StdDev: 7ms - First Byte: Avg: 10ms, Best: 1ms, 25th: 6ms, Median: 8ms, 75th: 13ms, 90th: 19ms, 99th: 41ms, Worst: 111ms StdDev: 7ms * Client_f - 125026 requests: - Avg: 11ms Fastest: 1ms Slowest: 108ms 50%: 8ms 90%: 19ms StdDev: 8ms - First Byte: Avg: 10ms, Best: 1ms, 25th: 6ms, Median: 8ms, 75th: 13ms, 90th: 19ms, 99th: 40ms, Worst: 108ms StdDev: 8ms * Client_g - 122350 requests: - Avg: 11ms Fastest: 1ms Slowest: 113ms 50%: 9ms 90%: 19ms StdDev: 8ms - First Byte: Avg: 11ms, Best: 1ms, 25th: 6ms, Median: 8ms, 75th: 13ms, 90th: 19ms, 99th: 41ms, Worst: 113ms StdDev: 8ms * Client_h - 129487 requests: - Avg: 10ms Fastest: 1ms Slowest: 92ms 50%: 8ms 90%: 19ms StdDev: 7ms - First Byte: Avg: 10ms, Best: 1ms, 25th: 5ms, Median: 8ms, 75th: 13ms, 90th: 18ms, 99th: 40ms, Worst: 92ms StdDev: 7ms Throughput: * Average: 5806.90 MiB/s, 60889.76 obj/s Throughput by host: * Client_a: - Average: 715.78 MiB/s, 7505.48 obj/s - Fastest: 880.4MiB/s - 50% Median: 762.9MiB/s - Slowest: 341.1MiB/s * Client_b: - Average: 710.95 MiB/s, 7454.83 obj/s - Fastest: 912.8MiB/s - 50% Median: 840.6MiB/s - Slowest: 349.5MiB/s * Client_c: - Average: 723.34 MiB/s, 7584.79 obj/s - Fastest: 955.8MiB/s - 50% Median: 874.3MiB/s - Slowest: 358.7MiB/s * Client_d: - Average: 725.85 MiB/s, 7611.07 obj/s - Fastest: 923.0MiB/s - 50% Median: 826.2MiB/s - Slowest: 351.3MiB/s * Client_e: - Average: 725.84 MiB/s, 7611.02 obj/s - Fastest: 982.7MiB/s - 50% Median: 888.0MiB/s - Slowest: 353.0MiB/s * Client_f: - Average: 722.67 MiB/s, 7577.72 obj/s - Fastest: 954.0MiB/s - 50% Median: 887.3MiB/s - Slowest: 341.8MiB/s * Client_g: - Average: 707.14 MiB/s, 7414.87 obj/s - Fastest: 904.6MiB/s - 50% Median: 800.5MiB/s - Slowest: 334.4MiB/s * Client_h: - Average: 748.46 MiB/s, 7848.17 obj/s - Fastest: 984.5MiB/s - 50% Median: 895.2MiB/s - Slowest: 359.2MiB/s Throughput, split into 16 x 1s: * Fastest: 7433.8MiB/s, 77949.34 obj/s (1s, starting 10:05:04 -0700) * 50% Median: 6995.5MiB/s, 73353.44 obj/s (1s, starting 10:05:09 -0700) * Slowest: 3043.0MiB/s, 31908.11 obj/s (1s, starting 10:04:55 -0700) Aggregated data saved to out.csv ``` CSV output: ``` index op host duration_s objects_per_op bytes full_ops partial_ops ops_started ops_ended errors mb_per_sec ops_ended_per_sec objs_per_sec reqs_ended_avg_ms start_time end_time 0 GET https://127.0.0.1:9000 1 1 3190810087 31338 1278 31978 31976 0 3042.993628501892 31976 31908.107407116204 20.138379674474603 2024-10-16 10:04:55.303550671 -0700 -0700 2024-10-16 10:04:56.303550671 -0700 -0700 1 GET https://127.0.0.1:9000 1 1 3826420194 37628 1280 38268 38268 0 3649.1586627960205 38268 38264.208218821586 16.844201928164512 2024-10-16 10:04:56.303550671 -0700 -0700 2024-10-16 10:04:57.303550671 -0700 -0700 2 GET https://127.0.0.1:9000 1 1 3675309926 36113 1280 36753 36753 0 3505.0486812591553 36753 36753.10570367611 17.4305407728349 2024-10-16 10:04:57.303550671 -0700 -0700 2024-10-16 10:04:58.303550671 -0700 -0700 3 GET https://127.0.0.1:9000 1 1 3851000336 37825 1280 38465 38465 0 3672.600112915039 38465 38510.009800292006 16.62246259396865 2024-10-16 10:04:58.303550671 -0700 -0700 2024-10-16 10:04:59.303550671 -0700 -0700 4 GET https://127.0.0.1:9000 1 1 3999119351 39376 1280 40016 40016 0 3813.857413291931 40016 39991.19982818898 15.959853549904944 2024-10-16 10:04:59.303550671 -0700 -0700 2024-10-16 10:05:00.303550671 -0700 -0700 5 GET https://127.0.0.1:9000 1 1 5410055832 53479 1280 54119 54119 0 5159.431297302246 54119 54100.56462554655 11.822470873556451 2024-10-16 10:05:00.303550671 -0700 -0700 2024-10-16 10:05:01.303550671 -0700 -0700 6 GET https://127.0.0.1:9000 1 1 6233877437 61720 1280 62360 62360 0 5945.088803291321 62360 62338.78092286412 10.302423205853005 2024-10-16 10:05:01.303550671 -0700 -0700 2024-10-16 10:05:02.303550671 -0700 -0700 7 GET https://127.0.0.1:9000 1 1 6779911447 67140 1280 67780 67780 0 6465.827414512634 67780 67799.12067143632 9.443938266435516 2024-10-16 10:05:02.303550671 -0700 -0700 2024-10-16 10:05:03.303550671 -0700 -0700 8 GET https://127.0.0.1:9000 1 1 7381796582 73156 1280 73796 73796 0 7039.829809188843 73796 73817.97236672255 8.663195216569932 2024-10-16 10:05:03.303550671 -0700 -0700 2024-10-16 10:05:04.303550671 -0700 -0700 9 GET https://127.0.0.1:9000 1 1 7794933103 77305 1280 77945 77945 0 7433.827498435974 77945 77949.33733362416 8.195419635383953 2024-10-16 10:05:04.303550671 -0700 -0700 2024-10-16 10:05:05.303550671 -0700 -0700 10 GET https://127.0.0.1:9000 1 1 7537589191 74755 1280 75395 75395 0 7188.405219078064 75395 75375.89852321758 8.487653227720598 2024-10-16 10:05:05.303550671 -0700 -0700 2024-10-16 10:05:06.303550671 -0700 -0700 11 GET https://127.0.0.1:9000 1 1 7383243897 73212 1279 73851 73852 0 7041.210076332092 73852 73832.44526772993 8.664933280926762 2024-10-16 10:05:06.303550671 -0700 -0700 2024-10-16 10:05:07.303550671 -0700 -0700 12 GET https://127.0.0.1:9000 1 1 7559543971 74930 1278 75569 75569 0 7209.342928886414 75569 75595.44604396267 8.476595284812577 2024-10-16 10:05:07.303550671 -0700 -0700 2024-10-16 10:05:08.303550671 -0700 -0700 13 GET https://127.0.0.1:9000 1 1 7506866224 74419 1279 75059 75058 0 7159.105514526367 75058 75068.66851186962 8.502268035972271 2024-10-16 10:05:08.303550671 -0700 -0700 2024-10-16 10:05:09.303550671 -0700 -0700 14 GET https://127.0.0.1:9000 1 1 7335342894 72790 1279 73429 73430 0 6995.528120040894 73430 73353.435550315 8.7262496441237 2024-10-16 10:05:09.303550671 -0700 -0700 2024-10-16 10:05:10.303550671 -0700 -0700 15 GET https://127.0.0.1:9000 1 1 7413331335 73480 1279 74120 74119 0 7069.903693199158 74119 74133.31963074762 8.639938812841535 2024-10-16 10:05:10.303550671 -0700 -0700 2024-10-16 10:05:11.303550671 -0700 -0700 index op host duration_s objects_per_op bytes full_ops partial_ops ops_started ops_ended errors mb_per_sec ops_ended_per_sec objs_per_sec reqs_ended_avg_ms start_time end_time 0 GET client_a 1 1 386025190 3788 160 3868 3868 0 368.1423091888428 3868 3860.252715587028 20.942079319027943 2024-10-16 10:04:55.303550671 -0700 -0700 2024-10-16 10:04:56.303550671 -0700 -0700 1 GET client_a 1 1 478320885 4698 160 4778 4778 0 456.1623430252075 4778 4783.209653813716 16.85720957764757 2024-10-16 10:04:56.303550671 -0700 -0700 2024-10-16 10:04:57.303550671 -0700 -0700 2 GET client_a 1 1 448844844 4420 160 4500 4500 0 428.0517997741699 4500 4488.449203509883 17.845506059333307 2024-10-16 10:04:57.303550671 -0700 -0700 2024-10-16 10:04:58.303550671 -0700 -0700 3 GET client_a 1 1 541319920 5319 160 5399 5399 0 516.2429046630859 5399 5413.200059422277 14.822916722356009 2024-10-16 10:04:58.303550671 -0700 -0700 2024-10-16 10:04:59.303550671 -0700 -0700 4 GET client_a 1 1 675667743 6687 160 6767 6767 0 644.3669729232788 6767 6756.67824304164 11.775649330870408 2024-10-16 10:04:59.303550671 -0700 -0700 2024-10-16 10:05:00.303550671 -0700 -0700 5 GET client_a 1 1 748786116 7400 160 7480 7480 0 714.098087310791 7480 7487.861888408718 10.660159039438456 2024-10-16 10:05:00.303550671 -0700 -0700 2024-10-16 10:05:01.303550671 -0700 -0700 6 GET client_a 1 1 781087936 7738 160 7818 7818 0 744.9035034179688 7818 7810.880203594163 10.285525322205181 2024-10-16 10:05:01.303550671 -0700 -0700 2024-10-16 10:05:02.303550671 -0700 -0700 7 GET client_a 1 1 791253666 7821 160 7901 7901 0 754.5982990264893 7901 7912.537426133125 10.106546248069847 2024-10-16 10:05:02.303550671 -0700 -0700 2024-10-16 10:05:03.303550671 -0700 -0700 8 GET client_a 1 1 802935412 7941 160 8021 8021 0 765.7388801574707 8021 8029.3549268835 9.959889334870978 2024-10-16 10:05:03.303550671 -0700 -0700 2024-10-16 10:05:04.303550671 -0700 -0700 9 GET client_a 1 1 899132210 8936 160 9016 9016 0 857.4792957305908 9016 8991.322825815023 8.893413242346924 2024-10-16 10:05:04.303550671 -0700 -0700 2024-10-16 10:05:05.303550671 -0700 -0700 10 GET client_a 1 1 907434953 8998 160 9078 9078 0 865.3974084854126 9078 9074.350417179407 8.806996751046501 2024-10-16 10:05:05.303550671 -0700 -0700 2024-10-16 10:05:06.303550671 -0700 -0700 11 GET client_a 1 1 909069846 9006 160 9086 9086 0 866.956563949585 9086 9090.699235212702 8.772049123596735 2024-10-16 10:05:06.303550671 -0700 -0700 2024-10-16 10:05:07.303550671 -0700 -0700 12 GET client_a 1 1 918820806 9102 160 9182 9182 0 876.2558040618896 9182 9188.208862280739 8.72855345992157 2024-10-16 10:05:07.303550671 -0700 -0700 2024-10-16 10:05:08.303550671 -0700 -0700 13 GET client_a 1 1 904159381 8948 160 9028 9028 0 862.2735795974731 9028 9041.594589278697 8.820645921245044 2024-10-16 10:05:08.303550671 -0700 -0700 2024-10-16 10:05:09.303550671 -0700 -0700 14 GET client_a 1 1 895185902 8886 160 8966 8966 0 853.7158031463623 8966 8951.859904394863 8.939140768458609 2024-10-16 10:05:09.303550671 -0700 -0700 2024-10-16 10:05:10.303550671 -0700 -0700 15 GET client_a 1 1 921195428 9136 160 9216 9216 0 878.5204200744629 9216 9211.955020986257 8.710529730034706 2024-10-16 10:05:10.303550671 -0700 -0700 2024-10-16 10:05:11.303550671 -0700 -0700 index op host duration_s objects_per_op bytes full_ops partial_ops ops_started ops_ended errors mb_per_sec ops_ended_per_sec objs_per_sec reqs_ended_avg_ms start_time end_time 0 GET client_b 1 1 399656169 3946 160 4026 4026 0 381.1418237686157 4026 3996.5624742176756 20.29723854992547 2024-10-16 10:04:55.303550671 -0700 -0700 2024-10-16 10:04:56.303550671 -0700 -0700 1 GET client_b 1 1 476798552 4682 160 4762 4762 0 454.71053314208984 4762 4767.986285852002 16.898080152876968 2024-10-16 10:04:56.303550671 -0700 -0700 2024-10-16 10:04:57.303550671 -0700 -0700 .... ``` --- cli/analyze.go | 6 +++--- pkg/aggregate/aggregate.go | 8 ++++++-- pkg/aggregate/requests.go | 17 ++++++++++++----- pkg/bench/analyze.go | 11 +++++++---- pkg/bench/ops.go | 13 ++++++++++--- 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/cli/analyze.go b/cli/analyze.go index 073b2862..1954251a 100644 --- a/cli/analyze.go +++ b/cli/analyze.go @@ -417,7 +417,7 @@ func writeSegs(ctx *cli.Context, wrSegs io.Writer, ops bench.Operations, allThre } segs.SortByTime() - err := segs.CSV(wrSegs) + err := segs.CSV(wrSegs, "") errorIf(probe.NewError(err), "Error writing analysis") start := segs[0].Start wantSegs := len(segs) @@ -425,7 +425,7 @@ func writeSegs(ctx *cli.Context, wrSegs io.Writer, ops bench.Operations, allThre // Write segments per endpoint eps := ops.SortSplitByEndpoint() if len(eps) == 1 { - cl := ops.SortSplitByClient() + cl := ops.SortSplitByClient("client_") if len(cl) > 1 { eps = cl } @@ -452,7 +452,7 @@ func writeSegs(ctx *cli.Context, wrSegs io.Writer, ops bench.Operations, allThre segs.SortByObjsPerSec() } segs.SortByTime() - err := segs.CSV(wrSegs) + err := segs.CSV(wrSegs, ep) errorIf(probe.NewError(err), "Error writing analysis") } } diff --git a/pkg/aggregate/aggregate.go b/pkg/aggregate/aggregate.go index 53e79b63..7bf96e8c 100644 --- a/pkg/aggregate/aggregate.go +++ b/pkg/aggregate/aggregate.go @@ -25,6 +25,9 @@ import ( "github.com/minio/warp/pkg/bench" ) +// Prefix used, when all host names are the same, but multiple clients were used. +var clientAsHostPrefix = "Client_" + // Aggregated contains aggregated data for a single benchmark run. type Aggregated struct { // MixedServerStats and MixedThroughputByHost is populated only when data is mixed. @@ -135,7 +138,7 @@ func Aggregate(o bench.Operations, opts Options) Aggregated { eps := o.SortSplitByEndpoint() if len(eps) == 1 { - cl := ops.SortSplitByClient() + cl := ops.SortSplitByClient(clientAsHostPrefix) if len(cl) > 1 { eps = cl } @@ -236,8 +239,9 @@ func Aggregate(o bench.Operations, opts Options) Aggregated { eps := allOps.SortSplitByEndpoint() if len(eps) == 1 { - cl := ops.SortSplitByClient() + cl := ops.SortSplitByClient(clientAsHostPrefix) if len(cl) > 1 { + a.HostNames = ops.ClientIDs(clientAsHostPrefix) eps = cl } } diff --git a/pkg/aggregate/requests.go b/pkg/aggregate/requests.go index bddfb7a4..45549dc5 100644 --- a/pkg/aggregate/requests.go +++ b/pkg/aggregate/requests.go @@ -234,7 +234,7 @@ func RequestAnalysisSingleSized(o bench.Operations, allThreads bool) *SingleSize res.HostNames = o.Endpoints() res.ByHost = RequestAnalysisHostsSingleSized(o) if len(res.HostNames) != len(res.ByHost) { - res.HostNames = o.ClientIDs() + res.HostNames = o.ClientIDs(clientAsHostPrefix) } return &res } @@ -243,10 +243,13 @@ func RequestAnalysisSingleSized(o bench.Operations, allThreads bool) *SingleSize func RequestAnalysisHostsSingleSized(o bench.Operations) map[string]SingleSizedRequests { eps := o.SortSplitByEndpoint() if len(eps) == 1 { - cl := o.SortSplitByClient() + cl := o.SortSplitByClient(clientAsHostPrefix) if len(cl) > 1 { eps = cl } + if len(eps) == 1 { + return nil + } } res := make(map[string]SingleSizedRequests, len(eps)) var wg sync.WaitGroup @@ -284,8 +287,8 @@ func RequestAnalysisMultiSized(o bench.Operations, allThreads bool) *MultiSizedR res.fill(active) res.ByHost = RequestAnalysisHostsMultiSized(active) res.HostNames = active.Endpoints() - if len(res.HostNames) != len(res.ByHost) { - res.HostNames = o.ClientIDs() + if len(res.HostNames) != len(res.ByHost) && len(res.ByHost) > 0 { + res.HostNames = o.ClientIDs(clientAsHostPrefix) } return &res } @@ -295,11 +298,15 @@ func RequestAnalysisHostsMultiSized(o bench.Operations) map[string]RequestSizeRa start, end := o.TimeRange() eps := o.SortSplitByEndpoint() if len(eps) == 1 { - cl := o.SortSplitByClient() + cl := o.SortSplitByClient(clientAsHostPrefix) if len(cl) > 1 { eps = cl } + if len(eps) == 1 { + return nil + } } + res := make(map[string]RequestSizeRange, len(eps)) var wg sync.WaitGroup var mu sync.Mutex diff --git a/pkg/bench/analyze.go b/pkg/bench/analyze.go index 58abc97a..e35eff63 100644 --- a/pkg/bench/analyze.go +++ b/pkg/bench/analyze.go @@ -235,7 +235,7 @@ func (s Segments) Print(w io.Writer) error { } // CSV writes segments to a supplied writer as CSV data. -func (s Segments) CSV(w io.Writer) error { +func (s Segments) CSV(w io.Writer, hostOvr string) error { cw := csv.NewWriter(w) cw.Comma = '\t' err := cw.Write([]string{ @@ -261,7 +261,7 @@ func (s Segments) CSV(w io.Writer) error { return err } for i, seg := range s { - err := seg.CSV(cw, i) + err := seg.CSV(cw, i, hostOvr) if err != nil { return err } @@ -271,12 +271,15 @@ func (s Segments) CSV(w io.Writer) error { } // CSV writes a CSV representation of the segment to the supplied writer. -func (s Segment) CSV(w *csv.Writer, idx int) error { +func (s Segment) CSV(w *csv.Writer, idx int, host string) error { mib, ops, objs := s.SpeedPerSec() + if host == "" { + host = s.Host + } return w.Write([]string{ fmt.Sprint(idx), s.OpType, - s.Host, + host, fmt.Sprint(float64(s.EndsBefore.Sub(s.Start)) / float64(time.Second)), fmt.Sprint(s.ObjsPerOp), fmt.Sprint(s.TotalBytes), diff --git a/pkg/bench/ops.go b/pkg/bench/ops.go index 5eb7891b..6f4551b8 100644 --- a/pkg/bench/ops.go +++ b/pkg/bench/ops.go @@ -386,7 +386,7 @@ func (o Operations) SortSplitByEndpoint() map[string]Operations { } // SortSplitByClient will sort operations by endpoint and split by host. -func (o Operations) SortSplitByClient() map[string]Operations { +func (o Operations) SortSplitByClient(prefix string) map[string]Operations { clients := o.Clients() o.SortByClient() dst := make(map[string]Operations, clients) @@ -405,6 +405,13 @@ func (o Operations) SortSplitByClient() map[string]Operations { if cl != "" { dst[cl] = o[start:] } + if prefix != "" { + dst2 := make(map[string]Operations, len(dst)) + for k, v := range dst { + dst2[prefix+k] = v + } + return dst2 + } return dst } @@ -891,7 +898,7 @@ func (o Operations) Endpoints() []string { return dst } -func (o Operations) ClientIDs() []string { +func (o Operations) ClientIDs(prefix string) []string { if len(o) == 0 { return nil } @@ -901,7 +908,7 @@ func (o Operations) ClientIDs() []string { } dst := make([]string, 0, len(found)) for k := range found { - dst = append(dst, k) + dst = append(dst, prefix+k) } sort.Strings(dst) return dst