← Commit list

3d445dd60d

Ron Kuper
Ron Kuper
2026-09-06
SUCCESS Duration: 406s

Subject

perf: add maprintf and simpleformat printf tests

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

tests/perf/Makefile.inc+2 -0
@@ -45,6 +45,8 @@ CURLX_C = \
TESTS_C = \
base64dec.c \
base64enc.c \
+ maprintf.c \
+ simpleformat.c \
snprintf.c \
urldecode.c \
urlencode.c \
tests/perf/README.md+18 -0
@@ -45,6 +45,24 @@ call:
./perf snprintf [loops]
+## `maprintf`
+
+This test repeatedly formats a request header block with `curl_maprintf()`,
+which allocates the result, and measures the time per call. It exercises the
+allocating output path and a `curl_off_t` conversion, which the `snprintf`
+test does not:
+
+ ./perf maprintf [loops]
+
+## `simpleformat`
+
+This test repeatedly formats a commonly used simple message with
+`curl_msnprintf()`: literal text plus `%s`, a `size_t` and a `curl_off_t`,
+with no width or precision. Where `snprintf` measures an elaborate format,
+this measures the common one:
+
+ ./perf simpleformat [loops]
+
## `urlencode`
This test URL (percent) encodes a 256-byte buffer that has every different
tests/perf/maprintf.c+75 -0
@@ -0,0 +1,75 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "first.h"
+
+/* snprintf.c times curl_msnprintf() into a caller's buffer. This test times
+ curl_maprintf(), which allocates and returns the result. libcurl builds
+ request lines and headers with curlx_dyn_addf(), which formats through the
+ same allocating code (curl_mvaprintf), so this exercises that path and its
+ per-byte cost, which differs from the fixed-buffer one. The format is a
+ request-header-like block: literal text, %s, and a curl_off_t. The
+ allocation and the free are inside the timed loop on purpose, because a
+ caller pays them. */
+
+static int test_maprintf(int argc, const char **argv)
+{
+ struct curltime start;
+ struct curltime end;
+ timediff_t us;
+ long long hn;
+
+ curl_off_t loops = 10000000, loop;
+
+ if(argc > 1) {
+ const char *ptr = argv[1];
+ curl_off_t num;
+ if(!curlx_str_number(&ptr, &num, CURL_OFF_T_MAX) && !*ptr)
+ loops = num;
+ }
+
+ start = curlx_now();
+ for(loop = 0; loop < loops; loop++) {
+ char *s = curl_maprintf("%s %s HTTP/1.1\r\n"
+ "Host: %s\r\n"
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
+ "POST", "/path/to/resource", "example.com",
+ (curl_off_t)4096);
+ if(!s) {
+ curl_mfprintf(stderr, "curl_maprintf() failed\n");
+ return 1;
+ }
+ curl_free(s);
+ }
+ end = curlx_now();
+ us = curlx_timediff_us(end, start); /* how many microseconds */
+ hn = loops ? us * 100000 / loops : 0; /* 100 times too big */
+ curl_mprintf("Loops: %" CURL_FORMAT_CURL_OFF_T "\n"
+ "Time: %lld usecs\n"
+ "Time/loop: %lld.%0lld ns\n",
+ loops,
+ (long long)us,
+ (long long)hn / 100,
+ (long long)hn % 100);
+ return 0;
+}
tests/perf/simpleformat.c+70 -0
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+#include "first.h"
+
+/* snprintf.c times a format that uses widths and a '*' argument. This test
+ times a commonly used simple format instead: literal text plus %s, a size_t
+ and a curl_off_t, with no width or precision. It is the shape of the
+ messages curl builds with infof() and similar all over the library; it is
+ modeled on one in lib/imap.c rather than copied from it, so it measures the
+ common case rather than the elaborate one. The sink is a caller's buffer,
+ as in snprintf.c. */
+
+static int test_simpleformat(int argc, const char **argv)
+{
+ struct curltime start;
+ struct curltime end;
+ timediff_t us;
+ long long hn;
+
+ curl_off_t loops = 10000000, loop;
+
+ char buffer[256];
+
+ if(argc > 1) {
+ const char *ptr = argv[1];
+ curl_off_t num;
+ if(!curlx_str_number(&ptr, &num, CURL_OFF_T_MAX) && !*ptr)
+ loops = num;
+ }
+
+ start = curlx_now();
+ for(loop = 0; loop < loops; loop++) {
+ curl_msnprintf(buffer, sizeof(buffer),
+ "%s: wrote %zu bytes, %" CURL_FORMAT_CURL_OFF_T
+ " bytes are left for transfer\n",
+ "upload", (size_t)4096, (curl_off_t)1048576);
+ }
+ end = curlx_now();
+ us = curlx_timediff_us(end, start); /* how many microseconds */
+ hn = loops ? us * 100000 / loops : 0; /* 100 times too big */
+ curl_mprintf("Loops: %" CURL_FORMAT_CURL_OFF_T "\n"
+ "Time: %lld usecs\n"
+ "Time/loop: %lld.%0lld ns\n",
+ loops,
+ (long long)us,
+ (long long)hn / 100,
+ (long long)hn % 100);
+ return 0;
+}