Conversation
|
Hi @JunTaoLuo, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution! The agreement was validated by .NET Foundation and real humans are currently evaluating your PR. TTYL, DNFBOT; |
There was a problem hiding this comment.
I believe there is still some contention on the naming of this method?
There was a problem hiding this comment.
There was a problem hiding this comment.
I don't think it should have the word "Constant" in it, as constants are a special thing already and this can't create them (despite the intent). I'm happy to just have it be Create and TryGetConstant be renamed to TryGetBytes
There was a problem hiding this comment.
I think "CreateXxx" and "TryGetXxx" should have the same "Xxx" in the name. The "Xxx" doesn't have to be "Constant".
That term was chosen originally because of how it was used: internal static class Constants { public static readonly StringValues TextPlain = StringValues.CreateConstant("text/plain"); }
Actually, wasn't it originally CreateBinaryConstant? How about CreateBinary and TryGetBinary? Or like you said CreateBytes and TryGetBytes?
The problem is: we don't want people to use the Create method unless they are creating a static readonly instance used the same way you use a constant.
If you have someone call StringValues.Create(foo) per-request - as if it was just an alias for the ctor - they'll actually be increasing their allocations per-request. That's why the "Constant" hint was in there: this method is for creating constants...
There was a problem hiding this comment.
If you have this CreateXxx method do you even need the associated constructor?
There was a problem hiding this comment.
Not really, the constructor could be internal
There was a problem hiding this comment.
I don't mind CreatePreEncoded/TryGetPreEncoded
|
Looks good to me, apart from the cc @Tratcher |
There was a problem hiding this comment.
Gross by design. Any recommendations for alternative designs?
There was a problem hiding this comment.
Couldn't we make EncodedBytes a public property and add a remark that says its only available for pre-encoded values? Two outs feels like bad design.
There was a problem hiding this comment.
It's better to keep them linked than in two separate properties. Otherwise you need to keep explaining the relationship between the two.
|
|
|
Testing performance for different scenarios for StringValues implementation with class vs struct gave the following results:
Each test configuration was run 5 times without error and the RPS values here are an average of those runs. Unknown Headers used are A few observations. First, although testing in the afternoon showed differences between struct vs class implementations, retesting here indicate otherwise, though class implementation seems to be slightly better in all scenarios. Also, pre-encoding headers seems to have a small benefit in most scenarios but is detrimental for unknown headers in the struct implementation. Full results here: |
909604e to
4befddb
Compare
|
Thanks, @JunTaoLuo. These results are interesting, and slightly unexpected. Was the variance between runs small for both the class and the struct cases? |
There was a problem hiding this comment.
We should null check the args in this scenario, we actually use them.
|
It seems like the source of regression here was adding additional fields. Did we experiment with designs where we try to minimize the number of fields? For instance omitting the encoding? |
|
@rynowak We tried several things. First we verified that making StringValues a class was significantly faster than the 2 field StringValues struct that existed prior to this change. We also tried out @lodejard's suggestion of making StringValues a single-field struct, but that still wasn't quite as fast (and not nearly as clean code-wise) as simply making StringValues a class. The "Struct Implementation" results shown here are from the single-field version of the StringValues struct (which most efficient struct version according to our benchmarks). Those "Struct Implementation" benchmark results are far better than what we have in dev today. You can see the single-field struct version of StringValues here: https://gist.github.com/AspNetSmurfLab/61c40908bb316ca8f42c Please forgive the sloppy coding in the gist, we were just trying to get benchmark results quickly. |
There was a problem hiding this comment.
You shouldn't need to initialize these anymore.
|
@halter73 I'd retest the |
|
Could there be an in place mutator? |
|
Ignore the mutator comment; it will go horribly wrong :P |
|
@benaadams The ClearFast change seems to make the difference between the struct/class versions of StrinvValues smaller, but the class version still performs better: StringValues struct: StringValues class: |
|
@halter73 can't argue with that. However, if going class, then mutators would be nice; though Which night have a perf impact; and null e.g.
What happens with The implicit conversions need to change to accept null values e.g. public static implicit operator string (StringValues values)
{
return values.GetStringValue();
}
public static implicit operator string[] (StringValues value)
{
return value.GetArrayValue();
}needs to change to public static implicit operator string (StringValues values)
{
if (values == null) return null;
return values.GetStringValue();
}
public static implicit operator string[] (StringValues value)
{
if (value == null) return EmptyArray;
return value.GetArrayValue();
}etc... |
|
I'd like to suggest a hold on this for now; there's a faster CopyFromAscii in Kestrel aspnet/KestrelHttpServer#527 and an even faster one to come when only pooled blocks are used aspnet/KestrelHttpServer#525 as one of the |
5802cb3 to
9020e65
Compare
9020e65 to
4671bc8
Compare
|
After the many kestrel optimizations, testing the performance of this optimization showed that it makes little difference. I saw ~1% improvement in the plaintext benchmark and after I added 16 more headers the performance improvement was bigger but less stable, hovering between 4-7% (ee aspnet/KestrelHttpServer#584 for more details). Note that the headers added were for illustration only and in real scenarios, it does not make sense to pre-encode all of them. In the end, we decided that this optimization is no longer relevant and will not be made. |
using statement duplicated
Fix #68 - use trace for header logging
Issue #64