Skip to content

Memory consumption #286

@piotrkowalczuk

Description

@piotrkowalczuk

Hello Team,

I am raising this issue to get an idea of whether we should choose protovalidate-go or protoc-gen-validate. As reported in other issues, some performance penalty is expected:

I am wondering what the target performance is. I ran a couple of benchmarks to estimate the effective memory utilization increase compared to our baseline. I have three scenarios:

  • Message encoding: 370MB
  • Message encoding + validation: 5800MB
  • Message encoding + optimized validation: 5500MB ❗ (CEL alone accounts for 3600MB)

The payload used for measuring has approximately 50 fields, nested in different configurations.

I'm wondering what we can do on our end to adopt the library:

  • Are the reported values within the range of expected utilization?
  • Is there a way to disable CEL, for example, if the directive is never used?
  • anything on the roadmap to take the resource consumption down?
Image
func BenchmarkMarshalAndValidate(b *testing.B) {
	cases := map[string]proto.Message{
		"medium": createSampleProtoMessage(),
		"large":  createLargeProtoMessage(),
	}

	for hint, msg := range cases {
		b.Run(hint, func(b *testing.B) {
			validator, err := protovalidate.New()
			if err != nil {
				b.Fatal(err)
			}

			b.ReportAllocs()
			b.ResetTimer()

			for n := 0; n < b.N+N; n++ {
				if err := validator.Validate(msg); err != nil {
					b.Fatal(err)
				}

				_, err := proto.Marshal(msg)
				if err != nil {
					b.Fatal(err)
				}
			}
		})
	}
}

func BenchmarkOptimizedValidateAndMarshal(b *testing.B) {
	cases := map[string]proto.Message{
		"medium": createSampleProtoMessage(),
		"large":  createLargeProtoMessage(),
	}

	for hint, msg := range cases {
		b.Run(hint, func(b *testing.B) {
			val, err := protovalidate.New(
				protovalidate.WithMessages(&schemav1.IdentifierEventOrder{}),
				//protovalidate.WithDisableLazy(),
				protovalidate.WithFailFast(),
			)
			if err != nil {
				b.Fatal(err)
			}
			if err := val.Validate(msg); err != nil {
				b.Fatal(err)
			}

			b.ReportAllocs()
			b.ResetTimer()

			for n := 0; n < b.N+N; n++ {
				if err := val.Validate(msg); err != nil {
					b.Fatal(err)
				}

				_, err := proto.Marshal(msg)
				if err != nil {
					b.Fatal(err)
				}
			}
		})
	}
}
cpu: Apple M1 Pro
BenchmarkJustMarshal/medium-10         	 2846248	       375.1 ns/op	     182 B/op	       1 allocs/op
BenchmarkJustMarshal/large-10          	 1490960	       803.4 ns/op	     409 B/op	       1 allocs/op
BenchmarkMarshalAndValidate/medium-10         	   94866	     10813 ns/op	    2245 B/op	      84 allocs/op
BenchmarkMarshalAndValidate/large-10          	   55632	     18842 ns/op	    4192 B/op	     138 allocs/op
BenchmarkOptimizedValidateAndMarshal/medium-10         	  108760	     10050 ns/op	    1996 B/op	      78 allocs/op
BenchmarkOptimizedValidateAndMarshal/large-10          	   54223	     18850 ns/op	    4074 B/op	     139 allocs/op

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions