Skip to content

Commit 09e5085

Browse files
committed
perf: Memory-align structs
Running https://github.com/dkorunic/betteralign api/client.go:40:13: 8 bytes saved: struct with 40 pointer bytes could be 32 api/prometheus/v1/api.go:545:24: 32 bytes saved: struct with 136 pointer bytes could be 104 api/prometheus/v1/api.go:569:16: 8 bytes saved: struct with 48 pointer bytes could be 40 api/prometheus/v1/api.go:592:19: 24 bytes saved: struct with 152 pointer bytes could be 128 api/prometheus/v1/api.go:607:20: 16 bytes saved: struct with 104 pointer bytes could be 88 api/prometheus/v1/api.go:633:19: 8 bytes saved: struct with 120 pointer bytes could be 112 api/prometheus/v1/api.go:667:18: 8 bytes saved: struct with 40 pointer bytes could be 32 api/prometheus/v1/api.go:676:17: 40 bytes saved: struct with 120 pointer bytes could be 80 api/prometheus/v1/api.go:707:7: 8 bytes saved: struct with 48 pointer bytes could be 40 api/prometheus/v1/api.go:753:10: 24 bytes saved: struct with 152 pointer bytes could be 128 api/prometheus/v1/api.go:798:10: 16 bytes saved: struct with 104 pointer bytes could be 88 api/prometheus/v1/api.go:822:7: 8 bytes saved: struct with 16 pointer bytes could be 8 prometheus/internal/difflib.go:89:22: 8 bytes saved: struct with 128 pointer bytes could be 120 prometheus/internal/difflib.go:536:18: 8 bytes saved: struct with 120 pointer bytes could be 112 prometheus/internal/go_collector_options.go:28:25: 8 bytes saved: struct with 24 pointer bytes could be 16 prometheus/counter.go:103:14: 32 bytes saved: struct with 96 pointer bytes could be 64 prometheus/desc.go:45:11: 32 bytes saved: struct with 96 pointer bytes could be 64 prometheus/gauge.go:90:12: 8 bytes saved: struct with 40 pointer bytes could be 32 prometheus/go_collector_latest.go:94:18: 8 bytes saved: struct with 120 pointer bytes could be 112 prometheus/go_collector_latest.go:463:21: 16 bytes saved: struct with 72 pointer bytes could be 56 prometheus/histogram.go:359:20: 72 bytes saved: struct with 168 pointer bytes could be 96 prometheus/histogram.go:607:22: 48 bytes saved: struct with 120 pointer bytes could be 72 prometheus/histogram.go:702:16: 8 bytes saved: struct of size 256 could be 248 prometheus/histogram.go:1285:21: 32 bytes saved: struct with 64 pointer bytes could be 32 prometheus/histogram.go:1658:22: 16 bytes saved: struct with 24 pointer bytes could be 8 prometheus/labels.go:41:23: 8 bytes saved: struct with 24 pointer bytes could be 16 prometheus/labels.go:113:21: 16 bytes saved: struct with 32 pointer bytes could be 16 prometheus/metric.go:68:11: 8 bytes saved: struct with 80 pointer bytes could be 72 prometheus/metric.go:207:15: 8 bytes saved: struct with 40 pointer bytes could be 32 prometheus/process_collector.go:24:23: 8 bytes saved: struct with 96 pointer bytes could be 88 prometheus/registry.go:260:15: 24 bytes saved: struct with 56 pointer bytes could be 32 prometheus/summary.go:88:18: 24 bytes saved: struct with 104 pointer bytes could be 80 prometheus/summary.go:274:14: 64 bytes saved: struct with 264 pointer bytes could be 200 prometheus/summary.go:426:26: 32 bytes saved: struct with 88 pointer bytes could be 56 prometheus/summary.go:694:19: 32 bytes saved: struct with 64 pointer bytes could be 32 prometheus/value.go:64:16: 8 bytes saved: struct with 48 pointer bytes could be 40 prometheus/vec.go:36:16: 16 bytes saved: struct with 48 pointer bytes could be 32 prometheus/vec.go:304:28: 16 bytes saved: struct with 40 pointer bytes could be 24 prometheus/vec.go:310:24: 8 bytes saved: struct with 16 pointer bytes could be 8 prometheus/vec.go:317:16: 24 bytes saved: struct with 48 pointer bytes could be 24 prometheus/wrap.go:81:25: 8 bytes saved: struct with 40 pointer bytes could be 32 prometheus/wrap.go:120:24: 8 bytes saved: struct with 40 pointer bytes could be 32 prometheus/wrap.go:161:21: 8 bytes saved: struct with 40 pointer bytes could be 32 prometheus/promhttp/delegator.go:38:30: 24 bytes saved: struct with 48 pointer bytes could be 24 prometheus/promhttp/http.go:349:18: 8 bytes saved: struct of size 120 could be 112 prometheus/promhttp/option.go:32:14: 16 bytes saved: struct with 40 pointer bytes could be 24 examples/middleware/httpmiddleware/httpmiddleware.go:31:17: 16 bytes saved: struct with 40 pointer bytes could be 24 prometheus/graphite/bridge.go:56:13: 32 bytes saved: struct with 88 pointer bytes could be 56 prometheus/graphite/bridge.go:85:13: 40 bytes saved: struct with 96 pointer bytes could be 56 prometheus/push/push.go:70:13: 16 bytes saved: struct with 168 pointer bytes could be 152
1 parent ac114f3 commit 09e5085

23 files changed

+285
-269
lines changed

api/client.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,17 @@ var DefaultRoundTripper http.RoundTripper = &http.Transport{
3838

3939
// Config defines configuration parameters for a new client.
4040
type Config struct {
41-
// The address of the Prometheus to connect to.
42-
Address string
41+
42+
// RoundTripper is used by the Client to drive HTTP requests. If not
43+
// provided, DefaultRoundTripper will be used.
44+
RoundTripper http.RoundTripper
4345

4446
// Client is used by the Client to drive HTTP requests. If not provided,
4547
// a new one based on the provided RoundTripper (or DefaultRoundTripper) will be used.
4648
Client *http.Client
4749

48-
// RoundTripper is used by the Client to drive HTTP requests. If not
49-
// provided, DefaultRoundTripper will be used.
50-
RoundTripper http.RoundTripper
50+
// The address of the Prometheus to connect to.
51+
Address string
5152
}
5253

5354
func (cfg *Config) roundTripper() http.RoundTripper {

api/prometheus/v1/api.go

+30-30
Original file line numberDiff line numberDiff line change
@@ -544,15 +544,15 @@ type BuildinfoResult struct {
544544
// RuntimeinfoResult contains the result from querying the runtimeinfo endpoint.
545545
type RuntimeinfoResult struct {
546546
StartTime time.Time `json:"startTime"`
547-
CWD string `json:"CWD"`
548-
ReloadConfigSuccess bool `json:"reloadConfigSuccess"`
549547
LastConfigTime time.Time `json:"lastConfigTime"`
550-
CorruptionCount int `json:"corruptionCount"`
551-
GoroutineCount int `json:"goroutineCount"`
552-
GOMAXPROCS int `json:"GOMAXPROCS"`
548+
CWD string `json:"CWD"`
553549
GOGC string `json:"GOGC"`
554550
GODEBUG string `json:"GODEBUG"`
555551
StorageRetention string `json:"storageRetention"`
552+
CorruptionCount int `json:"corruptionCount"`
553+
GoroutineCount int `json:"goroutineCount"`
554+
GOMAXPROCS int `json:"GOMAXPROCS"`
555+
ReloadConfigSuccess bool `json:"reloadConfigSuccess"`
556556
}
557557

558558
// SnapshotResult contains the result from querying the snapshot endpoint.
@@ -569,8 +569,8 @@ type RulesResult struct {
569569
type RuleGroup struct {
570570
Name string `json:"name"`
571571
File string `json:"file"`
572-
Interval float64 `json:"interval"`
573572
Rules Rules `json:"rules"`
573+
Interval float64 `json:"interval"`
574574
}
575575

576576
// Recording and alerting rules are stored in the same slice to preserve the order
@@ -590,28 +590,28 @@ type Rules []interface{}
590590

591591
// AlertingRule models a alerting rule.
592592
type AlertingRule struct {
593-
Name string `json:"name"`
594-
Query string `json:"query"`
595-
Duration float64 `json:"duration"`
593+
LastEvaluation time.Time `json:"lastEvaluation"`
596594
Labels model.LabelSet `json:"labels"`
597595
Annotations model.LabelSet `json:"annotations"`
598-
Alerts []*Alert `json:"alerts"`
596+
Name string `json:"name"`
597+
Query string `json:"query"`
599598
Health RuleHealth `json:"health"`
600599
LastError string `json:"lastError,omitempty"`
601-
EvaluationTime float64 `json:"evaluationTime"`
602-
LastEvaluation time.Time `json:"lastEvaluation"`
603600
State string `json:"state"`
601+
Alerts []*Alert `json:"alerts"`
602+
Duration float64 `json:"duration"`
603+
EvaluationTime float64 `json:"evaluationTime"`
604604
}
605605

606606
// RecordingRule models a recording rule.
607607
type RecordingRule struct {
608+
LastEvaluation time.Time `json:"lastEvaluation"`
609+
Labels model.LabelSet `json:"labels,omitempty"`
608610
Name string `json:"name"`
609611
Query string `json:"query"`
610-
Labels model.LabelSet `json:"labels,omitempty"`
611612
Health RuleHealth `json:"health"`
612613
LastError string `json:"lastError,omitempty"`
613614
EvaluationTime float64 `json:"evaluationTime"`
614-
LastEvaluation time.Time `json:"lastEvaluation"`
615615
}
616616

617617
// Alert models an active alert.
@@ -631,15 +631,15 @@ type TargetsResult struct {
631631

632632
// ActiveTarget models an active Prometheus scrape target.
633633
type ActiveTarget struct {
634+
LastScrape time.Time `json:"lastScrape"`
634635
DiscoveredLabels map[string]string `json:"discoveredLabels"`
635636
Labels model.LabelSet `json:"labels"`
636637
ScrapePool string `json:"scrapePool"`
637638
ScrapeURL string `json:"scrapeUrl"`
638639
GlobalURL string `json:"globalUrl"`
639640
LastError string `json:"lastError"`
640-
LastScrape time.Time `json:"lastScrape"`
641-
LastScrapeDuration float64 `json:"lastScrapeDuration"`
642641
Health HealthStatus `json:"health"`
642+
LastScrapeDuration float64 `json:"lastScrapeDuration"`
643643
}
644644

645645
// DroppedTarget models a dropped Prometheus scrape target.
@@ -665,20 +665,20 @@ type Metadata struct {
665665

666666
// queryResult contains result data for a query.
667667
type queryResult struct {
668-
Type model.ValueType `json:"resultType"`
669-
Result interface{} `json:"result"`
668+
Result interface{} `json:"result"`
670669

671670
// The decoded value.
672-
v model.Value
671+
v model.Value
672+
Type model.ValueType `json:"resultType"`
673673
}
674674

675675
// TSDBResult contains the result from querying the tsdb endpoint.
676676
type TSDBResult struct {
677-
HeadStats TSDBHeadStats `json:"headStats"`
678677
SeriesCountByMetricName []Stat `json:"seriesCountByMetricName"`
679678
LabelValueCountByLabelName []Stat `json:"labelValueCountByLabelName"`
680679
MemoryInBytesByLabelName []Stat `json:"memoryInBytesByLabelName"`
681680
SeriesCountByLabelValuePair []Stat `json:"seriesCountByLabelValuePair"`
681+
HeadStats TSDBHeadStats `json:"headStats"`
682682
}
683683

684684
// TSDBHeadStats contains TSDB stats
@@ -707,8 +707,8 @@ func (rg *RuleGroup) UnmarshalJSON(b []byte) error {
707707
v := struct {
708708
Name string `json:"name"`
709709
File string `json:"file"`
710-
Interval float64 `json:"interval"`
711710
Rules []json.RawMessage `json:"rules"`
711+
Interval float64 `json:"interval"`
712712
}{}
713713

714714
if err := json.Unmarshal(b, &v); err != nil {
@@ -751,17 +751,17 @@ func (r *AlertingRule) UnmarshalJSON(b []byte) error {
751751
}
752752

753753
rule := struct {
754-
Name string `json:"name"`
755-
Query string `json:"query"`
756-
Duration float64 `json:"duration"`
754+
LastEvaluation time.Time `json:"lastEvaluation"`
757755
Labels model.LabelSet `json:"labels"`
758756
Annotations model.LabelSet `json:"annotations"`
759-
Alerts []*Alert `json:"alerts"`
757+
Name string `json:"name"`
758+
Query string `json:"query"`
760759
Health RuleHealth `json:"health"`
761760
LastError string `json:"lastError,omitempty"`
762-
EvaluationTime float64 `json:"evaluationTime"`
763-
LastEvaluation time.Time `json:"lastEvaluation"`
764761
State string `json:"state"`
762+
Alerts []*Alert `json:"alerts"`
763+
Duration float64 `json:"duration"`
764+
EvaluationTime float64 `json:"evaluationTime"`
765765
}{}
766766
if err := json.Unmarshal(b, &rule); err != nil {
767767
return err
@@ -796,13 +796,13 @@ func (r *RecordingRule) UnmarshalJSON(b []byte) error {
796796
}
797797

798798
rule := struct {
799+
LastEvaluation time.Time `json:"lastEvaluation"`
800+
Labels model.LabelSet `json:"labels,omitempty"`
799801
Name string `json:"name"`
800802
Query string `json:"query"`
801-
Labels model.LabelSet `json:"labels,omitempty"`
802803
Health RuleHealth `json:"health"`
803804
LastError string `json:"lastError,omitempty"`
804805
EvaluationTime float64 `json:"evaluationTime"`
805-
LastEvaluation time.Time `json:"lastEvaluation"`
806806
}{}
807807
if err := json.Unmarshal(b, &rule); err != nil {
808808
return err
@@ -820,8 +820,8 @@ func (r *RecordingRule) UnmarshalJSON(b []byte) error {
820820

821821
func (qr *queryResult) UnmarshalJSON(b []byte) error {
822822
v := struct {
823-
Type model.ValueType `json:"resultType"`
824823
Result json.RawMessage `json:"result"`
824+
Type model.ValueType `json:"resultType"`
825825
}{}
826826

827827
err := json.Unmarshal(b, &v)

examples/middleware/httpmiddleware/httpmiddleware.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ type Middleware interface {
2929
}
3030

3131
type middleware struct {
32-
buckets []float64
3332
registry prometheus.Registerer
33+
buckets []float64
3434
}
3535

3636
// WrapHandler wraps the given HTTP handler for instrumentation:

prometheus/counter.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -101,22 +101,22 @@ func NewCounter(opts CounterOpts) Counter {
101101
}
102102

103103
type counter struct {
104+
selfCollector
105+
exemplar atomic.Value // Containing nil or a *dto.Exemplar.
106+
107+
desc *Desc
108+
109+
createdTs *timestamppb.Timestamp
110+
111+
// now is for testing purposes, by default it's time.Now.
112+
now func() time.Time
113+
labelPairs []*dto.LabelPair
104114
// valBits contains the bits of the represented float64 value, while
105115
// valInt stores values that are exact integers. Both have to go first
106116
// in the struct to guarantee alignment for atomic operations.
107117
// http://golang.org/pkg/sync/atomic/#pkg-note-BUG
108118
valBits uint64
109119
valInt uint64
110-
111-
selfCollector
112-
desc *Desc
113-
114-
createdTs *timestamppb.Timestamp
115-
labelPairs []*dto.LabelPair
116-
exemplar atomic.Value // Containing nil or a *dto.Exemplar.
117-
118-
// now is for testing purposes, by default it's time.Now.
119-
now func() time.Time
120120
}
121121

122122
func (c *counter) Desc() *Desc {

prometheus/desc.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,19 @@ import (
4343
//
4444
// Use NewDesc to create new Desc instances.
4545
type Desc struct {
46+
// err is an error that occurred during construction. It is reported on
47+
// registration time.
48+
err error
49+
// variableLabels contains names of labels and normalization function for
50+
// which the metric maintains variable values.
51+
variableLabels *compiledLabels
4652
// fqName has been built from Namespace, Subsystem, and Name.
4753
fqName string
4854
// help provides some helpful information about this metric.
4955
help string
5056
// constLabelPairs contains precalculated DTO label pairs based on
5157
// the constant labels.
5258
constLabelPairs []*dto.LabelPair
53-
// variableLabels contains names of labels and normalization function for
54-
// which the metric maintains variable values.
55-
variableLabels *compiledLabels
5659
// id is a hash of the values of the ConstLabels and fqName. This
5760
// must be unique among all registered descriptors and can therefore be
5861
// used as an identifier of the descriptor.
@@ -61,9 +64,6 @@ type Desc struct {
6164
// Help string. Each Desc with the same fqName must have the same
6265
// dimHash.
6366
dimHash uint64
64-
// err is an error that occurred during construction. It is reported on
65-
// registration time.
66-
err error
6767
}
6868

6969
// NewDesc allocates and initializes a new Desc. Errors are recorded in the Desc

prometheus/gauge.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,14 @@ func NewGauge(opts GaugeOpts) Gauge {
8888
}
8989

9090
type gauge struct {
91-
// valBits contains the bits of the represented float64 value. It has
92-
// to go first in the struct to guarantee alignment for atomic
93-
// operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG
94-
valBits uint64
95-
9691
selfCollector
9792

9893
desc *Desc
9994
labelPairs []*dto.LabelPair
95+
// valBits contains the bits of the represented float64 value. It has
96+
// to go first in the struct to guarantee alignment for atomic
97+
// operations. http://golang.org/pkg/sync/atomic/#pkg-note-BUG
98+
valBits uint64
10099
}
101100

102101
func (g *gauge) Desc() *Desc {

prometheus/go_collector_latest.go

+17-14
Original file line numberDiff line numberDiff line change
@@ -94,19 +94,17 @@ func bestEffortLookupRM(lookup []string) []metrics.Description {
9494
type goCollector struct {
9595
base baseGoCollector
9696

97-
// mu protects updates to all fields ensuring a consistent
98-
// snapshot is always produced by Collect.
99-
mu sync.Mutex
97+
// sampleMap allows lookup for MemStats metrics and runtime/metrics histograms for exact sums.
98+
sampleMap map[string]*metrics.Sample
99+
100+
rmExactSumMapForHist map[string]string
100101

101102
// Contains all samples that has to retrieved from runtime/metrics (not all of them will be exposed).
102103
sampleBuf []metrics.Sample
103-
// sampleMap allows lookup for MemStats metrics and runtime/metrics histograms for exact sums.
104-
sampleMap map[string]*metrics.Sample
105104

106105
// rmExposedMetrics represents all runtime/metrics package metrics
107106
// that were configured to be exposed.
108-
rmExposedMetrics []collectorMetric
109-
rmExactSumMapForHist map[string]string
107+
rmExposedMetrics []collectorMetric
110108

111109
// With Go 1.17, the runtime/metrics package was introduced.
112110
// From that point on, metric names produced by the runtime/metrics
@@ -115,7 +113,12 @@ type goCollector struct {
115113
//
116114
// This field exists to export the same values under the old names
117115
// as well.
118-
msMetrics memStatsMetrics
116+
msMetrics memStatsMetrics
117+
118+
// mu protects updates to all fields ensuring a consistent
119+
// snapshot is always produced by Collect.
120+
mu sync.Mutex
121+
119122
msMetricsEnabled bool
120123
}
121124

@@ -464,17 +467,17 @@ type batchHistogram struct {
464467
selfCollector
465468

466469
// Static fields updated only once.
467-
desc *Desc
468-
hasSum bool
470+
desc *Desc
471+
buckets []float64 // Inclusive lower bounds, like runtime/metrics.
472+
counts []uint64
473+
sum float64 // Used if hasSum is true.
469474

470475
// Because this histogram operates in batches, it just uses a
471476
// single mutex for everything. updates are always serialized
472477
// but Write calls may operate concurrently with updates.
473478
// Contention between these two sources should be rare.
474-
mu sync.Mutex
475-
buckets []float64 // Inclusive lower bounds, like runtime/metrics.
476-
counts []uint64
477-
sum float64 // Used if hasSum is true.
479+
mu sync.Mutex
480+
hasSum bool
478481
}
479482

480483
// newBatchHistogram creates a new batch histogram value with the given

0 commit comments

Comments
 (0)