← Commit list

415d800e7b

Viktor Szakats
Viktor Szakats
2026-08-31
SUCCESS Duration: 394s

Subject

build: add performance 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 →

configure.ac+5 -4
@@ -5557,12 +5557,13 @@ AC_CONFIG_FILES([\
tests/configurehelp.pm \
tests/certs/Makefile \
tests/data/Makefile \
- tests/server/Makefile \
- tests/libtest/Makefile \
- tests/unit/Makefile \
- tests/tunit/Makefile \
tests/http/config.ini \
tests/http/Makefile \
+ tests/libtest/Makefile \
+ tests/perf/Makefile \
+ tests/server/Makefile \
+ tests/tunit/Makefile \
+ tests/unit/Makefile \
projects/Makefile \
projects/vms/Makefile
])
tests/CMakeLists.txt+1 -0
@@ -49,6 +49,7 @@ add_custom_target(testdeps)
add_dependencies(testdeps "tt")
add_subdirectory(http)
+add_subdirectory(perf)
add_subdirectory(server)
add_subdirectory(libtest)
if(BUILD_CURL_EXE)
tests/Makefile.am+4 -3
@@ -95,7 +95,7 @@ BUILD_UNIT =
DIST_UNIT = unit tunit
endif
-SUBDIRS = certs data server libtest http $(BUILD_UNIT)
+SUBDIRS = certs data perf server libtest http $(BUILD_UNIT)
DIST_SUBDIRS = $(SUBDIRS) $(DIST_UNIT)
PERLFLAGS = -I$(srcdir)
@@ -177,9 +177,10 @@ ci-pytest: all
checksrc:
(cd libtest && $(MAKE) checksrc)
- (cd unit && $(MAKE) checksrc)
- (cd tunit && $(MAKE) checksrc)
+ (cd perf && $(MAKE) checksrc)
(cd server && $(MAKE) checksrc)
+ (cd tunit && $(MAKE) checksrc)
+ (cd unit && $(MAKE) checksrc)
all-local: build-certs
tests/libtest/Makefile.am+2 -3
@@ -56,19 +56,18 @@ CFLAGS += @CURL_CFLAG_EXTRAS@
# Prevent LIBS from being used for all link targets
LIBS = $(BLANK_AT_MAKETIME)
-if USE_CPPFLAG_CURL_STATICLIB
-AM_CPPFLAGS += -DCURL_STATICLIB
-endif
if DEBUGBUILD
AM_CPPFLAGS += -DDEBUGBUILD
endif
if USE_CPPFLAG_CURL_STATICLIB
+AM_CPPFLAGS += -DCURL_STATICLIB
curlx_c_lib =
else
# These are part of the libcurl static lib. Add them here when linking shared.
curlx_c_lib = $(CURLX_C)
endif
+
$(BUNDLE).c: $(top_srcdir)/scripts/mk-unity.pl Makefile.inc $(FIRST_C) $(UTILS_C) $(curlx_c_lib) $(TOOLX_C) $(TESTS_C) lib1521.c
@PERL@ $(top_srcdir)/scripts/mk-unity.pl --include $(UTILS_C) $(curlx_c_lib) $(TOOLX_C) --test $(TESTS_C) lib1521.c > $(BUNDLE).c
tests/perf/.gitignore+6 -0
@@ -0,0 +1,6 @@
+# Copyright (C) Daniel Stenberg, <[email protected]>, et al.
+#
+# SPDX-License-Identifier: curl
+
+perf
+perf.c
tests/perf/CMakeLists.txt+59 -0
@@ -0,0 +1,59 @@
+#***************************************************************************
+# _ _ ____ _
+# 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
+#
+###########################################################################
+
+# Get BUNDLE, FIRST_C, FIRST_H, UTILS_C, UTILS_H, CURLX_C, TOOLX_C, TESTS_C variables
+curl_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
+include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
+
+if(LIB_SELECTED STREQUAL LIB_STATIC)
+ set(CURLX_C "") # Already exported from the libcurl static build. Skip them.
+endif()
+
+if(_CURL_TESTS_CONCAT)
+ set(_mk_unity_extra "--concat" "-I${CMAKE_CURRENT_SOURCE_DIR}")
+endif()
+
+add_custom_command(OUTPUT "${BUNDLE}.c"
+ COMMAND ${PERL_EXECUTABLE} "${PROJECT_SOURCE_DIR}/scripts/mk-unity.pl" ${_mk_unity_extra}
+ --include ${UTILS_C} ${CURLX_C} ${TOOLX_C} --test ${TESTS_C} > "${BUNDLE}.c"
+ DEPENDS
+ "${PROJECT_SOURCE_DIR}/scripts/mk-unity.pl" "${CMAKE_CURRENT_SOURCE_DIR}/Makefile.inc"
+ ${FIRST_C} ${FIRST_H} ${UTILS_C} ${CURLX_C} ${TOOLX_C} ${TESTS_C}
+ VERBATIM)
+
+add_executable(${BUNDLE} EXCLUDE_FROM_ALL "${BUNDLE}.c")
+add_dependencies(tt ${BUNDLE})
+target_link_libraries(${BUNDLE} ${LIB_SELECTED} ${CURL_LIBS})
+target_include_directories(${BUNDLE} PRIVATE
+ "${PROJECT_BINARY_DIR}/lib" # for "curl_config.h"
+ "${PROJECT_SOURCE_DIR}/lib" # for "curl_setup.h", curlx
+ "${PROJECT_SOURCE_DIR}/src" # for toolx
+ "${CMAKE_CURRENT_SOURCE_DIR}" # for the generated bundle source to find included test sources
+)
+set_target_properties(${BUNDLE} PROPERTIES OUTPUT_NAME "${BUNDLE}" PROJECT_LABEL "Test ${BUNDLE}" UNITY_BUILD OFF)
+
+if(NOT _CURL_TESTS_CONCAT)
+ set_target_properties(${BUNDLE} PROPERTIES C_CLANG_TIDY "")
+ curl_add_clang_tidy_test_target("${BUNDLE}-clang-tidy" ${BUNDLE} ${FIRST_C} ${UTILS_C} ${TESTS_C})
+endif()
tests/perf/Makefile.am+82 -0
@@ -0,0 +1,82 @@
+#***************************************************************************
+# _ _ ____ _
+# 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
+#
+###########################################################################
+AUTOMAKE_OPTIONS = foreign nostdinc
+
+# Specify our include paths here, and do it relative to $(top_srcdir) and
+# $(top_builddir), to ensure that these paths which belong to the library
+# being currently built and tested are searched before the library which
+# might possibly already be installed in the system.
+#
+# $(top_srcdir)/include is for libcurl's external include files
+# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file
+# $(top_srcdir)/lib for libcurl's lib/curl_setup.h and other "borrowed" files
+# $(top_srcdir)/src for toolx header files
+# $(srcdir) for the generated bundle source to find included test sources
+
+AM_CPPFLAGS = -I$(top_srcdir)/include \
+ -I$(top_builddir)/lib \
+ -I$(top_srcdir)/lib \
+ -I$(top_srcdir)/src \
+ -I$(srcdir)
+
+# Get BUNDLE, FIRST_C, FIRST_H, UTILS_C, UTILS_H, CURLX_C, TOOLX_C, TESTS_C variables
+include Makefile.inc
+
+EXTRA_DIST = CMakeLists.txt README.md $(FIRST_C) $(FIRST_H) $(UTILS_C) $(UTILS_H) $(TESTS_C)
+
+CFLAGS += @CURL_CFLAG_EXTRAS@
+
+# Prevent LIBS from being used for all link targets
+LIBS = $(BLANK_AT_MAKETIME)
+
+if USE_CPPFLAG_CURL_STATICLIB
+AM_CPPFLAGS += -DCURL_STATICLIB
+curlx_c_lib =
+else
+# These are part of the libcurl static lib. Add them here when linking shared.
+curlx_c_lib = $(CURLX_C)
+endif
+
+$(BUNDLE).c: $(top_srcdir)/scripts/mk-unity.pl Makefile.inc $(FIRST_C) $(UTILS_C) $(curlx_c_lib) $(TOOLX_C) $(TESTS_C)
+ @PERL@ $(top_srcdir)/scripts/mk-unity.pl --include $(UTILS_C) $(curlx_c_lib) $(TOOLX_C) --test $(TESTS_C) > $(BUNDLE).c
+
+noinst_PROGRAMS = $(BUNDLE)
+nodist_perf_SOURCES = $(BUNDLE).c
+LDADD = $(top_builddir)/lib/libcurl.la @LIBCURL_PC_LIBS_PRIVATE@
+CLEANFILES = $(BUNDLE).c
+
+CHECKSRC = $(CS_$(V))
+CS_0 = @echo " RUN " $@;
+CS_1 =
+CS_ = $(CS_0)
+
+checksrc:
+ $(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) -W$(srcdir)/$(BUNDLE).c $(FIRST_C) $(FIRST_H) $(UTILS_C) $(UTILS_H) $(TESTS_C))
+
+if NOT_CURL_CI
+all-local: checksrc
+endif
+
+clean-local:
+ rm -f $(BUNDLE)
tests/perf/Makefile.inc+48 -0
@@ -0,0 +1,48 @@
+#***************************************************************************
+# _ _ ____ _
+# 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
+#
+###########################################################################
+# Shared between CMakeLists.txt and Makefile.am
+
+BUNDLE = perf
+
+# Files referenced from the bundle source
+FIRST_C = first.c
+FIRST_H = first.h
+
+# Common files used by the performance test programs
+UTILS_C =
+UTILS_H =
+
+CURLX_C = \
+ ../../lib/curlx/base64.c \
+ ../../lib/curlx/fopen.c \
+ ../../lib/curlx/multibyte.c \
+ ../../lib/curlx/strparse.c \
+ ../../lib/curlx/timeval.c \
+ ../../lib/curlx/warnless.c
+
+# All performance test programs
+TESTS_C = \
+ base64.c \
+ snprintf.c \
+ urlparser.c
tests/perf/README.md+36 -0
@@ -0,0 +1,36 @@
+<!--
+Copyright (C) Daniel Stenberg, <[email protected]>, et al.
+
+SPDX-License-Identifier: curl
+-->
+
+# Performance tests
+
+This directory contains small stand-alone libcurl-using programs that each
+test specific aspects of the library's performance.
+
+The idea is to have a set of tests here that can be used to verify various
+libcurl functions' performance when we have no other good means of doing so.
+Performance is best tested relatively. Does it run slower or faster than
+before?
+
+Ideally these tests run without using any servers.
+
+## `urlparser`
+
+Provide this test with a list of many URLs and it times how fast it can parse
+them: `./perf urlparser URLs.txt [loops]`
+
+A test sample of 100K URLs can be found
+[here](https://raw.githubusercontent.com/ada-url/url-various-datasets/refs/heads/main/top100/top100.txt)
+
+## `base64`
+
+This test first base64 encodes a 256-byte buffer that has every different
+byte octet represented. It then decodes that string. Repeatedly in a loop the
+provided number of times: `./perf base64 [loops]`
+
+## `snprintf`
+
+This test repeatedly formats a representative string and measures the time per
+call: `./perf snprintf [loops]`
tests/perf/base64.c+79 -0
@@ -0,0 +1,79 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+static int test_base64(int argc, const char **argv)
+{
+ struct curltime start;
+ struct curltime end;
+ timediff_t us;
+ long long hn;
+
+ curl_off_t loops = 10000000, loop;
+
+ unsigned char array[256];
+ unsigned int c;
+
+ 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;
+ }
+
+ for(c = 0; c < 256; c++) {
+ array[c] = (unsigned char)c;
+ }
+
+ start = curlx_now();
+ for(loop = 0; loop < loops; loop++) {
+ char *encoded;
+ size_t enclen;
+ CURLcode result =
+ curlx_base64_encode(array, sizeof(array), &encoded, &enclen);
+ if(!result) {
+ unsigned char *recoded = NULL;
+ size_t reclen;
+ /* now decode it again */
+ result = curlx_base64_decode(encoded, &recoded, &reclen);
+ curlx_free(recoded);
+ }
+ if(result) {
+ curl_mfprintf(stderr, "unexpected coding error: %d\n", (int)result);
+ return 1;
+ }
+ curlx_free(encoded);
+ }
+ end = curlx_now();
+ us = curlx_timediff_us(end, start); /* how many microseconds */
+ hn = loop ? us * 100000 / loops : 0; /* 100 times too big */
+ curl_mprintf("Loops: %" CURL_FORMAT_CURL_OFF_T "\n"
+ "Time: %lld usecs\n"
+ "Time/loop: %lld.%lld ns\n",
+ loops,
+ (long long)us,
+ (long long)hn / 100,
+ (long long)hn % 100);
+ return 0;
+}
tests/perf/first.c+67 -0
@@ -0,0 +1,67 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#ifdef _WIN32
+static void win32_cleanup(void)
+{
+ _flushall(); /* flush buffers of all streams regardless of their mode */
+}
+#endif
+
+int main(int argc, const char *argv[])
+{
+ entry_func_t entry_func;
+ const char *entry_name;
+ int result;
+ size_t tmp;
+
+ if(argc < 2) {
+ curl_mfprintf(stderr, "Pass perftest as first argument\n");
+ return 1;
+ }
+
+ entry_name = argv[1];
+ entry_func = NULL;
+ for(tmp = 0; s_entries[tmp].ptr; ++tmp) {
+ if(!strcmp(entry_name, s_entries[tmp].name)) {
+ entry_func = s_entries[tmp].ptr;
+ break;
+ }
+ }
+
+ if(!entry_func) {
+ curl_mfprintf(stderr, "Test '%s' not found.\n", entry_name);
+ return 99;
+ }
+
+#ifdef _WIN32
+ curlx_now_init();
+ atexit(win32_cleanup);
+#endif
+
+ result = entry_func(argc - 1, argv + 1);
+
+ return result;
+}
tests/perf/first.h+56 -0
@@ -0,0 +1,56 @@
+#ifndef HEADER_PERF_FIRST_H
+#define HEADER_PERF_FIRST_H
+/***************************************************************************
+ * _ _ ____ _
+ * 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
+ *
+ ***************************************************************************/
+#define CURL_NO_OLDIES
+#define CURL_DISABLE_DEPRECATION
+
+/* Now include the curl_setup.h file from libcurl's private libdir (the source
+ version, but that might include "curl_config.h" from the build directory so
+ we need both of them in the include path), so that we get good in-depth
+ knowledge about the system we are building this on */
+#include "curl_setup.h"
+
+#include "curlx/base64.h" /* for curlx_base64* */
+#include "curlx/fopen.h" /* for curlx_f*() */
+#include "curlx/strparse.h" /* for curlx_str_* parsing functions */
+#include "curlx/timeval.h" /* for curlx_now type and related functions */
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+typedef int (*entry_func_t)(int, const char **);
+
+struct entry_s {
+ const char *name;
+ entry_func_t ptr;
+};
+
+extern const struct entry_s s_entries[];
+
+#endif /* HEADER_PERF_FIRST_H */
tests/perf/snprintf.c+67 -0
@@ -0,0 +1,67 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+static int test_snprintf(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),
+ "Add %-4d stuff %u to %3d the %3u output %s "
+ "%*s"
+ "for %lld testing %lu\n",
+ 123, (unsigned int)123,
+ 123, (unsigned int)123, "helllo",
+ 14, "01234567890123456",
+ (long long)987871231231,
+ (unsigned long)6732673);
+ }
+ 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.%lld ns\n",
+ loops,
+ (long long)us,
+ (long long)hn / 100,
+ (long long)hn % 100);
+ return 0;
+}
tests/perf/urlparser.c+171 -0
@@ -0,0 +1,171 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+/*
+ * Read many URLs from a given file.
+ * Parse them with all listed option combinations
+ */
+static int test_urlparser(int argc, const char **argv)
+{
+ static const int options[] = {
+ CURLU_DEFAULT_PORT,
+ CURLU_DEFAULT_SCHEME,
+ CURLU_NON_SUPPORT_SCHEME,
+ CURLU_ALLOW_SPACE,
+ CURLU_GUESS_SCHEME,
+ CURLU_PATH_AS_IS,
+ CURLU_DISALLOW_USER
+ };
+
+ static char *urls[150000];
+
+ struct curltime start;
+ struct curltime end;
+ timediff_t us;
+ long long hn;
+
+ curl_off_t loops = 10, loop;
+
+ curl_off_t count = 0;
+ curl_off_t ecount = 0; /* errors */
+
+ int ret;
+ size_t o;
+ int fd;
+ char *buffer = NULL;
+ size_t i;
+ size_t nsize;
+ ssize_t nread;
+ size_t nurls = 0; /* number of URLs */
+ curlx_struct_stat info;
+ char *p;
+ CURLU *uh;
+
+ if(argc < 2) {
+ curl_mfprintf(stderr, "%s <URL file> [iterations]\n", argv[0]);
+ return 2;
+ }
+ if(argc > 2) {
+ const char *ptr = argv[2];
+ curl_off_t num;
+ if(!curlx_str_number(&ptr, &num, 100000) && !*ptr)
+ loops = num;
+ }
+
+ fd = curlx_open(argv[1], O_RDONLY | CURL_O_BINARY);
+ if(fd == -1) {
+ curl_mfprintf(stderr, "Cannot open %s, exiting\n", argv[1]);
+ return 3;
+ }
+
+ if(curlx_fstat(fd, &info) == -1) {
+ curlx_close(fd);
+ curl_mfprintf(stderr, "Cannot stat %s, exiting\n", argv[1]);
+ return 3;
+ }
+
+ ret = 4;
+
+ nsize = (size_t)info.st_size;
+
+ buffer = curlx_malloc(nsize + 1);
+ if(!buffer) {
+ curlx_close(fd);
+ curl_mfprintf(stderr, "Cannot malloc the buffer\n");
+ goto cleanup;
+ }
+
+ nread = read(fd, buffer, nsize);
+ curlx_close(fd);
+ if(nread != (ssize_t)nsize) {
+ curl_mfprintf(stderr, "Cannot load the file\n");
+ goto cleanup;
+ }
+
+ buffer[nsize] = 0;
+ p = buffer;
+ while(*p) {
+ if(nurls >= CURL_ARRAYSIZE(urls)) {
+ curl_mfprintf(stderr,
+ "Too many URLs in file, rebuild with higher max\n");
+ goto cleanup;
+ }
+ urls[nurls++] = p;
+ p = strchr(p, '\n');
+ if(!p)
+ break;
+ if(p > urls[nurls - 1] && p[-1] == '\r')
+ p[-1] = '\0';
+ *p = '\0';
+ p++;
+ }
+ curl_mprintf("Found %zu URLs to test for %" CURL_FORMAT_CURL_OFF_T
+ " iterations (%zu variations)\n",
+ nurls, loops, CURL_ARRAYSIZE(options));
+
+ uh = curl_url();
+ if(!uh) {
+ curl_mfprintf(stderr, "curl_url() failed\n");
+ goto cleanup;
+ }
+ start = curlx_now();
+ for(loop = 0; loop < loops; loop++) {
+ for(i = 0; i < nurls; i++) {
+ for(o = 0; o < CURL_ARRAYSIZE(options); o++) {
+ CURLUcode hcode = curl_url_set(uh, CURLUPART_URL, urls[i], options[o]);
+ count++;
+ if(hcode) {
+#if 0
+ curl_mfprintf(stderr, "Failed [%u]: %s\n", (int)hcode, buffer);
+#endif
+ ecount++;
+ }
+ }
+ }
+ }
+ end = curlx_now();
+ curl_url_cleanup(uh);
+ us = curlx_timediff_us(end, start); /* how many microseconds */
+ hn = count ? us * 100000 / count : 0; /* 100 times too big */
+ curl_mprintf("URLs: %" CURL_FORMAT_CURL_OFF_T "\n"
+ "Time: %lld usecs\n"
+ "Time/URL: %lld.%lld ns\n"
+ "URLs/sec: %lld\n"
+ "Errors: %" CURL_FORMAT_CURL_OFF_T "\n",
+ count,
+ (long long)us,
+ (long long)hn / 100,
+ (long long)hn % 100,
+ us ? (long long)(count * 1000000) / us : 0,
+ ecount);
+
+ ret = 0;
+
+cleanup:
+
+ curlx_free(buffer);
+
+ return ret;
+}