Commit Graph

300 Commits

Author SHA1 Message Date
Chris Vest
4036dac84d Add a flag to allow Buf.ensureWritable to compact buffer
Motivation:
The main use case with Buf.compact is in conjunction with ensureWritable.
It turns out we can get a simpler API, and faster methods, by combining those two operations, because it allows us to relax some guarantees and skip some steps in certain cases, which wouldn't be as neat or clean if they were two separate steps.

Modification:
Add a new Buf.ensureWritable method, which takes an allowCompaction argument.
In MemSegBuf, we can just delegate to compact() when applicable.
In CompositeBuf, we can sometimes get away with just reorganising the bufs array.

Result:
We can now do ensureWritable without allocating in some cases, and this can in particular make the operation faster for CompositeBuf.
2020-12-17 12:29:55 +01:00
Chris Vest
252ac38305 Simplify MemSegBuf.compact implementation 2020-12-17 12:29:55 +01:00
Chris Vest
0f303c7971 Add a Buf.compact method
Motivation:
Compaction makes more space available at the end of a buffer, by discarding bytes at the beginning that have already been processed.

Modification:
Add a copying compact method to Buf.

Result:
It is now possible to discard read bytes by calling `compact()`.
2020-12-17 12:29:55 +01:00
Chris Vest
cc685c0516
Merge pull request #17 from netty/buf-holder
Add BufHolder and BufRef helper classes
2020-12-17 11:45:11 +01:00
Chris Vest
008c5ed6ec Make BufHolder protected methods final if they're not meant to be overwritten 2020-12-16 17:06:22 +01:00
Chris Vest
6b91751bea Small polishing that addresses PR comments 2020-12-16 12:31:49 +01:00
Chris Vest
f83e7fa618 Add BufHolder and BufRef helper classes
Motivation:
There are many use cases where other objects will have fields that are buffers.
Since buffers are reference counted, their life cycle needs to be managed carefully.

Modification:
Add the abstract BufHolder, and the concrete sub-class BufRef, as neat building blocks for building other classes that contain field references to buffers.

The behaviours of closed/sent buffers have also been specified in tests, and tightened up in the code.

Result:
It is now easier to create classes/objects that wrap buffers.
2020-12-14 14:22:37 +01:00
Chris Vest
ab95abac25 The make clean command now also cleans up after failed build commands 2020-12-11 12:10:04 +01:00
Chris Vest
02eb4286fa Better method names and javadocs in RcSupport 2020-12-11 12:09:32 +01:00
Chris Vest
3cddd2b0b2
Merge pull request #16 from netty/bifurcate
Add a Buf.bifurcate method
2020-12-10 16:07:09 +01:00
Chris Vest
cccec1ae4c Add two more tests for interactions between bifurcation and send 2020-12-10 14:27:45 +01:00
Chris Vest
bb2264ac5b Address review comments on bifurcate PR 2020-12-10 12:51:18 +01:00
Chris Vest
b749106c0c Add a Buf.bifurcate method
Motivation:
There are use cases that involve accumulating data into a buffer, then carving out prefix slices and sending them off on their own journey for further processing.

Modification:
Add a Buf.bifurcate API, that split a buffer, and its ownership, in two.
Internally, the API will inject and maintain an atomically reference counted Drop instance, so that the original memory segment is not released until all bifurcated parts are closed.
This works particularly well for composite buffers, where only the buffer (if any) wherein the bifurcation point lands, will actually have its memory split. A composite buffer can otherwise just crack its buffer array in two.

Result:
We now have a safe way of breaking the single ownership of some memory into multiple parts, that can be sent and owned independently.
2020-12-10 10:29:31 +01:00
Chris Vest
deeea157c0
Merge pull request #11 from netty/byte-cursor
Turn ByteIterator into ByteCursor
2020-12-09 17:23:23 +01:00
Chris Vest
4960e8b3e7 Make ByteCursors from CompositeBuf slightly faster 2020-12-09 11:03:30 +01:00
Chris Vest
a7701c04b5 Update ByteCursor method names and related javadocs 2020-12-09 11:03:30 +01:00
Chris Vest
b2d0231f27 Specify the behaviour of ByteCursor.getByte and getLong, when relevant next* methods haven't been called 2020-12-09 11:02:51 +01:00
Chris Vest
6cc49c1c62 Turn ByteIterator into ByteCursor
Motivation:
Cursors are better than iterators in that they only need to check boundary conditions once per iteration, when processed in a loop.
This should make them easier for the compiler to optimise.

Modification:
Change the ByteIterator to a ByteCursor. The API is almost the same, but with a few subtle differences in semantics.
The primary difference is that the cursor movement and boundary condition checking and position movement happen at the same time, and do not need to occur when the values are fetched out of the cursor.
An iterator, on the other hand, needs to throw an exception if "next" is called too many times.

Result:
Simpler code, and hopefully faster code as well.
2020-12-09 11:02:51 +01:00
Chris Vest
3aeebdd058
Merge pull request #12 from netty/extend-composite
Make it possible to extend composite buffers after creation
2020-12-08 19:25:32 +01:00
Chris Vest
e8a38185bb
Merge pull request #15 from netty/fix-drop-gate
Fix drop race with Cleaner
2020-12-07 17:56:02 +01:00
Chris Vest
2ce8c7dc18 Fix drop race with Cleaner
Motivation:
We were seeing rare test failures where a cleaner had raced to close a memory segment we were using or closing.
The cause was that a single MemorySegment ended up used in multiple Buf instances.
When the SizeClassedMemoryPool was closed, the memory segments could be disposed without closing the gate in the NativeMemoryCleanerDrop.
The gate is important because it prevents double-frees of the memory segment.

Modification:
The fix is to change how the SizeClassedMemoryPool is closed, such that it always releases memory by calling `close()` on its buffers, which in turn will close the gate. The program will then proceed through the SizeClassedMemoryPool.drop implementation, which in turn will observe that the allocator is closed, and *then* dispose of the memory.

Result:
We should hopefully not see any more random test failures, but if we do, they would at least indicate a different bug.
This particular one was mostly showing up inside the cleaner threads, which were ignoring the exception, but occasionally I think the race went the other way, causing a test failure.
2020-12-07 17:35:21 +01:00
Chris Vest
2f99ee64a4
Merge pull request #14 from netty/benchmark-send
Add a benchmark for Buf.send()
2020-12-04 21:18:46 +01:00
Chris Vest
0c40143f5f Fix license header years, and style updates 2020-12-04 18:48:06 +01:00
Chris Vest
80185abec4 Add a benchmark for Buf.send()
Motivation:
This will likely be a somewhat common operation, as buffers move between eventloop and worker threads, so it's important to have an understanding of how it performs.

Modification:
Add a benchmark that specifically targets the send() operation on buffers.

Result:
We got benchmark numbers that clearly show the cost of confinement transfer
2020-12-04 16:27:08 +01:00
Chris Vest
236097e081 Make it possible to extend composite buffers after creation
Motivation:
Composite buffers are uniquely positioned to be able to extend their underlying storage relatively cheaply.
This fact is relied upon in a couple of buffer use cases within Netty, that we wish to support.

Modification:
Add a static `extend` method to Allocator, so that the CompositeBuf class can remain internal.
The `extend` method inserts the extension buffer at the end of the composite buffer as if it had been included from the start.
This involves checking offsets and byte order invariants.
We also require that the composite buffer be in an owned state.

Result:
It's now possible to extend a composite buffer with a specific buffer, after the composite buffer has been created.
2020-12-03 17:48:28 +01:00
Chris Vest
b0da25d888
Merge pull request #10 from netty/byte-itr-benchmark
Add benchmarks for ByteIterator
2020-12-02 15:14:18 +01:00
Chris Vest
6b7ea5f5cb Add benchmarks for ByteIterator
Motivation:
Capture the performance characteristics of this primitive for various buffer implementations.

Modification:
Add a benchmark that iterate 4KiB buffers forwards, and backwards, on various buffer implementations.

Result:
Another aspect of the implementation covered by benchmarks.
Turns out the composite iterators a somewhat slow.
2020-12-02 14:54:02 +01:00
Chris Vest
fcd97af4f9
Merge pull request #7 from netty/over-eager-cleaner
@chrisvest Capture build artifacts for failed builds
2020-12-01 14:58:06 +01:00
Chris Vest
e3c7f9b632 Capture build artifacts for failed builds
Motivation:
When a build fails, it's desirable to have the build artifacts available
so the build failure can be inspected, investigated and hopefully fixed.

Modification:
Change the Makefile and CI workflow such that the build artifacts are
captured and uploaded when the build fails.

Result:
A "target.zip" file is now available for download on failed GitHub
Actions builds.
2020-12-01 14:38:09 +01:00
Chris Vest
e039f6f7f5
Merge pull request #9 from netty/more-close-benchmarks
Add benchmark for closing pooled buffers
2020-12-01 11:46:42 +01:00
Chris Vest
4a409d2458 Add benchmark for closing pooled buffers
Motivation:
Pooled buffers are a very important use case, and they change the cost dynamics around shared memory segments, so it's worth looking into in detail.

Modification:
Add another explicit close of pooled direct buffers to MemorySegmentClosedByCleanerBenchmark

Result:
Explicitly closing of pooled buffers is even out-performing cleaner close on the "heavy" workload, so this is currently the fastest way to run that workload:

Benchmark                                                  (workload)  Mode  Cnt   Score   Error  Units
MemorySegmentClosedByCleanerBenchmark.cleanerClose              heavy  avgt  150  14,194 ± 0,558  us/op
MemorySegmentClosedByCleanerBenchmark.explicitClose             heavy  avgt  150  40,496 ± 0,414  us/op
MemorySegmentClosedByCleanerBenchmark.explicitPooledClose       heavy  avgt  150  12,723 ± 0,134  us/op
2020-12-01 11:15:44 +01:00
Chris Vest
89860b779a
Merge pull request #5 from netty/faster-send
Make Buf.send() faster
2020-11-26 13:59:47 +01:00
Chris Vest
a3f6ae6be8 Make Buf.send() faster
When send() a confined buffer, we had to first turn it into a shard buffer, so that it could be claimed by an arbitrary recipient thread.

As we've learned, however, closing shared segments is expensive.
We can speed up the send() call by simply leaving the segment shared.
This weakens the confinement of the received segment, though.
Currently no tests fails on that, but in the future we should re-implement confinement checking inside the Buf implementations themselves any, because pooled buffers also violate the confinement restriction, and we have a guiding principle that all buffers, regardless of implementation, should always behave the same.

The results of this change can be observed in the MemorySegmentClosedByCleanerBenchmark, with the heavy workload.
Explicitly closed segments now run the workload twice as fast, and the cleaner based closing is now 3 times faster.

Before:
Benchmark                                            (workload)  Mode  Cnt   Score   Error  Units
MemorySegmentClosedByCleanerBenchmark.cleanerClose        heavy  avgt  150  42,221 ± 0,943  us/op
MemorySegmentClosedByCleanerBenchmark.explicitClose       heavy  avgt  150  65,215 ± 0,761  us/op

After:
Benchmark                                            (workload)  Mode  Cnt   Score   Error  Units
MemorySegmentClosedByCleanerBenchmark.cleanerClose        heavy  avgt  150  13,871 ± 0,544  us/op
MemorySegmentClosedByCleanerBenchmark.explicitClose       heavy  avgt  150  37,516 ± 0,426  us/op
2020-11-26 11:31:23 +01:00
Chris Vest
34a58a763c
Merge pull request #4 from netty/benchmarks2
Add benchmarks examining the performance difference between explicitly closing buffers, and letting Cleaners close the buffers
2020-11-26 11:12:59 +01:00
Chris Vest
6364c4d170 Add a benchmark for examining the performance difference between explicitly closing memory segments, versus having them closed by cleaners 2020-11-26 10:37:14 +01:00
Chris Vest
f611d58a6e
Merge pull request #3 from netty/benchmarks
Add benchmarks for opening/closing shared/confined native/heap memory segments
2020-11-26 10:19:39 +01:00
Chris Vest
6078465721 Add a benchmark for opening and closing shared/confined native/heap memory segments 2020-11-24 10:56:22 +01:00
Chris Vest
cd9f84e856 The assertj-core dependency should only be available in test scope 2020-11-23 18:11:22 +01:00
Chris Vest
92c178ceb9 The BufTest.pooledBuffersMustResetStateBeforeReuse should run for all allocators 2020-11-23 18:10:58 +01:00
Chris Vest
eb7717b00a Move benchmarks to their own directory 2020-11-23 18:10:27 +01:00
Chris Vest
6e23ba139d
Merge pull request #2 from netty/cache-key
Include year and week number in build cache key
2020-11-23 12:00:43 +01:00
Chris Vest
5037d546e1 Include year and week number in build cache key
Also schedule a build to run at 06:30 in the morning, every Monday.
This way, the JDK and Netty 5 snapshots will be updated in the build cache every week.
2020-11-23 10:56:11 +01:00
Chris Vest
854a2a95dd Remove cruft from CI build workflow file 2020-11-21 21:40:57 +01:00
Chris Vest
c91478341b
Merge pull request #1 from netty/gh-workflow
Add a GitHub workflow for building PRs
2020-11-21 21:35:29 +01:00
Chris Vest
b171449de9 Try yet another different caching mechanism 2020-11-21 17:00:30 +01:00
Chris Vest
87d23f52db Try a different caching mechanism 2020-11-21 15:26:10 +01:00
Chris Vest
1f9ab72a44 Add more examples 2020-11-20 22:22:01 +01:00
Chris Vest
f3e494bce3 Add first example on how to use the new buffer API 2020-11-20 16:07:52 +01:00
Chris Vest
308b4df3b6 Try fixing multi-line workflow commands 2020-11-20 16:07:52 +01:00
Chris Vest
72eb5d3bcb Try adding a build cache that uses githubs package repo as a cache
Inspired by https://dev.to/dtinth/caching-docker-builds-in-github-actions-which-approach-is-the-fastest-a-research-18ei
2020-11-20 14:38:38 +01:00