gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r15863 - in libmicrohttpd: . src/testcurl


From: gnunet
Subject: [GNUnet-SVN] r15863 - in libmicrohttpd: . src/testcurl
Date: Thu, 7 Jul 2011 10:25:55 +0200

Author: grothoff
Date: 2011-07-07 10:25:55 +0200 (Thu, 07 Jul 2011)
New Revision: 15863

Added:
   libmicrohttpd/src/testcurl/gauger.h
   libmicrohttpd/src/testcurl/perf_get.c
   libmicrohttpd/src/testcurl/perf_get_concurrent.c
Modified:
   libmicrohttpd/ChangeLog
   libmicrohttpd/configure.ac
   libmicrohttpd/src/testcurl/Makefile.am
Log:
adding perf measurements

Modified: libmicrohttpd/ChangeLog
===================================================================
--- libmicrohttpd/ChangeLog     2011-07-07 08:23:46 UTC (rev 15862)
+++ libmicrohttpd/ChangeLog     2011-07-07 08:25:55 UTC (rev 15863)
@@ -1,3 +1,9 @@
+Thu Jul  7 10:24:20 CEST 2011
+       Adding performance measurements. -CG
+
+Thu Jun 23 14:21:13 CEST 2011
+       Releasing libmicrohttpd 0.9.12. -CG
+
 Wed Jun 22 14:32:23 CEST 2011
        Force closing connection if either the client asked it or
        if the response contains 'Connection: close' (so far,

Modified: libmicrohttpd/configure.ac
===================================================================
--- libmicrohttpd/configure.ac  2011-07-07 08:23:46 UTC (rev 15862)
+++ libmicrohttpd/configure.ac  2011-07-07 08:25:55 UTC (rev 15863)
@@ -81,46 +81,55 @@
      AC_DEFINE_UNQUOTED(OSX,1,[This is an OS X system])
      CFLAGS="-no-cpp-precomp -fno-common $CFLAGS"
      AM_CONDITIONAL(HAVE_GNU_LD, false)    
+     AM_CONDITIONAL(HAVE_W32, false)        
      ;;
 linux*)
      AC_DEFINE_UNQUOTED(LINUX,1,[This is a Linux system])
      AM_CONDITIONAL(HAVE_GNU_LD, true)    
+     AM_CONDITIONAL(HAVE_W32, false)        
      ;;
 freebsd*)
      AC_DEFINE_UNQUOTED(SOMEBSD,1,[This is a BSD system])
      AC_DEFINE_UNQUOTED(FREEBSD,1,[This is a FreeBSD system])
      AM_CONDITIONAL(HAVE_GNU_LD, true)    
+     AM_CONDITIONAL(HAVE_W32, false)        
      CFLAGS="-D_THREAD_SAFE $CFLAGS"
      ;;
 openbsd*)
      AC_DEFINE_UNQUOTED(SOMEBSD,1,[This is a BSD system])
      AC_DEFINE_UNQUOTED(OPENBSD,1,[This is an OpenBSD system])
      AM_CONDITIONAL(HAVE_GNU_LD, true)    
+     AM_CONDITIONAL(HAVE_W32, false)        
      ;;
 netbsd*)
      AC_DEFINE_UNQUOTED(SOMEBSD,1,[This is a BSD system])
      AC_DEFINE_UNQUOTED(NETBSD,1,[This is a NetBSD system])
      AM_CONDITIONAL(HAVE_GNU_LD, true)    
+     AM_CONDITIONAL(HAVE_W32, false)        
      ;;
 *solaris*)
      AC_DEFINE_UNQUOTED(SOLARIS,1,[This is a Solaris system])
      AC_DEFINE_UNQUOTED(_REENTRANT,1,[Need with solaris or errno doesnt work])
      AM_CONDITIONAL(HAVE_GNU_LD, false)    
+     AM_CONDITIONAL(HAVE_W32, false)        
      LDFLAGS="$LDFLAGS -lpthread"
      ;;
 *arm-linux*)
      AC_DEFINE_UNQUOTED(LINUX,1,[This is a Linux system])
      CFLAGS="-D_REENTRANT -fPIC -pipe $CFLAGS"
      AM_CONDITIONAL(HAVE_GNU_LD, true)    
+     AM_CONDITIONAL(HAVE_W32, false)        
      ;;
 *cygwin*)
      AC_DEFINE_UNQUOTED(CYGWIN,1,[This is a Cygwin system])
-     AM_CONDITIONAL(HAVE_GNU_LD, false)    
+     AM_CONDITIONAL(HAVE_GNU_LD, false)
+     AM_CONDITIONAL(HAVE_W32, false)        
      LDFLAGS="$LDFLAGS -no-undefined"
      ;;
 *mingw*)
      AC_DEFINE_UNQUOTED(MINGW,1,[This is a MinGW system])
      AC_DEFINE_UNQUOTED(WINDOWS,1,[This is a Windows system])
+     AM_CONDITIONAL(HAVE_W32, true)    
      LDFLAGS="$LDFLAGS -no-undefined -Wl,--export-all-symbols -lws2_32"
      AM_CONDITIONAL(HAVE_GNU_LD, true)    
      # check if PlibC is available
@@ -133,11 +142,13 @@
 *openedition*)
      AC_DEFINE_UNQUOTED(OS390,1,[This is a OS/390 system])
      AM_CONDITIONAL(HAVE_GNU_LD, false)    
+     AM_CONDITIONAL(HAVE_W32, false)        
     ;;
 *)
      AC_MSG_RESULT(Unrecognised OS $host_os)
      AC_DEFINE_UNQUOTED(OTHEROS,1,[Some strange OS])
      AM_CONDITIONAL(HAVE_GNU_LD, false)    
+     AM_CONDITIONAL(HAVE_W32, false)        
 ;;
 esac
 

Modified: libmicrohttpd/src/testcurl/Makefile.am
===================================================================
--- libmicrohttpd/src/testcurl/Makefile.am      2011-07-07 08:23:46 UTC (rev 
15862)
+++ libmicrohttpd/src/testcurl/Makefile.am      2011-07-07 08:25:55 UTC (rev 
15863)
@@ -19,6 +19,10 @@
 -I$(top_srcdir)/src/include \
 $(LIBCURL_CPPFLAGS)
 
+if !HAVE_W32
+PERF_GET_CONCURRENT=perf_get_concurrent
+endif
+
 check_PROGRAMS = \
   daemontest_get \
   daemontest_get_sendfile \
@@ -43,7 +47,10 @@
   daemontest_put_chunked \
   daemontest_iplimit11 \
   daemontest_termination \
-  daemontest_timeout
+  daemontest_timeout \
+  perf_get $(PERF_GET_CONCURRENT)
+
+
 noinst_PROGRAMS = \
   daemon_options_test
 
@@ -70,6 +77,20 @@
   $(top_builddir)/src/daemon/libmicrohttpd.la \
   @LIBCURL@ 
 
+perf_get_SOURCES = \
+  perf_get.c \
+  gauger.h
+perf_get_LDADD = \
+  $(top_builddir)/src/daemon/libmicrohttpd.la \
+  @LIBCURL@ 
+
+perf_get_concurrent_SOURCES = \
+  perf_get_concurrent.c \
+  gauger.h
+perf_get_concurrent_LDADD = \
+  $(top_builddir)/src/daemon/libmicrohttpd.la \
+  @LIBCURL@ 
+
 daemontest_digestauth_SOURCES = \
   daemontest_digestauth.c
 daemontest_digestauth_LDADD = \

Added: libmicrohttpd/src/testcurl/gauger.h
===================================================================
--- libmicrohttpd/src/testcurl/gauger.h                         (rev 0)
+++ libmicrohttpd/src/testcurl/gauger.h 2011-07-07 08:25:55 UTC (rev 15863)
@@ -0,0 +1,86 @@
+/** ---------------------------------------------------------------------------
+ * This software is in the public domain, furnished "as is", without technical
+ * support, and with no warranty, express or implied, as to its usefulness for
+ * any purpose.
+ *
+ * gauger.h
+ * Interface for C programs to log remotely to a gauger server
+ *
+ * Author: Bartlomiej Polot
+ * -------------------------------------------------------------------------*/
+#ifndef __GAUGER_H__
+#define __GAUGER_H__
+
+#ifndef WINDOWS
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/wait.h>
+
+#define GAUGER(category, counter, value, unit)\
+{\
+    const char * __gauger_v[10];                       \
+    char __gauger_s[32];\
+    pid_t __gauger_p;\
+    if(!(__gauger_p=fork())){\
+      if(!fork()){ \
+            sprintf(__gauger_s,"%Lf", (long double) (value));\
+            __gauger_v[0] = "gauger";\
+            __gauger_v[1] = "-n";\
+            __gauger_v[2] = counter;   \
+            __gauger_v[3] = "-d";\
+            __gauger_v[4] = __gauger_s;\
+            __gauger_v[5] = "-u";\
+            __gauger_v[6] = unit;      \
+            __gauger_v[7] = "-c";\
+            __gauger_v[8] = category;  \
+            __gauger_v[9] = (char *)NULL;\
+            execvp("gauger", (char*const*) __gauger_v);        \
+            _exit(1);\
+        }else{\
+            _exit(0);\
+        }\
+    }else{\
+        waitpid(__gauger_p,NULL,0);\
+    }\
+}
+
+#define GAUGER_ID(category, counter, value, unit, id)\
+{\
+    char* __gauger_v[12];\
+    char __gauger_s[32];\
+    pid_t __gauger_p;\
+    if(!(__gauger_p=fork())){\
+        if(!fork()){\
+            sprintf(__gauger_s,"%Lf", (long double) (value));\
+            __gauger_v[0] = "gauger";\
+            __gauger_v[1] = "-n";\
+            __gauger_v[2] = counter;\
+            __gauger_v[3] = "-d";\
+            __gauger_v[4] = __gauger_s;\
+            __gauger_v[5] = "-u";\
+            __gauger_v[6] = unit;\
+            __gauger_v[7] = "-i";\
+            __gauger_v[8] = id;\
+            __gauger_v[9] = "-c";\
+            __gauger_v[10] = category;\
+            __gauger_v[11] = (char *)NULL;\
+            execvp("gauger",__gauger_v);\
+            perror("gauger");\
+            _exit(1);\
+        }else{\
+            _exit(0);\
+        }\
+    }else{\
+        waitpid(__gauger_p,NULL,0);\
+    }\
+}
+
+#else
+
+#define GAUGER_ID(category, counter, value, unit, id) {}
+#define GAUGER(category, counter, value, unit) {}
+
+#endif // WINDOWS
+
+#endif

Added: libmicrohttpd/src/testcurl/perf_get.c
===================================================================
--- libmicrohttpd/src/testcurl/perf_get.c                               (rev 0)
+++ libmicrohttpd/src/testcurl/perf_get.c       2011-07-07 08:25:55 UTC (rev 
15863)
@@ -0,0 +1,491 @@
+/*
+     This file is part of libmicrohttpd
+     (C) 2007, 2009, 2011 Christian Grothoff
+
+     libmicrohttpd is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     libmicrohttpd is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with libmicrohttpd; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file perf_get.c
+ * @brief benchmark simple GET operations (sequential access).
+ *        Note that we run libcurl in the same process at the
+ *        same time, so the execution time given is the combined
+ *        time for both MHD and libcurl; it is quite possible
+ *        that more time is spend with libcurl than with MHD,
+ *        so the performance scores calculated with this code
+ *        should NOT be used to compare with other HTTP servers
+ *        (since MHD is actually better); only the relative
+ *        scores between MHD versions are meaningful.  
+ *        Furthermore, this code ONLY tests MHD processing
+ *        a single request at a time.  This is again
+ *        not universally meaningful (i.e. when comparing
+ *        multithreaded vs. single-threaded or select/poll).
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "gauger.h"
+
+#ifndef WINDOWS
+#include <unistd.h>
+#include <sys/socket.h>
+#endif
+
+/**
+ * How many rounds of operations do we do for each
+ * test?
+ */
+#define ROUNDS 500
+
+/**
+ * Do we use HTTP 1.1?
+ */
+static int oneone;
+
+/**
+ * Response to return (re-used).
+ */
+static struct MHD_Response *response;
+
+/**
+ * Time this round was started.
+ */
+static unsigned long long start_time;
+
+
+/**
+ * Get the current timestamp 
+ *
+ * @return current time in ms
+ */
+static unsigned long long 
+now ()
+{
+  struct timeval tv;
+
+  GETTIMEOFDAY (&tv, NULL);
+  return (((unsigned long long) tv.tv_sec * 1000LL) +
+         ((unsigned long long) tv.tv_usec / 1000LL));
+}
+
+
+/**
+ * Start the timer.
+ */
+static void 
+start_timer()
+{
+  start_time = now ();
+}
+
+
+/**
+ * Stop the timer and report performance
+ *
+ * @param desc description of the threading mode we used
+ */
+static void 
+stop (const char *desc)
+{
+  double rps = ((double) (ROUNDS * 1000)) / ((double) (now() - start_time));
+
+  fprintf (stderr,
+          "Sequential GETs using %s: %f %s\n",
+          desc,
+          rps,
+          "requests/s");
+  GAUGER (desc,
+         "Sequential GETs",
+         rps,
+         "requests/s");
+}
+
+
+struct CBC
+{
+  char *buf;
+  size_t pos;
+  size_t size;
+};
+
+
+static size_t
+copyBuffer (void *ptr, 
+           size_t size, size_t nmemb, 
+           void *ctx)
+{
+  struct CBC *cbc = ctx;
+
+  if (cbc->pos + size * nmemb > cbc->size)
+    return 0;                   /* overflow */
+  memcpy (&cbc->buf[cbc->pos], ptr, size * nmemb);
+  cbc->pos += size * nmemb;
+  return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+          struct MHD_Connection *connection,
+          const char *url,
+          const char *method,
+          const char *version,
+          const char *upload_data, size_t *upload_data_size,
+          void **unused)
+{
+  static int ptr;
+  const char *me = cls;
+  int ret;
+
+  if (0 != strcmp (me, method))
+    return MHD_NO;              /* unexpected method */
+  if (&ptr != *unused)
+    {
+      *unused = &ptr;
+      return MHD_YES;
+    }
+  *unused = NULL;
+  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+  if (ret == MHD_NO)
+    abort ();
+  return ret;
+}
+
+
+static int
+testInternalGet (int poll_flag)
+{
+  struct MHD_Daemon *d;
+  CURL *c;
+  char buf[2048];
+  struct CBC cbc;
+  CURLcode errornum;
+  unsigned int i;
+
+  cbc.buf = buf;
+  cbc.size = 2048;
+  d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG  | poll_flag,
+                        11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+  if (d == NULL)
+    return 1;
+  start_timer ();
+  for (i=0;i<ROUNDS;i++)
+    {
+      cbc.pos = 0;
+      c = curl_easy_init ();
+      curl_easy_setopt (c, CURLOPT_URL, "http://localhost:11080/hello_world";);
+      curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+      curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+      curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+      curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+      curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
+      if (oneone)
+       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+      else
+       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+      /* NOTE: use of CONNECTTIMEOUT without also
+        setting NOSIGNAL results in really weird
+        crashes on my system!*/
+      curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+      if (CURLE_OK != (errornum = curl_easy_perform (c)))
+       {
+         fprintf (stderr,
+                  "curl_easy_perform failed: `%s'\n",
+                  curl_easy_strerror (errornum));
+         curl_easy_cleanup (c);
+         MHD_stop_daemon (d);
+         return 2;
+       }
+      curl_easy_cleanup (c);
+    }
+  stop (poll_flag ? "internal poll" : "internal select");
+  MHD_stop_daemon (d);
+  if (cbc.pos != strlen ("/hello_world"))
+    return 4;
+  if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+    return 8;
+  return 0;
+}
+
+
+static int
+testMultithreadedGet (int poll_flag)
+{
+  struct MHD_Daemon *d;
+  CURL *c;
+  char buf[2048];
+  struct CBC cbc;
+  CURLcode errornum;
+  unsigned int i;
+
+  cbc.buf = buf;
+  cbc.size = 2048;
+  d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG  | 
poll_flag,
+                        1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+  if (d == NULL)
+    return 16;
+  start_timer ();
+  for (i=0;i<ROUNDS;i++)
+    {
+      cbc.pos = 0;
+      c = curl_easy_init ();
+      curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world";);
+      curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+      curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+      curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+      curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+      if (oneone)
+       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+      else
+       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+      curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
+      /* NOTE: use of CONNECTTIMEOUT without also
+        setting NOSIGNAL results in really weird
+        crashes on my system! */
+      curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+      if (CURLE_OK != (errornum = curl_easy_perform (c)))
+       {
+         fprintf (stderr,
+                  "curl_easy_perform failed: `%s'\n",
+                  curl_easy_strerror (errornum));
+         curl_easy_cleanup (c);
+         MHD_stop_daemon (d);
+         return 32;
+       }
+      curl_easy_cleanup (c);
+    }
+  stop (poll_flag ? "thread with poll" : "thread with select");
+  MHD_stop_daemon (d);
+  if (cbc.pos != strlen ("/hello_world"))
+    return 64;
+  if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+    return 128;
+  return 0;
+}
+
+static int
+testMultithreadedPoolGet (int poll_flag)
+{
+  struct MHD_Daemon *d;
+  CURL *c;
+  char buf[2048];
+  struct CBC cbc;
+  CURLcode errornum;
+  unsigned int i;
+
+  cbc.buf = buf;
+  cbc.size = 2048;
+  d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+                        1081, NULL, NULL, &ahc_echo, "GET",
+                        MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END);
+  if (d == NULL)
+    return 16;
+  start_timer ();
+  for (i=0;i<ROUNDS;i++)
+    {
+      cbc.pos = 0;
+      c = curl_easy_init ();
+      curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world";);
+      curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+      curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+      curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+      curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+      if (oneone)
+       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+      else
+       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+      curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
+      /* NOTE: use of CONNECTTIMEOUT without also
+        setting NOSIGNAL results in really weird
+        crashes on my system!*/
+      curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+      if (CURLE_OK != (errornum = curl_easy_perform (c)))
+       {
+         fprintf (stderr,
+                  "curl_easy_perform failed: `%s'\n",
+                  curl_easy_strerror (errornum));
+         curl_easy_cleanup (c);
+         MHD_stop_daemon (d);
+         return 32;
+       }
+      curl_easy_cleanup (c);
+    }
+  stop (poll_flag ? "thread pool with poll" : "thread pool with select");
+  MHD_stop_daemon (d);
+  if (cbc.pos != strlen ("/hello_world"))
+    return 64;
+  if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+    return 128;
+  return 0;
+}
+
+static int
+testExternalGet ()
+{
+  struct MHD_Daemon *d;
+  CURL *c;
+  char buf[2048];
+  struct CBC cbc;
+  CURLM *multi;
+  CURLMcode mret;
+  fd_set rs;
+  fd_set ws;
+  fd_set es;
+  int max;
+  int running;
+  struct CURLMsg *msg;
+  time_t start;
+  struct timeval tv;
+  unsigned int i;
+
+  multi = NULL;
+  cbc.buf = buf;
+  cbc.size = 2048;
+  d = MHD_start_daemon (MHD_USE_DEBUG,
+                        1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+  if (d == NULL)
+    return 256;
+  start_timer ();
+  multi = curl_multi_init ();
+  if (multi == NULL)
+    {
+      MHD_stop_daemon (d);
+      return 512;
+    }
+  for (i=0;i<ROUNDS;i++)
+    {
+      cbc.pos = 0;
+      c = curl_easy_init ();
+      curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1082/hello_world";);
+      curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+      curl_easy_setopt (c, CURLOPT_WRITEDATA, &cbc);
+      curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+      if (oneone)
+       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+      else
+       curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
+      curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+      curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
+      /* NOTE: use of CONNECTTIMEOUT without also
+        setting NOSIGNAL results in really weird
+        crashes on my system! */
+      curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+      mret = curl_multi_add_handle (multi, c);
+      if (mret != CURLM_OK)
+       {
+         curl_multi_cleanup (multi);
+         curl_easy_cleanup (c);
+         MHD_stop_daemon (d);
+         return 1024;
+       }
+      start = time (NULL);
+      while ((time (NULL) - start < 5) && (c != NULL))
+       {
+         max = 0;
+         FD_ZERO (&rs);
+         FD_ZERO (&ws);
+         FD_ZERO (&es);
+         curl_multi_perform (multi, &running);
+         mret = curl_multi_fdset (multi, &rs, &ws, &es, &max);
+         if (mret != CURLM_OK)
+           {
+             curl_multi_remove_handle (multi, c);
+             curl_multi_cleanup (multi);
+             curl_easy_cleanup (c);
+             MHD_stop_daemon (d);
+             return 2048;
+           }
+         if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+           {
+             curl_multi_remove_handle (multi, c);
+             curl_multi_cleanup (multi);
+             curl_easy_cleanup (c);
+             MHD_stop_daemon (d);
+             return 4096;
+           }
+         tv.tv_sec = 0;
+         tv.tv_usec = 1000;
+         select (max + 1, &rs, &ws, &es, &tv);
+         curl_multi_perform (multi, &running);
+         if (running == 0)
+           {
+             msg = curl_multi_info_read (multi, &running);
+             if (msg == NULL)
+               break;
+             if (msg->msg == CURLMSG_DONE)
+               {
+                 if (msg->data.result != CURLE_OK)
+                   printf ("%s failed at %s:%d: `%s'\n",
+                           "curl_multi_perform",
+                           __FILE__,
+                           __LINE__, curl_easy_strerror (msg->data.result));
+                 curl_multi_remove_handle (multi, c);
+                 curl_easy_cleanup (c);
+                 c = NULL;
+               }
+           }
+         MHD_run (d);
+       }
+      if (NULL != c)
+       {
+         curl_multi_remove_handle (multi, c);
+         curl_easy_cleanup (c);
+         fprintf (stderr, "Timeout!?\n");
+       }
+    }
+  stop ("external select");
+  if (multi != NULL)
+    {
+      curl_multi_cleanup (multi);
+    }
+  MHD_stop_daemon (d);
+  if (cbc.pos != strlen ("/hello_world"))
+    return 8192;
+  if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world")))
+    return 16384;
+  return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+  unsigned int errorCount = 0;
+
+  oneone = NULL != strstr (argv[0], "11");
+  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+    return 2;
+  response = MHD_create_response_from_buffer (strlen ("/hello_world"),
+                                             "/hello_world",
+                                             MHD_RESPMEM_MUST_COPY);
+  errorCount += testInternalGet (0);
+  errorCount += testMultithreadedGet (0);
+  errorCount += testMultithreadedPoolGet (0);
+  errorCount += testExternalGet ();
+  errorCount += testInternalGet (MHD_USE_POLL);
+  errorCount += testMultithreadedGet (MHD_USE_POLL);
+  errorCount += testMultithreadedPoolGet (MHD_USE_POLL);
+  MHD_destroy_response (response);
+  if (errorCount != 0)
+    fprintf (stderr, "Error (code: %u)\n", errorCount);
+  curl_global_cleanup ();
+  return errorCount != 0;       /* 0 == pass */
+}

Added: libmicrohttpd/src/testcurl/perf_get_concurrent.c
===================================================================
--- libmicrohttpd/src/testcurl/perf_get_concurrent.c                            
(rev 0)
+++ libmicrohttpd/src/testcurl/perf_get_concurrent.c    2011-07-07 08:25:55 UTC 
(rev 15863)
@@ -0,0 +1,338 @@
+/*
+     This file is part of libmicrohttpd
+     (C) 2007, 2009, 2011 Christian Grothoff
+
+     libmicrohttpd is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     libmicrohttpd is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with libmicrohttpd; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file perf_get_concurrent.c
+ * @brief benchmark concurrent GET operations
+ *        Note that we run libcurl on the machine at the
+ *        same time, so the execution time may be influenced
+ *        by the concurrent activity; it is quite possible
+ *        that more time is spend with libcurl than with MHD,
+ *        so the performance scores calculated with this code
+ *        should NOT be used to compare with other HTTP servers
+ *        (since MHD is actually better); only the relative
+ *        scores between MHD versions are meaningful.  
+ * @author Christian Grothoff
+ */
+
+#include "MHD_config.h"
+#include "platform.h"
+#include <curl/curl.h>
+#include <microhttpd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "gauger.h"
+
+/**
+ * How many rounds of operations do we do for each
+ * test (total number of requests will be ROUNDS * PAR).
+ */
+#define ROUNDS 500
+
+/**
+ * How many requests do we do in parallel?
+ */
+#define PAR 4
+
+/**
+ * Do we use HTTP 1.1?
+ */
+static int oneone;
+
+/**
+ * Response to return (re-used).
+ */
+static struct MHD_Response *response;
+
+/**
+ * Time this round was started.
+ */
+static unsigned long long start_time;
+
+
+/**
+ * Get the current timestamp 
+ *
+ * @return current time in ms
+ */
+static unsigned long long 
+now ()
+{
+  struct timeval tv;
+
+  GETTIMEOFDAY (&tv, NULL);
+  return (((unsigned long long) tv.tv_sec * 1000LL) +
+         ((unsigned long long) tv.tv_usec / 1000LL));
+}
+
+
+/**
+ * Start the timer.
+ */
+static void 
+start_timer()
+{
+  start_time = now ();
+}
+
+
+/**
+ * Stop the timer and report performance
+ *
+ * @param desc description of the threading mode we used
+ */
+static void 
+stop (const char *desc)
+{
+  double rps = ((double) (PAR * ROUNDS * 1000)) / ((double) (now() - 
start_time));
+
+  fprintf (stderr,
+          "Parallel GETs using %s: %f %s\n",
+          desc,
+          rps,
+          "requests/s");
+  GAUGER (desc,
+         "Parallel GETs",
+         rps,
+         "requests/s");
+}
+
+
+static size_t
+copyBuffer (void *ptr, 
+           size_t size, size_t nmemb, 
+           void *ctx)
+{
+  return size * nmemb;
+}
+
+static int
+ahc_echo (void *cls,
+          struct MHD_Connection *connection,
+          const char *url,
+          const char *method,
+          const char *version,
+          const char *upload_data, size_t *upload_data_size,
+          void **unused)
+{
+  static int ptr;
+  const char *me = cls;
+  int ret;
+
+  if (0 != strcmp (me, method))
+    return MHD_NO;              /* unexpected method */
+  if (&ptr != *unused)
+    {
+      *unused = &ptr;
+      return MHD_YES;
+    }
+  *unused = NULL;
+  ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
+  if (ret == MHD_NO)
+    abort ();
+  return ret;
+}
+
+
+static pid_t
+do_gets ()
+{
+  pid_t ret;
+  CURL *c;
+  CURLcode errornum;
+  unsigned int i;
+  unsigned int j;
+  pid_t par[PAR];
+  
+  ret = fork ();
+  if (ret == -1) abort ();
+  if (ret != 0)
+    return ret;
+  for (j=0;j<PAR;j++)
+    {
+      par[j] = fork ();
+      if (par[j] == 0)
+       {
+         for (i=0;i<ROUNDS;i++)
+           {
+             c = curl_easy_init ();
+             curl_easy_setopt (c, CURLOPT_URL, 
"http://localhost:1081/hello_world";);
+             curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
+             curl_easy_setopt (c, CURLOPT_WRITEDATA, NULL);
+             curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
+             curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
+             if (oneone)
+               curl_easy_setopt (c, CURLOPT_HTTP_VERSION, 
CURL_HTTP_VERSION_1_1);
+             else
+               curl_easy_setopt (c, CURLOPT_HTTP_VERSION, 
CURL_HTTP_VERSION_1_0);
+             curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
+             /* NOTE: use of CONNECTTIMEOUT without also
+                setting NOSIGNAL results in really weird
+                crashes on my system! */
+             curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
+             if (CURLE_OK != (errornum = curl_easy_perform (c)))
+               {
+                 fprintf (stderr,
+                          "curl_easy_perform failed: `%s'\n",
+                          curl_easy_strerror (errornum));
+                 curl_easy_cleanup (c);
+                 _exit (1);
+               }
+             curl_easy_cleanup (c);
+           }
+         _exit (0);
+       }
+    }
+  for (j=0;j<PAR;j++)
+    waitpid (par[j], NULL, 0);
+  _exit (0);
+}
+
+
+static void 
+join_gets (pid_t pid)
+{
+  int status;
+  
+  status = 1;
+  waitpid (pid, &status, 0);
+  if (0 != status)
+    abort ();
+}
+
+
+static int
+testInternalGet (int poll_flag)
+{
+  struct MHD_Daemon *d;
+
+  d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG  | poll_flag,
+                        1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+  if (d == NULL)
+    return 1;
+  start_timer ();
+  join_gets (do_gets ());
+  stop (poll_flag ? "internal poll" : "internal select");
+  MHD_stop_daemon (d);
+  return 0;
+}
+
+
+static int
+testMultithreadedGet (int poll_flag)
+{
+  struct MHD_Daemon *d;
+
+  d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG  | 
poll_flag,
+                        1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+  if (d == NULL)
+    return 16;
+  start_timer ();
+  join_gets (do_gets ());
+  stop (poll_flag ? "thread with poll" : "thread with select");
+  MHD_stop_daemon (d);
+  return 0;
+}
+
+static int
+testMultithreadedPoolGet (int poll_flag)
+{
+  struct MHD_Daemon *d;
+
+  d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
+                        1081, NULL, NULL, &ahc_echo, "GET",
+                        MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END);
+  if (d == NULL)
+    return 16;
+  start_timer ();
+  join_gets (do_gets ());
+  stop (poll_flag ? "thread pool with poll" : "thread pool with select");
+  MHD_stop_daemon (d);
+  return 0;
+}
+
+static int
+testExternalGet ()
+{
+  struct MHD_Daemon *d;
+  pid_t pid;
+  fd_set rs;
+  fd_set ws;
+  fd_set es;
+  int max;
+  struct timeval tv;
+  unsigned MHD_LONG_LONG tt;
+  int tret;
+
+  d = MHD_start_daemon (MHD_USE_DEBUG,
+                        1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
+  if (d == NULL)
+    return 256;
+  start_timer ();
+  pid = do_gets ();
+  while (0 == waitpid (pid, NULL, WNOHANG))
+    {
+      max = 0;
+      FD_ZERO (&rs);
+      FD_ZERO (&ws);
+      FD_ZERO (&es);
+      if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
+       {
+         MHD_stop_daemon (d);
+         return 4096;
+       }
+      tret = MHD_get_timeout (d, &tt);
+      if (MHD_YES != tret) tt = 1;
+      tv.tv_sec = tt / 1000;
+      tv.tv_usec = 1000 * (tt % 1000);
+      select (max + 1, &rs, &ws, &es, &tv);
+      MHD_run (d);
+    }
+  stop ("external select");
+  MHD_stop_daemon (d);
+  return 0;
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+  unsigned int errorCount = 0;
+
+  oneone = NULL != strstr (argv[0], "11");
+  if (0 != curl_global_init (CURL_GLOBAL_WIN32))
+    return 2;
+  response = MHD_create_response_from_buffer (strlen ("/hello_world"),
+                                             "/hello_world",
+                                             MHD_RESPMEM_MUST_COPY);
+  errorCount += testInternalGet (0);
+  errorCount += testMultithreadedGet (0);
+  errorCount += testMultithreadedPoolGet (0);
+  errorCount += testExternalGet ();
+  errorCount += testInternalGet (MHD_USE_POLL);
+  errorCount += testMultithreadedGet (MHD_USE_POLL);
+  errorCount += testMultithreadedPoolGet (MHD_USE_POLL);
+  MHD_destroy_response (response);
+  if (errorCount != 0)
+    fprintf (stderr, "Error (code: %u)\n", errorCount);
+  curl_global_cleanup ();
+  return errorCount != 0;       /* 0 == pass */
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]