Package Kit & packagefs: Allocate scratch buffers for decompression further up.

Zstd wants a ~90 KB scratch buffer to decompress our 64 KB chunks.
Rather than let it allocate that itself every time, pass in a 2*64KB
"scratch" buffer and statically allocate the working memory from it.
Pass it down using iovecs, and pass down the other buffers in the same
way, to reduce parameters.

Further, rework the object_cache used for heap decompression buffers
to contain objects sized as 4x64KB, so we only need to do one allocation
and deallocation for the compression/decompression and scratch buffers.
Set the minimum reserve to 1 so that the low-memory manager doesn't
reclaim this, as we'll need it when reading back data.

Improves packagefs I/O performance (and thus boot speeds at least a bit,
it appears.)

Change-Id: Id51f6f598b33b9d757a283184c533bb97049529f
Reviewed-on: https://review.haiku-os.org/c/haiku/+/8717
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
Augustin Cavalier 2024-12-26 21:33:35 -05:00 committed by waddlesplash
parent 7651b97c0a
commit f44cb411cc
15 changed files with 128 additions and 127 deletions

View File

@ -99,23 +99,23 @@ public:
public:
static const size_t kChunkSize = 64 * 1024;
#if defined(_KERNEL_MODE)
static void* sChunkCache;
static void* sQuadChunkCache;
#endif
protected:
virtual status_t ReadAndDecompressChunk(size_t chunkIndex,
void* compressedDataBuffer,
void* uncompressedDataBuffer) = 0;
void* uncompressedDataBuffer,
iovec* scratchBuffer = NULL) = 0;
status_t ReadAndDecompressChunkData(uint64 offset,
size_t compressedSize,
size_t uncompressedSize,
void* compressedDataBuffer,
void* uncompressedDataBuffer);
status_t DecompressChunkData(
void* compressedDataBuffer,
size_t compressedSize,
void* uncompressedDataBuffer,
size_t uncompressedSize);
iovec* scratchBuffer = NULL);
status_t DecompressChunkData(const iovec& compressedBuffer,
iovec& uncompressedBuffer,
iovec* scratchBuffer = NULL);
status_t ReadFileData(uint64 offset, void* buffer,
size_t size);

View File

@ -42,7 +42,8 @@ public:
protected:
virtual status_t ReadAndDecompressChunk(size_t chunkIndex,
void* compressedDataBuffer,
void* uncompressedDataBuffer);
void* uncompressedDataBuffer,
iovec* scratchBuffer = NULL);
private:
OffsetArray fOffsets;

View File

@ -57,7 +57,8 @@ public:
protected:
virtual status_t ReadAndDecompressChunk(size_t chunkIndex,
void* compressedDataBuffer,
void* uncompressedDataBuffer);
void* uncompressedDataBuffer,
iovec* scratchBuffer = NULL);
private:
struct Chunk;

View File

@ -7,6 +7,7 @@
#include <DataIO.h>
#include <sys/uio.h>
class BCompressionParameters {
@ -41,17 +42,12 @@ public:
const BDecompressionParameters* parameters,
BDataIO*& _stream);
virtual status_t CompressBuffer(const void* input,
size_t inputSize, void* output,
size_t outputSize, size_t& _compressedSize,
const BCompressionParameters* parameters
= NULL);
virtual status_t DecompressBuffer(const void* input,
size_t inputSize, void* output,
size_t outputSize,
size_t& _uncompressedSize,
const BDecompressionParameters* parameters
= NULL);
virtual status_t CompressBuffer(const iovec& input, iovec& output,
const BCompressionParameters* parameters = NULL,
iovec* scratch = NULL);
virtual status_t DecompressBuffer(const iovec& input, iovec& output,
const BDecompressionParameters* parameters = NULL,
iovec* scratch = NULL);
protected:
class BAbstractStream;

View File

@ -73,17 +73,12 @@ public:
const BDecompressionParameters* parameters,
BDataIO*& _stream);
virtual status_t CompressBuffer(const void* input,
size_t inputSize, void* output,
size_t outputSize, size_t& _compressedSize,
const BCompressionParameters* parameters
= NULL);
virtual status_t DecompressBuffer(const void* input,
size_t inputSize, void* output,
size_t outputSize,
size_t& _uncompressedSize,
const BDecompressionParameters* parameters
= NULL);
virtual status_t CompressBuffer(const iovec& input, iovec& output,
const BCompressionParameters* parameters = NULL,
iovec* scratch = NULL);
virtual status_t DecompressBuffer(const iovec& input, iovec& output,
const BDecompressionParameters* parameters = NULL,
iovec* scratch = NULL);
private:
struct CompressionStrategy;

View File

@ -69,17 +69,12 @@ public:
const BDecompressionParameters* parameters,
BDataIO*& _stream);
virtual status_t CompressBuffer(const void* input,
size_t inputSize, void* output,
size_t outputSize, size_t& _compressedSize,
const BCompressionParameters* parameters
= NULL);
virtual status_t DecompressBuffer(const void* input,
size_t inputSize, void* output,
size_t outputSize,
size_t& _uncompressedSize,
const BDecompressionParameters* parameters
= NULL);
virtual status_t CompressBuffer(const iovec& input, iovec& output,
const BCompressionParameters* parameters = NULL,
iovec* scratch = NULL);
virtual status_t DecompressBuffer(const iovec& input, iovec& output,
const BDecompressionParameters* parameters = NULL,
iovec* scratch = NULL);
private:
struct CompressionStrategy;

View File

@ -12,7 +12,7 @@ if [ FIsBuildFeatureEnabled zstd ] {
UseBuildFeatureHeaders zstd ;
Includes [ FGristFiles $(zstdSources) ]
: [ BuildFeatureAttribute zstd : headers ] ;
SubDirC++Flags -DZSTD_ENABLED ;
SubDirC++Flags -DZSTD_ENABLED -DZSTD_STATIC_LINKING_ONLY ;
}
local subDirs =

View File

@ -1144,11 +1144,13 @@ packagefs_std_ops(int32 op, ...)
return error;
}
PackageFileHeapAccessorBase::sChunkCache =
create_object_cache_etc("pkgfs heap buffers",
PackageFileHeapAccessorBase::kChunkSize, sizeof(void*),
0, /* magazine capacity, count */ 2, 1,
0, NULL, NULL, NULL, NULL);
object_cache* quadChunkCache;
PackageFileHeapAccessorBase::sQuadChunkCache = quadChunkCache =
create_object_cache("pkgfs heap buffers",
PackageFileHeapAccessorBase::kChunkSize * 4,
0, NULL, NULL, NULL);
object_cache_set_minimum_reserve(quadChunkCache, 1);
TwoKeyAVLTreeNode<void*>::sNodeCache =
create_object_cache_etc("pkgfs TKAVLTreeNodes",
sizeof(TwoKeyAVLTreeNode<void*>), 8,
@ -1172,7 +1174,7 @@ packagefs_std_ops(int32 op, ...)
PackageFSRoot::GlobalUninit();
delete_object_cache(TwoKeyAVLTreeNode<void*>::sNodeCache);
delete_object_cache((object_cache*)
PackageFileHeapAccessorBase::sChunkCache);
PackageFileHeapAccessorBase::sQuadChunkCache);
StringConstants::Cleanup();
StringPool::Cleanup();
exit_debugging();

View File

@ -31,7 +31,7 @@ namespace BPrivate {
#if defined(_KERNEL_MODE)
void* PackageFileHeapAccessorBase::sChunkCache = NULL;
void* PackageFileHeapAccessorBase::sQuadChunkCache = NULL;
#endif
@ -218,7 +218,7 @@ PackageFileHeapAccessorBase::ReadDataToOutput(off_t offset, size_t size,
// allocate buffers for compressed and uncompressed data
uint16* compressedDataBuffer, *uncompressedDataBuffer;
MemoryDeleter compressedMemoryDeleter, uncompressedMemoryDeleter;
iovec* scratch = NULL;
#if defined(_KERNEL_MODE) && !defined(_BOOT_MODE)
struct ObjectCacheDeleter {
@ -238,21 +238,24 @@ PackageFileHeapAccessorBase::ReadDataToOutput(off_t offset, size_t size,
}
};
ObjectCacheDeleter compressedCacheDeleter((object_cache*)sChunkCache),
uncompressedCacheDeleter((object_cache*)sChunkCache);
if (sChunkCache != NULL) {
compressedDataBuffer = (uint16*)object_cache_alloc((object_cache*)sChunkCache, 0);
uncompressedDataBuffer = (uint16*)object_cache_alloc((object_cache*)sChunkCache, 0);
compressedCacheDeleter.object = compressedDataBuffer;
uncompressedCacheDeleter.object = uncompressedDataBuffer;
} else
ObjectCacheDeleter chunkBufferDeleter((object_cache*)sQuadChunkCache);
uint8* quadChunkBuffer = (uint8*)object_cache_alloc((object_cache*)sQuadChunkCache, 0);
chunkBufferDeleter.object = quadChunkBuffer;
// segment data buffer
iovec localScratch;
compressedDataBuffer = (uint16*)(quadChunkBuffer + 0);
uncompressedDataBuffer = (uint16*)(quadChunkBuffer + kChunkSize);
localScratch.iov_base = (quadChunkBuffer + (kChunkSize * 2));
localScratch.iov_len = kChunkSize * 2;
scratch = &localScratch;
#else
MemoryDeleter compressedMemoryDeleter, uncompressedMemoryDeleter;
compressedDataBuffer = (uint16*)malloc(kChunkSize);
uncompressedDataBuffer = (uint16*)malloc(kChunkSize);
compressedMemoryDeleter.SetTo(compressedDataBuffer);
uncompressedMemoryDeleter.SetTo(uncompressedDataBuffer);
#endif
{
compressedDataBuffer = (uint16*)malloc(kChunkSize);
uncompressedDataBuffer = (uint16*)malloc(kChunkSize);
compressedMemoryDeleter.SetTo(compressedDataBuffer);
uncompressedMemoryDeleter.SetTo(uncompressedDataBuffer);
}
if (compressedDataBuffer == NULL || uncompressedDataBuffer == NULL)
return B_NO_MEMORY;
@ -264,7 +267,7 @@ PackageFileHeapAccessorBase::ReadDataToOutput(off_t offset, size_t size,
while (remainingBytes > 0) {
status_t error = ReadAndDecompressChunk(chunkIndex,
compressedDataBuffer, uncompressedDataBuffer);
compressedDataBuffer, uncompressedDataBuffer, scratch);
if (error != B_OK)
return error;
@ -289,8 +292,9 @@ PackageFileHeapAccessorBase::ReadDataToOutput(off_t offset, size_t size,
status_t
PackageFileHeapAccessorBase::ReadAndDecompressChunkData(uint64 offset,
size_t compressedSize, size_t uncompressedSize, void* compressedDataBuffer,
void* uncompressedDataBuffer)
size_t compressedSize, size_t uncompressedSize,
void* compressedDataBuffer, void* uncompressedDataBuffer,
iovec* scratchBuffer)
{
// if uncompressed, read directly into the uncompressed data buffer
if (compressedSize == uncompressedSize)
@ -301,27 +305,26 @@ PackageFileHeapAccessorBase::ReadAndDecompressChunkData(uint64 offset,
if (error != B_OK)
return error;
return DecompressChunkData(compressedDataBuffer, compressedSize,
uncompressedDataBuffer, uncompressedSize);
iovec compressed = { compressedDataBuffer, compressedSize },
uncompressed = { uncompressedDataBuffer, uncompressedSize };
return DecompressChunkData(compressed, uncompressed, scratchBuffer);
}
status_t
PackageFileHeapAccessorBase::DecompressChunkData(void* compressedDataBuffer,
size_t compressedSize, void* uncompressedDataBuffer,
size_t uncompressedSize)
PackageFileHeapAccessorBase::DecompressChunkData(const iovec& compressed,
iovec& uncompressed, iovec* scratchBuffer)
{
size_t actualSize;
const size_t uncompressedSize = uncompressed.iov_len;
status_t error = fDecompressionAlgorithm->algorithm->DecompressBuffer(
compressedDataBuffer, compressedSize, uncompressedDataBuffer,
uncompressedSize, actualSize, fDecompressionAlgorithm->parameters);
compressed, uncompressed, fDecompressionAlgorithm->parameters, scratchBuffer);
if (error != B_OK) {
fErrorOutput->PrintError("Failed to decompress chunk data: %s\n",
strerror(error));
return error;
}
if (actualSize != uncompressedSize) {
if (uncompressed.iov_len != uncompressedSize) {
fErrorOutput->PrintError("Failed to decompress chunk data: size "
"mismatch\n");
return B_ERROR;

View File

@ -153,7 +153,8 @@ PackageFileHeapReader::Clone() const
status_t
PackageFileHeapReader::ReadAndDecompressChunk(size_t chunkIndex,
void* compressedDataBuffer, void* uncompressedDataBuffer)
void* compressedDataBuffer, void* uncompressedDataBuffer,
iovec* scratchBuffer)
{
uint64 offset = fOffsets[chunkIndex];
bool isLastChunk
@ -166,7 +167,7 @@ PackageFileHeapReader::ReadAndDecompressChunk(size_t chunkIndex,
: kChunkSize;
return ReadAndDecompressChunkData(offset, compressedSize, uncompressedSize,
compressedDataBuffer, uncompressedDataBuffer);
compressedDataBuffer, uncompressedDataBuffer, scratchBuffer);
}

View File

@ -409,9 +409,9 @@ PackageFileHeapWriter::RemoveDataRanges(
} else if (decompressedChunk == &chunk) {
uncompressedData = decompressionBuffer;
} else {
status_t error = DecompressChunkData(chunk.buffer,
chunk.compressedSize, decompressionBuffer,
chunk.uncompressedSize);
iovec compressed = { chunk.buffer, chunk.compressedSize },
uncompressed = { decompressionBuffer, chunk.uncompressedSize };
status_t error = DecompressChunkData(compressed, uncompressed);
if (error != B_OK)
throw error;
@ -479,7 +479,8 @@ PackageFileHeapWriter::Finish()
status_t
PackageFileHeapWriter::ReadAndDecompressChunk(size_t chunkIndex,
void* compressedDataBuffer, void* uncompressedDataBuffer)
void* compressedDataBuffer, void* uncompressedDataBuffer,
iovec* scratchBuffer)
{
if (uint64(chunkIndex + 1) * kChunkSize > fUncompressedHeapSize) {
// The chunk has not been written to disk yet. Its data are still in the
@ -496,7 +497,7 @@ PackageFileHeapWriter::ReadAndDecompressChunk(size_t chunkIndex,
: fOffsets[chunkIndex + 1] - offset;
return ReadAndDecompressChunkData(offset, compressedSize, kChunkSize,
compressedDataBuffer, uncompressedDataBuffer);
compressedDataBuffer, uncompressedDataBuffer, scratchBuffer);
}
@ -562,9 +563,10 @@ PackageFileHeapWriter::_WriteDataCompressed(const void* data, size_t size)
if (fCompressionAlgorithm == NULL)
return B_BUFFER_OVERFLOW;
size_t compressedSize;
status_t error = fCompressionAlgorithm->algorithm->CompressBuffer(data,
size, fCompressedDataBuffer, size, compressedSize,
const iovec uncompressed = { (void*)data, size };
iovec compressed = { fCompressedDataBuffer, size };
status_t error = fCompressionAlgorithm->algorithm->CompressBuffer(
uncompressed, compressed,
fCompressionAlgorithm->parameters);
if (error != B_OK) {
if (error != B_BUFFER_OVERFLOW) {
@ -575,10 +577,10 @@ PackageFileHeapWriter::_WriteDataCompressed(const void* data, size_t size)
}
// only use compressed data when we've actually saved space
if (compressedSize == size)
if (compressed.iov_len == size)
return B_BUFFER_OVERFLOW;
return _WriteDataUncompressed(fCompressedDataBuffer, compressedSize);
return _WriteDataUncompressed(fCompressedDataBuffer, compressed.iov_len);
}

View File

@ -293,12 +293,11 @@ private:
if (error != B_OK)
return error;
size_t actuallyUncompressedSize;
BZlibCompressionAlgorithm().DecompressBuffer(
readBuffer->Buffer(), compressedSize,
fUncompressBuffer->Buffer(), uncompressedSize,
actuallyUncompressedSize);
if (error == B_OK && actuallyUncompressedSize != uncompressedSize)
iovec compressed = { readBuffer->Buffer(), compressedSize },
uncompressed = { fUncompressBuffer->Buffer(), uncompressedSize };
error = BZlibCompressionAlgorithm().DecompressBuffer(
compressed, uncompressed);
if (error == B_OK && uncompressed.iov_len != uncompressedSize)
error = B_BAD_DATA;
}

View File

@ -84,18 +84,16 @@ BCompressionAlgorithm::CreateDecompressingOutputStream(BDataIO* output,
status_t
BCompressionAlgorithm::CompressBuffer(const void* input, size_t inputSize,
void* output, size_t outputSize, size_t& _compressedSize,
const BCompressionParameters* parameters)
BCompressionAlgorithm::CompressBuffer(const iovec& input, iovec& output,
const BCompressionParameters* parameters, iovec* scratch)
{
return B_NOT_SUPPORTED;
}
status_t
BCompressionAlgorithm::DecompressBuffer(const void* input,
size_t inputSize, void* output, size_t outputSize,
size_t& _uncompressedSize, const BDecompressionParameters* parameters)
BCompressionAlgorithm::DecompressBuffer(const iovec& input, iovec& output,
const BDecompressionParameters* parameters, iovec* scratch)
{
return B_NOT_SUPPORTED;
}

View File

@ -366,9 +366,8 @@ BZlibCompressionAlgorithm::CreateDecompressingOutputStream(BDataIO* output,
status_t
BZlibCompressionAlgorithm::CompressBuffer(const void* input,
size_t inputSize, void* output, size_t outputSize, size_t& _compressedSize,
const BCompressionParameters* parameters)
BZlibCompressionAlgorithm::CompressBuffer(const iovec& input, iovec& output,
const BCompressionParameters* parameters, iovec* scratch)
{
#ifdef B_ZLIB_COMPRESSION_SUPPORT
const BZlibCompressionParameters* zlibParameters
@ -377,13 +376,13 @@ BZlibCompressionAlgorithm::CompressBuffer(const void* input,
? zlibParameters->CompressionLevel()
: B_ZLIB_COMPRESSION_DEFAULT;
uLongf bytesUsed = outputSize;
int zlibError = compress2((Bytef*)output, &bytesUsed, (const Bytef*)input,
(uLong)inputSize, compressionLevel);
uLongf bytesUsed = output.iov_len;
int zlibError = compress2((Bytef*)output.iov_base, &bytesUsed,
(const Bytef*)input.iov_base, (uLong)input.iov_len, compressionLevel);
if (zlibError != Z_OK)
return _TranslateZlibError(zlibError);
_compressedSize = (size_t)bytesUsed;
output.iov_len = (size_t)bytesUsed;
return B_OK;
#else
return B_NOT_SUPPORTED;
@ -392,17 +391,16 @@ BZlibCompressionAlgorithm::CompressBuffer(const void* input,
status_t
BZlibCompressionAlgorithm::DecompressBuffer(const void* input,
size_t inputSize, void* output, size_t outputSize,
size_t& _uncompressedSize, const BDecompressionParameters* parameters)
BZlibCompressionAlgorithm::DecompressBuffer(const iovec& input, iovec& output,
const BDecompressionParameters* parameters, iovec* scratch)
{
uLongf bytesUsed = outputSize;
int zlibError = uncompress((Bytef*)output, &bytesUsed, (const Bytef*)input,
(uLong)inputSize);
uLongf bytesUsed = output.iov_len;
int zlibError = uncompress((Bytef*)output.iov_base, &bytesUsed,
(const Bytef*)input.iov_base, (uLong)input.iov_len);
if (zlibError != Z_OK)
return _TranslateZlibError(zlibError);
_uncompressedSize = (size_t)bytesUsed;
output.iov_len = (size_t)bytesUsed;
return B_OK;
}

View File

@ -18,6 +18,7 @@
#include <zstd_errors.h>
#endif
#include <AutoDeleter.h>
#include <DataIO.h>
@ -367,23 +368,23 @@ BZstdCompressionAlgorithm::CreateDecompressingOutputStream(BDataIO* output,
status_t
BZstdCompressionAlgorithm::CompressBuffer(const void* input,
size_t inputSize, void* output, size_t outputSize, size_t& _compressedSize,
const BCompressionParameters* parameters)
BZstdCompressionAlgorithm::CompressBuffer(const iovec& input, iovec& output,
const BCompressionParameters* parameters, iovec* scratch)
{
#ifdef B_ZSTD_COMPRESSION_SUPPORT
// TODO: Make use of scratch buffer (if available.)
const BZstdCompressionParameters* zstdParameters
= dynamic_cast<const BZstdCompressionParameters*>(parameters);
int compressionLevel = zstdParameters != NULL
? zstdParameters->CompressionLevel()
: B_ZSTD_COMPRESSION_DEFAULT;
size_t zstdError = ZSTD_compress(output, outputSize, input,
inputSize, compressionLevel);
size_t zstdError = ZSTD_compress(output.iov_base, output.iov_len,
input.iov_base, input.iov_len, compressionLevel);
if (ZSTD_isError(zstdError))
return _TranslateZstdError(zstdError);
_compressedSize = zstdError;
output.iov_len = zstdError;
return B_OK;
#else
return B_NOT_SUPPORTED;
@ -392,17 +393,26 @@ BZstdCompressionAlgorithm::CompressBuffer(const void* input,
status_t
BZstdCompressionAlgorithm::DecompressBuffer(const void* input,
size_t inputSize, void* output, size_t outputSize,
size_t& _uncompressedSize, const BDecompressionParameters* parameters)
BZstdCompressionAlgorithm::DecompressBuffer(const iovec& input, iovec& output,
const BDecompressionParameters* parameters, iovec* scratch)
{
#ifdef ZSTD_ENABLED
size_t zstdError = ZSTD_decompress(output, outputSize, input,
inputSize);
ZSTD_DCtx* dctx;
CObjectDeleter<ZSTD_DCtx, size_t, ZSTD_freeDCtx> dctxDeleter;
#if defined(ZSTD_STATIC_LINKING_ONLY)
if (scratch != NULL)
dctx = ZSTD_initStaticDCtx(scratch->iov_base, scratch->iov_len);
else
#endif
dctxDeleter.SetTo(dctx = ZSTD_createDCtx());
size_t zstdError = ZSTD_decompressDCtx(dctx,
output.iov_base, output.iov_len,
input.iov_base, input.iov_len);
if (ZSTD_isError(zstdError))
return _TranslateZstdError(zstdError);
_uncompressedSize = zstdError;
output.iov_len = zstdError;
return B_OK;
#else
return B_NOT_SUPPORTED;