2017-06-17 00:43:15 +02:00
|
|
|
--TEST--
|
|
|
|
Memory Leakage Test
|
|
|
|
--DESCRIPTION--
|
|
|
|
Checks for memory leaks using memory_get_usage(). memory_get_usage() only tracks the memory that is allocated using
|
|
|
|
emalloc (which only allocate memory in the memory space allocated for the PHP process).
|
|
|
|
--ENV--
|
|
|
|
PHPT_EXEC=true
|
|
|
|
--SKIPIF--
|
2019-01-08 00:36:59 +01:00
|
|
|
<?php require('skipif_azure_dw.inc'); ?>
|
2017-06-17 00:43:15 +02:00
|
|
|
--FILE--
|
|
|
|
<?php
|
|
|
|
include 'MsCommon.inc';
|
|
|
|
|
2019-08-20 21:38:09 +02:00
|
|
|
const _NUM_PASSES = 20;
|
|
|
|
const _NUM_ROWS1 = 10;
|
|
|
|
const _NUM_ROWS2 = 15;
|
|
|
|
|
2017-06-17 00:43:15 +02:00
|
|
|
function MemCheck($noPasses, $noRows1, $noRows2, $startStep, $endStep, $leakThreshold)
|
|
|
|
{
|
|
|
|
include 'MsSetup.inc';
|
|
|
|
|
|
|
|
$testName = "Memory Leakage Check";
|
|
|
|
|
|
|
|
StartTest($testName);
|
|
|
|
|
|
|
|
Setup();
|
|
|
|
|
|
|
|
Trace("Execution setup: $noPasses passes over a table with $noRows1 => ".($noRows1 + $noRows2)." rows.\n");
|
|
|
|
$conn1 = Connect();
|
|
|
|
|
|
|
|
CreateTable($conn1, $tableName);
|
|
|
|
$noRowsInserted = InsertRows($conn1, $tableName, $noRows1);
|
|
|
|
|
|
|
|
// Calibration
|
|
|
|
$phpLeak = RunTest($noPasses, 0, $tableName, $conn1, false, 0);
|
|
|
|
Trace("\n0. Calibration\t - PHP memory leak: $phpLeak bytes\n");
|
|
|
|
|
|
|
|
// Preliminary Execution
|
|
|
|
Trace("\nPreliminary Execution:\n");
|
|
|
|
$drvLeak = 0;
|
|
|
|
for ($j = 0; $j < 2; $j++)
|
|
|
|
{
|
|
|
|
$leak = ExecTest(1, $noRows1, $startStep, $endStep, $tableName, $conn1, (($j % 2) != 0), $phpLeak);
|
|
|
|
if ($leak > $drvLeak)
|
|
|
|
{
|
|
|
|
$drvLeak = $leak;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$totalLeak = 0;
|
|
|
|
|
|
|
|
// Execution
|
|
|
|
$noRows = $noRows1;
|
|
|
|
$prepared = false;
|
|
|
|
Trace("\nActual Execution:\n");
|
|
|
|
for ($j = 0; $j < 4; $j++)
|
|
|
|
{
|
|
|
|
switch ($j)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
$prepared = false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
$prepared = false;
|
|
|
|
InsertRows($conn1, $tableName, $noRows2);
|
|
|
|
$noRows += $noRows2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
$prepared = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
$prepared = true;
|
|
|
|
InsertRows($conn1, $tableName, $noRows2);
|
|
|
|
$noRows += $noRows2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
$leak = ExecTest($noPasses, $noRows, $startStep, $endStep, $tableName, $conn1, $prepared, $phpLeak) - $drvLeak;
|
|
|
|
if ($leak > $totalLeak)
|
|
|
|
{
|
|
|
|
$totalLeak = $leak;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$conn1 = null;
|
|
|
|
|
|
|
|
$conn2 = Connect();
|
|
|
|
DropTable($conn2, $tableName);
|
|
|
|
$conn2 = null;
|
|
|
|
|
|
|
|
if ($totalLeak > 0)
|
|
|
|
{
|
|
|
|
$expectedLeak = min($drvLeak, $leakThreshold) * $noPasses;
|
|
|
|
Trace("Driver memory leak: $totalLeak bytes (max expected: $expectedLeak)\n");
|
|
|
|
if ($totalLeak > $expectedLeak)
|
|
|
|
{
|
|
|
|
die("Memory leaks detected: $totalLeak bytes\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EndTest($testName);
|
|
|
|
}
|
|
|
|
|
|
|
|
function ExecTest($noPasses, $noRows, $startStep, $endStep, $tableName, $conn, $prepared, $phpLeak)
|
|
|
|
{
|
|
|
|
$leak = 0;
|
|
|
|
|
|
|
|
// Execution
|
|
|
|
if ($prepared)
|
|
|
|
{
|
|
|
|
Trace("\nPrepared Query Mode\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Trace("\nDirect Query Mode\n");
|
|
|
|
}
|
|
|
|
for ($i = $startStep; $i <= $endStep; $i++)
|
|
|
|
{
|
|
|
|
switch ($i)
|
|
|
|
{
|
|
|
|
case 0: // Calibration
|
|
|
|
Trace("$i. Calibration\t - ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: // connection only
|
|
|
|
Trace("$i. Connection\t - ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2: // query
|
|
|
|
Trace("$i. Query\t - ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: // fetch
|
|
|
|
Trace("$i. Fetch\t - ");
|
|
|
|
break;
|
|
|
|
|
2019-08-20 21:38:09 +02:00
|
|
|
case 4: // fetchAll
|
|
|
|
Trace("$i. FetchAll\t - ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5: // fetch object
|
|
|
|
trace("$i. Fetch Object\t - ");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 6: // fetch column
|
|
|
|
trace("$i. Fetch Column\t - ");
|
|
|
|
break;
|
|
|
|
|
2017-06-17 00:43:15 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
$memLeak = RunTest($noPasses, $noRows, $tableName, $conn, $prepared, $i) - $phpLeak;
|
|
|
|
Trace("Driver memory leak: $memLeak bytes\n");
|
|
|
|
if ($memLeak > $leak)
|
|
|
|
{
|
|
|
|
$leak = $memLeak;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ($leak);
|
|
|
|
}
|
|
|
|
|
|
|
|
function RunTest($noPasses, $noRows, $tableName, $conn, $prepared, $mode)
|
|
|
|
{
|
|
|
|
$leak = 0;
|
|
|
|
for ($k = 1; $k <= $noPasses; $k++)
|
|
|
|
{
|
|
|
|
$tsql = "SELECT * FROM [$tableName]";
|
|
|
|
$memStart = 0;
|
|
|
|
$memEnd = 0;
|
|
|
|
$conn2 = null;
|
|
|
|
$stmt = null;
|
|
|
|
$row = null;
|
|
|
|
$rowCount = 0;
|
|
|
|
$fldCount = 0;
|
|
|
|
|
|
|
|
$memStart = memory_get_usage();
|
|
|
|
switch ($mode)
|
|
|
|
{
|
|
|
|
case 0: // calibration
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: // connection
|
|
|
|
$conn2 = GetConnection();
|
|
|
|
unset($conn2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2: // query
|
|
|
|
$stmt = ExecuteQueryEx($conn, $tsql, ($prepared ? false : true));
|
|
|
|
$fldCount = $stmt->columnCount();
|
|
|
|
$stmt->closeCursor();
|
|
|
|
unset($stmt);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3: // fetch
|
|
|
|
$stmt = ExecuteQueryEx($conn, $tsql, ($prepared ? false : true));
|
|
|
|
$fldCount = $stmt->columnCount();
|
|
|
|
while ($row = $stmt->fetch())
|
|
|
|
{
|
|
|
|
unset($row);
|
|
|
|
$rowCount++;
|
|
|
|
}
|
|
|
|
$stmt->closeCursor();
|
|
|
|
unset($stmt);
|
|
|
|
if ($rowCount != $noRows)
|
|
|
|
{
|
|
|
|
die("$rowCount rows retrieved instead of $noRows\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2019-08-20 21:38:09 +02:00
|
|
|
case 4: // fetchAll
|
|
|
|
$stmt = ExecuteQueryEx($conn, $tsql, ($prepared ? false : true));
|
|
|
|
$fldCount = $stmt->columnCount();
|
|
|
|
$result = $stmt->fetchAll();
|
|
|
|
$rowCount = count($result);
|
|
|
|
unset($result);
|
|
|
|
$stmt->closeCursor();
|
|
|
|
unset($stmt);
|
|
|
|
if ($rowCount != $noRows) {
|
|
|
|
die("$rowCount rows retrieved instead of $noRows\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5: // fetchObject
|
|
|
|
$stmt = ExecuteQueryEx($conn, $tsql, ($prepared ? false : true));
|
|
|
|
$fldCount = $stmt->columnCount();
|
|
|
|
while ($obj = $stmt->fetchObject()) {
|
|
|
|
unset($obj);
|
|
|
|
$rowCount++;
|
|
|
|
}
|
|
|
|
$stmt->closeCursor();
|
|
|
|
unset($stmt);
|
|
|
|
if ($rowCount != $noRows) {
|
|
|
|
die("$rowCount rows retrieved instead of $noRows\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 6: // fetchColumn
|
|
|
|
$stmt = ExecuteQueryEx($conn, $tsql, ($prepared ? false : true));
|
|
|
|
$fldCount = $stmt->columnCount();
|
|
|
|
// Check for "false" to terminate because fetchColumn may return NULL
|
|
|
|
while (($result = $stmt->fetchColumn()) !== false) {
|
|
|
|
unset($result);
|
|
|
|
$rowCount++;
|
|
|
|
}
|
|
|
|
$stmt->closeCursor();
|
|
|
|
unset($stmt);
|
|
|
|
if ($rowCount != $noRows) {
|
|
|
|
die("$rowCount rows retrieved instead of $noRows\n");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2017-06-17 00:43:15 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
$memEnd = memory_get_usage();
|
|
|
|
if ($memEnd > $memStart)
|
|
|
|
{
|
|
|
|
$leak += ($memEnd - $memStart);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return ($leak);
|
|
|
|
}
|
|
|
|
|
|
|
|
function GetConnection()
|
|
|
|
{
|
|
|
|
include 'MsSetup.inc';
|
2017-06-17 01:51:04 +02:00
|
|
|
$conn = PDOConnect('PDO', $server, $uid, $pwd, true);
|
2017-06-17 00:43:15 +02:00
|
|
|
return ($conn);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
// Repro
|
|
|
|
//
|
|
|
|
//--------------------------------------------------------------------
|
|
|
|
function Repro()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2019-08-20 21:38:09 +02:00
|
|
|
MemCheck(_NUM_PASSES, _NUM_ROWS1, _NUM_ROWS2, 1, 6, 0);
|
2017-06-17 00:43:15 +02:00
|
|
|
}
|
|
|
|
catch (Exception $e)
|
|
|
|
{
|
|
|
|
echo $e->getMessage();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Repro();
|
|
|
|
|
|
|
|
?>
|
|
|
|
--EXPECT--
|
|
|
|
Test "Memory Leakage Check" completed successfully.
|