Coverage Report

Created: 2026-07-07 17:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/core/memcpy_small.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
// This file is copied from
18
// https://github.com/ClickHouse/ClickHouse/blob/master/src/Common/MemcpySmall.h
19
// and modified by Doris
20
21
#pragma once
22
23
#include <glog/logging.h>
24
#include <string.h>
25
26
#include <cstdint>
27
#include <memory>
28
29
#if defined(__SSE2__) || defined(__aarch64__)
30
#include "util/sse_util.hpp"
31
32
/** memcpy function could work suboptimal if all the following conditions are met:
33
  * 1. Size of memory region is relatively small (approximately, under 50 bytes).
34
  * 2. Size of memory region is not known at compile-time.
35
  *
36
  * In that case, memcpy works suboptimal by following reasons:
37
  * 1. Function is not inlined.
38
  * 2. Much time/instructions are spend to process "tails" of data.
39
  *
40
  * There are cases when function could be implemented in more optimal way, with help of some assumptions.
41
  * One of that assumptions - ability to read and write some number of bytes after end of passed memory regions.
42
  * Under that assumption, it is possible not to implement difficult code to process tails of data and do copy always by big chunks.
43
  *
44
  * This case is typical, for example, when many small pieces of data are gathered to single contiguous piece of memory in a loop.
45
  * - because each next copy will overwrite excessive data after previous copy.
46
  *
47
  * Assumption that size of memory region is small enough allows us to not unroll the loop.
48
  * This is slower, when size of memory is actually big.
49
  *
50
  * Use with caution.
51
  */
52
53
namespace doris::detail {
54
inline void memcpy_small_allow_read_write_overflow15_impl(char* __restrict dst,
55
2.46M
                                                          const char* __restrict src, ssize_t n) {
56
82.8M
    while (n > 0) {
57
80.4M
        _mm_storeu_si128(reinterpret_cast<__m128i*>(dst),
58
80.4M
                         _mm_loadu_si128(reinterpret_cast<const __m128i*>(src)));
59
60
80.4M
        dst += 16;
61
80.4M
        src += 16;
62
80.4M
        n -= 16;
63
80.4M
    }
64
2.46M
}
65
} // namespace doris::detail
66
67
/** Works under assumption, that it's possible to read up to 15 excessive bytes after end of 'src' region
68
  *  and to write any garbage into up to 15 bytes after end of 'dst' region.
69
  */
70
inline void memcpy_small_allow_read_write_overflow15(void* __restrict dst,
71
2.46M
                                                     const void* __restrict src, size_t n) {
72
2.46M
    doris::detail::memcpy_small_allow_read_write_overflow15_impl(
73
2.46M
            reinterpret_cast<char*>(dst), reinterpret_cast<const char*>(src), n);
74
2.46M
}
75
76
/** NOTE There was also a function, that assumes, that you could read any bytes inside same memory page of src.
77
  * This function was unused, and also it requires special handling for Valgrind and ASan.
78
  */
79
80
#else /// Implementation for other platforms.
81
82
inline void memcpy_small_allow_read_write_overflow15(void* __restrict dst,
83
                                                     const void* __restrict src, size_t n) {
84
    memcpy(dst, src, n);
85
}
86
87
#endif
88
89
// assume input address not aligned by default
90
// hint to compiler that we are copying fixed size data, so it can optimize the copy using SIMD instructions if possible.
91
template <typename T, bool aligned = false>
92
29.0M
void memcpy_fixed(char* lhs, const char* rhs) {
93
29.0M
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
275k
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
275k
               sizeof(T));
97
28.7M
    } else {
98
28.7M
        memcpy(lhs, rhs, sizeof(T));
99
28.7M
    }
100
29.0M
}
_Z12memcpy_fixedItLb0EEvPcPKc
Line
Count
Source
92
892
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
892
    } else {
98
892
        memcpy(lhs, rhs, sizeof(T));
99
892
    }
100
892
}
_Z12memcpy_fixedIhLb0EEvPcPKc
Line
Count
Source
92
91.8k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
91.8k
    } else {
98
91.8k
        memcpy(lhs, rhs, sizeof(T));
99
91.8k
    }
100
91.8k
}
_Z12memcpy_fixedIjLb0EEvPcPKc
Line
Count
Source
92
1.38M
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
1.38M
    } else {
98
1.38M
        memcpy(lhs, rhs, sizeof(T));
99
1.38M
    }
100
1.38M
}
_Z12memcpy_fixedIdLb0EEvPcPKc
Line
Count
Source
92
11.0k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
11.0k
    } else {
98
11.0k
        memcpy(lhs, rhs, sizeof(T));
99
11.0k
    }
100
11.0k
}
_Z12memcpy_fixedIlLb0EEvPcPKc
Line
Count
Source
92
13.5M
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
13.5M
    } else {
98
13.5M
        memcpy(lhs, rhs, sizeof(T));
99
13.5M
    }
100
13.5M
}
_Z12memcpy_fixedIiLb0EEvPcPKc
Line
Count
Source
92
8.21k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
8.21k
    } else {
98
8.21k
        memcpy(lhs, rhs, sizeof(T));
99
8.21k
    }
100
8.21k
}
_Z12memcpy_fixedIbLb0EEvPcPKc
Line
Count
Source
92
116
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
116
    } else {
98
116
        memcpy(lhs, rhs, sizeof(T));
99
116
    }
100
116
}
_Z12memcpy_fixedIhLb1EEvPcPKc
Line
Count
Source
92
35.5k
void memcpy_fixed(char* lhs, const char* rhs) {
93
35.5k
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
35.5k
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
35.5k
               sizeof(T));
97
    } else {
98
        memcpy(lhs, rhs, sizeof(T));
99
    }
100
35.5k
}
_Z12memcpy_fixedItLb1EEvPcPKc
Line
Count
Source
92
16.8k
void memcpy_fixed(char* lhs, const char* rhs) {
93
16.8k
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
16.8k
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
16.8k
               sizeof(T));
97
    } else {
98
        memcpy(lhs, rhs, sizeof(T));
99
    }
100
16.8k
}
_Z12memcpy_fixedIjLb1EEvPcPKc
Line
Count
Source
92
65.8k
void memcpy_fixed(char* lhs, const char* rhs) {
93
65.8k
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
65.8k
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
65.8k
               sizeof(T));
97
    } else {
98
        memcpy(lhs, rhs, sizeof(T));
99
    }
100
65.8k
}
_Z12memcpy_fixedImLb1EEvPcPKc
Line
Count
Source
92
115k
void memcpy_fixed(char* lhs, const char* rhs) {
93
115k
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
115k
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
115k
               sizeof(T));
97
    } else {
98
        memcpy(lhs, rhs, sizeof(T));
99
    }
100
115k
}
_Z12memcpy_fixedImLb0EEvPcPKc
Line
Count
Source
92
74.3k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
74.3k
    } else {
98
74.3k
        memcpy(lhs, rhs, sizeof(T));
99
74.3k
    }
100
74.3k
}
_Z12memcpy_fixedIN4wide7integerILm128EjEELb1EEvPcPKc
Line
Count
Source
92
41.2k
void memcpy_fixed(char* lhs, const char* rhs) {
93
41.2k
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
41.2k
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
41.2k
               sizeof(T));
97
    } else {
98
        memcpy(lhs, rhs, sizeof(T));
99
    }
100
41.2k
}
_Z12memcpy_fixedIN4wide7integerILm128EjEELb0EEvPcPKc
Line
Count
Source
92
11.9k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
11.9k
    } else {
98
11.9k
        memcpy(lhs, rhs, sizeof(T));
99
11.9k
    }
100
11.9k
}
_Z12memcpy_fixedIN5doris7DecimalIiEELb0EEvPcPKc
Line
Count
Source
92
2.49k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
2.49k
    } else {
98
2.49k
        memcpy(lhs, rhs, sizeof(T));
99
2.49k
    }
100
2.49k
}
_Z12memcpy_fixedIN5doris7DecimalIlEELb0EEvPcPKc
Line
Count
Source
92
13.5M
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
13.5M
    } else {
98
13.5M
        memcpy(lhs, rhs, sizeof(T));
99
13.5M
    }
100
13.5M
}
_Z12memcpy_fixedIN5doris14DecimalV2ValueELb0EEvPcPKc
Line
Count
Source
92
12.9k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
12.9k
    } else {
98
12.9k
        memcpy(lhs, rhs, sizeof(T));
99
12.9k
    }
100
12.9k
}
_Z12memcpy_fixedIN5doris12Decimal128V3ELb0EEvPcPKc
Line
Count
Source
92
10.9k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
10.9k
    } else {
98
10.9k
        memcpy(lhs, rhs, sizeof(T));
99
10.9k
    }
100
10.9k
}
_Z12memcpy_fixedIN5doris7DecimalIN4wide7integerILm256EiEEEELb0EEvPcPKc
Line
Count
Source
92
8.74k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
8.74k
    } else {
98
8.74k
        memcpy(lhs, rhs, sizeof(T));
99
8.74k
    }
100
8.74k
}
_Z12memcpy_fixedIaLb0EEvPcPKc
Line
Count
Source
92
7.89k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
7.89k
    } else {
98
7.89k
        memcpy(lhs, rhs, sizeof(T));
99
7.89k
    }
100
7.89k
}
_Z12memcpy_fixedIsLb0EEvPcPKc
Line
Count
Source
92
7.00k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
7.00k
    } else {
98
7.00k
        memcpy(lhs, rhs, sizeof(T));
99
7.00k
    }
100
7.00k
}
_Z12memcpy_fixedInLb0EEvPcPKc
Line
Count
Source
92
6.74k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
6.74k
    } else {
98
6.74k
        memcpy(lhs, rhs, sizeof(T));
99
6.74k
    }
100
6.74k
}
_Z12memcpy_fixedIfLb0EEvPcPKc
Line
Count
Source
92
6.70k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
6.70k
    } else {
98
6.70k
        memcpy(lhs, rhs, sizeof(T));
99
6.70k
    }
100
6.70k
}
_Z12memcpy_fixedIoLb0EEvPcPKc
Line
Count
Source
92
6.66k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
6.66k
    } else {
98
6.66k
        memcpy(lhs, rhs, sizeof(T));
99
6.66k
    }
100
6.66k
}
_Z12memcpy_fixedIN5doris16VecDateTimeValueELb0EEvPcPKc
Line
Count
Source
92
9.36k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
9.36k
    } else {
98
9.36k
        memcpy(lhs, rhs, sizeof(T));
99
9.36k
    }
100
9.36k
}
_Z12memcpy_fixedIN5doris11DateV2ValueINS0_15DateV2ValueTypeEEELb0EEvPcPKc
Line
Count
Source
92
4.49k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
4.49k
    } else {
98
4.49k
        memcpy(lhs, rhs, sizeof(T));
99
4.49k
    }
100
4.49k
}
_Z12memcpy_fixedIN5doris11DateV2ValueINS0_19DateTimeV2ValueTypeEEELb0EEvPcPKc
Line
Count
Source
92
8.60k
void memcpy_fixed(char* lhs, const char* rhs) {
93
    if constexpr (aligned) {
94
        // hint aligned address to compiler
95
        memcpy(std::assume_aligned<alignof(T)>(lhs), std::assume_aligned<alignof(T)>(rhs),
96
               sizeof(T));
97
8.60k
    } else {
98
8.60k
        memcpy(lhs, rhs, sizeof(T));
99
8.60k
    }
100
8.60k
}
Unexecuted instantiation: _Z12memcpy_fixedIN5doris16TimestampTzValueELb0EEvPcPKc
Unexecuted instantiation: _Z12memcpy_fixedIN5doris10VarMomentsIdLm4EEELb0EEvPcPKc
Unexecuted instantiation: _Z12memcpy_fixedIN5doris10VarMomentsIdLm3EEELb0EEvPcPKc
Unexecuted instantiation: _Z12memcpy_fixedIN5doris7DecimalInEELb0EEvPcPKc
101
102
template <int max_size>
103
134
inline void memcpy_small(char* lhs, const char* rhs, size_t n) {
104
134
    DCHECK_NE(n, 0);
105
134
    if constexpr (max_size >= 4) {
106
134
        if (n >= 4) {
107
118
            memcpy_fixed<uint32_t>(lhs, rhs);
108
118
            lhs += 4;
109
118
            rhs += 4;
110
118
            n -= 4;
111
118
        }
112
134
    }
113
654
    while (n >= 1) {
114
520
        memcpy_fixed<uint8_t>(lhs, rhs);
115
520
        lhs++;
116
520
        rhs++;
117
520
        n--;
118
520
    }
119
134
}
_Z12memcpy_smallILi4EEvPcPKcm
Line
Count
Source
103
20
inline void memcpy_small(char* lhs, const char* rhs, size_t n) {
104
20
    DCHECK_NE(n, 0);
105
20
    if constexpr (max_size >= 4) {
106
20
        if (n >= 4) {
107
4
            memcpy_fixed<uint32_t>(lhs, rhs);
108
4
            lhs += 4;
109
4
            rhs += 4;
110
4
            n -= 4;
111
4
        }
112
20
    }
113
68
    while (n >= 1) {
114
48
        memcpy_fixed<uint8_t>(lhs, rhs);
115
48
        lhs++;
116
48
        rhs++;
117
48
        n--;
118
48
    }
119
20
}
_Z12memcpy_smallILi8EEvPcPKcm
Line
Count
Source
103
34
inline void memcpy_small(char* lhs, const char* rhs, size_t n) {
104
34
    DCHECK_NE(n, 0);
105
34
    if constexpr (max_size >= 4) {
106
34
        if (n >= 4) {
107
34
            memcpy_fixed<uint32_t>(lhs, rhs);
108
34
            lhs += 4;
109
34
            rhs += 4;
110
34
            n -= 4;
111
34
        }
112
34
    }
113
74
    while (n >= 1) {
114
40
        memcpy_fixed<uint8_t>(lhs, rhs);
115
40
        lhs++;
116
40
        rhs++;
117
40
        n--;
118
40
    }
119
34
}
_Z12memcpy_smallILi16EEvPcPKcm
Line
Count
Source
103
80
inline void memcpy_small(char* lhs, const char* rhs, size_t n) {
104
80
    DCHECK_NE(n, 0);
105
80
    if constexpr (max_size >= 4) {
106
80
        if (n >= 4) {
107
80
            memcpy_fixed<uint32_t>(lhs, rhs);
108
80
            lhs += 4;
109
80
            rhs += 4;
110
80
            n -= 4;
111
80
        }
112
80
    }
113
512
    while (n >= 1) {
114
432
        memcpy_fixed<uint8_t>(lhs, rhs);
115
432
        lhs++;
116
432
        rhs++;
117
432
        n--;
118
432
    }
119
80
}
120
121
template <>
122
28.4k
inline void memcpy_small<2>(char* lhs, const char* rhs, size_t n) {
123
28.4k
    DCHECK_NE(n, 0);
124
28.4k
    if (n == 2) {
125
4
        memcpy_fixed<uint16_t>(lhs, rhs);
126
28.4k
    } else {
127
28.4k
        memcpy_fixed<uint8_t>(lhs, rhs);
128
28.4k
    }
129
28.4k
}