Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

String pool for MemoryPoolIteratorExtensions.GetAsciiString() #1154

Closed
Yves57 opened this issue Oct 7, 2016 · 3 comments
Closed

String pool for MemoryPoolIteratorExtensions.GetAsciiString() #1154

Yves57 opened this issue Oct 7, 2016 · 3 comments
Milestone

Comments

@Yves57
Copy link
Contributor

Yves57 commented Oct 7, 2016

Just a question for curiosity. When reading the request header (and few other things), a new string is allocated in MemoryPoolIteratorExtensions.GetAsciiString().
But in case of several requests for a same connection:

  1. Each request header contains few strings to allocate.
  2. Some strings have probably the same length between requests.

So I was asking myself if a small but very optimized string pool attached to the Frame instance would not be intersesting to limit string allocation when several requests are done in a same connection.

I have made a prototype, and of course string allocation count goes down to 0 after the first request. Nevertheless to be honest I didn't see significant performance gain. But my computer is quite old and my prototype is not optimal, so I'm not sure that it was a reliable benchmark.

Of course the difference would not be huge for a large MVC View request, but for a "plaintext" performance test?

@halter73
Copy link
Member

halter73 commented Oct 7, 2016

Is your prototype anything like @benaadams #411 PR from last year? At the time, it showed a small enough improvement in plaintext benchmark (which is pretty much a best case scenario for this type of change), that we decided it wasn't worth the additional complexity.

@Yves57
Copy link
Contributor Author

Yves57 commented Oct 7, 2016

I had not found the issue. Yes, it is the same starting observation.
There is a difference in the implementation: instead of hashing the string, my prototype is only focused on the string length (there are problably only very few strings with a given length in the header):

    public const int PoolSize = 32;

        private string[] _pool;

        private uint _used;

        public string Get(int length)
        {
            if (_used == uint.MaxValue ||
                _charCount + length > MaxCharCount)
            {
                return new string('\0', length);
            }

            int freeIndex = -1;
            for (int i = 0; i < PoolSize; i++)
            {
                if ((_used & (1 << i)) == 0)
                {
                    var str = _pool[i];

                    if (str == null)
                    {
                        freeIndex = i;
                    }
                    else if (str.Length == length)
                    {
                        _used |= 1u << i;
                        return str;
                    }
                    else if (freeIndex < 0)
                    {
                        freeIndex = i;
                    }
                }
            }

            _used |= 1u << freeIndex;
            _charCount += length;
            _pool[freeIndex] = new string('\0', length);

            return _pool[freeIndex];
        }

       // Called for every request
        public void Reset()
        {
            _used = 0;
            _charCount = 0;
        }

But I clearly don't know if it makes a big difference with the #411 algorithm...

@muratg muratg added this to the Discussions milestone Oct 31, 2016
@muratg
Copy link
Contributor

muratg commented May 12, 2017

We are closing this issue because no further action is planned for this issue. If you still have any issues or questions, please log a new issue with any additional details that you have.

@muratg muratg closed this as completed May 12, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants