[Cobalt 1.1 privacy] Handle unset event_code_buffer_max in
PrivacyEncodingParamsCalculator
If a metric does not have event_code_buffer_max set, the
PrivacyEncodingParamsCalculator now computes the number of
valid event vectors for the metric and uses that as the
effective event_code_buffer_max when computing sparsity.
Bug: 72699
Change-Id: I08260ac98eb2ae0af103bacdc767b6875f0adcd5
Reviewed-on: https://fuchsia-review.googlesource.com/c/cobalt/+/504739
Commit-Queue: Laura Peskin <pesk@google.com>
Reviewed-by: Jared Weinstein <jaredweinstein@google.com>
diff --git a/src/bin/config_parser/src/privacy/privacy_encoding_params.go b/src/bin/config_parser/src/privacy/privacy_encoding_params.go
index 5beb245..7b8f5f1 100644
--- a/src/bin/config_parser/src/privacy/privacy_encoding_params.go
+++ b/src/bin/config_parser/src/privacy/privacy_encoding_params.go
@@ -339,7 +339,7 @@
config.ReportDefinition_SELECT_MOST_COMMON:
numEventVectors, err = 1, nil
case config.ReportDefinition_AT_LEAST_ONCE:
- numEventVectors, err = metric.EventCodeBufferMax, nil
+ numEventVectors, err = getEventCodeBufferMax(metric), nil
default:
err = fmt.Errorf("unexpected LocalAggregationProcedure: %v", report.LocalAggregationProcedure)
}
@@ -352,7 +352,7 @@
config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS,
config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS,
config.ReportDefinition_STRING_COUNTS:
- numEventVectors, err = metric.EventCodeBufferMax, nil
+ numEventVectors, err = getEventCodeBufferMax(metric), nil
default:
err = fmt.Errorf("unsupported ReportType: %v", report.ReportType)
@@ -360,6 +360,33 @@
return numEventVectors, err
}
+// Returns the maximum number of event vectors for which a device stores local aggregates.
+// This is either the event_code_buffer_max value specified in the MetricDefinition, or
+// (if that field is unset) the total number of valid event vectors.
+func getEventCodeBufferMax(metric *config.MetricDefinition) (bufferMax uint64) {
+ if metric.EventCodeBufferMax != 0 {
+ return metric.EventCodeBufferMax
+ }
+ return numEventVectors(metric)
+}
+
+// Returns the total number of valid event vectors for a MetricDefinition.
+func numEventVectors(metric *config.MetricDefinition) (numEventVectors uint64) {
+ numEventVectors = 1
+ for _, dim := range metric.MetricDimensions {
+ numEventVectors *= uint64(numEventCodes(dim))
+ }
+ return numEventVectors
+}
+
+// A helper function returning the number of valid event codes for a MetricDimension.
+func numEventCodes(dim *config.MetricDefinition_MetricDimension) (numEventCodes uint32) {
+ if dim.MaxEventCode != 0 {
+ return dim.MaxEventCode + 1
+ }
+ return uint32(len(dim.EventCodes))
+}
+
// Returns the max number of buckets which may be populated in a contribution for |report| for each event vector defined in |metric|.
// Returns 1 for reports for which a contribution consists of a single integer per event vector.
func getNumBucketsPerEventVector(metric *config.MetricDefinition, report *config.ReportDefinition) (numBuckets uint64, err error) {
diff --git a/src/bin/config_parser/src/privacy/privacy_encoding_params_test.go b/src/bin/config_parser/src/privacy/privacy_encoding_params_test.go
index da98652..d084d70 100644
--- a/src/bin/config_parser/src/privacy/privacy_encoding_params_test.go
+++ b/src/bin/config_parser/src/privacy/privacy_encoding_params_test.go
@@ -181,21 +181,74 @@
}
}
+func TestGetEventCodeBufferMax(t *testing.T) {
+ var eventCodeBufferMax uint64 = 5
+ var maxEventCode uint32 = 2
+
+ dimensionMaxEventCode := config.MetricDefinition_MetricDimension{
+ Dimension: "dim0",
+ MaxEventCode: maxEventCode,
+ }
+ dimensionNoMaxEventCode := config.MetricDefinition_MetricDimension{
+ Dimension: "dim1",
+ EventCodes: map[uint32]string{0: "event0", 1: "event1", 5: "event5"},
+ }
+ metricDimensions := []*config.MetricDefinition_MetricDimension{
+ &dimensionMaxEventCode,
+ &dimensionNoMaxEventCode,
+ }
+
+ metricMaxSet := config.MetricDefinition{
+ MetricName: "MetricWithEventCodeBufferMaxSet",
+ EventCodeBufferMax: eventCodeBufferMax,
+ MetricDimensions: metricDimensions,
+ }
+ metricMaxUnset := config.MetricDefinition{
+ MetricName: "MetricWithEventCodeBufferMaxUnset",
+ MetricDimensions: metricDimensions,
+ }
+ var tests = []struct {
+ metric *config.MetricDefinition
+ expected uint64
+ }{
+ {&metricMaxSet, uint64(eventCodeBufferMax)},
+ {&metricMaxUnset, uint64((maxEventCode + 1) * 3)},
+ }
+ for _, test := range tests {
+ result := getEventCodeBufferMax(test.metric)
+ if result != test.expected {
+ t.Errorf("eventCodeBufferMax() for metric %s: expected %d, got %d",
+ test.metric.MetricName, test.expected, result)
+ }
+ }
+
+}
+
func TestGetSparsityForReport(t *testing.T) {
var eventCodeBufferMax uint64 = 5
var stringBufferMax uint32 = 3
var numLinearBuckets uint32 = 7
+ var maxEventCode uint32 = 2
linearBuckets := config.LinearIntegerBuckets{NumBuckets: numLinearBuckets}
buckets := config.IntegerBuckets{
Buckets: &config.IntegerBuckets_Linear{&linearBuckets},
}
+ dimension := config.MetricDefinition_MetricDimension{
+ Dimension: "dim0",
+ MaxEventCode: maxEventCode,
+ }
+
// Metrics
occurrenceMetric := config.MetricDefinition{
MetricType: config.MetricDefinition_OCCURRENCE,
EventCodeBufferMax: eventCodeBufferMax,
}
+ occurrenceMetricEventCodeBufferMaxUnset := config.MetricDefinition{
+ MetricType: config.MetricDefinition_OCCURRENCE,
+ MetricDimensions: []*config.MetricDefinition_MetricDimension{&dimension},
+ }
integerMetric := config.MetricDefinition{
MetricType: config.MetricDefinition_INTEGER,
EventCodeBufferMax: eventCodeBufferMax,
@@ -279,9 +332,12 @@
}{
// Valid input:
{args{&occurrenceMetric, &fleetwideOccurrenceCountsReport}, true, eventCodeBufferMax},
+ {args{&occurrenceMetricEventCodeBufferMaxUnset, &fleetwideOccurrenceCountsReport}, true,
+ uint64(maxEventCode) + 1},
{args{&occurrenceMetric, &atLeastOnceUniqueDeviceCountsReport}, true, eventCodeBufferMax},
{args{&occurrenceMetric, &selectFirstUniqueDeviceCountsReport}, true, 1},
{args{&occurrenceMetric, &selectMostCommonUniqueDeviceCountsReport}, true, 1},
+ {args{&occurrenceMetricEventCodeBufferMaxUnset, &selectMostCommonUniqueDeviceCountsReport}, true, 1},
{args{&occurrenceMetric, &uniqueDeviceHistogramsReport}, true, eventCodeBufferMax},
{args{&occurrenceMetric, &hourlyValueHistogramsReport}, true, eventCodeBufferMax},
{args{&occurrenceMetric, &uniqueDeviceNumericStatsReport}, true, eventCodeBufferMax},