You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@harmony.apache.org by Regis <xu...@gmail.com> on 2007/10/16 09:58:59 UTC

[classlib][performance] InitialContext searches for jndi.properties every contruction time(Harmony-4942)

Hi,
I survey the issue Harmony-4942, found the Harmony's behavior of finding 
"jndi.properties" file is not the same as ri's:
Harmony re-search the whole CLASSPATH every construction time, while ri 
just search once when using a classloader to
find the file at first time. The following code prove it:

=============begin=============

             URL url = new File("test1").toURL();
             URLClassLoader cltest1 = new URLClassLoader(new URL[] { url },
                     Thread.currentThread().getContextClassLoader());
             Thread test1 = new Thread(new Runnable() {

                 public void run() {
                     try {
                         System.out.println("test1 classloader"
                                 + Thread.currentThread()
                                         .getContextClassLoader());
                         FileOutputStream fos = new FileOutputStream(
                                 "test1/jndi.properties");
                         PrintStream ps = new PrintStream(fos);
                         ps
 
.println("java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory");
 
ps.println("java.naming.provider.url=http://test1");
                         ps.close();

                         InitialContext context = new InitialContext();
                         System.out.println("test1.context=    " + context);
                         System.out.println("test1.context.env="
                                 + context.getEnvironment());

                         File file = new File("test1/jndi.properties");
                         file.delete();

                         // create new properties file with different values
                         fos = new FileOutputStream(
                                 "test1/jndi.properties");
                         ps = new PrintStream(fos);
                         ps
 
.println("java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory");
 
ps.println("java.naming.provider.url=http://test1.new");
                         ps.close();

                         context = new InitialContext();
                         System.out.println("test1.new.context=" + context);
                         System.out.println("test1.new.context.env="
                                 + context.getEnvironment());

                     } catch (Exception e) {
                         e.printStackTrace();
                     }
                 }

             });
             // use different classloader
             test1.setContextClassLoader(cltest1);

             test1.start();

             url = new File("test2").toURL();
             URLClassLoader clSrc = new URLClassLoader(new URL[] { url 
}, Thread
                     .currentThread().getContextClassLoader());

             Thread test2 = new Thread(new Runnable() {

                 public void run() {
                     try {
                         System.out.println("test2 classloader"
                                 + Thread.currentThread()
                                         .getContextClassLoader());
                         FileOutputStream fos = new FileOutputStream(
                                 "test2/jndi.properties");
                         PrintStream ps = new PrintStream(fos);
                         ps
 
.println("java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory");
 
ps.println("java.naming.provider.url=http://test2");
                         ps.close();
                         InitialContext context = new InitialContext();
                         System.out.println("test2.context=    " + context);
                         System.out.println("test2.context.env="
                                 + context.getEnvironment());
                     } catch (Exception e) {
                         e.printStackTrace();
                     }
                 }

             });

             // use different classloader
             test2.setContextClassLoader(clSrc);
             test2.start();

===================end=================
(I slightly modify MyDefaultInitialContextFactory, add environment 
values to MyInitialContext after initial)

the output is below, using jre1.6.0:

============start output===============

test1 classloaderjava.net.URLClassLoader@42e816
test1.context=    javax.naming.InitialContext@60aeb0
test1.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory, 
java.naming.provider.url=http://test1}
test1.new.context=javax.naming.InitialContext@16caf43
test1.new.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory, 
java.naming.provider.url=http://test1}
test2 classloaderjava.net.URLClassLoader@8813f2
test2.context=    javax.naming.InitialContext@1d58aae
test2.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory, 
java.naming.provider.url=http://test2}

=============end output=================

So under same classloader, ri just search property file once.

In harmony we can use a map to hold property values for each classloader 
to avoid search at every construction time.
But i found Harmony is still slower than ri at first time to constuct 
InitialContext object, the most time is consumed at
org.apache.harmony.jndi.internal.EnvironmentReader line 233:
p.load(is);

Then i write some sample code to test performance of Properties.load():

Properties pro = new Properties();
          URL url = new
 
URL("jar:file:/home/bahamut/harmony/trunk/deploy/jdk/jre/lib/boot/jndi.jar!/jndi.properties");
          InputStream in = url.openStream();
          long start = System.currentTimeMillis();
          pro.load(in);
          long end = System.currentTimeMillis();
          System.out.println("time: " + (end - start));
          in.close();

          pro = new Properties();
          url = new
 
URL("jar:file:/home/bahamut/harmony/trunk/deploy/jdk/jre/lib/boot/jndi.jar!/jndi.properties");
          in = url.openStream();
          start = System.currentTimeMillis();
          pro.load(in);
          end = System.currentTimeMillis();
          System.out.println("time: " + (end - start));
          in.close();

output of ri:
time: 1
time: 0

output of harmony:
time: 231
time: 1

Harmony is slower than ri *two hundred* times!!
in above test, property file is in jndi.jar about 230k, if not in jar 
file, the time of harmony and ri are very close,
so i think there must be some problems of archive module. Is it because 
of we using different algorithm with ri,
or our implementation has bugs?

Best Regards,
Regis.

Re: [classlib][performance] InitialContext searches for jndi.properties every contruction time(Harmony-4942)

Posted by Regis <xu...@gmail.com>.
Today i update from svn, then build and run the performance tests, 
harmony and
ri have the same result! I don't know what make this happen, maybe it's 
my mistake,
I will close jira 4950 and create path for 4942 soon.

Spark Shen wrote:
> I executed your test on windows XP.
> And the result is:
> output of RI:
> time: 0
> time: 0
> 
> output of harmony:
> time: 0
> time: 0
> 
> Seems the performance problem only occurs on RH linux platform. At this
> point, my guess is native I/O of archive module on RH Linux
> may cause the slowdown. I checked JIRA 4950. It would be better to specify
> the environment information for this JIRA.
> 
> 2007/10/16, Regis <xu...@gmail.com>:
>>
>> Spark Shen wrote:
>>> Hi
>>> I read your comments in
>> http://issues.apache.org/jira/browse/HARMONY-4942.
>>> And I agree with you different apps context uses different classloader
>> for
>>> loading different
>>> properties as you said.
>>>
>>> I did not catch you is 'I'm not sure how ri do this'.
>> just want to clarify behavior of ri
>>> I just want to clarify my understanding here:
>>> You are not quite sure about how RI handle modification to the same
>>> jndi.properties file
>>> in different classloaders. And in your post here, you proved that,
>> indeed
>>> different classloaders in RI will
>>> overwrite each other.
>>>
>>> And I think we'd better follow RI, since many application servers are
>>> already running stably on it.
>> agree
>>> 2007/10/16, Regis <xu...@gmail.com>:
>>>> Hi,
>>>> I survey the issue Harmony-4942, found the Harmony's behavior of
>> finding
>>>> "jndi.properties" file is not the same as ri's:
>>>> Harmony re-search the whole CLASSPATH every construction time, while ri
>>>> just search once when using a classloader to
>>>> find the file at first time. The following code prove it:
>>>>
>>>> =============begin=============
>>>>
>>>>              URL url = new File("test1").toURL();
>>>>              URLClassLoader cltest1 = new URLClassLoader(new URL[] {
>> url
>>>> },
>>>>                      Thread.currentThread().getContextClassLoader());
>>>>              Thread test1 = new Thread(new Runnable() {
>>>>
>>>>                  public void run() {
>>>>                      try {
>>>>                          System.out.println("test1 classloader"
>>>>                                  + Thread.currentThread()
>>>>                                          .getContextClassLoader());
>>>>                          FileOutputStream fos = new FileOutputStream(
>>>>                                  "test1/jndi.properties");
>>>>                          PrintStream ps = new PrintStream(fos);
>>>>                          ps
>>>>
>>>> .println("
>>>> java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
>> ");
>>>> ps.println("java.naming.provider.url=http://test1");
>>>>                          ps.close();
>>>>
>>>>                          InitialContext context = new InitialContext();
>>>>                          System.out.println("test1.context=    " +
>>>> context);
>>>>                          System.out.println("test1.context.env="
>>>>                                  + context.getEnvironment());
>>>>
>>>>                          File file = new File("test1/jndi.properties");
>>>>                          file.delete();
>>>>
>>>>                          // create new properties file with different
>>>> values
>>>>                          fos = new FileOutputStream(
>>>>                                  "test1/jndi.properties");
>>>>                          ps = new PrintStream(fos);
>>>>                          ps
>>>>
>>>> .println("
>>>> java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
>> ");
>>>> ps.println("java.naming.provider.url=http://test1.new");
>>>>                          ps.close();
>>>>
>>>>                          context = new InitialContext();
>>>>                          System.out.println("test1.new.context=" +
>>>> context);
>>>>                          System.out.println("test1.new.context.env="
>>>>                                  + context.getEnvironment());
>>>>
>>>>                      } catch (Exception e) {
>>>>                          e.printStackTrace();
>>>>                      }
>>>>                  }
>>>>
>>>>              });
>>>>              // use different classloader
>>>>              test1.setContextClassLoader(cltest1);
>>>>
>>>>              test1.start();
>>>>
>>>>              url = new File("test2").toURL();
>>>>              URLClassLoader clSrc = new URLClassLoader(new URL[] { url
>>>> }, Thread
>>>>                      .currentThread().getContextClassLoader());
>>>>
>>>>              Thread test2 = new Thread(new Runnable() {
>>>>
>>>>                  public void run() {
>>>>                      try {
>>>>                          System.out.println("test2 classloader"
>>>>                                  + Thread.currentThread()
>>>>                                          .getContextClassLoader());
>>>>                          FileOutputStream fos = new FileOutputStream(
>>>>                                  "test2/jndi.properties");
>>>>                          PrintStream ps = new PrintStream(fos);
>>>>                          ps
>>>>
>>>> .println("
>>>> java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
>> ");
>>>> ps.println("java.naming.provider.url=http://test2");
>>>>                          ps.close();
>>>>                          InitialContext context = new InitialContext();
>>>>                          System.out.println("test2.context=    " +
>>>> context);
>>>>                          System.out.println("test2.context.env="
>>>>                                  + context.getEnvironment());
>>>>                      } catch (Exception e) {
>>>>                          e.printStackTrace();
>>>>                      }
>>>>                  }
>>>>
>>>>              });
>>>>
>>>>              // use different classloader
>>>>              test2.setContextClassLoader(clSrc);
>>>>              test2.start();
>>>>
>>>> ===================end=================
>>>> (I slightly modify MyDefaultInitialContextFactory, add environment
>>>> values to MyInitialContext after initial)
>>>>
>>>> the output is below, using jre1.6.0:
>>>>
>>>> ============start output===============
>>>>
>>>> test1 classloaderjava.net.URLClassLoader@42e816
>>>> test1.context=    javax.naming.InitialContext@60aeb0
>>>>
>>>>
>> test1.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
>>>> ,
>>>> java.naming.provider.url=http://test1}
>>>> test1.new.context=javax.naming.InitialContext@16caf43
>>>>
>>>>
>> test1.new.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
>>>> ,
>>>> java.naming.provider.url=http://test1}
>>>> test2 classloaderjava.net.URLClassLoader@8813f2
>>>> test2.context=    javax.naming.InitialContext@1d58aae
>>>>
>>>>
>> test2.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
>>>> ,
>>>> java.naming.provider.url=http://test2}
>>>>
>>>> =============end output=================
>>>>
>>>> So under same classloader, ri just search property file once.
>>>>
>>>> In harmony we can use a map to hold property values for each
>> classloader
>>>> to avoid search at every construction time.
>>>> But i found Harmony is still slower than ri at first time to constuct
>>>> InitialContext object, the most time is consumed at
>>>> org.apache.harmony.jndi.internal.EnvironmentReader line 233:
>>>> p.load(is);
>>>
>>> As for the performance issue in Properties.java, I think may be it's
>> caused
>>> by lack of cache. I am interested, and will look into the issue.
>>> BTW, did you report a seperate JIRA for it?
>> the jira is here: https://issues.apache.org/jira/browse/HARMONY-4950
>>> Then i write some sample code to test performance of Properties.load():
>>>> Properties pro = new Properties();
>>>>           URL url = new
>>>>
>>>>
>>>>
>> URL("jar:file:/home/bahamut/harmony/trunk/deploy/jdk/jre/lib/boot/jndi.jar!/jndi.properties");
>>>>           InputStream in = url.openStream();
>>>>           long start = System.currentTimeMillis();
>>>>           pro.load(in);
>>>>           long end = System.currentTimeMillis();
>>>>           System.out.println("time: " + (end - start));
>>>>           in.close();
>>>>
>>>>           pro = new Properties();
>>>>           url = new
>>>>
>>>>
>>>>
>> URL("jar:file:/home/bahamut/harmony/trunk/deploy/jdk/jre/lib/boot/jndi.jar!/jndi.properties");
>>>>           in = url.openStream();
>>>>           start = System.currentTimeMillis();
>>>>           pro.load(in);
>>>>           end = System.currentTimeMillis();
>>>>           System.out.println("time: " + (end - start));
>>>>           in.close();
>>>>
>>>> output of ri:
>>>> time: 1
>>>> time: 0
>>>>
>>>> output of harmony:
>>>> time: 231
>>>> time: 1
>>>>
>>>> Harmony is slower than ri *two hundred* times!!
>>>> in above test, property file is in jndi.jar about 230k, if not in jar
>>>> file, the time of harmony and ri are very close,
>>>> so i think there must be some problems of archive module. Is it because
>>>> of we using different algorithm with ri,
>>>> or our implementation has bugs?
>>>>
>>>> Best Regards,
>>>> Regis.
>>>>
>>>
>>>
>> Best Regards,
>> Regis.
>>
> 
> 
> 

Re: [classlib][performance] InitialContext searches for jndi.properties every contruction time(Harmony-4942)

Posted by Spark Shen <sm...@gmail.com>.
I executed your test on windows XP.
And the result is:
output of RI:
time: 0
time: 0

output of harmony:
time: 0
time: 0

Seems the performance problem only occurs on RH linux platform. At this
point, my guess is native I/O of archive module on RH Linux
may cause the slowdown. I checked JIRA 4950. It would be better to specify
the environment information for this JIRA.

2007/10/16, Regis <xu...@gmail.com>:
>
>
> Spark Shen wrote:
> > Hi
> > I read your comments in
> http://issues.apache.org/jira/browse/HARMONY-4942.
> > And I agree with you different apps context uses different classloader
> for
> > loading different
> > properties as you said.
> >
> > I did not catch you is 'I'm not sure how ri do this'.
> just want to clarify behavior of ri
> > I just want to clarify my understanding here:
> > You are not quite sure about how RI handle modification to the same
> > jndi.properties file
> > in different classloaders. And in your post here, you proved that,
> indeed
> > different classloaders in RI will
> > overwrite each other.
> >
> > And I think we'd better follow RI, since many application servers are
> > already running stably on it.
> agree
> > 2007/10/16, Regis <xu...@gmail.com>:
> >> Hi,
> >> I survey the issue Harmony-4942, found the Harmony's behavior of
> finding
> >> "jndi.properties" file is not the same as ri's:
> >> Harmony re-search the whole CLASSPATH every construction time, while ri
> >> just search once when using a classloader to
> >> find the file at first time. The following code prove it:
> >>
> >> =============begin=============
> >>
> >>              URL url = new File("test1").toURL();
> >>              URLClassLoader cltest1 = new URLClassLoader(new URL[] {
> url
> >> },
> >>                      Thread.currentThread().getContextClassLoader());
> >>              Thread test1 = new Thread(new Runnable() {
> >>
> >>                  public void run() {
> >>                      try {
> >>                          System.out.println("test1 classloader"
> >>                                  + Thread.currentThread()
> >>                                          .getContextClassLoader());
> >>                          FileOutputStream fos = new FileOutputStream(
> >>                                  "test1/jndi.properties");
> >>                          PrintStream ps = new PrintStream(fos);
> >>                          ps
> >>
> >> .println("
> >> java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
> ");
> >>
> >> ps.println("java.naming.provider.url=http://test1");
> >>                          ps.close();
> >>
> >>                          InitialContext context = new InitialContext();
> >>                          System.out.println("test1.context=    " +
> >> context);
> >>                          System.out.println("test1.context.env="
> >>                                  + context.getEnvironment());
> >>
> >>                          File file = new File("test1/jndi.properties");
> >>                          file.delete();
> >>
> >>                          // create new properties file with different
> >> values
> >>                          fos = new FileOutputStream(
> >>                                  "test1/jndi.properties");
> >>                          ps = new PrintStream(fos);
> >>                          ps
> >>
> >> .println("
> >> java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
> ");
> >>
> >> ps.println("java.naming.provider.url=http://test1.new");
> >>                          ps.close();
> >>
> >>                          context = new InitialContext();
> >>                          System.out.println("test1.new.context=" +
> >> context);
> >>                          System.out.println("test1.new.context.env="
> >>                                  + context.getEnvironment());
> >>
> >>                      } catch (Exception e) {
> >>                          e.printStackTrace();
> >>                      }
> >>                  }
> >>
> >>              });
> >>              // use different classloader
> >>              test1.setContextClassLoader(cltest1);
> >>
> >>              test1.start();
> >>
> >>              url = new File("test2").toURL();
> >>              URLClassLoader clSrc = new URLClassLoader(new URL[] { url
> >> }, Thread
> >>                      .currentThread().getContextClassLoader());
> >>
> >>              Thread test2 = new Thread(new Runnable() {
> >>
> >>                  public void run() {
> >>                      try {
> >>                          System.out.println("test2 classloader"
> >>                                  + Thread.currentThread()
> >>                                          .getContextClassLoader());
> >>                          FileOutputStream fos = new FileOutputStream(
> >>                                  "test2/jndi.properties");
> >>                          PrintStream ps = new PrintStream(fos);
> >>                          ps
> >>
> >> .println("
> >> java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
> ");
> >>
> >> ps.println("java.naming.provider.url=http://test2");
> >>                          ps.close();
> >>                          InitialContext context = new InitialContext();
> >>                          System.out.println("test2.context=    " +
> >> context);
> >>                          System.out.println("test2.context.env="
> >>                                  + context.getEnvironment());
> >>                      } catch (Exception e) {
> >>                          e.printStackTrace();
> >>                      }
> >>                  }
> >>
> >>              });
> >>
> >>              // use different classloader
> >>              test2.setContextClassLoader(clSrc);
> >>              test2.start();
> >>
> >> ===================end=================
> >> (I slightly modify MyDefaultInitialContextFactory, add environment
> >> values to MyInitialContext after initial)
> >>
> >> the output is below, using jre1.6.0:
> >>
> >> ============start output===============
> >>
> >> test1 classloaderjava.net.URLClassLoader@42e816
> >> test1.context=    javax.naming.InitialContext@60aeb0
> >>
> >>
> test1.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
> >> ,
> >> java.naming.provider.url=http://test1}
> >> test1.new.context=javax.naming.InitialContext@16caf43
> >>
> >>
> test1.new.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
> >> ,
> >> java.naming.provider.url=http://test1}
> >> test2 classloaderjava.net.URLClassLoader@8813f2
> >> test2.context=    javax.naming.InitialContext@1d58aae
> >>
> >>
> test2.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
> >> ,
> >> java.naming.provider.url=http://test2}
> >>
> >> =============end output=================
> >>
> >> So under same classloader, ri just search property file once.
> >>
> >> In harmony we can use a map to hold property values for each
> classloader
> >> to avoid search at every construction time.
> >> But i found Harmony is still slower than ri at first time to constuct
> >> InitialContext object, the most time is consumed at
> >> org.apache.harmony.jndi.internal.EnvironmentReader line 233:
> >> p.load(is);
> >
> >
> > As for the performance issue in Properties.java, I think may be it's
> caused
> > by lack of cache. I am interested, and will look into the issue.
> > BTW, did you report a seperate JIRA for it?
> the jira is here: https://issues.apache.org/jira/browse/HARMONY-4950
> >
> > Then i write some sample code to test performance of Properties.load():
> >> Properties pro = new Properties();
> >>           URL url = new
> >>
> >>
> >>
> URL("jar:file:/home/bahamut/harmony/trunk/deploy/jdk/jre/lib/boot/jndi.jar!/jndi.properties");
> >>           InputStream in = url.openStream();
> >>           long start = System.currentTimeMillis();
> >>           pro.load(in);
> >>           long end = System.currentTimeMillis();
> >>           System.out.println("time: " + (end - start));
> >>           in.close();
> >>
> >>           pro = new Properties();
> >>           url = new
> >>
> >>
> >>
> URL("jar:file:/home/bahamut/harmony/trunk/deploy/jdk/jre/lib/boot/jndi.jar!/jndi.properties");
> >>           in = url.openStream();
> >>           start = System.currentTimeMillis();
> >>           pro.load(in);
> >>           end = System.currentTimeMillis();
> >>           System.out.println("time: " + (end - start));
> >>           in.close();
> >>
> >> output of ri:
> >> time: 1
> >> time: 0
> >>
> >> output of harmony:
> >> time: 231
> >> time: 1
> >>
> >> Harmony is slower than ri *two hundred* times!!
> >> in above test, property file is in jndi.jar about 230k, if not in jar
> >> file, the time of harmony and ri are very close,
> >> so i think there must be some problems of archive module. Is it because
> >> of we using different algorithm with ri,
> >> or our implementation has bugs?
> >>
> >> Best Regards,
> >> Regis.
> >>
> >
> >
> >
>
> Best Regards,
> Regis.
>



-- 
Spark Shen
China Software Development Lab, IBM

Re: [classlib][performance] InitialContext searches for jndi.properties every contruction time(Harmony-4942)

Posted by Regis <xu...@gmail.com>.
Spark Shen wrote:
> Hi
> I read your comments in http://issues.apache.org/jira/browse/HARMONY-4942.
> And I agree with you different apps context uses different classloader for
> loading different
> properties as you said.
> 
> I did not catch you is 'I'm not sure how ri do this'.
just want to clarify behavior of ri
> I just want to clarify my understanding here:
> You are not quite sure about how RI handle modification to the same
> jndi.properties file
> in different classloaders. And in your post here, you proved that, indeed
> different classloaders in RI will
> overwrite each other.
> 
> And I think we'd better follow RI, since many application servers are
> already running stably on it.
agree
> 2007/10/16, Regis <xu...@gmail.com>:
>> Hi,
>> I survey the issue Harmony-4942, found the Harmony's behavior of finding
>> "jndi.properties" file is not the same as ri's:
>> Harmony re-search the whole CLASSPATH every construction time, while ri
>> just search once when using a classloader to
>> find the file at first time. The following code prove it:
>>
>> =============begin=============
>>
>>              URL url = new File("test1").toURL();
>>              URLClassLoader cltest1 = new URLClassLoader(new URL[] { url
>> },
>>                      Thread.currentThread().getContextClassLoader());
>>              Thread test1 = new Thread(new Runnable() {
>>
>>                  public void run() {
>>                      try {
>>                          System.out.println("test1 classloader"
>>                                  + Thread.currentThread()
>>                                          .getContextClassLoader());
>>                          FileOutputStream fos = new FileOutputStream(
>>                                  "test1/jndi.properties");
>>                          PrintStream ps = new PrintStream(fos);
>>                          ps
>>
>> .println("
>> java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory");
>>
>> ps.println("java.naming.provider.url=http://test1");
>>                          ps.close();
>>
>>                          InitialContext context = new InitialContext();
>>                          System.out.println("test1.context=    " +
>> context);
>>                          System.out.println("test1.context.env="
>>                                  + context.getEnvironment());
>>
>>                          File file = new File("test1/jndi.properties");
>>                          file.delete();
>>
>>                          // create new properties file with different
>> values
>>                          fos = new FileOutputStream(
>>                                  "test1/jndi.properties");
>>                          ps = new PrintStream(fos);
>>                          ps
>>
>> .println("
>> java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory");
>>
>> ps.println("java.naming.provider.url=http://test1.new");
>>                          ps.close();
>>
>>                          context = new InitialContext();
>>                          System.out.println("test1.new.context=" +
>> context);
>>                          System.out.println("test1.new.context.env="
>>                                  + context.getEnvironment());
>>
>>                      } catch (Exception e) {
>>                          e.printStackTrace();
>>                      }
>>                  }
>>
>>              });
>>              // use different classloader
>>              test1.setContextClassLoader(cltest1);
>>
>>              test1.start();
>>
>>              url = new File("test2").toURL();
>>              URLClassLoader clSrc = new URLClassLoader(new URL[] { url
>> }, Thread
>>                      .currentThread().getContextClassLoader());
>>
>>              Thread test2 = new Thread(new Runnable() {
>>
>>                  public void run() {
>>                      try {
>>                          System.out.println("test2 classloader"
>>                                  + Thread.currentThread()
>>                                          .getContextClassLoader());
>>                          FileOutputStream fos = new FileOutputStream(
>>                                  "test2/jndi.properties");
>>                          PrintStream ps = new PrintStream(fos);
>>                          ps
>>
>> .println("
>> java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory");
>>
>> ps.println("java.naming.provider.url=http://test2");
>>                          ps.close();
>>                          InitialContext context = new InitialContext();
>>                          System.out.println("test2.context=    " +
>> context);
>>                          System.out.println("test2.context.env="
>>                                  + context.getEnvironment());
>>                      } catch (Exception e) {
>>                          e.printStackTrace();
>>                      }
>>                  }
>>
>>              });
>>
>>              // use different classloader
>>              test2.setContextClassLoader(clSrc);
>>              test2.start();
>>
>> ===================end=================
>> (I slightly modify MyDefaultInitialContextFactory, add environment
>> values to MyInitialContext after initial)
>>
>> the output is below, using jre1.6.0:
>>
>> ============start output===============
>>
>> test1 classloaderjava.net.URLClassLoader@42e816
>> test1.context=    javax.naming.InitialContext@60aeb0
>>
>> test1.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
>> ,
>> java.naming.provider.url=http://test1}
>> test1.new.context=javax.naming.InitialContext@16caf43
>>
>> test1.new.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
>> ,
>> java.naming.provider.url=http://test1}
>> test2 classloaderjava.net.URLClassLoader@8813f2
>> test2.context=    javax.naming.InitialContext@1d58aae
>>
>> test2.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
>> ,
>> java.naming.provider.url=http://test2}
>>
>> =============end output=================
>>
>> So under same classloader, ri just search property file once.
>>
>> In harmony we can use a map to hold property values for each classloader
>> to avoid search at every construction time.
>> But i found Harmony is still slower than ri at first time to constuct
>> InitialContext object, the most time is consumed at
>> org.apache.harmony.jndi.internal.EnvironmentReader line 233:
>> p.load(is);
> 
> 
> As for the performance issue in Properties.java, I think may be it's caused
> by lack of cache. I am interested, and will look into the issue.
> BTW, did you report a seperate JIRA for it?
the jira is here: https://issues.apache.org/jira/browse/HARMONY-4950
> 
> Then i write some sample code to test performance of Properties.load():
>> Properties pro = new Properties();
>>           URL url = new
>>
>>
>> URL("jar:file:/home/bahamut/harmony/trunk/deploy/jdk/jre/lib/boot/jndi.jar!/jndi.properties");
>>           InputStream in = url.openStream();
>>           long start = System.currentTimeMillis();
>>           pro.load(in);
>>           long end = System.currentTimeMillis();
>>           System.out.println("time: " + (end - start));
>>           in.close();
>>
>>           pro = new Properties();
>>           url = new
>>
>>
>> URL("jar:file:/home/bahamut/harmony/trunk/deploy/jdk/jre/lib/boot/jndi.jar!/jndi.properties");
>>           in = url.openStream();
>>           start = System.currentTimeMillis();
>>           pro.load(in);
>>           end = System.currentTimeMillis();
>>           System.out.println("time: " + (end - start));
>>           in.close();
>>
>> output of ri:
>> time: 1
>> time: 0
>>
>> output of harmony:
>> time: 231
>> time: 1
>>
>> Harmony is slower than ri *two hundred* times!!
>> in above test, property file is in jndi.jar about 230k, if not in jar
>> file, the time of harmony and ri are very close,
>> so i think there must be some problems of archive module. Is it because
>> of we using different algorithm with ri,
>> or our implementation has bugs?
>>
>> Best Regards,
>> Regis.
>>
> 
> 
> 

Best Regards,
Regis.

Re: [classlib][performance] InitialContext searches for jndi.properties every contruction time(Harmony-4942)

Posted by Spark Shen <sm...@gmail.com>.
Hi
I read your comments in http://issues.apache.org/jira/browse/HARMONY-4942.
And I agree with you different apps context uses different classloader for
loading different
properties as you said.

I did not catch you is 'I'm not sure how ri do this'.
I just want to clarify my understanding here:
You are not quite sure about how RI handle modification to the same
jndi.properties file
in different classloaders. And in your post here, you proved that, indeed
different classloaders in RI will
overwrite each other.

And I think we'd better follow RI, since many application servers are
already running stably on it.
2007/10/16, Regis <xu...@gmail.com>:
>
> Hi,
> I survey the issue Harmony-4942, found the Harmony's behavior of finding
> "jndi.properties" file is not the same as ri's:
> Harmony re-search the whole CLASSPATH every construction time, while ri
> just search once when using a classloader to
> find the file at first time. The following code prove it:
>
> =============begin=============
>
>              URL url = new File("test1").toURL();
>              URLClassLoader cltest1 = new URLClassLoader(new URL[] { url
> },
>                      Thread.currentThread().getContextClassLoader());
>              Thread test1 = new Thread(new Runnable() {
>
>                  public void run() {
>                      try {
>                          System.out.println("test1 classloader"
>                                  + Thread.currentThread()
>                                          .getContextClassLoader());
>                          FileOutputStream fos = new FileOutputStream(
>                                  "test1/jndi.properties");
>                          PrintStream ps = new PrintStream(fos);
>                          ps
>
> .println("
> java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory");
>
> ps.println("java.naming.provider.url=http://test1");
>                          ps.close();
>
>                          InitialContext context = new InitialContext();
>                          System.out.println("test1.context=    " +
> context);
>                          System.out.println("test1.context.env="
>                                  + context.getEnvironment());
>
>                          File file = new File("test1/jndi.properties");
>                          file.delete();
>
>                          // create new properties file with different
> values
>                          fos = new FileOutputStream(
>                                  "test1/jndi.properties");
>                          ps = new PrintStream(fos);
>                          ps
>
> .println("
> java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory");
>
> ps.println("java.naming.provider.url=http://test1.new");
>                          ps.close();
>
>                          context = new InitialContext();
>                          System.out.println("test1.new.context=" +
> context);
>                          System.out.println("test1.new.context.env="
>                                  + context.getEnvironment());
>
>                      } catch (Exception e) {
>                          e.printStackTrace();
>                      }
>                  }
>
>              });
>              // use different classloader
>              test1.setContextClassLoader(cltest1);
>
>              test1.start();
>
>              url = new File("test2").toURL();
>              URLClassLoader clSrc = new URLClassLoader(new URL[] { url
> }, Thread
>                      .currentThread().getContextClassLoader());
>
>              Thread test2 = new Thread(new Runnable() {
>
>                  public void run() {
>                      try {
>                          System.out.println("test2 classloader"
>                                  + Thread.currentThread()
>                                          .getContextClassLoader());
>                          FileOutputStream fos = new FileOutputStream(
>                                  "test2/jndi.properties");
>                          PrintStream ps = new PrintStream(fos);
>                          ps
>
> .println("
> java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory");
>
> ps.println("java.naming.provider.url=http://test2");
>                          ps.close();
>                          InitialContext context = new InitialContext();
>                          System.out.println("test2.context=    " +
> context);
>                          System.out.println("test2.context.env="
>                                  + context.getEnvironment());
>                      } catch (Exception e) {
>                          e.printStackTrace();
>                      }
>                  }
>
>              });
>
>              // use different classloader
>              test2.setContextClassLoader(clSrc);
>              test2.start();
>
> ===================end=================
> (I slightly modify MyDefaultInitialContextFactory, add environment
> values to MyInitialContext after initial)
>
> the output is below, using jre1.6.0:
>
> ============start output===============
>
> test1 classloaderjava.net.URLClassLoader@42e816
> test1.context=    javax.naming.InitialContext@60aeb0
>
> test1.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
> ,
> java.naming.provider.url=http://test1}
> test1.new.context=javax.naming.InitialContext@16caf43
>
> test1.new.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
> ,
> java.naming.provider.url=http://test1}
> test2 classloaderjava.net.URLClassLoader@8813f2
> test2.context=    javax.naming.InitialContext@1d58aae
>
> test2.context.env={java.naming.factory.initial=regis.jndi.MyDefaultInitialContextFactory
> ,
> java.naming.provider.url=http://test2}
>
> =============end output=================
>
> So under same classloader, ri just search property file once.
>
> In harmony we can use a map to hold property values for each classloader
> to avoid search at every construction time.
> But i found Harmony is still slower than ri at first time to constuct
> InitialContext object, the most time is consumed at
> org.apache.harmony.jndi.internal.EnvironmentReader line 233:
> p.load(is);


As for the performance issue in Properties.java, I think may be it's caused
by lack of cache. I am interested, and will look into the issue.
BTW, did you report a seperate JIRA for it?

Then i write some sample code to test performance of Properties.load():
>
> Properties pro = new Properties();
>           URL url = new
>
>
> URL("jar:file:/home/bahamut/harmony/trunk/deploy/jdk/jre/lib/boot/jndi.jar!/jndi.properties");
>           InputStream in = url.openStream();
>           long start = System.currentTimeMillis();
>           pro.load(in);
>           long end = System.currentTimeMillis();
>           System.out.println("time: " + (end - start));
>           in.close();
>
>           pro = new Properties();
>           url = new
>
>
> URL("jar:file:/home/bahamut/harmony/trunk/deploy/jdk/jre/lib/boot/jndi.jar!/jndi.properties");
>           in = url.openStream();
>           start = System.currentTimeMillis();
>           pro.load(in);
>           end = System.currentTimeMillis();
>           System.out.println("time: " + (end - start));
>           in.close();
>
> output of ri:
> time: 1
> time: 0
>
> output of harmony:
> time: 231
> time: 1
>
> Harmony is slower than ri *two hundred* times!!
> in above test, property file is in jndi.jar about 230k, if not in jar
> file, the time of harmony and ri are very close,
> so i think there must be some problems of archive module. Is it because
> of we using different algorithm with ri,
> or our implementation has bugs?
>
> Best Regards,
> Regis.
>



-- 
Spark Shen
China Software Development Lab, IBM