/*****************************************************************************/ #ifdef COMMENTS_WITH_COMMENTS /* MemBufDemo.c This script is intended to demonstrate the use of the MemBufLib..() functions, as well as allowing a direct comparison of the throughputs of the mailbox (default) and memory-buffer IPCs for script output. Testing indicates transfer bandwidth in excess of 2x of the standard mailbox IPC, along with notable improvements in resource utilisation. YMMV with platform, O/S version and TCP/IP stack (i.e. as the relative bottlenecks shuffle about). The memory-buffer IPC is intended for bulk data transfer from a script to the server and then on to the client. In this case, "bulk" means megabytes, tens of megabytes, hundreds of megabytes, and so forth. For kilobytes, tens, hundreds of kilobytes the mailbox IPC is suitable for most applications. To compare the throughputs of the actual IPC, it is best to eliminate as much storage access as possible (often the slowest element in a VMS system). This script ganerates a block of data comprising a repeating byte value. The value is incremented with each block and ranges from 0x00 thru to 0xff before repeating. The memset() used to populate the block is very efficient. It is recommended to use a command-line tool such as cURL or wget with output directed to the NL: device. Output can also be directed to storage for the purposes of comparing the content of both IPCs while building confidence in the memory-buffer IPC. Adding "-v" to cURL or "--server-response" to wget to observe the response header. The behaviour of the script is controlled by keys in the query string. ?+[b|m]++ No query string the default behaviour is a 10MB transfer via mailbox IPC. $ curl -o nl: http://the.host/cgi-bin/membufdemo $ wget "-O" NL: http://the.host/cgi-bin/membufdemo The first key can be an integer number of *megabytes* to transfer. For 5MB and 100MB respectively: $ curl -o nl: http://the.host/cgi-bin/membufdemo?5 $ curl -o nl: http://the.host/cgi-bin/membufdemo?100 The second key is a character indicating the IPC; 'm' for mailbox (default) and 'b' for (memory-)buffer. The first and third examples are mailbox and the second and fourth memory-buffer. $ curl -o nl: http://the.host/cgi-bin/membufdemo?5 $ curl -o nl: http://the.host/cgi-bin/membufdemo?5+b $ curl -o nl: http://the.host/cgi-bin/membufdemo?250+m $ curl -o nl: http://the.host/cgi-bin/membufdemo?250+b The third key is an integer number of bytes for the record size. This is the mailbox maximum record size (MRS) in kilobytes, and so is limited to the WASD configuration for script SYS$OUTPUT size. With memory-buffer it can be specified as any size up to size of the memory-buffer itself. The default is the mailbox MRS size. The first example specifies a MRS of 32kB and the second 256kB. $ curl -o nl: http://the.host/cgi-bin/membufdemo?100+m+32 $ curl -o nl: http://the.host/cgi-bin/membufdemo?100+b+256 The fourth key is an integer number of megabytes for the memory-buffer. The default is 1MB. Any value may be provided here with the server memory-buffer manager either providing that size of an error report back in the callout. The first examples request a 2MB memory-buffer and the second 5MB. $ curl -o nl: http://the.host/cgi-bin/membufdemo?100+b+256+2 $ curl -o nl: http://the.host/cgi-bin/membufdemo?100+b+128+5 To compare the data provided by both environments direct output to files and use the difference UTILITY. $ curl -o []TEST.DAT http://the.host/cgi-bin/membufdemo?50 $ curl -o []TEST.DAT http://the.host/cgi-bin/membufdemo?50+b $ diff TEST.DAT WATCH may be used to observe the behaviour and data, etc., but beware with such large datasets many browsers cannot cope with the copious report output, particularly with [x]network-octets item, and in the case of mailbox IPC, with the [x]DCL item. YMMV. COMPARISON ---------- Actual data generated by this utility comparing standard mailbox IPC with memory-buffer on a x86-64 VirtualBox hosted system across a 1Gbps LAN with cURL at the command-line on a 6 CPU 32GB macOS 15.1. From the WASD Server Statistics / Environment report: innotek GmbH VirtualBox "Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz" with 3 CPUs and 7GB running VMS V9.2-2 X86VMS$ @kits:vups innotek GmbH VirtualBox with 3 CPU and 7936MB running VMS V9.2-2 Approximate System VUPs Rating : 651.8 ( min: 648.6 max: 653.4 ) Apache (2.4.62) comparison uses port 7780 and a DCL wrapper procedure with the WASD script executable. X86VMS$ type APACHE$COMMON:[CGI-BIN]membufdemo.com $ apache$dcl_env $ membufdemo == "$apache$root:[cgi-bin]membufdemo.exe" $ membufdemo YMMV: in absolute terms but the relative performance should remain. Note: the cURL download speeds are MEGA-BYTES-per-second. Cleartext (port 80) so no TLS overhead. % curl -o /dev/null "http://x86vms.lan/cgi-bin/membufdemo?1000" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1000M 100 1000M 0 0 45.5M 0 0:00:21 0:00:21 --:--:-- 43.6M ^^^^^ Cleartext (again no TLS overhead) using memory-buffer. % curl -o /dev/null "http://x86vms.lan/cgi-bin/membufdemo?1000+b" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1000M 100 1000M 0 0 76.0M 0 0:00:13 0:00:13 --:--:-- 74.0M ^^^^^ With (cgi-bin) TLS secured connection. % curl -o /dev/null "https://x86vms.lan/cgi-bin/membufdemo?1000" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1000M 100 1000M 0 0 27.3M 0 0:00:36 0:00:36 --:--:-- 26.9M ^^^^^ Cleartext (again no TLS overhead) with VMS Apache. % curl -o /dev/null "http://x86vms.lan:7780/cgi-bin/membufdemo?1000" Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 1000M 0 1000M 0 0 17.2M 0 --:--:-- 0:00:58 --:--:-- 18.1M ^^^^^ TLS with (cgi-bin) VMS Apache: % curl -k -o /dev/null "https://x86vms.lan:7443/cgi-bin/membufdemo?1000" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1000M 0 1000M 0 0 14.0M 0 --:--:-- 0:01:11 --:--:-- 13.9M ^^^^^ With (module) VMS Apache: % curl -o /dev/null "http://x86vms.lan:7780/membufdemo?1000" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1000M 0 1000M 0 0 27.2M 0 --:--:-- 0:00:36 --:--:-- 27.9M ^^^^^ With (module) TLS VMS Apache: % curl -o /dev/null "https://x86vms.lan:4443/membufdemo?1000" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1000M 0 1000M 0 0 17.4M 0 --:--:-- 0:00:57 --:--:-- 19.0M ^^^^^ By way of comparison, the WASD /stream function shows the maximim bandwidth attainable over the LAN. % curl -o /dev/null "http://x86vms.lan/stream/text:1g" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1024M 100 1024M 0 0 82.8M 0 0:00:12 0:00:12 --:--:-- 86.9M ^^^^^ Eliminating the actual physical LAN by having cURL on the same x86 system shows the further potential moving data on 10Gbps and greater bandwidth. X86VMS$ curl -o NL: "http://x86vms.lan/cgi-bin/membufdemo?1000" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1000M 100 1000M 0 0 38.7M 0 0:00:25 0:00:25 --:--:-- 25.6M ^^^^^ X86VMS$ curl -o NL: "http://x86vms.lan/cgi-bin/membufdemo?1000+b" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1000M 100 1000M 0 0 137M 0 0:00:07 0:00:07 --:--:-- 135M ^^^^ With cURL running on the same system as Apache: X86VMS$ curl -o NL: "http://x86vms.lan:7780/cgi-bin/membufdemo?1000" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1000M 100 1000M 0 0 80.5M 0 0:00:12 0:00:12 --:--:-- 79.8M ^^^^^ X86VMS$ curl -o NL: "http://x86vms.lan:7780/membufdemo?1000" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1000M 0 1000M 0 0 62.8M 0 --:--:-- 0:00:15 --:--:-- 60.5M ^^^^^ Again, the WASD /stream function shows the maximim bandwidth attainable. X86VMS$ curl -o NL: "http://x86vms.lan/stream/test:1g" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 1024M 100 1024M 0 0 144M 0 0:00:07 0:00:07 --:--:-- 142M ^^^^ It is obvious that memory-buffer provides significantly greater throughput than mailbox (from the http:// test) and that with TLS network transport the encryption becomes a significant overhead and choke-point. POSTSCRIPT: The comparison also illustrates that the WASD environment can deliver significant bandwidth through its script->server->network pathways. On the demonstration class of system; ~40MBps with the default mailbox IPC and ~82MBps using the memory-buffer IPC, approximately 80% available LAN bandwidth. The WASD bandwidth is more than competitive with VMS Apache at ~18MBps, even when using vanilla mailbox IPC, but particularly when using the memory buffer. LOGICAL NAMES ------------- None. BUILD DETAILS ------------- See BUILD_MEMBUFDEMO.COM procedure. COPYRIGHT --------- Copyright (C) 2017-2024 Mark G.Daniel Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. VERSION HISTORY --------------- 27-OCT-2024 MGD v1.1.0, tweaks (and adapt for comparison with Apache) 12-OCT-2017 MGD initial */ #endif /* COMMENTS_WITH_COMMENTS */ /*****************************************************************************/ #define SOFTWAREVN "1.1.0" #define SOFTWARENM "MEMBUFDEMO" #ifdef __ALPHA char SoftwareID [] = SOFTWARENM " AXP-" SOFTWAREVN; #endif #ifdef __ia64 char SoftwareID [] = SOFTWARENM " IA64-" SOFTWAREVN; #endif #ifdef __x86_64 char SoftwareID [] = SOFTWARENM " X86-" SOFTWAREVN; #endif #include #include #include #include #include #include "membuflib.h" void MemBufDemoAbort (int); /*****************************************************************************/ #ifndef APACHE_MOD main (int argc, char* argv[]) { int bcnt, cnt, gwmrs, gsize, mbfs, mrs, retval, status, total; char *bptr, *cptr, *gname, *mbptr, *qsptr, *sptr; /*********/ /* begin */ /*********/ if (argc > 1) if (!strcasecmp (argv[1], "/version")) { printf ("%%%s-I-VERSION, %s (%s)\n", SOFTWARENM, SoftwareID, MemBufLibVersion()); exit (1); } gsize = gwmrs = mrs = mbfs = total = 0; gname = mbptr = NULL; /* WASD variable providing mailbox capacity */ if (!(cptr = getenv("WWW_GATEWAY_MRS"))) if (!(cptr = getenv("GATEWAY_MRS"))) cptr = "0"; if (isdigit(*cptr)) gwmrs = mrs = atoi(cptr); if (!(qsptr = getenv ("WWW_QUERY_STRING"))) if (!(qsptr = getenv ("QUERY_STRING"))) qsptr = "0"; /* first is the total transfer in megabytes */ cptr = qsptr; if (isdigit(*cptr)) total = atoi(cptr); if (total <= 0) total = 100; total *= (1024 * 1024); /* second is using 'm' mailbox (default) or memory-'b'uffer */ while (*cptr && *cptr != '+') cptr++; if (*cptr) cptr++; if (*cptr == 'b') mbptr = ""; /* third is size of MRS in bytes */ while (*cptr && *cptr != '+') cptr++; if (*cptr) cptr++; if (isdigit(*cptr)) mrs = atoi(cptr); if (!mbptr && gwmrs && mrs > gwmrs) mrs = gwmrs; else if (mrs <= 0) mrs = 8192; if (!(bptr = malloc(mrs))) exit (vaxc$errno); /* fourth is memory-buffer size is in *megabytes* */ while (*cptr && *cptr != '+') cptr++; if (*cptr) cptr++; mbfs = 0; if (isdigit(*cptr)) mbfs = atoi(cptr); if (mbptr) { if (!(cptr = getenv("WWW_SERVER_SOFTWARE"))) if (!(cptr = getenv("SERVER_SOFTWARE"))) cptr = ""; if (strstr (cptr, "Apache")) MemBufDemoAbort (44); /* using memory buffer */ status = MemBufLibBegin (mbfs, &gname, NULL, &gsize); if (!(status & 1)) MemBufDemoAbort (status); } /*******************/ /* response header */ /*******************/ if (!(stdout = freopen ("SYS$OUTPUT", "w", stdout, "ctx=bin"))) exit (vaxc$errno); fprintf (stdout, "Status: 200\r\n\ Content-Type: application/octet-stream\r\n\ Content-Length: %d\r\n\ Content-Encoding: none\r\n\ X-query: %s\n\ X-mrs: %d\r\n\ X-mbuf: %s %u\r\n\ \r\n", total, qsptr, mrs, gname ? gname : "NULL", gsize); fflush (stdout); /**************/ /* write data */ /**************/ cnt = 0; for (cptr = bptr; cptr < bptr + mrs; cptr++) *cptr = cnt++ & 0xff; bcnt = 0; while (bcnt < total) { if (((cnt = mrs) + bcnt) > total) cnt = total - bcnt; if (mbptr) retval = MemBufLibWrite (bptr, cnt); else retval = fwrite (bptr, cnt, 1, stdout); if (!retval) exit (44); bcnt += cnt; } /************/ /* finalise */ /************/ if (mbptr) MemBufLibEnd (); } /*****************************************************************************/ void MemBufDemoAbort (int status) { /*********/ /* begin */ /*********/ fprintf (stdout, "Status: 500\r\n\ Content-Type: text/plain\r\n\ \r\n\ Status: %%X%08.08X\n", status); exit (status); } #endif #ifdef APACHE_MOD /*****************************************************************************/ /* MOD_MEMBUFDEMO.C - VMS Apache membufdemo module $ copy WASD_EXE:MOD_MEMBUFDEMO.EXE APACHE$COMMON:[MODULES] Activate it in Apache's httpd.conf file: # httpd.conf LoadModule membufdemo_module modules/mod_membufdemo.exe SetHandler membufdemo Restart Apache using: $ apachectl restart Monkey see - monkey do. Speaks volumes of my Apache sophistication. Developed for VSI X86VMS APACHEWS 2.4.62. */ /*****************************************************************************/ #include "httpd.h" #include "http_config.h" #include "http_protocol.h" #include "ap_config.h" static void membufdemo_out (request_rec *req, int total, int mrs) { int cnt; char *bptr, *cptr; if (!(bptr = malloc(mrs))) exit (vaxc$errno); cnt = 0; for (cptr = bptr; cptr < bptr + mrs; cptr++) *cptr = cnt++ & 0xff; ap_set_content_type (req, "application/binary"); ap_rprintf (req, "total:%d mrs:%d\n", total, mrs); while (total > 0) { ap_rwrite (bptr, mrs, req); if (req->connection->aborted) break; total -= mrs; } } static int membufdemo_handler (request_rec *req) { int mrs, total; char *cptr; if (!req->the_request || !strstr (req->the_request, "membufdemo")) return DECLINED; mrs = total = -1; if (req->the_request) { if (!strstr (req->the_request, "membufdemo")) return DECLINED; if (cptr = strchr (req->the_request, '?')) { /* using the equivalent syntax to WASD MemBufDemo() */ if (*cptr) cptr++; if (isdigit(*cptr)) total = atoi(cptr); while (*cptr && isdigit(*cptr) && !isspace(*cptr)) cptr++; /* skip over any intervening chars */ while (*cptr && !isdigit(*cptr) && !isspace(*cptr)) cptr++; if (isdigit(*cptr)) mrs = atoi(cptr); } } if (total <= 0 || total > 1000000) total = 1000; total *= (1024 * 1024); if (mrs <= 0 || mrs >= 65000) mrs = 8000; membufdemo_out (req, total, mrs); return OK; } static void membufdemo_register_hooks (apr_pool_t *pool) { fprintf (stdout, "\n ** membufdemo_register_hooks **\n\n"); ap_hook_handler (membufdemo_handler, NULL, NULL, APR_HOOK_LAST); } /* dispatch list for API hooks */ module AP_MODULE_DECLARE_DATA membufdemo_module = { STANDARD20_MODULE_STUFF, NULL, /* create per-dir config structures */ NULL, /* merge per-dir config structures */ NULL, /* create per-server config structures */ NULL, /* merge per-server config structures */ NULL, /* table of config file commands */ membufdemo_register_hooks /* register hooks */ }; #endif /*****************************************************************************/