Skip to content

Commit df5ab5d

Browse files
committed
More stress tests
1 parent 291275f commit df5ab5d

13 files changed

+408
-236
lines changed

cpp/arcticdb/CMakeLists.txt

+12-4
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,11 @@ set(arcticdb_srcs
381381
util/lazy.hpp
382382
util/type_traits.hpp
383383
util/variant.hpp
384+
util/min_max_integer.hpp
385+
util/mean.hpp
386+
util/min_max_float.hpp
387+
util/sum.hpp
388+
util/vector_common.hpp
384389
version/de_dup_map.hpp
385390
version/op_log.hpp
386391
version/schema_checks.hpp
@@ -523,7 +528,7 @@ set(arcticdb_srcs
523528
version/version_core.cpp
524529
version/version_store_api.cpp
525530
version/version_utils.cpp
526-
version/version_map_batch_methods.cpp util/min_max_integer.hpp util/mean.hpp util/min_max_float.hpp util/sum.hpp)
531+
version/version_map_batch_methods.cpp )
527532

528533
add_library(arcticdb_core_object OBJECT ${arcticdb_srcs})
529534

@@ -750,8 +755,8 @@ if (SSL_LINK)
750755
find_package(OpenSSL REQUIRED)
751756
list(APPEND arcticdb_core_libraries OpenSSL::SSL)
752757
if (NOT WIN32)
753-
#list(APPEND arcticdb_core_libraries ${KERBEROS_LIBRARY})
754-
#list(APPEND arcticdb_core_includes ${KERBEROS_INCLUDE_DIR})
758+
list(APPEND arcticdb_core_libraries ${KERBEROS_LIBRARY})
759+
list(APPEND arcticdb_core_includes ${KERBEROS_INCLUDE_DIR})
755760
endif()
756761
endif ()
757762
target_link_libraries(arcticdb_core_object PUBLIC ${arcticdb_core_libraries})
@@ -968,6 +973,9 @@ if(${TEST})
968973
util/test/test_storage_lock.cpp
969974
util/test/test_string_pool.cpp
970975
util/test/test_string_utils.cpp
976+
util/test/test_min_max_float.cpp
977+
util/test/test_sum.cpp
978+
util/test/test_mean.cpp
971979
util/test/test_tracing_allocator.cpp
972980
version/test/test_append.cpp
973981
version/test/test_key_block.cpp
@@ -980,7 +988,7 @@ if(${TEST})
980988
version/test/test_version_map_batch.cpp
981989
version/test/test_version_store.cpp
982990
version/test/version_map_model.hpp
983-
python/python_handlers.cpp util/test/test_min_max_float.cpp util/test/test_sum.cpp util/test/test_mean.cpp)
991+
python/python_handlers.cpp)
984992

985993
set(EXECUTABLE_PERMS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) # 755
986994

cpp/arcticdb/column_store/block.hpp

+12-9
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
namespace arcticdb {
1616

1717
struct MemBlock {
18-
static const size_t Align = 128;
1918
static const size_t MinSize = 64;
2019
using magic_t = arcticdb::util::MagicNum<'M', 'e', 'm', 'b'>;
2120
magic_t magic_;
@@ -136,17 +135,21 @@ struct MemBlock {
136135
bool owns_external_data_ = false;
137136

138137
static const size_t HeaderDataSize =
139-
sizeof(magic_) + // 8 bytes
140-
sizeof(bytes_) + // 8 bytes
141-
sizeof(capacity_) + // 8 bytes
138+
sizeof(magic_) +
139+
sizeof(bytes_) +
140+
sizeof(capacity_) +
142141
sizeof(external_data_) +
143142
sizeof(offset_) +
144-
sizeof(timestamp_) +
143+
sizeof(timestamp_) +
145144
sizeof(owns_external_data_);
146145

147-
uint8_t pad[Align - HeaderDataSize];
148-
static const size_t HeaderSize = HeaderDataSize + sizeof(pad);
149-
static_assert(HeaderSize == Align);
150-
uint8_t data_[MinSize];
146+
static const size_t DataAlignment = 64;
147+
static const size_t PadSize = (DataAlignment - (HeaderDataSize % DataAlignment)) % DataAlignment;
148+
149+
uint8_t pad[PadSize];
150+
static const size_t HeaderSize = HeaderDataSize + PadSize;
151+
static_assert(HeaderSize % DataAlignment == 0, "Header size must be aligned to 64 bytes");
152+
153+
alignas(DataAlignment) uint8_t data_[MinSize];
151154
};
152155
}

cpp/arcticdb/column_store/chunked_buffer.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ std::vector<ChunkedBufferImpl<BlockSize>> split(const ChunkedBufferImpl<BlockSiz
6868
}
6969

7070
template std::vector<ChunkedBufferImpl<64>> split(const ChunkedBufferImpl<64>& input, size_t nbytes);
71-
template std::vector<ChunkedBufferImpl<3968>> split(const ChunkedBufferImpl<3968>& input, size_t nbytes);
71+
template std::vector<ChunkedBufferImpl<4032ul>> split(const ChunkedBufferImpl<4032ul>& input, size_t nbytes);
7272

7373
// Inclusive of start_byte, exclusive of end_byte
7474
template <size_t BlockSize>
@@ -112,6 +112,6 @@ ChunkedBufferImpl<BlockSize> truncate(const ChunkedBufferImpl<BlockSize>& input,
112112
}
113113

114114
template ChunkedBufferImpl<64> truncate(const ChunkedBufferImpl<64>& input, size_t start_byte, size_t end_byte);
115-
template ChunkedBufferImpl<3968> truncate(const ChunkedBufferImpl<3968>& input, size_t start_byte, size_t end_byte);
115+
template ChunkedBufferImpl<4032ul> truncate(const ChunkedBufferImpl<4032ul>& input, size_t start_byte, size_t end_byte);
116116

117117
} //namespace arcticdb

cpp/arcticdb/column_store/chunked_buffer.hpp

-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ class ChunkedBufferImpl {
3939

4040
using BlockType = MemBlock;
4141

42-
static_assert(sizeof(BlockType) == BlockType::Align + BlockType::MinSize);
4342
static_assert(DefaultBlockSize >= BlockType::MinSize);
4443

4544
public:

cpp/arcticdb/util/mean.hpp

+35-54
Original file line numberDiff line numberDiff line change
@@ -3,98 +3,79 @@
33
#include <type_traits>
44
#include <cstddef>
55

6+
#include <arcticdb/util/vector_common.hpp>
67

7-
template<typename T>
8-
struct is_supported_type : std::false_type {};
9-
10-
template<> struct is_supported_type<int8_t> : std::true_type {};
11-
template<> struct is_supported_type<uint8_t> : std::true_type {};
12-
template<> struct is_supported_type<int16_t> : std::true_type {};
13-
template<> struct is_supported_type<uint16_t> : std::true_type {};
14-
template<> struct is_supported_type<int32_t> : std::true_type {};
15-
template<> struct is_supported_type<uint32_t> : std::true_type {};
16-
template<> struct is_supported_type<int64_t> : std::true_type {};
17-
template<> struct is_supported_type<uint64_t> : std::true_type {};
18-
template<> struct is_supported_type<float> : std::true_type {};
19-
template<> struct is_supported_type<double> : std::true_type {};
20-
21-
template<typename T>
22-
struct MeanResult {
23-
T mean;
24-
size_t count; // Useful for floating point to know how many non-NaN values
25-
};
8+
namespace arcticdb {
269

2710
template<typename T>
2811
class MeanFinder {
29-
static_assert(is_supported_type<T>::value, "Unsupported type");
30-
31-
using VectorType = T __attribute__((vector_size(64)));
12+
static_assert(is_supported_int<T>::value || is_supported_float<T>::value, "Unsupported type");
3213

3314
public:
34-
3515
static double find(const T* data, size_t n) {
16+
using VectorType = vector_type<T>;
17+
using AccumVectorType = vector_type<double>;
3618

37-
using AccumVectorType = double __attribute__((vector_size(64)));
38-
19+
AccumVectorType vsum = {0.0};
3920
const size_t elements_per_vector = sizeof(VectorType) / sizeof(T);
40-
const size_t vlen = n / elements_per_vector;
21+
const size_t doubles_per_vector = sizeof(AccumVectorType) / sizeof(double);
22+
const size_t vectors_per_acc = elements_per_vector / doubles_per_vector;
4123

42-
AccumVectorType sum_vec = {0};
43-
AccumVectorType count_vec = {0};
44-
double total_sum = 0;
4524
size_t valid_count = 0;
4625

47-
for(size_t i = 0; i < vlen; i++) {
48-
VectorType v = reinterpret_cast<const VectorType*>(data)[i];
26+
const auto* vdata = reinterpret_cast<const VectorType*>(data);
27+
const size_t vector_len = n / elements_per_vector;
28+
29+
for(size_t i = 0; i < vector_len; i++) {
30+
VectorType v = vdata[i];
4931

5032
if constexpr(std::is_floating_point_v<T>) {
51-
VectorType mask = v == v; // !NaN
52-
VectorType valid = v & mask;
53-
VectorType replaced = VectorType{0} & ~mask;
54-
v = valid | replaced;
33+
VectorType mask = v == v;
34+
v = v & mask;
5535

56-
AccumVectorType count_mask;
36+
const T* mask_arr = reinterpret_cast<const T*>(&mask);
5737
for(size_t j = 0; j < elements_per_vector; j++) {
58-
count_mask[j] = reinterpret_cast<const T*>(&mask)[j] != 0 ? 1.0 : 0.0;
38+
if(mask_arr[j] != 0) valid_count++;
5939
}
60-
count_vec += count_mask;
6140
} else {
62-
count_vec += AccumVectorType{1};
41+
valid_count += elements_per_vector;
6342
}
6443

65-
AccumVectorType v_double;
66-
for(size_t j = 0; j < elements_per_vector; j++) {
67-
v_double[j] = static_cast<double>(reinterpret_cast<const T*>(&v)[j]);
44+
const T* v_arr = reinterpret_cast<const T*>(&v);
45+
for(size_t chunk = 0; chunk < vectors_per_acc; chunk++) {
46+
for(size_t j = 0; j < doubles_per_vector; j++) {
47+
size_t idx = chunk * doubles_per_vector + j;
48+
reinterpret_cast<double*>(&vsum)[j] += static_cast<double>(v_arr[idx]);
49+
}
6850
}
69-
sum_vec += v_double;
7051
}
7152

72-
const double* sum_arr = reinterpret_cast<const double*>(&sum_vec);
73-
const double* count_arr = reinterpret_cast<const double*>(&count_vec);
74-
for(size_t i = 0; i < elements_per_vector; i++) {
75-
total_sum += sum_arr[i];
76-
valid_count += static_cast<size_t>(count_arr[i]);
53+
double total = 0.0;
54+
const auto* sum_arr = reinterpret_cast<const double*>(&vsum);
55+
for(size_t i = 0; i < doubles_per_vector; i++) {
56+
total += sum_arr[i];
7757
}
7858

79-
const T* remain = data + (vlen * elements_per_vector);
59+
const T* remain = data + (vector_len * elements_per_vector);
8060
for(size_t i = 0; i < n % elements_per_vector; i++) {
8161
if constexpr(std::is_floating_point_v<T>) {
8262
if (remain[i] == remain[i]) { // Not NaN
83-
total_sum += static_cast<double>(remain[i]);
63+
total += static_cast<double>(remain[i]);
8464
valid_count++;
8565
}
8666
} else {
87-
total_sum += static_cast<double>(remain[i]);
67+
total += static_cast<double>(remain[i]);
8868
valid_count++;
8969
}
9070
}
9171

92-
double mean = valid_count > 0 ? total_sum / valid_count : 0.0;
93-
return mean;
72+
return valid_count > 0 ? total / static_cast<double>(valid_count) : 0.0;
9473
}
9574
};
9675

9776
template<typename T>
98-
double find_mean(const T* data, size_t n) {
77+
double find_mean(const T *data, size_t n) {
9978
return MeanFinder<T>::find(data, n);
10079
}
80+
81+
} // namespace arcticdb

cpp/arcticdb/util/min_max_float.hpp

+29-35
Original file line numberDiff line numberDiff line change
@@ -4,54 +4,51 @@
44
#include <cstddef>
55
#include <algorithm>
66

7-
namespace arcticdb {
7+
#include <arcticdb/util/vector_common.hpp>
88

9-
template<typename T>
10-
struct is_supported_float : std::false_type {};
9+
namespace arcticdb {
1110

1211
template<typename T>
1312
using vector_type __attribute__((vector_size(64))) = T;
1413

15-
template<> struct is_supported_float<float> : std::true_type {};
16-
template<> struct is_supported_float<double> : std::true_type {};
17-
1814
template<typename T>
1915
class FloatMinFinder {
2016
static_assert(is_supported_float<T>::value, "Type must be float or double");
2117
static_assert(std::is_floating_point_v<T>, "Type must be floating point");
2218

2319
public:
24-
static T find(const T *data, size_t n) {
25-
using vec_t __attribute__((vector_size(64))) = T;
20+
static T find(const T* data, size_t n) {
21+
using vec_t = vector_type<T>;
2622

23+
// Initialize min vector with infinity
2724
vec_t vmin;
28-
for (size_t i = 0; i < sizeof(vec_t) / sizeof(T); i++) {
29-
reinterpret_cast<T *>(&vmin)[i] = std::numeric_limits<T>::infinity();
25+
for(size_t i = 0; i < sizeof(vec_t)/sizeof(T); i++) {
26+
reinterpret_cast<T*>(&vmin)[i] = std::numeric_limits<T>::infinity();
3027
}
3128

32-
const vec_t *vdata = reinterpret_cast<const vec_t *>(data);
29+
// Process full vectors
30+
const vec_t* vdata = reinterpret_cast<const vec_t*>(data);
3331
const size_t elements_per_vector = sizeof(vec_t) / sizeof(T);
3432
const size_t vlen = n / elements_per_vector;
3533

36-
for (size_t i = 0; i < vlen; i++) {
34+
// Main SIMD loop
35+
for(size_t i = 0; i < vlen; i++) {
3736
vec_t v = vdata[i];
38-
vec_t mask = v == v; // !NaN
39-
vec_t valid = v & mask;
40-
vec_t replaced = vmin & ~mask;
41-
v = valid | replaced;
4237
vmin = (v < vmin) ? v : vmin;
4338
}
4439

40+
// Reduce vector to scalar
4541
T min_val = std::numeric_limits<T>::infinity();
46-
const T *min_arr = reinterpret_cast<const T *>(&vmin);
47-
for (size_t i = 0; i < elements_per_vector; i++) {
42+
const T* min_arr = reinterpret_cast<const T*>(&vmin);
43+
for(size_t i = 0; i < elements_per_vector; i++) {
4844
if (min_arr[i] == min_arr[i]) { // Not NaN
4945
min_val = std::min(min_val, min_arr[i]);
5046
}
5147
}
5248

53-
const T *remain = data + (vlen * elements_per_vector);
54-
for (size_t i = 0; i < n % elements_per_vector; i++) {
49+
// Handle remainder
50+
const T* remain = data + (vlen * elements_per_vector);
51+
for(size_t i = 0; i < n % elements_per_vector; i++) {
5552
if (remain[i] == remain[i]) { // Not NaN
5653
min_val = std::min(min_val, remain[i]);
5754
}
@@ -67,41 +64,38 @@ class FloatMaxFinder {
6764
static_assert(std::is_floating_point_v<T>, "Type must be floating point");
6865

6966
public:
70-
static T find(const T *data, size_t n) {
67+
static T find(const T* data, size_t n) {
7168
using vec_t = vector_type<T>;
7269

7370
// Initialize max vector with negative infinity
7471
vec_t vmax;
75-
for (size_t i = 0; i < sizeof(vec_t) / sizeof(T); i++) {
76-
reinterpret_cast<T *>(&vmax)[i] = -std::numeric_limits<T>::infinity();
72+
for(size_t i = 0; i < sizeof(vec_t)/sizeof(T); i++) {
73+
reinterpret_cast<T*>(&vmax)[i] = -std::numeric_limits<T>::infinity();
7774
}
7875

79-
const vec_t *vdata = reinterpret_cast<const vec_t *>(data);
76+
// Process full vectors
77+
const vec_t* vdata = reinterpret_cast<const vec_t*>(data);
8078
const size_t elements_per_vector = sizeof(vec_t) / sizeof(T);
8179
const size_t vlen = n / elements_per_vector;
8280

8381
// Main SIMD loop
84-
for (size_t i = 0; i < vlen; i++) {
82+
for(size_t i = 0; i < vlen; i++) {
8583
vec_t v = vdata[i];
86-
// Create mask for non-NaN values
87-
vec_t mask = v == v; // false for NaN
88-
vec_t valid = v & mask;
89-
vec_t replaced = vmax & ~mask;
90-
v = valid | replaced;
91-
// Vector max
9284
vmax = (v > vmax) ? v : vmax;
9385
}
9486

87+
// Reduce vector to scalar
9588
T max_val = -std::numeric_limits<T>::infinity();
96-
const T *max_arr = reinterpret_cast<const T *>(&vmax);
97-
for (size_t i = 0; i < elements_per_vector; i++) {
89+
const T* max_arr = reinterpret_cast<const T*>(&vmax);
90+
for(size_t i = 0; i < elements_per_vector; i++) {
9891
if (max_arr[i] == max_arr[i]) { // Not NaN
9992
max_val = std::max(max_val, max_arr[i]);
10093
}
10194
}
10295

103-
const T *remain = data + (vlen * elements_per_vector);
104-
for (size_t i = 0; i < n % elements_per_vector; i++) {
96+
// Handle remainder
97+
const T* remain = data + (vlen * elements_per_vector);
98+
for(size_t i = 0; i < n % elements_per_vector; i++) {
10599
if (remain[i] == remain[i]) { // Not NaN
106100
max_val = std::max(max_val, remain[i]);
107101
}

0 commit comments

Comments
 (0)