Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(outputs): Only copy metric to output when needed #15883

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

LarsStegman
Copy link
Contributor

@LarsStegman LarsStegman commented Sep 14, 2024

Summary

This PR makes sure that an output plugin will really select a metric for outputting, before copying it. This improvement had a big impact on runtime/gc time in real world performance. After this change the amount of gc time went down from 55% of the CPU time to 25%.

In our real world case every output plugin was only interested in a subset of the metric and there was no overlap between the subsets. This means that (x-1)/x% of all the copied metrics were immediately discarded, where x is the number of outputs.

Checklist

  • No AI generated code was used in this PR

Related issues

resolves #15882

@srebhan
Copy link
Member

srebhan commented Sep 16, 2024

Thanks a lot @LarsStegman for your investigation!!!

How about moving the copy into the running_output model and pass in a flag if a copy is required like

	for metric := range unit.src {
		for i, output := range unit.outputs {
			output.AddMetric(metric, i < len(a.Config.Outputs) - 1)
		}
	}

and in the model do

func (r *RunningOutput) AddMetric(m telegraf.Metric, requireCopy bool) {
	metric := m

	ok, err := r.Config.Filter.Select(metric)
	if err != nil {
		r.log.Errorf("filtering failed: %v", err)
	} else if !ok {
		r.metricFiltered(metric)
		return
	}

	if requireCopy {
		metric = m.Copy()
	}

	r.Config.Filter.Modify(metric)
	if len(metric.FieldList()) == 0 {
		r.metricFiltered(metric)
		return
	}
        ...
}

This way we do not need to expose the interna of the output model into the agent.

@srebhan srebhan self-assigned this Sep 16, 2024
@LarsStegman
Copy link
Contributor Author

Yeah, that's also a good solution for me. I will make that change!

@LarsStegman LarsStegman force-pushed the perf/only-copy-metric-when-needed branch 2 times, most recently from 784da6d to a61bddf Compare September 17, 2024 13:48
@LarsStegman
Copy link
Contributor Author

@srebhan I am not sure why the memory leak test is failing. I should be making fewer allocations, not more. Do you have any idea?

@srebhan
Copy link
Member

srebhan commented Sep 19, 2024

@LarsStegman this is unrelated and unfortunately a flaky test... We need to look at it some time but currently things are busy. Ignore the issue for now...

Copy link
Member

@srebhan srebhan left a comment

Choose a reason for hiding this comment

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

Awesome! I wonder if we should keep the original AddMetric function signature and always copy the metric and have a second function AddMetricNoCopy which does not copy the metric. This way we save a few ifs and can keep the tests as they were...

@LarsStegman
Copy link
Contributor Author

That does sound like a better solution to be honest. All the ifs were getting a bit iffy.

@LarsStegman LarsStegman force-pushed the perf/only-copy-metric-when-needed branch from a61bddf to b080e56 Compare September 19, 2024 11:57
@LarsStegman
Copy link
Contributor Author

Alright, I do like this better!

@LarsStegman LarsStegman force-pushed the perf/only-copy-metric-when-needed branch from 589c177 to 6da9241 Compare September 21, 2024 06:12
Copy link
Member

@srebhan srebhan left a comment

Choose a reason for hiding this comment

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

Nice. Just get rid of the underscore in the function name and we are good to go.

models/running_output.go Outdated Show resolved Hide resolved
Copy link
Member

@srebhan srebhan left a comment

Choose a reason for hiding this comment

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

Nice! Thanks @LarsStegman!

@srebhan srebhan changed the title perf(agent): only copy metric to output when needed feat(outputs): Only copy metric to output when needed Sep 30, 2024
@telegraf-tiger telegraf-tiger bot added the feat Improvement on an existing feature such as adding a new setting/mode to an existing plugin label Sep 30, 2024
@srebhan srebhan added area/agent plugin/output 1. Request for new output plugins 2. Issues/PRs that are related to out plugins labels Sep 30, 2024
@srebhan
Copy link
Member

srebhan commented Oct 1, 2024

@LarsStegman you need this

diff --git a/plugins/inputs/cloud_pubsub_push/cloud_pubsub_push_test.go b/plugins/inputs/cloud_pubsub_push/cloud_pubsub_push_test.go
index 252b843fc..9e8aa07d1 100644
--- a/plugins/inputs/cloud_pubsub_push/cloud_pubsub_push_test.go
+++ b/plugins/inputs/cloud_pubsub_push/cloud_pubsub_push_test.go
@@ -196,6 +196,7 @@ func TestServeHTTP(t *testing.T) {
                        for m := range d {
                                ro.AddMetric(m)
                                ro.Write() //nolint:errcheck // test will fail anyway if the write fails
+                               m.Accept()
                        }
                }(dst)
 

to pass the unit-tests. Those tests are horrible but that's the easiest fix...

@telegraf-tiger
Copy link
Contributor

telegraf-tiger bot commented Oct 1, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/agent feat Improvement on an existing feature such as adding a new setting/mode to an existing plugin plugin/output 1. Request for new output plugins 2. Issues/PRs that are related to out plugins
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Many memory allocations with multiple output plugins
2 participants