php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #18367 Echoing long strings unexpectedly slow
Submitted: 2002-07-16 09:27 UTC Modified: 2002-09-22 19:09 UTC
Votes:3
Avg. Score:4.0 ± 0.0
Reproduced:2 of 2 (100.0%)
Same Version:1 (50.0%)
Same OS:0 (0.0%)
From: van dot binsbergen at taktik dot ch Assigned:
Status: Not a bug Package: Performance problem
PHP Version: 4.2.1 OS: All
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: van dot binsbergen at taktik dot ch
New email:
PHP Version: OS:

 

 [2002-07-16 09:27 UTC] van dot binsbergen at taktik dot ch
This is a follow-up to http://bugs.php.net/bug.php?id=18029 
(I can't reach the author of this bug, so I will do it this 
way). 18029 is in status "bogus", but I don't think this is 
correct. In my opinion it is buggy behaviour of either PHP 
or apache or both in combination. Please read the following 
to see why I think this can and has to be changed. 

What I noticed on my system:
Redhat Linux 7.2 (Kernel 2.4.7-10)
Apache/1.3.26 (Unix) PHP/4.2.1 mod_ssl/2.8.10 OpenSSL/
0.9.6b
resp. Apache/1.3.26 (Unix) PHP/4.2.0 mod_ssl/2.8.10 
OpenSSL/0.9.6b

Outputting a string of x characters length takes 2 
milliseconds.
Outputting a string of x+1 characters length takes 340 
milliseconds.

x is a number between 12000 and 15000.

It does not matter whether I use echo, print, print_r or 
whatever to output the string.

When I split the string in smaller parts and output the 
results separately, everything is normal.

The timeout occurs if my browser is remote (ping-time about 
200ms). This happens NOT, if my browser is in a LAN or 
local with the server, i.e. very close. The hint to TCP/IP 
window size (Nagle Algorithm) given by Ron Kuris to Shawn 
(owner of bug 18029) matches with this and the above 
observations. Execution of the Script does not continue 
before the ACK from the client for the first packet is 
received. This means that in scripts working with long 
strings the execution time of the script depends on the 
ping-time between the server and the client, and the 
duration of the idle time goes up together with the length 
of the string, i.e. a roundtrip is made for each multiple 
of the window size.

I have positive reports of this from four systems, amongst 
them PHP 4.2.0 und 4.2.1; Apache 1.3.23, 1.3.24 and 1.3.26; 
OS Redhat, Cobalt and Windows 2000. I have 5 negative 
reports, but maybe all false negative because they were 
tested locally.

Below is a test php script that can be used to verify this. 
There is also an equivalent perl script. I used it on the 
same host as a CGI-Script and found everything works fine 
there.

I might be wrong of course, but I think this thing has to 
be treated as a bug because
1) it should be avoided 
2) it can be avoided

Please let me tell you why:
1) 
- There is growing number of modern PHP applications 
depending on the possibility of flawlessly outputting large 
strings. PEAR Cache for instance is affected, but template 
processors and XML/XSL applications as well. Of course 
these applications could all care themselves about 
splitting their output in smaller chunks, but this is very 
inefficient.
- Although there is no additional CPU load, the number of 
running httpd-processes is kept high - for nothing. I don't 
know whether this is actually bad, but it sure is not very 
cool.
- Clients have a bad response time although the server and 
network performance is good. 

2)
- The fact that a Perl CGI script (see below) can do the 
same thing without any problems shows imo that it is 
possible in some way to avoid these roundtrips! I have to 
admit that I have no idea of the apache/php interna, but I 
would be very glad if someone of the experts had a look at 
this.

Thank you in advance!

Urs

<?php
/**
Long string performance behaviour test
*/

// ------ small Benchmark suite (as in in perl's Benchmark) 
---------
class Benchmark {
    var $time = 0;
    function Benchmark() {
       $mt = microtime();
       $a = explode(" ",$mt);
       $t = $a[0] + $a[1];
       $this->time = round(1000 * $t);
    }
}

function timestr($ms) {
    return sprintf("%01.2f", $ms/1000) . " seconds";
}

function timediff($b1, $b2) {
    $ms = ($b1->time - $b2->time);
    return $ms;
}

// ------ test procedure ---------

// prepare
($len = $_GET[l]) || ($len = 12905);
$loop = floor($len / 5);
$rest = $len % 5;
$rlen = 5 * $loop;
$str = "";

$t0 = new Benchmark;

// generate the long string
for($i=0; $i<=$loop; $i++) {
       $str = $str . "1234";
       $str .= "\n";
}
$str .= str_repeat(".",$rest);

// report
$t1 = new Benchmark;
$report .=  "<h1>Long string performance behaviour test</
h1>";
$report = "\n<br>\n<br>Generated a string with $len 
characters"
        . " (use ?l=12345 in the URI to override)";
$report .=  "\n<br>(took me " . timestr(timediff($t1, $t0)) 
. ")";

// print the long string
print $str;

// report again
$t2 = new Benchmark;
$report .= "\n<br>Time to output string: 
".timestr(timediff($t2, $t1));
print $report;
?>





test.pl:

#! /usr/bin/perl

use CGI qw(:standard);
use Benchmark;

print header();

# prepare
($len = param("l")) || ($len = 50000);
$loop = int($len / 5);
$rest = $len % 5;
$rlen = 5 * $loop;
$str = "";

$t0 = new Benchmark;

# generate the long string
for($i=0; $i<=$loop; $i++)
{
    $str = $str . "1234 ";
}

# report
$t1 = new Benchmark;
$report .=  "<h1>Long string performance behaviour test</
h1>";
$report = "\n<br>\n<br>Generated a string with $len 
characters"
        . " (use ?l=12345 in the URI to override)";
$report .=  "\n<br>(took me " . timestr(timediff($t1, $t0)) 
. ")";

# print the long string
print $str;

# report again
$t2 = new Benchmark;
$report .= "\n<br>Time to output string: 
".timestr(timediff($t2, $t1));
print $report;


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2002-08-15 09:10 UTC] van dot binsbergen at taktik dot ch
Hi team!
Was there any progress regarding this thing? Please tell me 
if you need more info. Thank you for your attention.
Urs
 [2002-09-22 16:35 UTC] iliaa@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

I've tried the suggested test and did not see any significant slowdown you've mentioned. Infact the benchmarks came about the same. There is one thing however, that may have skewed the benchmark towards Perl in your initial code. In Perl you seperate the text with a space, while in PHP you use a new line.
 [2002-09-22 17:56 UTC] van dot binsbergen at taktik dot ch
> I've tried the suggested test and did not see any
> significant slowdown you've mentioned. 
Did you really test with a server which which is in a 
significant distance to your client machine? 
And if so, which PHP and Apache Version did you use?

I mean, I didn't invent this story, you know. Neither did 
the other users who faced this thing. I was just trying to 
track down the reason. Although I do not understand much of 
the interna it seems very likely to me that the reason sits 
in php OR in apache OR in the playing together of both.

> There is one thing however, that may have skewed the 
> benchmark towards Perl in your initial code. In Perl 
> you seperate the text with a space, while in
> PHP you use a new line.
Sorry for this negligence, I tested in fact both variants 
in both systems and it wasn't any difference.

PS: I do not understand your hint to the manual. If the 
manual says something about this, can you please point me 
to the exact location?
 [2002-09-22 18:50 UTC] iliaa@php.net
I've used Apache 1.3.26 and today's CVS of php. This test was done across local network, which is very important for this test, because your bechmark also includes network latency in it's test. Meaning that if you do this test over a slow connection the timings would reflect that fact.
Because the 2nd timing won't be taken until the printed data is recieved by the browser on the other end.
I've also done more accurate tests using php-cli on the console where there is network overhead.

My benchmark resulted in the following timings for printing
250000 byte long string 10000 times.
PHP - 0.824s
Perl - 1m2.245s

Ignore the manual comment, that is automatically added by the bug tracking system.
 [2002-09-22 19:09 UTC] van dot binsbergen at taktik dot ch
Hi!
Thanks for your reply and taking your time!
> because your bechmark also includes network latency in 
> it's test. Meaning that if you do this test over a slow 
> connection the timings would reflect that fact.
> Because the 2nd timing won't be taken until the printed 
> data is recieved by the browser on the other end.
This is just what I do not understand! Why should the 
engine wait for the browser's acknowledgment? Isn't this a 
matter for the webserver buffer or whatever? And why does 
perl the other way? And why does the same thing not happen 
if I output the same string in small portions instead of as 
a whole?
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Mar 28 15:01:29 2024 UTC