-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
MutableHttpFields.asImmutable avoids copy #10651
Conversation
Avoid a copy in MutableHttpFields.asImmutable if the mutable is never mutated again.
Signed-off-by: Ludovic Orban <[email protected]>
Signed-off-by: Ludovic Orban <[email protected]>
@@ -59,7 +58,7 @@ public HttpFields asImmutable() | |||
public int hashCode() | |||
{ | |||
int hash = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't the hash function start with an arbitrary prime number? (not 0
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, since we do xor's in the loop, starting with a hash of 31 would improve the spreading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gregw this should be a prime number.
jetty-core/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java
Outdated
Show resolved
Hide resolved
@gregw FYI the |
Avoid a copy in MutableHttpFields.asImmutable if the mutable is never mutated again.
Do not persist a defaulted charset used in the request. Throw UnsupportedEncodingException from getReader Improve performance with asciiEqualsIgnoreCase HttpMethod is case-insensitive
jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java
Outdated
Show resolved
Hide resolved
* @return true if the string ends with the substring, ignoring {@link StandardCharsets#US_ASCII} case differences. | ||
* @deprecated Use {@link #asciiEndsWithIgnoreCase(String, String)} | ||
*/ | ||
@Deprecated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Deprecated(since = "12.0.3")
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not against the since
attribute, but either we are consistent, run through the code add it to all deprecations, and we have a policy, otherwise it's not so useful and inconsistent.
Signed-off-by: Ludovic Orban <[email protected]>
…lations EnumSet Signed-off-by: Ludovic Orban <[email protected]>
…cation Signed-off-by: Ludovic Orban <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some open thoughts
jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
Show resolved
Hide resolved
jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MutableHttpFields.java
Show resolved
Hide resolved
jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/UriCompliance.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/UriCompliance.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hashCode()
implementation in ImmutableHttpFields
is non-ideal.
But that hints at a larger issue in the codebase.
Probably should review that across the codebase in a future PR.
@@ -59,7 +58,7 @@ public HttpFields asImmutable() | |||
public int hashCode() | |||
{ | |||
int hash = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gregw this should be a prime number.
…/HttpFields_asImmutable
prime hash seeds
@joakime this is already a bit of an omnibus PR, so I have fixed the other hash calculations I can see that are based on 0. |
} | ||
else if (fields != null) | ||
{ | ||
_fields = new HttpField[fields.size() + INITIAL_SIZE]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_fields = new HttpField[fields.size() + INITIAL_SIZE]; | |
_fields = new HttpField[fields.size() + SIZE_INCREMENT]; |
@gregw I have an extra set of small but potentially controversial changes worth 1-2% of perf in my |
Signed-off-by: Ludovic Orban <[email protected]>
Signed-off-by: Ludovic Orban <[email protected]>
@@ -479,10 +479,10 @@ private static class RetainedBucket | |||
private RetainedBucket(int capacity, int poolSize) | |||
{ | |||
if (poolSize <= ConcurrentPool.OPTIMAL_MAX_SIZE) | |||
_pool = new ConcurrentPool<>(ConcurrentPool.StrategyType.THREAD_ID, poolSize, true); | |||
_pool = new ConcurrentPool<>(ConcurrentPool.StrategyType.THREAD_ID, poolSize, false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lorban I like this change as THREAD_ID and the ThreadLocal cache are kind of trying to do the same thing anyway.
However, I wonder if we could improve the THREAD_ID algorithm a little bit. Currently it is used as:
case THREAD_ID -> (int)(Thread.currentThread().getId() % size);
The problem here is that typically the threads in use will be consecutive IDs, so if there are 50 threads in use and the pool is 100 in size, it may be that 50 consecutive entries are all in use and that an acquire by a thread that already has used one buffer will now need to scan over 49 others to find an empty slot. Perhaps we should be treating it a little more like an initial hash and spreading the thread ID over the available size more. Perhaps the following would work a little bit better:
case THREAD_ID -> (int)((Thread.currentThread().getId() * 31) % size);
(31 selected because it is prime)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I modified the THREAD_ID strategy to multiply by 31, ran the benchmark, and measured no noticeable change.
Using the thread id as an index combined with the randomness of the OS' scheduler is already spreading the threads sufficiently well, it seems.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still it might be best to keep the * 31. It is probably rare that all threads need buffers at exactly the same time, but I also think it could occur. It may be the benchmark is not the right pattern to make it happen. So you saw no cost to doing this, so let's keep it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wrote a micro benchmark to see exactly what's going on and the * 31 costs exactly two cheap instructions: shift left by 5, then subtract once.
No big deal, so I'm okay to keep this change.
Signed-off-by: Ludovic Orban <[email protected]>
@sbordet nudge |
Avoid a copy in MutableHttpFields.asImmutable if the mutable is never mutated again.
Other minor improvements are included:
HttpHeader#is(String)
HttpMethod#is(String)