PHP输出缓冲区基准测试(微时间与usleep一起使用时不准确?)

时间:2011-04-20 13:21:08

标签: php buffer microtime usleep

我发布了一个可以重现的奇怪行为(至少在apache2 + php5上)。 我不知道我做错了,但让我解释一下我想要实现的目标。

我需要发送大块的二进制数据(比方说30)并分析最后的平均Kbit / s:

我将每个块输出时间,每个块大小相加,并在最后执行我的Kbit / s计算。

    <?php

// build my binary chunk
$var= '';
$o=10000;
while($o--)
{
    $var.= pack('N', 85985);
}

// get the size, prepare the memory.
$size = strlen($var);
$tt_sent = 0;
$tt_time = 0;

// I send my chunk 30 times
for ($i = 0; $i < 30; $i++)
{
    // start time
    $t = microtime(true);
    echo $var."\n";
    ob_flush();
    flush();
    $e = microtime(true);
    // end time
    // the difference should reprenent what it takes to the server to 
    // transmit chunk to client right ?

    // add this chuck bench to the total
    $tt_time += round($e-$t,4);
    $tt_sent += $size;
}

// total result
echo "\n total: ".(($tt_sent*8)/($tt_time)/1024)."\n";

?>

在上面这个例子中,它到目前为止工作(在localhost上,它通过不同的测试从​​7000到10000 Kbit / s振荡)。

现在,让我说我想塑造传输,因为我知道客户端将有足够的数据块来处理一秒钟。

我决定使用usleep(1000000)来标记块传输之间的暂停。

    <?php

// build my binary chunk
$var= '';
$o=10000;
while($o--)
{
    $var.= pack('N', 85985);
}

// get the size, prepare the memory.
$size = strlen($var);
$tt_sent = 0;
$tt_time = 0;

// I send my chunk 30 times
for ($i = 0; $i < 30; $i++)
{
    // start time
    $t = microtime(true);
    echo $var."\n";
    ob_flush();
    flush();
    $e = microtime(true);
    // end time
    // the difference should reprenent what it takes to the server to 
    // transmit chunk to client right ?

    // add this chuck bench to the total
    $tt_time += round($e-$t,4);
    $tt_sent += $size;

    usleep(1000000);
}

// total result
echo "\n total: ".(($tt_sent*8)/($tt_time)/1024)."\n";

?>

在最后一个例子中,我不知道为什么,计算出的带宽可以从72000 Kbit / s跳到1,200,000,这是完全不准确/不相关的。 问题的一部分是,每次发送一个块时(第一次睡眠后),测量输出我的块的时间都是非常低的。

我做错了什么?缓冲区输出是否不同步?

1 个答案:

答案 0 :(得分:0)

我不确定这些测试是多么明确,但我发现它很有趣。在我的盒子上,我的平均值 170000 kb / s 。从联网的盒子中,这个数字上升到 280000 kb / s 附近。我想我们必须假设microtime(true)是相当准确的,即使我读它依赖于操作系统。你是基于Linux的系统吗?真正的问题是我们如何计算在1秒钟内转移的千比特?我尝试预测在1秒内可以发送多少块,然后存储计算出的Kb / s,以便在结束时进行平均。我在flush()之前添加了一个sleep(1),这导致了预期的负kb / s。

感觉不对,我有兴趣知道你是否改进了你的测试方法。祝你好运!

<?php
// build my binary chunk
$var= '';
$o=10000;

//Alternative to get actual bytes
$m1 = memory_get_usage();
while($o--)
{
    $var.= pack('N', 85985);
}
$m2 = memory_get_usage();

//Your size estimate
$size = strlen($var);

//Calculate alternative bytes
$bytes = ($m2 - $m1); //40108

//Convert to Kilobytes 1 Kilobyte = 1024 bytes
$kilobytes = $size/1024;

//Convert to Kilobits 1 byte = 8 bits
$kilobits = $kilobytes * 8;

//Display our data for the record
echo "<pre>size: $size</pre>";
echo "<pre>bytes: $bytes</pre>";
echo "<pre>kilobytes: $kilobytes</pre>";
echo "<pre>kilobits: $kilobits</pre>";
echo "<hr />";

//The test count
$count = 100;

//Initialize total kb/s variable
$total = 0;

for ($i = 0; $i < $count; $i++)
{
    // Start Time
    $start = microtime(true);

    // Utilize html comment to prevent browser from parsing
    echo "<!-- $var -->";

    // End Time
    $end = microtime(true);

    // Seconds it took to flush binary chunk
    $seconds = $end - $start;

    // Calculate how many chunks we can send in 1 second
    $chunks = (1/$seconds);

    // Calculate the kilobits per second
    $kbs = $chunks * $kilobits;

    // Store the kbs and we'll average all of them out of the loop
    $total += $kbs;
}

//Process the average (data generation) kilobits per second
$average = $total/$count;

echo "<h4>Average kbit/s: $average</h4>";

<强>分析

即使我在测试中得到一些任意值,它仍然是一个可以测量的值。使用联网计算机可以深入了解实际情况。我原本认为localhost机器的价值会高于联网盒子,但测试证明了其他方面。在本地主机上时,我们必须发送原始二进制数据并接收它。这当然表明两个线程正在共享cpu周期,因此当在同一台机器上的浏览器中进行测试时,假定的kb / s值实际上更低。因此,我们确实在测量cpu周期,并且当允许服务器作为服务器时,我们获得更高的值。

当您将测试计数增加到1000时,会出现一些有趣的事情。首先不要让浏览器解析数据。尝试在如此高的测试用例中呈现原始数据需要很多cpu。我们可以用系统监视器和任务管理器手动监视正在发生的事情。在我的情况下,本地是一个Linux服务器,网络框是XP。您可以通过这种方式获得一些真正的kb / s速度,并且很明显我们主要使用cpu和网络接口动态提供数据。服务器不会复制数据,因此无论我们设置测试计数有多高,我们只需要40千字节的内存空间。因此,40千字节可以在1000个测试案例中动态生成40兆字节,在10000个案例中可以生成400毫兆。

在运行测试用例10000几次后,我在xp中将firefox与虚拟内存崩溃,导致低错误。 Linux服务器上的系统监视器在cpu和网络中显示出一些可以理解的峰值,但是整体上推送了大量数据并且有足够的空间。在linux上运行10000个案例几次实际上将交换驱动器旋转并固定服务器cpu周期。最有趣的事实是,我在上面获得的值只有当我在firefox中接收并在本地测试时在apache中传输时才会改变。我几乎锁定了xp盒子,但我的网络值~280000 kb / s在打印输出时没有改变。

<强>结论:

我们在上面得到的kb / s值实际上是无用的,然后证明它没用。然而,测试本身显示了一些有趣的东西。在高测试情况下,我相信我实际上可以在服务器和客户端看到一些物理缓冲。我们的测试脚本实际上将数据转储到apache并且它被释放以继续其工作。 Apache处理转移的细节当然。这实际上很不错,但事实证明我们无法通过这种方式测量从服务器到浏览器的实际传输速率。我们可以测量我们的服务器数据生成速率,我想这是否在某种程度上有意义。你猜怎么着!冲洗实际上减慢了速度。 Theres因冲洗而受罚。在这种情况下,没有理由,删除flush()实际上加快了我们的数据生成速度。由于我们不处理网络问题,因此我们的上述价值实际上更有意义地保留为Kilobytes。它没有任何用处,所以我没有改变。