New XMLService is not what I expected.

[adrotate group=”9″]

As posted in the previous post I was setting up the Zend Server on our V6R1 system to give the new XMLSERVICE a try to see if the program calls would be faster using it rather than the old i5_toolkit API’s. Unfortunately we had to abandon the V6R1 install due to a number of problems with the install of the XMLSERVICE and the NewToolkit install. After 5 hours of installing and configuring trying to get things running we were ready to give up.

However we decided to give it a go on the V7R1 system as it did seem to compile the RPG XMLSERVICE programs etc OK. We installed the latest download of the ZendServer but did not install the update Cum package. This seems to have resolved our initial problem with the XMLSERVICE requests which ended in error when calling the Db2supp.php script? But that might be a total co-incidence.

Once we had everything installed we connected all of our old web configurations back up and started the main webserver (we have 5 virtualhosts running below the main webserver) to begin testing the setup. As far as the main PHP services went everything seemed to be running OK so we decide to set up the XMLSERVICE.

First program we compiled CRTXML worked perfectly and the XMLSERVICE programs all created correctly. However as we wanted to use the ZENDSVR install we then tried to run the CRTXML2 program, this ended with an error creating the XMLSERVICE program due to some missing definitions. A quick compare of the 2 programs showed the CRTXML2 program did not create or embed the PLUDB2 or PLUGSQL modules in the service programs. We amended the program and re-created it and then everything worked as it should.

Next we had to link the NewToolkit directory to the web server we were going to use and add the relevant configs to make sure we could use the symbolic links we created to the directory.

The XMLSERVICE is started the first time it is called according to the documentation but to be honest its a bit sparse and not easily understood when this is the first time you go to use it. I am not an expert in the product but I did get it working so it can’t be that bad. So all we had to do was create a couple of scripts to test things out.

A program is shipped in the NewToolkit library which can be compiled and used for the tests. It is called ZZCALL and is an RPG program that takes a few parameters and just adds some values to them. I am not an RPG expert as I have said all along, but the program is pretty simple which is all we needed for the test.

The next thing we needed is the scripts which will call the program and capture time information as they run.

First program calls the RPG program sending in new parameters each time.


<?php
/*
RPG program parameters definition
INCHARA S 1a
INCHARB S 1a
INDEC1 S 7p 4
INDEC2 S 12p 2
INDS1 DS
DSCHARA 1a
DSCHARB 1a
DSDEC1 7p 4
DSDEC2 12p 2
*/
include_once 'authorization.php';
include_once '../API/ToolkitService.php';
include_once 'helpshow.php';

$loop = 5000;

$start_time = microtime();
echo "New Zend Toolkit. Input value is changing on each call.<br><br>";

try {
$ToolkitServiceObj = ToolkitService::getInstance($db, $user, $pass);
}
catch (Exception $e) {
echo $e->getMessage(), "n";
exit();
}

$ToolkitServiceObj->setToolkitServiceParams(array('InternalKey'=>"/tmp/$user"));

$IOParam['var1'] = array("in"=>"Y", "out"=>"" );
$param[] = $ToolkitServiceObj->AddParameterChar('both', 1,'INCHARA', 'var1', $IOParam['var1']['in']);

$IOParam['var2'] = array( "in"=>"Z", "out"=>"" );
$param[] = $ToolkitServiceObj->AddParameterChar('both', 1,'INCHARB', 'var2', $IOParam['var2']['in']);

$IOParam['var3'] = array( "in"=>"001.0001" ,"out"=>"");
$param[] = $ToolkitServiceObj->AddParameterPackDec('both', 7, 4, 'INDEC1', 'var3', '001.0001');

$IOParam['var4'] = array( "in"=>"0000000003.04","out"=>"" );
$param[] = $ToolkitServiceObj->AddParameterPackDec('both',12,2,'INDEC2', 'var4', '0000000003.04');

$IOParam['ds1'] = array( "in"=>"A" ,"out"=>"");
$ds[] = $ToolkitServiceObj->AddParameterChar('both', 1, 'DSCHARA', 'ds1','A');

$IOParam['ds2'] = array( "in"=>"B" ,"out"=>"");
$ds[] = $ToolkitServiceObj->AddParameterChar('both', 1, 'DSCHARB', 'ds2','B');

$IOParam['ds3'] = array( "in"=>"005.0007","out"=>"" );
$ds[] = $ToolkitServiceObj->AddParameterPackDec('both',7, 4, 'DSDEC1', 'ds3', '005.0007' );

$IOParam['ds4'] = array("in"=>"0000000006.08" ,"out"=>"");
$ds[] = $ToolkitServiceObj->AddParameterPackDec('both',12, 2, 'DSDEC1', 'ds4', '0000000006.08');

//$param[] = array('ds'=>$ds);
$param[] = $ToolkitServiceObj->AddDataStruct($ds);
$param[2]->setParamValue(0);
for ($i=0;$i<$loop;$i++) {
$result = $ToolkitServiceObj->PgmCall('ZZCALL', "ZENDSVR", $param, null, null);
$param[2]->setParamValue($result['io_param']['ds3']);
} // end loop

$end_time = microtime();
$wire_time= control_microtime_used($start_time,$end_time)*1000000;
echo
sprintf("<br><strong>Time (loop=$loop) total=%1.2f sec (%1.2f ms per call)</strong><br>",
round($wire_time/1000000,2),
round(($wire_time/$loop)/1000,2));

if($result){

/*update parameters array by return values */
foreach($IOParam as $key=> &$element){
$element['out'] = $result['io_param'][$key];
}

echo "<br>";
showTableWithHeader(array("Parameter name","Input value", "Output value"), $IOParam);
}
else
echo "Execution failed.";
/* Do not use the disconnect() function for "state full" connection */
$ToolkitServiceObj->disconnect();

function control_microtime_used($before,$after) {
return (substr($after,11)-substr($before,11))+(substr($after,0,9)-substr($before,0,9));
}

?>

Running this script resulted in the following results.

New Zend Toolkit. Input value is changing on each call.

Time (loop=5000) total=26.11 sec (5.22 ms per call)

Parameter name Input value Output value
var1 Y C
var2 Z D
var3 001.0001 321.1234
var4 0000000003.04 1234567890.12
ds1 A E
ds2 B F
ds3 005.0007 333.3330
ds4 0000000006.08 4444444444.44

The next test we ran would just call the program without changing the parameters to see what effect it had.


<?php
/*
RPG program parameters definition
INCHARA S 1a
INCHARB S 1a
INDEC1 S 7p 4
INDEC2 S 12p 2
INDS1 DS
DSCHARA 1a
DSCHARB 1a
DSDEC1 7p 4
DSDEC2 12p 2
*/
include_once 'authorization.php';
include_once '../API/ToolkitService.php';
include_once 'helpshow.php';

$loop = 5000;

$start_time = microtime();
echo "New Zend Toolkit. Input values never change on each call.<br><br>";

try {
$ToolkitServiceObj = ToolkitService::getInstance($db, $user, $pass);
}
catch (Exception $e) {
echo $e->getMessage(), "n";
exit();
}

$ToolkitServiceObj->setToolkitServiceParams(array('InternalKey'=>"/tmp/$user"));

$IOParam['var1'] = array("in"=>"Y", "out"=>"" );
$param[] = $ToolkitServiceObj->AddParameterChar('both', 1,'INCHARA', 'var1', $IOParam['var1']['in']);

$IOParam['var2'] = array( "in"=>"Z", "out"=>"" );
$param[] = $ToolkitServiceObj->AddParameterChar('both', 1,'INCHARB', 'var2', $IOParam['var2']['in']);

$IOParam['var3'] = array( "in"=>"001.0001" ,"out"=>"");
$param[] = $ToolkitServiceObj->AddParameterPackDec('both', 7, 4, 'INDEC1', 'var3', '001.0001');

$IOParam['var4'] = array( "in"=>"0000000003.04","out"=>"" );
$param[] = $ToolkitServiceObj->AddParameterPackDec('both',12,2,'INDEC2', 'var4', '0000000003.04');

$IOParam['ds1'] = array( "in"=>"A" ,"out"=>"");
$ds[] = $ToolkitServiceObj->AddParameterChar('both', 1, 'DSCHARA', 'ds1','A');

$IOParam['ds2'] = array( "in"=>"B" ,"out"=>"");
$ds[] = $ToolkitServiceObj->AddParameterChar('both', 1, 'DSCHARB', 'ds2','B');

$IOParam['ds3'] = array( "in"=>"005.0007","out"=>"" );
$ds[] = $ToolkitServiceObj->AddParameterPackDec('both',7, 4, 'DSDEC1', 'ds3', '005.0007' );

$IOParam['ds4'] = array("in"=>"0000000006.08" ,"out"=>"");
$ds[] = $ToolkitServiceObj->AddParameterPackDec('both',12, 2, 'DSDEC1', 'ds4', '0000000006.08');

//$param[] = array('ds'=>$ds);
$param[] = $ToolkitServiceObj->AddDataStruct($ds);
$param[2]->setParamValue(0);
for ($i=0;$i<$loop;$i++) {
$result = $ToolkitServiceObj->PgmCall('ZZCALL', "ZENDSVR", $param, null, null);
//$param[2]->setParamValue($result['io_param']['ds3']);
} // end loop

$end_time = microtime();
$wire_time= control_microtime_used($start_time,$end_time)*1000000;
echo
sprintf("<br><strong>Time (loop=$loop) total=%1.2f sec (%1.2f ms per call)</strong><br>",
round($wire_time/1000000,2),
round(($wire_time/$loop)/1000,2));

if($result){

/*update parameters array by return values */
foreach($IOParam as $key=> &$element){
$element['out'] = $result['io_param'][$key];
}

echo "<br>";
showTableWithHeader(array("Parameter name","Input value", "Output value"), $IOParam);
}
else
echo "Execution failed.";
/* Do not use the disconnect() function for "state full" connection */
$ToolkitServiceObj->disconnect();

function control_microtime_used($before,$after) {
return (substr($after,11)-substr($before,11))+(substr($after,0,9)-substr($before,0,9));
}

?>

This resulted in the following output.

New Zend Toolkit. Input values never change on each call.

Time (loop=5000) total=26.95 sec (5.39 ms per call)

Parameter name Input value Output value
var1 Y C
var2 Z D
var3 001.0001 321.1234
var4 0000000003.04 1234567890.12
ds1 A E
ds2 B F
ds3 005.0007 333.3330
ds4 0000000006.08 4444444444.44

After this we ran the same request using the old i5_toolkit option using the following code.


<?php
//require_once('connection.inc');

$loop = 5000;

$start_time = microtime();
echo "Original Easycom Toolkit.<br><br>";

$conn = i5_connect( "", "", "");
if (!$conn)
{ $tab = i5_error();
die("Connect: ".$tab[2]." "."$tab[3], $tab[0]");
}

/* prepare */
$description =
array
(
// single parms
array
( "Name"=>"INCHARA","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_CHAR,"Length"=>"1"),
array
( "Name"=>"INCHARB","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_CHAR,"Length"=>"1"),
array
( "Name"=>"INDEC1","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_PACKED,"Length"=>"7.4"),
array
( "Name"=>"INDEC2","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_PACKED,"Length"=>"12.2"),
// structure parm
array
( "DSName"=>"INDS1",
"Count"=>1,
"DSParm"=>
array
(
array
( "Name"=>"DSCHARA","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_CHAR,"Length"=>"1"),
array
( "Name"=>"DSCHARB","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_CHAR,"Length"=>"1"),
array
( "Name"=>"DSDEC1","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_PACKED,"Length"=>"7.4"),
array
( "Name"=>"DSDEC2","IO"=>I5_IN|I5_OUT,"Type"=>I5_TYPE_PACKED,"Length"=>"12.2"),
)
)
);
$pgm = i5_program_prepare("ZENDSVR/ZZCALL", $description);
if (!$pgm)
{ $tab = i5_error();
die("Prepare: ".$tab[2]." "."$tab[3], $tab[0]");
}

// *** parameter list allocation
$list=
array
(
"DSCHARA"=>"x",
"DSCHARB"=>"y",
"DSDEC1"=>66.6666,
"DSDEC2"=>77777.77,
);
// *** parameter values passed to procedure
$in =
array
(
"INCHARA"=>"a",
"INCHARB"=>"b",
"INDEC1"=>0,
"INDEC2"=>222.22,
"INDS1"=>$list,
);
// *** name of variables created for out parameters
$out =
array
(
"INCHARA"=>"INCHARA",
"INCHARB"=>"INCHARB",
"INDEC1"=>"INDEC1",
"INDEC2"=>"INDEC2",
"INDS1"=>"OUTDS1",
);

for ($i=0;$i<$loop;$i++) {
$rc=i5_program_call($pgm, $in, $out);
if ($rc != false)
{
}
else
{ $tab = i5_error();
die("Call: ".$tab[2]." "."$tab[3], $tab[0]");
}
$in['INDEC1']=$OUTDS1['DSDEC1'];
} // end loop

$end_time = microtime();
$wire_time= control_microtime_used($start_time,$end_time)*1000000;
echo
sprintf("<br><strong>Time (loop=$loop) total=%1.2f sec (%1.2f ms per call)</strong><br>",
round($wire_time/1000000,2),
round(($wire_time/$loop)/1000,2));

echo "<br>";
echo $INCHARA."<br>";
echo $INCHARB."<br>";
echo $INDEC1."<br>";
echo $INDEC2."<br>";
echo $OUTDS1['DSDEC1'].'<br>';
//var_dump($INDS1);

/* close */
/*flush();
set_time_limit(60);
for(;;);
*/

$rc = i5_close($conn);

function control_microtime_used($before,$after) {
return (substr($after,11)-substr($before,11))+(substr($after,0,9)-substr($before,0,9));
}

This resulted in the following output.

Original Easycom Toolkit.

Time (loop=5000) total=0.66 sec (0.13 ms per call)

C
D
321.1234
1234567890.12
333.333

Next we looked at the new XML request using the new i5_toolkit, this is available for download from the Aura website and will install the required objects over an existing ZendCore or ZendServer install. This is good for those developers who wanted an XML type interface for program calls especially as Zend regularly said it was something users wanted as they found the old i5_toolkit method difficult to understand.

This is the code it ran.


<?php
//require_once('connection.inc');

$loop = 5000; //50000;

$start_time = microtime();
echo "Xml Easycom, using Associative Arrays Input/Output.<br><br>";

$conn = i5_connect( "", "", "");
if (!$conn)
{ $tab = i5_error();
die("Connect: ".$tab[2]." "."$tab[3], $tab[0]");
}

/* prepare */

$SRPG="DS1 DS;
DSCHARA 1a;
DSCHARB 1a;
DSDEC1 7p4;
DSDEC2 12p2;

ZZCALL PR extpgm(ZENDSVR/ZZCALL);
INCHARA 1a;
INCHARB 1a;
INDEC1 7p4;
INDEC2 12p2;
INDS1 likeds(DS1);
";
i5_XmlDefine ("s-rpg", $SRPG);

// *** parameter list allocation
$list=array(
"DSCHARA"=>"x",
"DSCHARB"=>"y",
"DSDEC1"=>66.6666,
"DSDEC2"=>77777.77,
);
$ArrayIn["INCHARA"] = "a";
$ArrayIn["INCHARB"] = "b";
$ArrayIn["INDEC1"] = 0;
$ArrayIn["INDEC2"] = 222.22;
$ArrayIn["INDS1"] = $list;

for ($i=0;$i<$loop;$i++) {
$ArrayIn["INDEC1"] = $i/1000;
$ArrayOut = i5_XmlCallProgram ("ZZCALL", $ArrayIn);
$ArrayIn["INDEC1"] = $ArrayOut['INDS1']['DSDEC1'];
} // end loop

$end_time = microtime();
$wire_time= control_microtime_used($start_time,$end_time)*1000000;
echo
sprintf("<br><strong>Time (loop=$loop) total=%1.2f sec (%1.2f ms per call)</strong><br>",
round($wire_time/1000000,2),
round(($wire_time/$loop)/1000,2));

echo '<UL><LI><PRE>';
print_r($ArrayOut);
echo '</PRE></LI></UL>';

/* close */
/*flush();
set_time_limit(60);
for(;;);
*/

$rc = i5_close($conn);

function control_microtime_used($before,$after) {
return (substr($after,11)-substr($before,11))+(substr($after,0,9)-substr($before,0,9));
}

This is the output.

Xml Easycom, using Associative Arrays Input/Output.

Time (loop=5000) total=4.27 sec (0.85 ms per call)

Array
(
[INCHARA] => C
[INCHARB] => D
[INDEC1] => 321.1234
[INDEC2] => 1234567890.12
[INDS1] => Array
(
[DSCHARA] => E
[DSCHARB] => F
[DSDEC1] => 333.333
[DSDEC2] => 4444444444.44
)

)

Finally we decide to look at the performance hit using our preferred installation which is Easycom Server running on the IBMi with Apache and PHP running on a PC or Linux server. The script run on the Linux/PC box with the program being run on the IBMi. The ode we ran is eactly the same code which ran for the test on the IBMi.

here is the output.

Original Easycom Toolkit.

Time (loop=5000) total=1.23 sec (0.25 ms per call)

C
D
321.1234
1234567890.12
333.333

So it looks like the claims against the Easycom i5_toolkit and how the new toolkit is much faster do not stand up in this situation? Is this representative? Maybe Maybe not.. As you can see from the above the old i5_toolkit is around 5 times faster (actually over 40 see the comment) than the new XMLSERVICE using the test programs, the new XML request provided in the new i5_toolkit is also slower than it predecessor but no way near as slow as the new XMLSERVICE, even running the old i5_toolkit requests on a PC and adding the delay for communication is still faster than the new IBM/Zend toolkit.

So we have done what we set out to do and looked at a simple test to see if the new XMLSERVICE stands up to its marketing, our opinion is it is not as fast based on our very simple tests. If you have different results share them with us.

If you would like to understand more about our PHP experiences let us know.

Chris…

One thought on “New XMLService is not what I expected.”

  1. I was getting a bit tired last night which seems to have fogged my math… I said the Old Easycom solution was 5 times faster but that is way understated as it is actually over 4o times faster! This morning I also took the opportunity to look at the XML request available under Easycom from the PC which resulted in the following output.

    Xml Easycom, using Associative Arrays Input/Output.

    Time (loop=5000) total=5.39 sec (1.08 ms per call)

    Array
    (
    [INCHARA] => C
    [INCHARB] => D
    [INDEC1] => 321.1234
    [INDEC2] => 1234567890.12
    [INDS1] => Array
    (
    [DSCHARA] => E
    [DSCHARB] => F
    [DSDEC1] => 333.3330
    [DSDEC2] => 4444444444.44
    )

    )

    So it is not as fast as the old calling method, probably because it has to do a lot of work to build the XML requests and interpret the results? While these are our results we are not sure if they are indicative of what you would see, they only reflect what we saw with the programs listed above. If you have an application which does lots of program calls this could make a lot of difference but if you have limited program calls in your application the results may not be as advantageous.

    Chris…

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.