Archived

This forum has been archived. Please start a new discussion on GitHub.

Java Performance of Ice.Util.createInputStream

Hello,

I am working on an application with some very tight performance requirements.

Below are three typical lines of code for deserializing data.

The SessionStartMessage is a very small message ( 2 strings in it ).

1) Ice.InputStream inputStream = Ice.Util.createInputStream(communicator, msg);

2) SessionStartMessage sessionStart = new SessionStartMessage();

3) sessionStart.ice_read( inputStream );


When I have timed these three lines of code I get a time of 2.5 microseconds. 99 percent
of this time occurs for processing line 1 above ( Ice.Util.createInputStream ).

Is there a way to reuse this stream object as it is so expensive to create or should I be
using a different technique?

Thanks,
Glenn

Comments

  • No, there is no way to reuse the stream object for different data. All you can do is call rewind() to reset the stream position to the beginning.

    If you follow the code that executes when you create an input stream, you will see that it doesn't do a lot: it allocates a BasicStream that, in turn, allocates a buffer. Other than that, there is just a handful of member variable initializations.

    How big is the message overall? I suspect that a fair amount of the total cost might be copying the data into the internal buffer of the stream.

    Cheers,

    Michi.
  • Hello Michi,

    Thank you for your quick response.

    What does "different data" mean? Do you mean different slice structures?

    Can I use the same stream over again by just rewinding it? If so, can I use
    this for different slice structure or do it need one stream per message?

    Here is the constructor for this message:
    public SessionStartMessage(String username, String password)
    {
    this.username = username;
    this.password = password;
    }
    So this message is very small. Perhaps 30 bytes or so.


    That is why I am a little confused as to why Ice.Util.createInputStream() is taking 2.5
    microseconds to execute.

    Glenn

    michi wrote: »
    No, there is no way to reuse the stream object for different data. All you can do is call rewind() to reset the stream position to the beginning.

    If you follow the code that executes when you create an input stream, you will see that it doesn't do a lot: it allocates a BasicStream that, in turn, allocates a buffer. Other than that, there is just a handful of member variable initializations.

    How big is the message overall? I suspect that a fair amount of the total cost might be copying the data into the internal buffer of the stream.

    Cheers,

    Michi.
  • glennleidy wrote: »
    What does "different data" mean? Do you mean different slice structures?

    You initialize the stream as follows:
    Ice.InputStream inputStream = Ice.Util.createInputStream(communicator, msg);
    

    The msg parameter is the data that is parsed by the stream. That data cannot be changed after the stream is created.
    Can I use the same stream over again by just rewinding it? If so, can I use
    this for different slice structure or do it need one stream per message?

    If you rewind the stream, you can parse the same data again. But, for different messages, you need different streams.
    That is why I am a little confused as to why Ice.Util.createInputStream() is taking 2.5 microseconds to execute.

    Can you trace into the run time to see how that time is split among the various things that happen as part of createInputStream?

    Cheers,

    Michi.
  • Hello Michi,

    Thanks again for being so responsive.

    I am a little unsure of how to evaluate library software for which I do not have the source code for.

    I have created a couple of methods which I hope demonstrates the issue.

    I quess we are down to one remaining question as to why it takes 2.5 microseconds
    to Ice.InputStream inputStream = Ice.Util.createInputStream(communicator, msg)
    where msg is about 30 bytes in length.


    Here are two sample methods which (I think) demonstrates the issue.

    The first method attempts to determine how long it take to deserialize
    data. I get an average time of 2800 nanoseconds or (2.8 microseconds) when I run this.
    I have confirmed that 99 percent of the time is used in the createInputStream() method.

    The second method simply creates a new ArrayList and adds an object to it.
    When I run this I get an average time of 119 nanoseconds.


    Glenn



    private void evalSliceDecodeTCSessionStartRequest()
    {
    SliceMessageCreator sliceMessageCreator = new SliceMessageCreator(ByteOrder.LITTLE_ENDIAN, null);
    TCSessionStartRequestMessage sessionStart = new TCSessionStartRequestMessage();
    sessionStart.username = "glenn";
    sessionStart.password = "kobe";
    byte[] msg = sliceMessageCreator.encodeSessionStartMessage(sessionStart);

    Communicator communicator = Ice.Util.initialize();

    startTime = System.nanoTime();
    for ( int i=0; i<TEST_COUNT; i++ )
    {
    Ice.InputStream inputStream = Ice.Util.createInputStream(communicator, msg);

    TCSessionStartRequestMessage sessionStartParse = new TCSessionStartRequestMessage();
    sessionStartParse.ice_read( inputStream );

    }

    System.out.println( "evalSliceDecodeTCSessionStartRequest avg execution time (in nanoSeconds)=" +
    ( System.nanoTime() - startTime)/TEST_COUNT );
    }

    private void evalCreateArrayList()
    {
    SliceMessageCreator sliceMessageCreator = new SliceMessageCreator(ByteOrder.LITTLE_ENDIAN, null);
    TCSessionStartRequestMessage sessionStart = new TCSessionStartRequestMessage();
    sessionStart.username = "glenn";
    sessionStart.password = "kobe";
    byte[] msg = sliceMessageCreator.encodeSessionStartMessage(sessionStart);

    Communicator communicator = Ice.Util.initialize();

    startTime = System.nanoTime();
    for ( int i=0; i<TEST_COUNT; i++ )
    {
    ArrayList arrayList = new ArrayList();
    arrayList.add( sessionStart );

    }

    System.out.println( "evalCreateArrayList avg execution time (in nanoSeconds)=" +
    ( System.nanoTime() - startTime)/TEST_COUNT );
    }


    Glenn
    michi wrote: »
    You initialize the stream as follows:
    Ice.InputStream inputStream = Ice.Util.createInputStream(communicator, msg);
    

    The msg parameter is the data that is parsed by the stream. That data cannot be changed after the stream is created.



    If you rewind the stream, you can parse the same data again. But, for different messages, you need different streams.



    Can you trace into the run time to see how that time is split among the various things that happen as part of createInputStream?

    Cheers,

    Michi.
  • matthew
    matthew NL, Canada
    glennleidy wrote: »
    ...

    I am a little unsure of how to evaluate library software for which I do not have the source code for.
    ...

    Perhaps I'm misunderstand what you are saying, but the full source code for Ice is available for download.
  • Hello Matthew,

    I did not know that the source code is available so thank you for the information.

    Unfortunately, I do not have the time to install and configure your source code
    in my environment.

    I guess the question still stands should this call:

    Ice.InputStream inputStream = Ice.Util.createInputStream(communicator, msg);

    take 2.5 microseconds to execute with a 30 byte message? Do you see a different
    number at your end? This seems way too long to me.

    I would think this would be easily reproducible in your environment as well.

    Again, thanks to everyone at ICE for being so responsive.


    Glenn

    matthew wrote: »
    Perhaps I'm misunderstand what you are saying, but the full source code for Ice is available for download.
  • matthew
    matthew NL, Canada
    You can improve the performance somewhat by setting "Ice.CacheMessageBuffers=0".

    To this point we haven't viewed this piece of code as very performance sensitive. I suspect the performance could be somewhat improved with some careful optimization. If it matters for you, you should consider contacting sales@zeroc.com, and we can discuss how to help you further.
  • Hello Matthew,

    I will give this a try. To date all I have done is use the "ice.jar" file to
    use your library.

    I am unsure of how to do this: "Ice.CacheMessageBuffers=0". Is this a config
    entry in a file? Can I do this directly in code ( preferred )?

    Thanks,
    Glenn
    matthew wrote: »
    You can improve the performance somewhat by setting "Ice.CacheMessageBuffers=0".

    To this point we haven't viewed this piece of code as very performance sensitive. I suspect the performance could be somewhat improved with some careful optimization. If it matters for you, you should consider contacting sales@zeroc.com, and we can discuss how to help you further.
  • dwayne
    dwayne St. John's, Newfoundland
    glennleidy wrote: »
    I am unsure of how to do this: "Ice.CacheMessageBuffers=0". Is this a config
    entry in a file? Can I do this directly in code ( preferred )?

    Ice.CacheMessageBuffers is a property. You can set it from the command line.
    java Server --Ice.CacheMessageBuffers=0
    
    You can also set it in a configuration file or programatically. See chapter 30 of the manual for more details on the ways to use properties.