Performance crime: Params

You might heard params are evil. Have you ever seen the performance bill for that?

How to find out where params are used?

Memory allocation report shows all allocations, we’ll start from here:

Method with params creates an array behind the scenes, so hunting for object[]:

IL code proves sad truth – array is always created:

Even though there is a faster Concat with 4 arguments, it is not picked due to type mismatch. The similar issue takes place for Item.GetUniqueId():

How faster could it be without params?

2.7 times faster by simply calling .ToString prior combining values. Impressive, huh?

        [Benchmark]
        public void Stock()
        {
            var data = _item.InnerData;
            for (int i = 0; i < N; i++)
            {
                var clone = new Item(_id, data, database);
                var uniqueId = clone.GetUniqueId();
            }
        }

        [Benchmark]
        public void NoBoxing()
        {
            var data = _item.InnerData;
            for (int i = 0; i < N; i++)
            {
                var clone = new Item(_id, data, database);
                var uniqueId = string.Concat(clone.Database.Name, clone.ID.ToString(), clone.Language.Name, clone.Version.ToString());                
            }
        }

2.4 times less memory used (omitting justCopyItem from both runs: 27.5 vs 11.47 MB)

Conclusion

Params could make your program slower out of nothing. Luckily, there are automated solutions (like Roslyn Clr Heap Allocation Analyzer) that help detecting these kind of issues in early development stages.

Although modern compilers produce smarter code that does not involve array creation in this case, new language features (string interpolation) brings new challenges.

2 thoughts on “Performance crime: Params

  1. What would you use instead params?

    Refactoring all the methods and overloading them seems like a lot of work and I believe it’s more readable to have one function instead of 2

    Like

    1. Indeed there is no escape when method semantically needs an array to operate with.
      However, the example with string concat shows a large percent of calls would need to join a few strings as max.
      This usage pattern justifies the necessity of overloads.

      And yea, the trick is optimize frequently-used methods that indeed could win from the refactoring: https://youtu.be/RwSlubTBnew?t=100

      Like

Leave a Reply to Nikolay Mitikov Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: