Skip to content

Conversation

@sd2k
Copy link
Contributor

@sd2k sd2k commented Oct 6, 2025

There are already fast paths for certain types, but floats and various
others were missing, so we were falling back to a very allocation-heavy
interface{} method where every value was boxed then unboxed later.
Now that we have generic vectors we can read directly into them and
avoid a ton of allocations, which can improve things,
especially for larger vectors.

I think the 10_000 benches are dominated by string allocations so the sec/op
doesn't change much but there are 3x fewer allocs which will reduce GC
pressure significantly for larger frames.

Interesting benchmark results:

                                                │    old.txt    │               new.txt                │
                                                │    sec/op     │    sec/op     vs base                │
FrameUnmarshalJSON_Sizes/Rows_10                   6.019µ ±  2%   5.584µ ±  2%   -7.22% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_100                  29.21µ ±  1%   25.36µ ±  1%  -13.17% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_1000                 272.1µ ±  1%   233.1µ ±  2%  -14.34% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_10000                2.574m ±  2%   2.599m ±  1%        ~ (p=0.123 n=10)

                                    │    old.txt    │                new.txt                │
                                    │      B/s      │      B/s       vs base                │
FrameUnmarshalJSON_Sizes/Rows_10      83.19Mi ±  2%   89.67Mi ±  2%   +7.78% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_100     103.4Mi ±  1%   119.1Mi ±  1%  +15.17% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_1000    110.1Mi ±  1%   128.5Mi ±  2%  +16.74% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_10000   122.9Mi ±  2%   121.7Mi ±  1%        ~ (p=0.123 n=10)

                                                │    old.txt    │                new.txt                 │
                                                │     B/op      │     B/op      vs base                  │
FrameUnmarshalJSON_Sizes/Rows_10                   3.328Ki ± 0%   2.953Ki ± 0%  -11.27% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_100                  15.50Ki ± 0%   12.67Ki ± 0%  -18.25% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_1000                132.44Ki ± 0%   98.73Ki ± 0%  -25.45% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_10000                1.822Mi ± 0%   1.320Mi ± 0%  -27.59% (p=0.000 n=10)

                                                │   old.txt   │                new.txt                │
                                                │  allocs/op  │  allocs/op   vs base                  │
FrameUnmarshalJSON_Sizes/Rows_10                  100.00 ± 0%    77.00 ± 0%  -23.00% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_100                  373.0 ± 0%    170.0 ± 0%  -54.42% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_1000                3.076k ± 0%   1.073k ± 0%  -65.12% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_10000               30.09k ± 0%   10.08k ± 0%  -66.50% (p=0.000 n=10)

all:

======================================================================
Benchmark Comparison Results
======================================================================
goos: linux
goarch: amd64
pkg: github.com/grafana/grafana-plugin-sdk-go/data
cpu: AMD Ryzen 9 7950X 16-Core Processor
                                                │    old.txt    │               new.txt                │
                                                │    sec/op     │    sec/op     vs base                │
FrameToJSON_IncludeAll                            10.069µ ±  1%   9.991µ ±  1%        ~ (p=0.072 n=10)
FrameToJSON_SchemaOnly                             5.299µ ±  1%   5.365µ ±  1%   +1.26% (p=0.009 n=10)
FrameToJSON_DataOnly                               4.622µ ±  1%   4.645µ ±  2%        ~ (p=0.579 n=10)
FrameJSONCache_Create                              10.16µ ±  1%   10.11µ ±  0%        ~ (p=0.075 n=10)
FrameJSONCache_Bytes/IncludeAll                    461.6n ± 10%   455.2n ± 10%        ~ (p=0.218 n=10)
FrameJSONCache_Bytes/SchemaOnly                    354.1n ±  2%   356.2n ±  2%        ~ (p=0.382 n=10)
FrameJSONCache_Bytes/DataOnly                      184.5n ±  3%   181.6n ±  4%        ~ (p=0.078 n=10)
FrameUnmarshalJSON                                 80.41µ ±  2%   80.70µ ±  2%        ~ (p=0.796 n=10)
FrameUnmarshalJSON_FromFrameToJSON                 80.56µ ±  2%   79.34µ ±  2%        ~ (p=0.089 n=10)
FrameMarshalJSON_Sizes/Rows_10                     3.415µ ±  2%   3.410µ ±  1%        ~ (p=0.436 n=10)
FrameMarshalJSON_Sizes/Rows_100                    21.38µ ±  1%   21.39µ ±  1%        ~ (p=0.896 n=10)
FrameMarshalJSON_Sizes/Rows_1000                   205.7µ ±  1%   204.0µ ±  2%   -0.81% (p=0.007 n=10)
FrameMarshalJSON_Sizes/Rows_10000                  1.966m ±  1%   1.935m ±  2%   -1.55% (p=0.007 n=10)
FrameUnmarshalJSON_Sizes/Rows_10                   6.019µ ±  2%   5.584µ ±  2%   -7.22% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_100                  29.21µ ±  1%   25.36µ ±  1%  -13.17% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_1000                 272.1µ ±  1%   233.1µ ±  2%  -14.34% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_10000                2.574m ±  2%   2.599m ±  1%        ~ (p=0.123 n=10)
FrameMarshalJSON_FieldTypes/TimeNoNanos            52.14µ ±  1%   51.18µ ±  2%   -1.84% (p=0.003 n=10)
FrameMarshalJSON_FieldTypes/TimeWithNanos          90.23µ ±  2%   90.99µ ±  3%        ~ (p=0.315 n=10)
FrameMarshalJSON_FieldTypes/NullableTime           49.15µ ±  2%   49.76µ ±  3%        ~ (p=0.063 n=10)
FrameMarshalJSON_FieldTypes/Float64Clean           64.32µ ±  1%   64.04µ ±  1%        ~ (p=0.165 n=10)
FrameMarshalJSON_FieldTypes/Float64WithSpecials    60.91µ ±  1%   60.29µ ±  1%   -1.01% (p=0.029 n=10)
FrameMarshalJSON_FieldTypes/Float32WithSpecials    59.00µ ±  1%   58.67µ ±  1%        ~ (p=0.075 n=10)
FrameMarshalJSON_FieldTypes/Int64                  25.49µ ±  2%   26.06µ ±  3%        ~ (p=0.063 n=10)
FrameMarshalJSON_FieldTypes/NullableInt64          25.35µ ±  1%   25.44µ ±  3%        ~ (p=0.271 n=10)
FrameMarshalJSON_FieldTypes/Uint64                 25.04µ ±  2%   24.78µ ±  2%        ~ (p=0.165 n=10)
FrameMarshalJSON_FieldTypes/NullableUint64         25.18µ ±  1%   25.09µ ±  1%   -0.36% (p=0.023 n=10)
FrameMarshalJSON_FieldTypes/String                 52.35µ ±  1%   52.24µ ±  2%        ~ (p=1.000 n=10)
FrameMarshalJSON_FieldTypes/NullableString         50.64µ ±  2%   50.17µ ±  3%        ~ (p=0.481 n=10)
FrameMarshalJSON_FieldTypes/Bool                   26.08µ ±  1%   26.08µ ±  2%        ~ (p=0.481 n=10)
FrameMarshalJSON_FieldTypes/JSON                   67.88µ ±  1%   67.22µ ±  3%   -0.97% (p=0.035 n=10)
FrameMarshalJSON_FieldTypes/Enum                   17.48µ ±  1%   17.86µ ±  2%   +2.18% (p=0.029 n=10)
FrameMarshalJSON_Parallel                          33.38µ ±  2%   33.13µ ±  3%        ~ (p=0.796 n=10)
FrameMarshalJSON_ParallelLarge                     207.2µ ±  1%   204.3µ ±  2%   -1.41% (p=0.015 n=10)
FrameUnmarshalJSON_Parallel                        79.99µ ±  3%   79.83µ ±  2%        ~ (p=0.481 n=10)
FrameMarshalJSON_WithLabels/NoLabels               153.3µ ±  2%   153.3µ ±  3%        ~ (p=0.529 n=10)
FrameMarshalJSON_WithLabels/SmallLabels            154.5µ ±  2%   152.0µ ±  1%   -1.62% (p=0.007 n=10)
FrameMarshalJSON_WithLabels/ManyLabels             154.5µ ±  1%   152.9µ ±  4%        ~ (p=0.481 n=10)
FrameMarshalJSON_WithMeta/NoMeta                   152.4µ ±  1%   151.5µ ±  1%        ~ (p=0.218 n=10)
FrameMarshalJSON_WithMeta/WithMeta                 155.5µ ±  1%   156.3µ ±  2%        ~ (p=0.579 n=10)
ArrowToJSON                                        37.96µ ±  2%   37.82µ ±  1%        ~ (p=0.436 n=10)
FrameRoundtrip                                     122.2µ ±  3%   120.0µ ±  2%        ~ (p=0.075 n=10)
FrameToJSON                                        10.33µ ±  1%   10.34µ ±  1%        ~ (p=0.897 n=10)
FrameMarshalJSONStd                                33.52µ ±  2%   33.52µ ±  3%        ~ (p=0.796 n=10)
FrameMarshalJSONIter                               10.22µ ±  1%   10.11µ ±  1%        ~ (p=0.060 n=10)
geomean                                            34.85µ         34.46µ         -1.12%

                                    │    old.txt    │                new.txt                │
                                    │      B/s      │      B/s       vs base                │
FrameToJSON_IncludeAll                538.6Mi ±  1%   542.9Mi ±  1%        ~ (p=0.072 n=10)
FrameToJSON_SchemaOnly                658.9Mi ±  1%   650.8Mi ±  1%   -1.24% (p=0.009 n=10)
FrameToJSON_DataOnly                  418.3Mi ±  1%   416.2Mi ±  2%        ~ (p=0.579 n=10)
FrameJSONCache_Create                 534.1Mi ±  1%   536.7Mi ±  0%        ~ (p=0.075 n=10)
FrameJSONCache_Bytes/IncludeAll       11.47Gi ± 12%   11.63Gi ± 11%        ~ (p=0.218 n=10)
FrameJSONCache_Bytes/SchemaOnly       9.631Gi ±  2%   9.573Gi ±  2%        ~ (p=0.393 n=10)
FrameJSONCache_Bytes/DataOnly         10.23Gi ±  3%   10.39Gi ±  3%        ~ (p=0.075 n=10)
FrameUnmarshalJSON                    67.57Mi ±  2%   67.32Mi ±  2%        ~ (p=0.796 n=10)
FrameUnmarshalJSON_FromFrameToJSON    67.32Mi ±  2%   68.36Mi ±  2%        ~ (p=0.086 n=10)
FrameMarshalJSON_Sizes/Rows_10        146.6Mi ±  2%   146.8Mi ±  1%        ~ (p=0.436 n=10)
FrameMarshalJSON_Sizes/Rows_100       141.3Mi ±  1%   141.3Mi ±  1%        ~ (p=0.896 n=10)
FrameMarshalJSON_Sizes/Rows_1000      145.6Mi ±  1%   146.8Mi ±  2%   +0.82% (p=0.007 n=10)
FrameMarshalJSON_Sizes/Rows_10000     160.9Mi ±  1%   163.5Mi ±  2%   +1.58% (p=0.007 n=10)
FrameUnmarshalJSON_Sizes/Rows_10      83.19Mi ±  2%   89.67Mi ±  2%   +7.78% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_100     103.4Mi ±  1%   119.1Mi ±  1%  +15.17% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_1000    110.1Mi ±  1%   128.5Mi ±  2%  +16.74% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_10000   122.9Mi ±  2%   121.7Mi ±  1%        ~ (p=0.123 n=10)
ArrowToJSON                           142.9Mi ±  2%   143.4Mi ±  1%        ~ (p=0.436 n=10)
FrameToJSON                           525.0Mi ±  1%   524.6Mi ±  1%        ~ (p=0.928 n=10)
FrameMarshalJSONStd                   162.1Mi ±  2%   162.1Mi ±  3%        ~ (p=0.796 n=10)
FrameMarshalJSONIter                  530.4Mi ±  1%   536.5Mi ±  1%        ~ (p=0.063 n=10)
geomean                               341.6Mi         348.6Mi         +2.07%

                                                │    old.txt    │                new.txt                 │
                                                │     B/op      │     B/op      vs base                  │
FrameToJSON_IncludeAll                             8.120Ki ± 0%   8.120Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameToJSON_SchemaOnly                             4.821Ki ± 0%   4.821Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameToJSON_DataOnly                               3.297Ki ± 0%   3.297Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameJSONCache_Create                              8.120Ki ± 0%   8.120Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameJSONCache_Bytes/IncludeAll                    6.000Ki ± 0%   6.000Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameJSONCache_Bytes/SchemaOnly                    4.000Ki ± 0%   4.000Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameJSONCache_Bytes/DataOnly                      2.000Ki ± 0%   2.000Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameUnmarshalJSON                                 24.84Ki ± 0%   24.54Ki ± 0%   -1.23% (p=0.000 n=10)
FrameUnmarshalJSON_FromFrameToJSON                 24.84Ki ± 0%   24.54Ki ± 0%   -1.23% (p=0.000 n=10)
FrameMarshalJSON_Sizes/Rows_10                     1.203Ki ± 0%   1.203Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_Sizes/Rows_100                    6.329Ki ± 0%   6.329Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_Sizes/Rows_1000                   64.09Ki ± 0%   64.09Ki ± 0%        ~ (p=1.000 n=10)
FrameMarshalJSON_Sizes/Rows_10000                  656.2Ki ± 0%   656.2Ki ± 0%        ~ (p=0.420 n=10)
FrameUnmarshalJSON_Sizes/Rows_10                   3.328Ki ± 0%   2.953Ki ± 0%  -11.27% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_100                  15.50Ki ± 0%   12.67Ki ± 0%  -18.25% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_1000                132.44Ki ± 0%   98.73Ki ± 0%  -25.45% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_10000                1.822Mi ± 0%   1.320Mi ± 0%  -27.59% (p=0.000 n=10)
FrameMarshalJSON_FieldTypes/TimeNoNanos            16.00Ki ± 0%   16.00Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/TimeWithNanos          36.01Ki ± 0%   36.01Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/NullableTime           13.50Ki ± 0%   13.50Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Float64Clean           12.00Ki ± 0%   12.00Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Float64WithSpecials    13.25Ki ± 0%   13.25Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Float32WithSpecials    13.25Ki ± 0%   13.25Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Int64                  8.001Ki ± 0%   8.001Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/NullableInt64          9.501Ki ± 0%   9.501Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Uint64                 8.001Ki ± 0%   8.001Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/NullableUint64         9.501Ki ± 0%   9.501Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/String                 24.00Ki ± 0%   24.00Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/NullableString         24.00Ki ± 0%   24.00Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Bool                   12.00Ki ± 0%   12.00Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/JSON                   28.00Ki ± 0%   28.00Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Enum                   4.500Ki ± 0%   4.500Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_Parallel                          14.12Ki ± 0%   14.12Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_ParallelLarge                     64.09Ki ± 0%   64.09Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameUnmarshalJSON_Parallel                        24.84Ki ± 0%   24.54Ki ± 0%   -1.23% (p=0.000 n=10)
FrameMarshalJSON_WithLabels/NoLabels               40.05Ki ± 0%   40.05Ki ± 0%        ~ (p=1.000 n=10)
FrameMarshalJSON_WithLabels/SmallLabels            40.06Ki ± 0%   40.06Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_WithLabels/ManyLabels             40.06Ki ± 0%   40.06Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_WithMeta/NoMeta                   40.05Ki ± 0%   40.05Ki ± 0%        ~ (p=0.582 n=10)
FrameMarshalJSON_WithMeta/WithMeta                 40.60Ki ± 0%   40.60Ki ± 0%        ~ (p=1.000 n=10) ¹
ArrowToJSON                                        54.22Ki ± 0%   54.21Ki ± 0%        ~ (p=0.491 n=10)
FrameRoundtrip                                     38.97Ki ± 0%   38.67Ki ± 0%   -0.78% (p=0.000 n=10)
FrameToJSON                                        8.120Ki ± 0%   8.120Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSONStd                                14.12Ki ± 0%   14.12Ki ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSONIter                               8.049Ki ± 0%   8.049Ki ± 0%        ~ (p=1.000 n=10) ¹
geomean                                            17.27Ki        16.90Ki        -2.16%
¹ all samples are equal

                                                │   old.txt   │                new.txt                │
                                                │  allocs/op  │  allocs/op   vs base                  │
FrameToJSON_IncludeAll                             31.00 ± 0%    31.00 ± 0%        ~ (p=1.000 n=10) ¹
FrameToJSON_SchemaOnly                             26.00 ± 0%    26.00 ± 0%        ~ (p=1.000 n=10) ¹
FrameToJSON_DataOnly                               6.000 ± 0%    6.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameJSONCache_Create                              32.00 ± 0%    32.00 ± 0%        ~ (p=1.000 n=10) ¹
FrameJSONCache_Bytes/IncludeAll                    1.000 ± 0%    1.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameJSONCache_Bytes/SchemaOnly                    1.000 ± 0%    1.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameJSONCache_Bytes/DataOnly                      1.000 ± 0%    1.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameUnmarshalJSON                                 770.0 ± 0%    757.0 ± 0%   -1.69% (p=0.000 n=10)
FrameUnmarshalJSON_FromFrameToJSON                 770.0 ± 0%    757.0 ± 0%   -1.69% (p=0.000 n=10)
FrameMarshalJSON_Sizes/Rows_10                     3.000 ± 0%    3.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_Sizes/Rows_100                    3.000 ± 0%    3.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_Sizes/Rows_1000                   3.000 ± 0%    3.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_Sizes/Rows_10000                  4.000 ± 0%    4.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameUnmarshalJSON_Sizes/Rows_10                  100.00 ± 0%    77.00 ± 0%  -23.00% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_100                  373.0 ± 0%    170.0 ± 0%  -54.42% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_1000                3.076k ± 0%   1.073k ± 0%  -65.12% (p=0.000 n=10)
FrameUnmarshalJSON_Sizes/Rows_10000               30.09k ± 0%   10.08k ± 0%  -66.50% (p=0.000 n=10)
FrameMarshalJSON_FieldTypes/TimeNoNanos            2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/TimeWithNanos          3.000 ± 0%    3.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/NullableTime           2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Float64Clean           2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Float64WithSpecials    2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Float32WithSpecials    2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Int64                  2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/NullableInt64          2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Uint64                 2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/NullableUint64         2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/String                 2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/NullableString         2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Bool                   2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/JSON                   2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_FieldTypes/Enum                   2.000 ± 0%    2.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_Parallel                          32.00 ± 0%    32.00 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_ParallelLarge                     3.000 ± 0%    3.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameUnmarshalJSON_Parallel                        770.0 ± 0%    757.0 ± 0%   -1.69% (p=0.000 n=10)
FrameMarshalJSON_WithLabels/NoLabels               3.000 ± 0%    3.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_WithLabels/SmallLabels            3.000 ± 0%    3.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_WithLabels/ManyLabels             3.000 ± 0%    3.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_WithMeta/NoMeta                   3.000 ± 0%    3.000 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSON_WithMeta/WithMeta                 15.00 ± 0%    15.00 ± 0%        ~ (p=1.000 n=10) ¹
ArrowToJSON                                        666.0 ± 0%    666.0 ± 0%        ~ (p=1.000 n=10) ¹
FrameRoundtrip                                     802.0 ± 0%    789.0 ± 0%   -1.62% (p=0.000 n=10)
FrameToJSON                                        32.00 ± 0%    32.00 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSONStd                                32.00 ± 0%    32.00 ± 0%        ~ (p=1.000 n=10) ¹
FrameMarshalJSONIter                               29.00 ± 0%    29.00 ± 0%        ~ (p=1.000 n=10) ¹
geomean                                            11.89         11.06        -6.99%
¹ all samples are equal

There are already fast paths for certain types, but floats and various
others were missing, so we were falling back to a very allocation-heavy
interface{} method where every value was boxed then unboxed later.
Now that we have generic vectors we can read directly into them and
avoid a ton of allocations, which speeds things up dramatically,
especially for larger vectors.

Benchmarks for JSON unmarshalling:

```
goos: linux
goarch: amd64
pkg: github.com/grafana/grafana-plugin-sdk-go/data
cpu: AMD Ryzen 9 7950X 16-Core Processor
                                       │ benchmark-baseline.txt │         benchmark-final.txt         │
                                       │         sec/op         │    sec/op     vs base               │
FrameUnmarshalJSON-32                              77.72µ ± ∞ ¹   76.13µ ± ∞ ¹        ~ (p=0.421 n=5)
FrameUnmarshalJSON_FromFrameToJSON-32              74.86µ ± ∞ ¹   76.81µ ± ∞ ¹   +2.60% (p=0.032 n=5)
FrameUnmarshalJSON_Sizes/Rows_10-32                5.345µ ± ∞ ¹   5.065µ ± ∞ ¹   -5.24% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_100-32               25.44µ ± ∞ ¹   22.27µ ± ∞ ¹  -12.44% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_1000-32              231.4µ ± ∞ ¹   199.0µ ± ∞ ¹  -13.99% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_10000-32             2.523m ± ∞ ¹   2.090m ± ∞ ¹  -17.19% (p=0.008 n=5)
FrameUnmarshalJSON_Parallel-32                     25.92µ ± ∞ ¹   25.42µ ± ∞ ¹        ~ (p=1.000 n=5)
geomean                                            73.85µ         68.36µ         -7.43%
¹ need >= 6 samples for confidence interval at level 0.95

                                       │ benchmark-baseline.txt │         benchmark-final.txt          │
                                       │          B/s           │      B/s       vs base               │
FrameUnmarshalJSON-32                             69.90Mi ± ∞ ¹   71.37Mi ± ∞ ¹        ~ (p=0.421 n=5)
FrameUnmarshalJSON_FromFrameToJSON-32             72.45Mi ± ∞ ¹   70.61Mi ± ∞ ¹   -2.54% (p=0.040 n=5)
FrameUnmarshalJSON_Sizes/Rows_10-32               93.67Mi ± ∞ ¹   98.85Mi ± ∞ ¹   +5.53% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_100-32              118.8Mi ± ∞ ¹   135.6Mi ± ∞ ¹  +14.21% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_1000-32             129.4Mi ± ∞ ¹   150.5Mi ± ∞ ¹  +16.26% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_10000-32            125.4Mi ± ∞ ¹   151.4Mi ± ∞ ¹  +20.75% (p=0.008 n=5)
geomean                                           98.52Mi         107.5Mi         +9.07%
¹ need >= 6 samples for confidence interval at level 0.95

                                       │ benchmark-baseline.txt │         benchmark-final.txt          │
                                       │          B/op          │     B/op       vs base               │
FrameUnmarshalJSON-32                             24.84Ki ± ∞ ¹   24.54Ki ± ∞ ¹   -1.23% (p=0.008 n=5)
FrameUnmarshalJSON_FromFrameToJSON-32             24.84Ki ± ∞ ¹   24.54Ki ± ∞ ¹   -1.23% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_10-32               3.328Ki ± ∞ ¹   2.953Ki ± ∞ ¹  -11.27% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_100-32              15.50Ki ± ∞ ¹   12.67Ki ± ∞ ¹  -18.25% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_1000-32            132.44Ki ± ∞ ¹   98.73Ki ± ∞ ¹  -25.45% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_10000-32            1.822Mi ± ∞ ¹   1.320Mi ± ∞ ¹  -27.59% (p=0.008 n=5)
FrameUnmarshalJSON_Parallel-32                    24.84Ki ± ∞ ¹   24.54Ki ± ∞ ¹   -1.22% (p=0.008 n=5)
geomean                                           41.02Ki         35.69Ki        -13.00%
¹ need >= 6 samples for confidence interval at level 0.95

                                       │ benchmark-baseline.txt │         benchmark-final.txt         │
                                       │       allocs/op        │  allocs/op    vs base               │
FrameUnmarshalJSON-32                               770.0 ± ∞ ¹    757.0 ± ∞ ¹   -1.69% (p=0.008 n=5)
FrameUnmarshalJSON_FromFrameToJSON-32               770.0 ± ∞ ¹    757.0 ± ∞ ¹   -1.69% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_10-32                100.00 ± ∞ ¹    77.00 ± ∞ ¹  -23.00% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_100-32                373.0 ± ∞ ¹    170.0 ± ∞ ¹  -54.42% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_1000-32              3.076k ± ∞ ¹   1.073k ± ∞ ¹  -65.12% (p=0.008 n=5)
FrameUnmarshalJSON_Sizes/Rows_10000-32             30.09k ± ∞ ¹   10.08k ± ∞ ¹  -66.50% (p=0.008 n=5)
FrameUnmarshalJSON_Parallel-32                      770.0 ± ∞ ¹    757.0 ± ∞ ¹   -1.69% (p=0.008 n=5)
geomean                                            1.067k          671.3        -37.10%
¹ need >= 6 samples for confidence interval at level 0.95
```
@sd2k sd2k requested a review from toddtreece October 6, 2025 22:55
@sd2k sd2k changed the title PoC: Use generics instead of code gen for vectors opt: add more fast paths when reading vector from JSON Oct 6, 2025
Copy link
Member

@toddtreece toddtreece left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

@github-project-automation github-project-automation bot moved this from 📬 Triage to 🔬 In review in Plugins Platform / Grafana Community Oct 7, 2025
@sd2k sd2k marked this pull request as ready for review October 7, 2025 05:05
@sd2k sd2k requested a review from a team as a code owner October 7, 2025 05:05
@sd2k sd2k merged commit 71dc29e into toddtreece/generics Oct 7, 2025
6 checks passed
@sd2k sd2k deleted the bsull/more-generics branch October 7, 2025 05:51
@github-project-automation github-project-automation bot moved this from 🔬 In review to 🚀 Shipped in Plugins Platform / Grafana Community Oct 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

2 participants