On my arm64 dev board, CentOS 7.4, the default OS page size is 64k, one SSD disk,
ceph version is 13.2.1. When I do fio randread test(bs=4k), the ceph-osd process uses a
large amount of memory(more than 20G), while bs=64, just more than 2G.
After traceing the mem allocate process, it is found to be related to page size
alignment - applying for small mem(4k) but align to big page size(64k) will lead
to waste memory.
With reference to the original create_page_aligned, add a new interface
create_small_page_aligned to useing 4k alignment. Go through all the callers of
create_page_aligned, divide the big and small page align according to the
relationship between applying for and current page size. Individual callers with
their own context logic not do the diversion.
After using the patch, do the fio randread test(bs=4k) in 64k page size OS, the
memory used by the ceph-osd process be reduced from more than 20G to about 3G;
for the bs=16k case, the memory used is also significantly reduced; while the
reading performance has not been reduced.
When I porting the patch to the last ceph tree(version 14.0.0-xxx), also made a
comparative verification. For the fio(bs=4k) test, although the current 14.0.0-x
version is less mem expensive than the 13.2.1 version, but the memory usage of
using the patche is also reduced significantly.
The following is a partial comparison of validation data, different software and
hardware environments may have different test values, the better the performance
of the SSD, the more memory it will use.
ceph version bs VIRT RES
13.2.1 64k
3600896 2.7g
13.2.1 64k
3610112 2.7g
13.2.1 64k
3614208 2.7g
13.2.1 16k
7485184 6.4g
13.2.1 16k
7486208 6.4g
13.2.1 16k
7486208 6.4g
13.2.1 4k 23.7g 22.9g <--A lot of waste
13.2.1 4k 23.7g 22.9g
13.2.1 4k 23.7g 22.9g
13.2.1+patch 64k
3632384 2.7g
13.2.1+patch 64k
3636480 2.7g
13.2.1+patch 64k
3640576 2.7g
13.2.1+patch 16k
3175296 2.2g
13.2.1+patch 16k
3175296 2.2g
13.2.1+patch 16k
3176320 2.2g
13.2.1+patch 4k
4265920 3.3g <--Reasonable usage quantity
13.2.1+patch 4k
4265920 3.3g
13.2.1+patch 4k
4265920 3.3g
14.0.0-x 64k
6230784 4.4g
14.0.0-x 64k
5731840 4.1g
14.0.0-x 64k
4547072 3.5g
14.0.0-x 64k
4544000 3.6g
14.0.0-x 16k
6272192 5.2g
14.0.0-x 16k
6343168 5.3g
14.0.0-x 16k
6357696 5.3g
14.0.0-x 4k 10.1g 9.3g <--A lot of waste
14.0.0-x 4k 10.3g 9.6g
14.0.0-x 4k 10.3g 9.4g
14.0.0-x+patch 64k
5974464 4.6g
14.0.0-x+patch 64k
4547008 3.5g
14.0.0-x+patch 64k
4556288 3.6g
14.0.0-x+patch 16k
4058560 3.1g
14.0.0-x+patch 16k
4053504 3.1g
14.0.0-x+patch 16k
4062720 3.1g
14.0.0-x+patch 4k
5283264 4.3g <--Reasonable usage quantity
14.0.0-x+patch 4k
5324224 4.3g
14.0.0-x+patch 4k
5297600 4.3g
Signed-off-by: Jiang Yutang <yutang2.jiang@hxt-semitech.com>
buffer::raw* buffer::create_page_aligned(unsigned len) {
return create_aligned(len, CEPH_PAGE_SIZE);
}
+ buffer::raw* buffer::create_small_page_aligned(unsigned len) {
+ if (len < CEPH_PAGE_SIZE) {
+ return create_aligned(len, CEPH_BUFFER_ALLOC_UNIT);
+ } else
+ return create_aligned(len, CEPH_PAGE_SIZE);
+ }
buffer::raw* buffer::create_zero_copy(unsigned len, int fd, int64_t *offset) {
#ifdef CEPH_HAVE_SPLICE
unsigned int len = i.length();
unsigned int out_len = qzMaxCompressedLength(len);
- bufferptr ptr = buffer::create_page_aligned(out_len);
+ bufferptr ptr = buffer::create_small_page_aligned(out_len);
int rc = qzCompress(&session, c_in, &len, (unsigned char *)ptr.c_str(), &out_len, 1);
if (rc != QZ_OK)
return -1;
len = tmp.length();
}
unsigned int out_len = len * expansion_ratio[ratio_idx];
- bufferptr ptr = buffer::create_page_aligned(out_len);
+ bufferptr ptr = buffer::create_small_page_aligned(out_len);
if (joint)
rc = qzDecompress(&session, (const unsigned char*)tmp.c_str(), &len, (unsigned char*)ptr.c_str(), &out_len);
size_t available_in = i->length();
size_t max_comp_size = BrotliEncoderMaxCompressedSize(available_in);
size_t available_out = max_comp_size;
- bufferptr ptr = buffer::create_page_aligned(max_comp_size);
+ bufferptr ptr = buffer::create_small_page_aligned(max_comp_size);
uint8_t* next_out = (uint8_t*)ptr.c_str();
const uint8_t* next_in = (uint8_t*)i->c_str();
++i;
if (qat_enabled)
return qat_accel.compress(src, dst);
#endif
- bufferptr outptr = buffer::create_page_aligned(
+ bufferptr outptr = buffer::create_small_page_aligned(
LZ4_compressBound(src.length()));
LZ4_stream_t lz4_stream;
LZ4_resetStream(&lz4_stream);
return qat_accel.compress(src, dst);
#endif
BufferlistSource source(const_cast<bufferlist&>(src).begin(), src.length());
- bufferptr ptr = buffer::create_page_aligned(
+ bufferptr ptr = buffer::create_small_page_aligned(
snappy::MaxCompressedLength(src.length()));
snappy::UncheckedByteArraySink sink(ptr.c_str());
snappy::Compress(&source, &sink);
size_t left = src.length();
size_t const out_max = ZSTD_compressBound(left);
- bufferptr outptr = buffer::create_page_aligned(out_max);
+ bufferptr outptr = buffer::create_small_page_aligned(out_max);
ZSTD_outBuffer_s outbuf;
outbuf.dst = outptr.c_str();
outbuf.size = outptr.length();
raw* create_aligned(unsigned len, unsigned align);
raw* create_aligned_in_mempool(unsigned len, unsigned align, int mempool);
raw* create_page_aligned(unsigned len);
+ raw* create_small_page_aligned(unsigned len);
raw* create_zero_copy(unsigned len, int fd, int64_t *offset);
raw* create_unshareable(unsigned len);
raw* create_static(unsigned len, char *buf);
left -= head;
}
alloc_len += left;
- bufferptr ptr(buffer::create_page_aligned(alloc_len));
+ bufferptr ptr(buffer::create_small_page_aligned(alloc_len));
if (head)
ptr.set_offset(CEPH_PAGE_SIZE - head);
data.push_back(std::move(ptr));
}
unsigned middle = left & CEPH_PAGE_MASK;
if (middle > 0) {
- data.push_back(buffer::create_page_aligned(middle));
+ data.push_back(buffer::create_small_page_aligned(middle));
left -= middle;
}
if (left) {
size_t pad_count = 0;
if (front_pad) {
size_t front_copy = std::min<uint64_t>(chunk_size - front_pad, length);
- bufferptr z = buffer::create_page_aligned(chunk_size);
+ bufferptr z = buffer::create_small_page_aligned(chunk_size);
z.zero(0, front_pad, false);
pad_count += front_pad;
bl->copy(0, front_copy, z.c_str() + front_pad);
_aio_log_start(ioc, off, len);
- bufferptr p = buffer::create_page_aligned(len);
+ bufferptr p = buffer::create_small_page_aligned(len);
int r = ::pread(buffered ? fd_buffered : fd_direct,
p.c_str(), len, off);
if (r < 0) {
{
uint64_t aligned_off = align_down(off, block_size);
uint64_t aligned_len = align_up(off+len, block_size) - aligned_off;
- bufferptr p = buffer::create_page_aligned(aligned_len);
+ bufferptr p = buffer::create_small_page_aligned(aligned_len);
int r = 0;
r = ::pread(fd_direct, p.c_str(), aligned_len, aligned_off);
ceph_assert(is_valid_io(off, len));
Task *t = new Task(this, IOCommand::READ_COMMAND, off, len, 1);
- bufferptr p = buffer::create_page_aligned(len);
+ bufferptr p = buffer::create_small_page_aligned(len);
int r = 0;
t->ctx = ioc;
char *buf = p.c_str();
Task *t = new Task(this, IOCommand::READ_COMMAND, off, len);
- bufferptr p = buffer::create_page_aligned(len);
+ bufferptr p = buffer::create_small_page_aligned(len);
pbl->append(p);
t->ctx = ioc;
char* buf = p.c_str();
dout(5) << __func__ << " " << off << "~" << len << dendl;
ceph_assert(is_valid_io(off, len));
- bufferptr p = buffer::create_page_aligned(len);
+ bufferptr p = buffer::create_small_page_aligned(len);
memcpy(p.c_str(), addr + off, len);
pbl->clear();
void pread(uint64_t _offset, uint64_t len) {
offset = _offset;
length = len;
- bufferptr p = buffer::create_page_aligned(length);
+ bufferptr p = buffer::create_small_page_aligned(length);
io_prep_pread(&iocb, fd, p.c_str(), length, offset);
bl.append(std::move(p));
}
dout(10) << "read_header" << dendl;
bufferlist bl;
- buffer::ptr bp = buffer::create_page_aligned(block_size);
+ buffer::ptr bp = buffer::create_small_page_aligned(block_size);
char* bpdata = bp.c_str();
int r = ::pread(fd, bpdata, bp.length(), 0);
header.committed_up_to = journaled_seq;
}
encode(header, bl);
- bufferptr bp = buffer::create_page_aligned(get_top());
+ bufferptr bp = buffer::create_small_page_aligned(get_top());
// don't use bp.zero() here, because it also invalidates
// crc cache (which is not yet populated anyway)
char* data = bp.c_str();