2011-12-30 17:57:02 +00:00
|
|
|
#pragma once
|
2011-06-27 18:22:14 +00:00
|
|
|
|
2012-06-22 16:54:51 +00:00
|
|
|
#include <boost/noncopyable.hpp>
|
2011-06-27 18:22:14 +00:00
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/ProfileEvents.h>
|
|
|
|
#include <Common/Allocator.h>
|
2014-01-04 04:53:07 +00:00
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/Exception.h>
|
|
|
|
#include <Core/Defines.h>
|
2011-06-27 18:22:14 +00:00
|
|
|
|
|
|
|
|
2016-10-24 02:02:37 +00:00
|
|
|
namespace ProfileEvents
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
extern const Event IOBufferAllocs;
|
|
|
|
extern const Event IOBufferAllocBytes;
|
2016-10-24 02:02:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-06-27 18:22:14 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
|
2016-10-24 02:02:37 +00:00
|
|
|
/** Replacement for std::vector<char> to use in buffers.
|
|
|
|
* Differs in that is doesn't do unneeded memset. (And also tries to do as little as possible.)
|
|
|
|
* Also allows to allocate aligned piece of memory (to use with O_DIRECT, for example).
|
2013-09-08 05:53:10 +00:00
|
|
|
*/
|
2019-04-06 15:27:39 +00:00
|
|
|
template <typename Allocator = Allocator<false>>
|
|
|
|
struct Memory : boost::noncopyable, Allocator
|
2012-06-21 18:43:29 +00:00
|
|
|
{
|
2018-08-30 20:12:15 +00:00
|
|
|
/// Padding is needed to allow usage of 'memcpySmallAllowReadWriteOverflow15' function with this buffer.
|
Padding for IO buffers.
Testing data
```
select 'aaaaaaaa','bbbbbbbb','cccccccc','dddddddd','eeeeeeee','ffffffff','gggg','hhh' from numbers(3000000) into outfile '/tmp/test.tsv'
```
Testing command
```
echo "select count() from file('/tmp/test.tsv', CSV, 'a String, b String, c String, d String, e String, f String, g String, h String') where not ignore(e)" | clickhouse-benchmark
```
TSV parser has less overhead than CSV, using it would better unveil the benefits of memcpySmall.
Before
```
QPS: 1.662, RPS: 4985463.906, MiB/s: 603.823, result RPS: 1.662, result MiB/s: 0.000.
0.000% 0.559 sec.
10.000% 0.564 sec.
20.000% 0.568 sec.
30.000% 0.572 sec.
40.000% 0.575 sec.
50.000% 0.581 sec.
60.000% 0.592 sec.
70.000% 0.624 sec.
80.000% 0.639 sec.
90.000% 0.664 sec.
95.000% 0.686 sec.
99.000% 0.711 sec.
99.900% 0.715 sec.
99.990% 0.716 sec.
```
After
```
QPS: 1.861, RPS: 5582303.107, MiB/s: 676.110, result RPS: 1.861, result MiB/s: 0.000.
0.000% 0.510 sec.
10.000% 0.514 sec.
20.000% 0.517 sec.
30.000% 0.521 sec.
40.000% 0.523 sec.
50.000% 0.527 sec.
60.000% 0.530 sec.
70.000% 0.539 sec.
80.000% 0.558 sec.
90.000% 0.584 sec.
95.000% 0.589 sec.
99.000% 0.608 sec.
99.900% 0.655 sec.
99.990% 0.663 sec.
```
2018-08-27 19:14:15 +00:00
|
|
|
static constexpr size_t pad_right = 15;
|
2018-08-30 20:12:15 +00:00
|
|
|
|
|
|
|
size_t m_capacity = 0; /// With padding.
|
2017-04-01 07:20:54 +00:00
|
|
|
size_t m_size = 0;
|
|
|
|
char * m_data = nullptr;
|
|
|
|
size_t alignment = 0;
|
|
|
|
|
|
|
|
Memory() {}
|
|
|
|
|
|
|
|
/// If alignment != 0, then allocate memory aligned to specified value.
|
|
|
|
Memory(size_t size_, size_t alignment_ = 0) : m_capacity(size_), m_size(m_capacity), alignment(alignment_)
|
|
|
|
{
|
|
|
|
alloc();
|
|
|
|
}
|
|
|
|
|
|
|
|
~Memory()
|
|
|
|
{
|
|
|
|
dealloc();
|
|
|
|
}
|
|
|
|
|
2017-08-30 20:23:29 +00:00
|
|
|
Memory(Memory && rhs) noexcept
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
*this = std::move(rhs);
|
|
|
|
}
|
|
|
|
|
2017-08-30 20:23:29 +00:00
|
|
|
Memory & operator=(Memory && rhs) noexcept
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
std::swap(m_capacity, rhs.m_capacity);
|
|
|
|
std::swap(m_size, rhs.m_size);
|
|
|
|
std::swap(m_data, rhs.m_data);
|
|
|
|
std::swap(alignment, rhs.alignment);
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t size() const { return m_size; }
|
|
|
|
const char & operator[](size_t i) const { return m_data[i]; }
|
|
|
|
char & operator[](size_t i) { return m_data[i]; }
|
|
|
|
const char * data() const { return m_data; }
|
|
|
|
char * data() { return m_data; }
|
|
|
|
|
|
|
|
void resize(size_t new_size)
|
|
|
|
{
|
|
|
|
if (0 == m_capacity)
|
|
|
|
{
|
2018-08-30 20:12:15 +00:00
|
|
|
m_size = new_size;
|
|
|
|
m_capacity = new_size;
|
2017-04-01 07:20:54 +00:00
|
|
|
alloc();
|
|
|
|
}
|
2019-11-18 15:21:03 +00:00
|
|
|
else if (new_size <= m_capacity - pad_right)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
m_size = new_size;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Padding for IO buffers.
Testing data
```
select 'aaaaaaaa','bbbbbbbb','cccccccc','dddddddd','eeeeeeee','ffffffff','gggg','hhh' from numbers(3000000) into outfile '/tmp/test.tsv'
```
Testing command
```
echo "select count() from file('/tmp/test.tsv', CSV, 'a String, b String, c String, d String, e String, f String, g String, h String') where not ignore(e)" | clickhouse-benchmark
```
TSV parser has less overhead than CSV, using it would better unveil the benefits of memcpySmall.
Before
```
QPS: 1.662, RPS: 4985463.906, MiB/s: 603.823, result RPS: 1.662, result MiB/s: 0.000.
0.000% 0.559 sec.
10.000% 0.564 sec.
20.000% 0.568 sec.
30.000% 0.572 sec.
40.000% 0.575 sec.
50.000% 0.581 sec.
60.000% 0.592 sec.
70.000% 0.624 sec.
80.000% 0.639 sec.
90.000% 0.664 sec.
95.000% 0.686 sec.
99.000% 0.711 sec.
99.900% 0.715 sec.
99.990% 0.716 sec.
```
After
```
QPS: 1.861, RPS: 5582303.107, MiB/s: 676.110, result RPS: 1.861, result MiB/s: 0.000.
0.000% 0.510 sec.
10.000% 0.514 sec.
20.000% 0.517 sec.
30.000% 0.521 sec.
40.000% 0.523 sec.
50.000% 0.527 sec.
60.000% 0.530 sec.
70.000% 0.539 sec.
80.000% 0.558 sec.
90.000% 0.584 sec.
95.000% 0.589 sec.
99.000% 0.608 sec.
99.900% 0.655 sec.
99.990% 0.663 sec.
```
2018-08-27 19:14:15 +00:00
|
|
|
size_t new_capacity = align(new_size + pad_right, alignment);
|
|
|
|
m_data = static_cast<char *>(Allocator::realloc(m_data, m_capacity, new_capacity, alignment));
|
|
|
|
m_capacity = new_capacity;
|
|
|
|
m_size = m_capacity - pad_right;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-07 21:04:48 +00:00
|
|
|
private:
|
2017-04-01 07:20:54 +00:00
|
|
|
static size_t align(const size_t value, const size_t alignment)
|
|
|
|
{
|
|
|
|
if (!alignment)
|
|
|
|
return value;
|
|
|
|
|
|
|
|
return (value + alignment - 1) / alignment * alignment;
|
|
|
|
}
|
2015-08-16 13:00:22 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
void alloc()
|
|
|
|
{
|
|
|
|
if (!m_capacity)
|
|
|
|
{
|
|
|
|
m_data = nullptr;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
Padding for IO buffers.
Testing data
```
select 'aaaaaaaa','bbbbbbbb','cccccccc','dddddddd','eeeeeeee','ffffffff','gggg','hhh' from numbers(3000000) into outfile '/tmp/test.tsv'
```
Testing command
```
echo "select count() from file('/tmp/test.tsv', CSV, 'a String, b String, c String, d String, e String, f String, g String, h String') where not ignore(e)" | clickhouse-benchmark
```
TSV parser has less overhead than CSV, using it would better unveil the benefits of memcpySmall.
Before
```
QPS: 1.662, RPS: 4985463.906, MiB/s: 603.823, result RPS: 1.662, result MiB/s: 0.000.
0.000% 0.559 sec.
10.000% 0.564 sec.
20.000% 0.568 sec.
30.000% 0.572 sec.
40.000% 0.575 sec.
50.000% 0.581 sec.
60.000% 0.592 sec.
70.000% 0.624 sec.
80.000% 0.639 sec.
90.000% 0.664 sec.
95.000% 0.686 sec.
99.000% 0.711 sec.
99.900% 0.715 sec.
99.990% 0.716 sec.
```
After
```
QPS: 1.861, RPS: 5582303.107, MiB/s: 676.110, result RPS: 1.861, result MiB/s: 0.000.
0.000% 0.510 sec.
10.000% 0.514 sec.
20.000% 0.517 sec.
30.000% 0.521 sec.
40.000% 0.523 sec.
50.000% 0.527 sec.
60.000% 0.530 sec.
70.000% 0.539 sec.
80.000% 0.558 sec.
90.000% 0.584 sec.
95.000% 0.589 sec.
99.000% 0.608 sec.
99.900% 0.655 sec.
99.990% 0.663 sec.
```
2018-08-27 19:14:15 +00:00
|
|
|
size_t padded_capacity = m_capacity + pad_right;
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
ProfileEvents::increment(ProfileEvents::IOBufferAllocs);
|
Padding for IO buffers.
Testing data
```
select 'aaaaaaaa','bbbbbbbb','cccccccc','dddddddd','eeeeeeee','ffffffff','gggg','hhh' from numbers(3000000) into outfile '/tmp/test.tsv'
```
Testing command
```
echo "select count() from file('/tmp/test.tsv', CSV, 'a String, b String, c String, d String, e String, f String, g String, h String') where not ignore(e)" | clickhouse-benchmark
```
TSV parser has less overhead than CSV, using it would better unveil the benefits of memcpySmall.
Before
```
QPS: 1.662, RPS: 4985463.906, MiB/s: 603.823, result RPS: 1.662, result MiB/s: 0.000.
0.000% 0.559 sec.
10.000% 0.564 sec.
20.000% 0.568 sec.
30.000% 0.572 sec.
40.000% 0.575 sec.
50.000% 0.581 sec.
60.000% 0.592 sec.
70.000% 0.624 sec.
80.000% 0.639 sec.
90.000% 0.664 sec.
95.000% 0.686 sec.
99.000% 0.711 sec.
99.900% 0.715 sec.
99.990% 0.716 sec.
```
After
```
QPS: 1.861, RPS: 5582303.107, MiB/s: 676.110, result RPS: 1.861, result MiB/s: 0.000.
0.000% 0.510 sec.
10.000% 0.514 sec.
20.000% 0.517 sec.
30.000% 0.521 sec.
40.000% 0.523 sec.
50.000% 0.527 sec.
60.000% 0.530 sec.
70.000% 0.539 sec.
80.000% 0.558 sec.
90.000% 0.584 sec.
95.000% 0.589 sec.
99.000% 0.608 sec.
99.900% 0.655 sec.
99.990% 0.663 sec.
```
2018-08-27 19:14:15 +00:00
|
|
|
ProfileEvents::increment(ProfileEvents::IOBufferAllocBytes, padded_capacity);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
Padding for IO buffers.
Testing data
```
select 'aaaaaaaa','bbbbbbbb','cccccccc','dddddddd','eeeeeeee','ffffffff','gggg','hhh' from numbers(3000000) into outfile '/tmp/test.tsv'
```
Testing command
```
echo "select count() from file('/tmp/test.tsv', CSV, 'a String, b String, c String, d String, e String, f String, g String, h String') where not ignore(e)" | clickhouse-benchmark
```
TSV parser has less overhead than CSV, using it would better unveil the benefits of memcpySmall.
Before
```
QPS: 1.662, RPS: 4985463.906, MiB/s: 603.823, result RPS: 1.662, result MiB/s: 0.000.
0.000% 0.559 sec.
10.000% 0.564 sec.
20.000% 0.568 sec.
30.000% 0.572 sec.
40.000% 0.575 sec.
50.000% 0.581 sec.
60.000% 0.592 sec.
70.000% 0.624 sec.
80.000% 0.639 sec.
90.000% 0.664 sec.
95.000% 0.686 sec.
99.000% 0.711 sec.
99.900% 0.715 sec.
99.990% 0.716 sec.
```
After
```
QPS: 1.861, RPS: 5582303.107, MiB/s: 676.110, result RPS: 1.861, result MiB/s: 0.000.
0.000% 0.510 sec.
10.000% 0.514 sec.
20.000% 0.517 sec.
30.000% 0.521 sec.
40.000% 0.523 sec.
50.000% 0.527 sec.
60.000% 0.530 sec.
70.000% 0.539 sec.
80.000% 0.558 sec.
90.000% 0.584 sec.
95.000% 0.589 sec.
99.000% 0.608 sec.
99.900% 0.655 sec.
99.990% 0.663 sec.
```
2018-08-27 19:14:15 +00:00
|
|
|
size_t new_capacity = align(padded_capacity, alignment);
|
2017-04-01 07:20:54 +00:00
|
|
|
m_data = static_cast<char *>(Allocator::alloc(new_capacity, alignment));
|
|
|
|
m_capacity = new_capacity;
|
Padding for IO buffers.
Testing data
```
select 'aaaaaaaa','bbbbbbbb','cccccccc','dddddddd','eeeeeeee','ffffffff','gggg','hhh' from numbers(3000000) into outfile '/tmp/test.tsv'
```
Testing command
```
echo "select count() from file('/tmp/test.tsv', CSV, 'a String, b String, c String, d String, e String, f String, g String, h String') where not ignore(e)" | clickhouse-benchmark
```
TSV parser has less overhead than CSV, using it would better unveil the benefits of memcpySmall.
Before
```
QPS: 1.662, RPS: 4985463.906, MiB/s: 603.823, result RPS: 1.662, result MiB/s: 0.000.
0.000% 0.559 sec.
10.000% 0.564 sec.
20.000% 0.568 sec.
30.000% 0.572 sec.
40.000% 0.575 sec.
50.000% 0.581 sec.
60.000% 0.592 sec.
70.000% 0.624 sec.
80.000% 0.639 sec.
90.000% 0.664 sec.
95.000% 0.686 sec.
99.000% 0.711 sec.
99.900% 0.715 sec.
99.990% 0.716 sec.
```
After
```
QPS: 1.861, RPS: 5582303.107, MiB/s: 676.110, result RPS: 1.861, result MiB/s: 0.000.
0.000% 0.510 sec.
10.000% 0.514 sec.
20.000% 0.517 sec.
30.000% 0.521 sec.
40.000% 0.523 sec.
50.000% 0.527 sec.
60.000% 0.530 sec.
70.000% 0.539 sec.
80.000% 0.558 sec.
90.000% 0.584 sec.
95.000% 0.589 sec.
99.000% 0.608 sec.
99.900% 0.655 sec.
99.990% 0.663 sec.
```
2018-08-27 19:14:15 +00:00
|
|
|
m_size = m_capacity - pad_right;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void dealloc()
|
|
|
|
{
|
|
|
|
if (!m_data)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Allocator::free(m_data, m_capacity);
|
|
|
|
m_data = nullptr; /// To avoid double free if next alloc will throw an exception.
|
|
|
|
}
|
2013-09-08 05:53:10 +00:00
|
|
|
};
|
2012-06-21 18:43:29 +00:00
|
|
|
|
|
|
|
|
2016-10-24 02:02:37 +00:00
|
|
|
/** Buffer that could own its working memory.
|
|
|
|
* Template parameter: ReadBuffer or WriteBuffer
|
2011-06-27 18:22:14 +00:00
|
|
|
*/
|
|
|
|
template <typename Base>
|
|
|
|
class BufferWithOwnMemory : public Base
|
|
|
|
{
|
|
|
|
protected:
|
2019-04-06 15:27:39 +00:00
|
|
|
Memory<> memory;
|
2011-06-27 18:22:14 +00:00
|
|
|
public:
|
2017-04-01 07:20:54 +00:00
|
|
|
/// If non-nullptr 'existing_memory' is passed, then buffer will not create its own memory and will use existing_memory without ownership.
|
|
|
|
BufferWithOwnMemory(size_t size = DBMS_DEFAULT_BUFFER_SIZE, char * existing_memory = nullptr, size_t alignment = 0)
|
|
|
|
: Base(nullptr, 0), memory(existing_memory ? 0 : size, alignment)
|
|
|
|
{
|
|
|
|
Base::set(existing_memory ? existing_memory : memory.data(), size);
|
Padding for IO buffers.
Testing data
```
select 'aaaaaaaa','bbbbbbbb','cccccccc','dddddddd','eeeeeeee','ffffffff','gggg','hhh' from numbers(3000000) into outfile '/tmp/test.tsv'
```
Testing command
```
echo "select count() from file('/tmp/test.tsv', CSV, 'a String, b String, c String, d String, e String, f String, g String, h String') where not ignore(e)" | clickhouse-benchmark
```
TSV parser has less overhead than CSV, using it would better unveil the benefits of memcpySmall.
Before
```
QPS: 1.662, RPS: 4985463.906, MiB/s: 603.823, result RPS: 1.662, result MiB/s: 0.000.
0.000% 0.559 sec.
10.000% 0.564 sec.
20.000% 0.568 sec.
30.000% 0.572 sec.
40.000% 0.575 sec.
50.000% 0.581 sec.
60.000% 0.592 sec.
70.000% 0.624 sec.
80.000% 0.639 sec.
90.000% 0.664 sec.
95.000% 0.686 sec.
99.000% 0.711 sec.
99.900% 0.715 sec.
99.990% 0.716 sec.
```
After
```
QPS: 1.861, RPS: 5582303.107, MiB/s: 676.110, result RPS: 1.861, result MiB/s: 0.000.
0.000% 0.510 sec.
10.000% 0.514 sec.
20.000% 0.517 sec.
30.000% 0.521 sec.
40.000% 0.523 sec.
50.000% 0.527 sec.
60.000% 0.530 sec.
70.000% 0.539 sec.
80.000% 0.558 sec.
90.000% 0.584 sec.
95.000% 0.589 sec.
99.000% 0.608 sec.
99.900% 0.655 sec.
99.990% 0.663 sec.
```
2018-08-27 19:14:15 +00:00
|
|
|
Base::padded = !existing_memory;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2011-06-27 18:22:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
}
|