diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index daf3296..1c4daa4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -48,10 +48,22 @@ jobs:
- name: Build
run: autoreconf -ivf && ./configure --disable-tls && make -j
+ build-ubuntu-latest:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install dependencies
+ run: |
+ sudo apt-get -qq update
+ sudo apt-get install lcov autoconf automake pkg-config libevent-dev libpcre3-dev
+
+ - name: Build
+ run: autoreconf -ivf && ./configure --disable-tls && make -j
+
build-ubuntu:
strategy:
matrix:
- platform: [ubuntu-latest, ubuntu-20.04]
+ platform: [ubuntu-22.04, ubuntu-20.04]
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
@@ -61,6 +73,8 @@ jobs:
sudo apt-get install lcov autoconf automake pkg-config libevent-dev libpcre3-dev libssl-dev
- name: Build
+ # for coverage reports we need to use Ubuntu 22.04 or lower
+ # (given Ubuntu 24.04 uses lcov >= 2.0 which is not support on autoconf still)
run: autoreconf -ivf && ./configure --enable-code-coverage && make -j
- name: Setup Python
uses: actions/setup-python@v2
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index b30dc80..5a575f7 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -17,9 +17,15 @@ on:
description: "Docker images for smoke testing (comma-separated, e.g., ubuntu:20.04,ubuntu:22.04,ubuntu:24.04)"
required: false
default: "ubuntu:20.04,ubuntu:22.04,ubuntu:24.04"
+ build_runner:
+ description: "os in which build steps run on"
+ required: false
+ default: "ubuntu-22.04"
+ type: string
jobs:
build-source-package:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
+ continue-on-error: true
strategy:
matrix:
dist: ${{ fromJSON(vars.BUILD_DISTS) }}
@@ -27,11 +33,31 @@ jobs:
- uses: actions/checkout@v4
with:
path: sources
+ - name: Validate configure.ac version matches GitHub Release (only on release)
+ if: github.event.release.tag_name != ''
+ env:
+ VERSION: ${{ github.event.release.tag_name }}
+ run: |
+ # Extract the current version from configure.ac
+ CURRENT_VERSION=$(awk -F'[(),]' '/AC_INIT/ {print $3}' sources/configure.ac | tr -d ' ')
+
+ echo "Current configure.ac version: $CURRENT_VERSION"
+ echo "GitHub Release version: $VERSION"
+
+ # Check if versions match
+ if [ "$CURRENT_VERSION" != "$VERSION" ]; then
+ echo "❌ Version mismatch! configure.ac: $CURRENT_VERSION, GitHub Release: $VERSION"
+ exit 1 # Fail the build
+ else
+ echo "Version match. Proceeding with the build."
+ fi
- name: Install dependencies
run: |
sudo apt-get update && \
sudo apt-get install \
- debhelper dput libevent-dev libpcre2-dev libssl-dev pkg-config
+ build-essential autoconf automake libpcre3-dev libevent-dev \
+ pkg-config zlib1g-dev libssl-dev libboost-all-dev cmake flex \
+ debhelper dput
- name: Create changelog
env:
VERSION: ${{ github.event.inputs.tag_name || github.event.release.tag_name }}
@@ -61,7 +87,8 @@ jobs:
memtier-benchmark_*.tar.*
build-binary-package:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
+ continue-on-error: true
environment: build
strategy:
matrix:
@@ -119,13 +146,10 @@ jobs:
*.deb
smoke-test-packages:
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
needs: build-binary-package
env:
ARCH: amd64
- # required by ubuntu:bionic
- # https://github.blog/changelog/2024-03-07-github-actions-all-actions-will-run-on-node20-instead-of-node16-by-default/
- ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
strategy:
matrix:
image: ${{ fromJSON(vars.SMOKE_TEST_IMAGES) }}
@@ -139,15 +163,7 @@ jobs:
exit 1
fi
echo "BUILD_ARCH=$BUILD_ARCH" >> $GITHUB_ENV
- - name: Get binary packages for ubuntu:bionic
- if: matrix.image == 'ubuntu:bionic'
- uses: actions/download-artifact@v3
- with:
- name: binary-${{ env.BUILD_ARCH }}-${{ env.ARCH }}
- path: binary-${{ env.BUILD_ARCH }}-${{ env.ARCH }}
-
- - name: Get binary packages for other versions
- if: matrix.image != 'ubuntu:bionic'
+ - name: Get binary packages
uses: actions/download-artifact@v4
with:
name: binary-${{ env.BUILD_ARCH }}-${{ env.ARCH }}
@@ -160,7 +176,7 @@ jobs:
publish-to-apt:
env:
DEB_S3_VERSION: "0.11.3"
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
environment: build
needs: smoke-test-packages
steps:
diff --git a/configure.ac b/configure.ac
index 15f3d9a..185e865 100755
--- a/configure.ac
+++ b/configure.ac
@@ -16,7 +16,7 @@ dnl You should have received a copy of the GNU General Public License
dnl along with this program. If not, see .
AC_PREREQ(2.59)
-AC_INIT(memtier_benchmark,2.1.2,oss@redis.com)
+AC_INIT(memtier_benchmark,2.1.4,oss@redis.com)
AC_CONFIG_SRCDIR([memtier_benchmark.cpp])
AC_CONFIG_HEADER([config.h])
AM_INIT_AUTOMAKE
diff --git a/deps/hdr_histogram/.dirstamp b/deps/hdr_histogram/.dirstamp
new file mode 100644
index 0000000..e69de29
diff --git a/deps/hdr_histogram/hdr_histogram.c b/deps/hdr_histogram/hdr_histogram.c
index 7bb6422..b3b48e0 100644
--- a/deps/hdr_histogram/hdr_histogram.c
+++ b/deps/hdr_histogram/hdr_histogram.c
@@ -643,28 +643,67 @@ int64_t hdr_min(const struct hdr_histogram* h)
return non_zero_min(h);
}
+static int64_t get_value_from_idx_up_to_count(const struct hdr_histogram* h, int64_t count_at_percentile)
+{
+ int64_t count_to_idx = 0;
+
+ count_at_percentile = 0 < count_at_percentile ? count_at_percentile : 1;
+ for (int32_t idx = 0; idx < h->counts_len; idx++)
+ {
+ count_to_idx += h->counts[idx];
+ if (count_to_idx >= count_at_percentile)
+ {
+ return hdr_value_at_index(h, idx);
+ }
+ }
+
+ return 0;
+}
+
int64_t hdr_value_at_percentile(const struct hdr_histogram* h, double percentile)
{
- struct hdr_iter iter;
- int64_t total = 0;
double requested_percentile = percentile < 100.0 ? percentile : 100.0;
int64_t count_at_percentile =
(int64_t) (((requested_percentile / 100) * h->total_count) + 0.5);
- count_at_percentile = count_at_percentile > 1 ? count_at_percentile : 1;
+ int64_t value_from_idx = get_value_from_idx_up_to_count(h, count_at_percentile);
+ if (percentile == 0.0)
+ {
+ return lowest_equivalent_value(h, value_from_idx);
+ }
+ return highest_equivalent_value(h, value_from_idx);
+}
- hdr_iter_init(&iter, h);
+int hdr_value_at_percentiles(const struct hdr_histogram *h, const double *percentiles, int64_t *values, size_t length)
+{
+ if (NULL == percentiles || NULL == values)
+ {
+ return EINVAL;
+ }
- while (hdr_iter_next(&iter))
+ struct hdr_iter iter;
+ const int64_t total_count = h->total_count;
+ // to avoid allocations we use the values array for intermediate computation
+ // i.e. to store the expected cumulative count at each percentile
+ for (size_t i = 0; i < length; i++)
{
- total += iter.count;
+ const double requested_percentile = percentiles[i] < 100.0 ? percentiles[i] : 100.0;
+ const int64_t count_at_percentile =
+ (int64_t) (((requested_percentile / 100) * total_count) + 0.5);
+ values[i] = count_at_percentile > 1 ? count_at_percentile : 1;
+ }
- if (total >= count_at_percentile)
+ hdr_iter_init(&iter, h);
+ int64_t total = 0;
+ size_t at_pos = 0;
+ while (hdr_iter_next(&iter) && at_pos < length)
+ {
+ total += iter.count;
+ while (at_pos < length && total >= values[at_pos])
{
- int64_t value_from_index = iter.value;
- return highest_equivalent_value(h, value_from_index);
+ values[at_pos] = highest_equivalent_value(h, iter.value);
+ at_pos++;
}
}
-
return 0;
}
diff --git a/deps/hdr_histogram/hdr_histogram.h b/deps/hdr_histogram/hdr_histogram.h
index dc35416..ad1e3a3 100644
--- a/deps/hdr_histogram/hdr_histogram.h
+++ b/deps/hdr_histogram/hdr_histogram.h
@@ -284,6 +284,18 @@ int64_t hdr_max(const struct hdr_histogram* h);
*/
int64_t hdr_value_at_percentile(const struct hdr_histogram* h, double percentile);
+/**
+ * Get the values at the given percentiles.
+ *
+ * @param h "This" pointer.
+ * @param percentiles The ordered percentiles array to get the values for.
+ * @param length Number of elements in the arrays.
+ * @param values Destination array containing the values at the given percentiles.
+ * The values array should be allocated by the caller.
+ * @return 0 on success, ENOMEM if the provided destination array is null.
+ */
+int hdr_value_at_percentiles(const struct hdr_histogram *h, const double *percentiles, int64_t *values, size_t length);
+
/**
* Gets the standard deviation for the values in the histogram.
*
diff --git a/run_stats.cpp b/run_stats.cpp
index f945377..a5e38a0 100644
--- a/run_stats.cpp
+++ b/run_stats.cpp
@@ -117,8 +117,9 @@ run_stats::run_stats(benchmark_config *config) :
{
memset(&m_start_time, 0, sizeof(m_start_time));
memset(&m_end_time, 0, sizeof(m_end_time));
- quantiles_list = config->print_percentiles.quantile_list;
-
+ std::vector quantiles_list_float = config->print_percentiles.quantile_list;
+ std::sort(quantiles_list_float.begin(), quantiles_list_float.end());
+ quantiles_list = std::vector(quantiles_list_float.begin(), quantiles_list_float.end());
if (config->arbitrary_commands->is_defined()) {
setup_arbitrary_commands(config->arbitrary_commands->size());
}
@@ -882,7 +883,7 @@ void run_stats::summarize(totals& result) const
void result_print_to_json(json_handler * jsonhandler, const char * type, double ops_sec,
double hits, double miss, double moved, double ask, double kbs, double kbs_rx, double kbs_tx,
double latency, long m_total_latency, long ops,
- std::vector quantile_list, struct hdr_histogram* latency_histogram,
+ std::vector quantile_list, struct hdr_histogram* latency_histogram,
std::vector timestamps,
std::vector timeserie_stats )
{
diff --git a/run_stats.h b/run_stats.h
index 580ef1f..14796ea 100644
--- a/run_stats.h
+++ b/run_stats.h
@@ -97,7 +97,7 @@ class run_stats {
totals m_totals;
std::list m_stats;
- std::vector quantiles_list;
+ std::vector quantiles_list;
// current second stats ( appended to m_stats and reset every second )
one_second_stats m_cur_stats;
diff --git a/run_stats_types.cpp b/run_stats_types.cpp
index 77068dd..7ae7b0e 100644
--- a/run_stats_types.cpp
+++ b/run_stats_types.cpp
@@ -72,11 +72,14 @@ void one_sec_cmd_stats::merge(const one_sec_cmd_stats& other) {
m_min_latency = other.m_min_latency < m_min_latency ? other.m_min_latency : m_min_latency;
}
-void one_sec_cmd_stats::summarize_quantiles(safe_hdr_histogram histogram, std::vector quantiles) {
- for (std::size_t i = 0; i < quantiles.size(); i++){
- const float quantile = quantiles[i];
- const double value = hdr_value_at_percentile(histogram, quantile)/ (double) LATENCY_HDR_RESULTS_MULTIPLIER;
- summarized_quantile_values.push_back(value);
+void one_sec_cmd_stats::summarize_quantiles(safe_hdr_histogram histogram, std::vector sorted_quantiles) {
+ std::vector values(sorted_quantiles.size());
+ int result = hdr_value_at_percentiles(histogram, sorted_quantiles.data(), values.data(), sorted_quantiles.size());
+ if (result != 0) {
+ return;
+ }
+ for (std::size_t i = 0; i < sorted_quantiles.size(); i++) {
+ summarized_quantile_values.push_back(values[i] / static_cast(LATENCY_HDR_RESULTS_MULTIPLIER));
}
}
diff --git a/run_stats_types.h b/run_stats_types.h
index 827c86d..2b6e982 100644
--- a/run_stats_types.h
+++ b/run_stats_types.h
@@ -24,7 +24,7 @@
#define LATENCY_HDR_SIGDIGTS 3
#define LATENCY_HDR_SEC_MIN_VALUE 10
#define LATENCY_HDR_SEC_MAX_VALUE 600000000 ## LL
-#define LATENCY_HDR_SEC_SIGDIGTS 3
+#define LATENCY_HDR_SEC_SIGDIGTS 2
#define LATENCY_HDR_RESULTS_MULTIPLIER 1000
#define LATENCY_HDR_GRANULARITY 10
@@ -90,7 +90,14 @@ class one_sec_cmd_stats {
one_sec_cmd_stats();
void reset();
void merge(const one_sec_cmd_stats& other);
- void summarize_quantiles(safe_hdr_histogram histogram, std::vector quantiles);
+ /**
+ * Summarizes quantiles from the given histogram.
+ *
+ * @param histogram The histogram from which quantile values are extracted.
+ * @param sorted_quantiles A sorted (ascending order) vector of quantiles for which values will be computed.
+ * The caller must ensure the vector is sorted from smallest to largest.
+ */
+ void summarize_quantiles(safe_hdr_histogram histogram, std::vector sorted_quantiles);
void update_op(unsigned int bytes_rx, unsigned int bytes_tx, unsigned int latency);
void update_op(unsigned int bytes_rx, unsigned int bytes_tx, unsigned int latency, unsigned int hits, unsigned int misses);
void update_moved_op(unsigned int bytes_rx, unsigned int bytes_tx, unsigned int latency);