Skip to content
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

RocksJava: Improve 'get' performance #7597

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open

Conversation

alucarded
Copy link
Contributor

Summary:

  1. Parametrize GetBenchmarks with key and value sizes
  2. Add benchmarks for existing 'get' methods:
  • with preallocated value byte array: RocksDB#get(ColumnFamilyHandle, byte[], byte[])
  • using ByteBuffer: RocksDB#get(ColumnFamilyHandle, ReadOptions, ByteBuffer, ByteBuffer)
  1. Add experimental RocksDB#getCritical(ColumnFamilyHandle, byte[], byte[]), which uses GetPrimitiveArrayCritical instead of GetByteArrayRegion. Add benchmark for the new method.
  2. Add experimental RocksDB#getUnsafe(ColumnFamilyHandle, ReadOptions, byte[]), which uses sun.misc.Unsafe to access value data returned with native PinnableSlice object. Java PinnableSlice object ownes the native counterpart. Add benchmark for the new method.
  3. Benchmark results ("Score" column contains throughput in operations per second)

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zhichao-cao has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@facebook-github-bot
Copy link
Contributor

@alucarded has updated the pull request. You must reimport the pull request before landing.

@adamretter
Copy link
Collaborator

I will shortly do some final benchmarking, where I just check a couple of this before we merge this.

@adamretter adamretter self-assigned this Nov 15, 2020
Copy link
Contributor

@javeme javeme left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking forward to continuous work~

Comment on lines +214 to +219
// For testing correctness:
// assert res > 0;
// final byte[] ret = new byte[valueSize];
// valueBuf.get(ret);
// System.out.println(str(ret));
// valueBuf.flip();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the unused code?

assert(pinnable_slice != nullptr);
pinnable_slice->Reset();
delete pinnable_slice;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expect blank line here

Comment on lines +1226 to +1233
ret_arr[0] = reinterpret_cast<jlong>(value_slice);
ret_arr[1] = reinterpret_cast<jlong>(value_slice->data());

env->ReleasePrimitiveArrayCritical(jret_data, ret_arr, 0);

*has_exception = false;

return static_cast<jint>(value_slice->size_);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we construct a PinnableSlice instance and just return it here?

}

@Benchmark
public void preallocatedByteBufferGet() throws RocksDBException {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems this test has the best throughput

static const int kStatusError = -2;

char* key =
reinterpret_cast<char*>(env->GetPrimitiveArrayCritical(jkey, nullptr));
Copy link
Contributor

@javeme javeme Dec 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use direct buffer to pass key to prevent GetPrimitiveArrayCritical+ReleasePrimitiveArrayCritical?

ROCKSDB_NAMESPACE::Slice key_slice(key_start_ptr, jkey_len);

// TODO(yhchiang): we might save one memory allocation here by adding
// a DB::Get() function which takes preallocated jbyte* as input.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking forward to this feature

@adamretter
Copy link
Collaborator

Based on the Benchmark results provided by @alucarded (Benchmark results ("Score" column contains throughput in operations per second)). I have plotted a very simple rplot to show the results more quickly
Rplot


In summary, preallocated methods offer better performance as you can potentially allocate once and amortize the cost over subsequent calls.

  1. Pursuing API interfaces for preallocatedByteByfferGet and preallocatedGet seems obvious as these are the two APIs that end-users are comfortable working with.

  2. The thing that detracts from implementing an unsafe API, is that at some point the user has to perform additional the work to get the data into/out of that structure, and so the performance increase is then negated.

  3. The preallocatedCriticalGet could be interesting, but whether to use the JNI Critical API methods or not is very much a choice for the user that is embedding RocksJava. The Critical methods can have an impact on the ability of the JVM to perform GC. So it will depend on the users application and memory use profile as to whether Critical is a good fit for them. We could add this as a potential option.

@adamretter and @alanpaxton will pick up this work that our colleague @alucarded started, and continue with it. Likely producing one or two PR's that supersede and incorporate the moist important aspects of this PR.

alanpaxton added a commit to alanpaxton/rocksdb that referenced this pull request Nov 23, 2022
Benchmarks are a subset of facebook#7597

We just want to benchmark existing JNI methods with some potential performance improvements.
alanpaxton added a commit to alanpaxton/rocksdb that referenced this pull request Nov 23, 2022
Benchmarks are a subset of facebook#7597

We just want to benchmark existing JNI methods with some potential performance improvements.
alanpaxton added a commit to alanpaxton/rocksdb that referenced this pull request Dec 16, 2022
Benchmarks are a subset of facebook#7597

We just want to benchmark existing JNI methods with some potential performance improvements.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants