Re: Triq.hrl

17 views
Skip to first unread message

Kresten Krab Thorup

unread,
Dec 28, 2010, 2:37:16 AM12/28/10
to Pavlo Baron, Erik Søe Sørensen, erj...@googlegroups.com
Don't think there has ever been a proper way for this. Feel free to fix it. ej used to be called erl.sh, so it's a while since this worked.

At any rate it would be great to have these tests properly embedded in the CI setup on erjang01.hosted.netic.dk.

Also, I'd like it if you could include the erjang google group on discussions like these so people can search these q/a's in the future.

Kresten

Oh, btw. My gsm modem is only giving me 300 bytes/sec where I am now so I can't really do much right now...

On 28/12/2010, at 13.09, "Pavlo Baron" <p...@pbit.org> wrote:

> I think it wouldn't make much sense if I start doing
> -include_lib(include-path/file) where all other tests do -include(file).
> There must be a tri(q)c, and I'm missing it :) Maybe Kresten knows it :)
> At some point, I can do it in a dirty way and marry Triq with my erlang
> installation to get it done, but am still looking for a nice way.
>
> AllTests does run "perfectly" btw., but all miss Triq.hrl of course.
> What I get is the complete list of beam-jars.
>
> Running tests from the command line with run_erl_tests.sh isn't really
> an option, isn't it? This script changes into src/test/erl, compiles
> everything with standard erlc and tries to execute ./erl.sh. There is no
> script like that in the folder. Or should it somehow point to the
> ej(x)-variants?
>
> rgds
> Pavlo
>
> Am 28.12.2010 00:27, schrieb Erik Søe Sørensen:
>> Den 28-12-2010 00:12, Pavlo Baron skrev:
>>> Hi all,
>>>
>>> I have a quick question. After having prepared empty method bodies
>>> for all binary: methods throwing NotImplemented in the first step, I
>>> wanted to start implementing one method after another providing tests
>>> in parallel. The AllTests suite isn't green for me, and I can't
>>> manage to run the tests from the shell using the (bit broken?) shell
>>> test runner since the Triq.hrl is included without path as file
>>> include in the erl tests.
>>>
>>> Is it assumed to be in the same source folder? The code:add_path
>>> trick in the .erlang file doesn't work for me at least on
>>> Windows/Cygwin to make the missing path part visible. How do you
>>> manage to enable Triq for the tests? Wouldn't it make sense to make
>>> the include on the application level, such as?:
>>>
>>> -include_lib("triq/include/triq.hrl").
>> I think this would indeed be the correct solution.
>> I'm not sure those tests have ever worked with AllTests; I've run them
>> manually.
>> Probably, the test runner should be informed about the location of
>> Triq in some way - and skip those tests if Triq is not available.
>> To our defense, the tests in question are recent additions... and we
>> may still change to using a more general property checking tool.
>> I'll put doing something about the issue on my todo list...
>>
>>> well, the question might be naive - I don't know the infrastructure
>>> of the solution very well yet :)
>>>
>>> And the very question is: should I ask these questions per email or
>>> on the group?
>> I must confess I so far haven't followed the group; seeing that it's
>> not all spam these days it would probably be wise to do so... I just
>> fixed that.
>>
>> /Erik
>>
>

Pavlo Baron

unread,
Dec 28, 2010, 2:49:34 AM12/28/10
to Erjang
ok, I'm anyway at this spot during next days trying to get the tests
running and going to find a common solution for Triq include. I will
make a suggestion.

Erik Søe Sørensen

unread,
Dec 28, 2010, 5:12:39 AM12/28/10
to erj...@googlegroups.com
Great.
Some solutions I see are:
(a) assume that the environment variable TRIQ_HOME points to a triq installation, and add the proper "-I" flags when compiling.
(b) likewise, but with a symlink instead.
(c) Specify the include path in the ERL_COMPILER_OPTIONS variable, and the code path in ~/.erlang .

Pavlo Baron

unread,
Dec 28, 2010, 3:21:35 PM12/28/10
to Erjang
of course it cannot work when I set ERLL_COMPILER_OPTIONS=[{i,"..."}] :
((

one letter, and at least the triq include is working now, so it's the
option (c) from
your list without any code modification, of course - thx :)

in order to run AllTests, one can set ERL_COMPILER_OPTIONS as env
variable in Eclipse for the JUnit
runner, so one doesn't need to set it globally for the whole
environment. Shouldn't it generally be
documented somewhere, maybe in the README?

Option (a) would be interesting if we would like to control
compilation via configuration, don't you think?
Smth. real general in the config file, like:

erjang.app1.home=<path>
erjang.app2.home=<path>

which would then be understood by the compiler as the home of an OTP
application and used for the following parameters:

-pz <path>/ebin
-i <path>/include

if -pz or -pa, could also be configured if necessary. This way,
compiler could be extended with libs without the need to
configure the local environment (so you stay independent from erjang
in your erlang environment and don't switch users or play with shell
scripts/exports
or such), so all the libs could also be packaged with the erjang
distribution.

Just an idea - for the first step, Triq works for me :)

thx, rgds - Pavlo

Pavlo Baron

unread,
Dec 28, 2010, 8:10:01 PM12/28/10
to Erjang
found one example of how the tests are being executed right now incl.
triq dependencies

% ../../../ej -sname erj@mcilroy -pz ~/OSS/triq/ebin/ -other erl
% c(ets_test, [{i, "/home/erik/OSS/triq/include"}]).
% ets_test:main().

would have also worked for me for one single test file... :)

@Kresten: the Hudson job doesn't look like if it would run those
tests. I'm not allowed to look deeper,
but it's 100% sunshine :) Currently, the AllTests suite fails at 70%
of OTP compilation. I guess it would
make sense to split it into single tests and take it under ant's
control so Hudson can go on after
test errors, but count them (I remember it does this with the cloud
icon).
The split might be interesting to implement though.

Kresten Krab Thorup

unread,
Dec 28, 2010, 10:34:17 PM12/28/10
to erj...@googlegroups.com, Erjang
Yes. I think it would make sense to generate .java files - one for each triq or compiled beam file so that it works better with Hudson/junit test frameworks.

Kresten

Pavlo Baron

unread,
Dec 30, 2010, 4:13:48 AM12/30/10
to Erjang
I have implemented generation of test classes and pushed it to my
fork. Use the ant script, for example "ant test" generates all
classes, compiles and runs them. "ant gen-test-classes" would only
generate them to "src/test/java/erjang". Classes are not further
subpackaged/grouped. The question is: should this also be done
somehow? I have tested it as a whole from the ant script and as single
unit tests from IntelliJ. Both has worked.

Feedback is very welcome :)

Happy New Year!

On 29 Dez., 04:34, Kresten Krab Thorup <k...@trifork.com> wrote:
> Yes. I think it would make sense to generate .java files - one for each triq or compiled beam file so that it works better with Hudson/junit test frameworks.
>
> Kresten
>

Pavlo Baron

unread,
Dec 30, 2010, 6:38:56 PM12/30/10
to Erjang
Hi,

after having experimented with test cases, I have noticed that those
based on Triq are not really running. I get the following exception
for the most of them (those not implementing the test() function don't
work at all since it's expected by the run_wrapper - I think some
consolidation should be done there):

-------------------------snip-----------------------------------

31.12.2010 00:19:21 erjang.EModuleManager$FunctionInfo$1 invoke
INFO: failed to load error_logger:info_report/1
(error_handler:undefined_function/3 not found)
erjang.ErlangUndefined: undefined: error_logger:info_report/1
at erjang.EModuleManager$FunctionInfo$1.invoke(EModuleManager.java:
167)
at erjang.EFunHandler1.go(Unknown Source)
at erjang.EFunHandler1.invoke(Unknown Source)
at erjang.EFun1.invoke(Unknown Source)
at erjang.EProc.execute(EProc.java:486)
at kilim.Task._runExecute(Task.java:400)
at kilim.WorkerThread.run(WorkerThread.java:47)
erjang.ErlangUndefined: undefined: error_logger:info_report/1
at erjang.EModuleManager$FunctionInfo$1.invoke(EModuleManager.java:
167)
at erjang.EFunHandler1.go(Unknown Source)
at erjang.EFunHandler1.invoke(Unknown Source)
at erjang.EFun1.invoke(Unknown Source)
at erjang.EProc.execute(EProc.java:486)
at kilim.Task._runExecute(Task.java:400)
at kilim.WorkerThread.run(WorkerThread.java:47)

Process finished with exit code 0

-------------------------snap-----------------------------------

Somewhere some logging happens, but currently the error_logger isn't
really implemented. This code spot isn't that obvious, 'cause neither
the test under consideration (float_tests.erl) nor the run_wrapper
itself do any logging. Any idea where this logging can happen?

Thx, rgds
Pavlo

Pavlo Baron schrieb:

Kresten Krab Thorup

unread,
Dec 30, 2010, 9:54:36 PM12/30/10
to erj...@googlegroups.com, Erjang
Perhaps you can pull trifork/erjang and recommit because I cannot merge your brach.

Pavlo Baron

unread,
Dec 31, 2010, 3:19:25 AM12/31/10
to Erjang
done, sorry :)

If the merge still doesn't work, could you please paste what it
complains about? thx

On 31 Dez., 03:54, Kresten Krab Thorup <k...@trifork.com> wrote:
> Perhaps you can pull trifork/erjang and recommit because I cannot merge your brach.
>

Pavlo Baron

unread,
Jan 1, 2011, 3:27:27 PM1/1/11
to Erjang
stupid me as I assumed that this logging could only happen in a bif :
( Well, still learning a lot about Erjang every day :) It must be in
the Erlang code, weird that it doesn't find error_logger:info_report/
1. But I think I could try to analyze it now.

On 31 Dez. 2010, 03:54, Kresten Krab Thorup <k...@trifork.com> wrote:
> Perhaps you can pull trifork/erjang and recommit because I cannot merge your brach.
>

Pavlo Baron

unread,
Jan 1, 2011, 6:18:41 PM1/1/11
to Erjang
ok, that was an easy one - own blindness. I just had to include
~/.erjang/*.jar to the classpath for the tests. I have commited the
new build.xml with the fix to my fork (in an IDE, same has to be done
of course).
But now it complains about missing erjang/EFun2 (I don't see this
class anywhere):

testwoven:
[echo] Testing Tasks ======================
[junit] Testsuite: erjang.sizes_tests_erl_TEST
[junit] junit.framework.TestListener: addError(c:\Users\pb\code\ex
\erjang\sr
c\test\erl\sizes_tests.erl, erjang/EFun2)
[junit] Tests run: 1, Failures: 0, Errors: 1, Time elapsed: 1,298
sec
[junit]
[junit] ------------- Standard Output ---------------
[junit] ------------- ---------------- ---------------
[junit] Testcase: compiling and running sizes_tests.erl: Caused
an ERROR
[junit] erjang/EFun2
[junit] java.lang.NoClassDefFoundError: erjang/EFun2
[junit] at java.lang.ClassLoader.defineClass1(Native Method)
[junit] at
java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
[junit] at java.lang.ClassLoader.defineClass(ClassLoader.java:
616)
[junit] at
java.security.SecureClassLoader.defineClass(SecureClassLoader
.java:141)
[junit] at
java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
[junit] at java.net.URLClassLoader.access
$000(URLClassLoader.java:58)
[junit] at java.net.URLClassLoader$1.run(URLClassLoader.java:
197)
[junit] at java.security.AccessController.doPrivileged(Native
Method)
[junit] at
java.net.URLClassLoader.findClass(URLClassLoader.java:190)
[junit] at java.lang.ClassLoader.loadClass(ClassLoader.java:
307)
[junit] at sun.misc.Launcher
$AppClassLoader.loadClass(Launcher.java:301)

[junit] at java.lang.ClassLoader.loadClass(ClassLoader.java:
248)
[junit] at java.lang.Class.getDeclaredConstructors0(Native
Method)
[junit] at
java.lang.Class.privateGetDeclaredConstructors(Class.java:238
9)
[junit] at java.lang.Class.getConstructor0(Class.java:2699)
[junit] at java.lang.Class.newInstance0(Class.java:326)
[junit] at java.lang.Class.newInstance(Class.java:308)
[junit] at
erjang.EModuleLoader.load_compiled_module(EModuleLoader.java:
158)
[junit] at erjang.EModuleLoader.load_module(EModuleLoader.java:
84)
[junit] at erjang.EModuleLoader.load_module(EModuleLoader.java:
65)
[junit] at
erjang.EModuleLoader.find_and_load_module(EModuleLoader.java:
61)
[junit] at erjang.TestRunFile.load(TestRunFile.java:152)
[junit] at erjang.TestRunFile.run(TestRunFile.java:126)
[junit] Caused by: java.lang.ClassNotFoundException: erjang.EFun2
[junit] at java.net.URLClassLoader$1.run(URLClassLoader.java:
202)
[junit] at java.security.AccessController.doPrivileged(Native
Method)
[junit] at
java.net.URLClassLoader.findClass(URLClassLoader.java:190)
[junit] at java.lang.ClassLoader.loadClass(ClassLoader.java:
307)
[junit] at sun.misc.Launcher
$AppClassLoader.loadClass(Launcher.java:301)

[junit] at java.lang.ClassLoader.loadClass(ClassLoader.java:
248)
[junit]
[junit]
[junit] Test erjang.sizes_tests_erl_TEST FAILED
> ...
>
> Erfahren Sie mehr »

Pavlo Baron

unread,
Jan 2, 2011, 3:20:02 AM1/2/11
to Erjang
ok, got it - it's the EModuleClassLoader who should find those ETupleX
and EFunX but who seems to be broken in case of unit tests being
executed separately. I'll try to fix it.
> ...
>
> Erfahren Sie mehr »

Pavlo Baron

unread,
Jan 2, 2011, 12:51:54 PM1/2/11
to Erjang
ok, I have pushed a fix to my fork. That was quite tricky, and I am
not very happy with the solution to be honest. Please read the long
comment in TestRunFile.run.
Right now, I am preloading half the world. init:boot/1 does it
selectively, so in my case I go up to a _lot_ of PermGen space only to
run one test. As I wrote there, I
think it would make sense to execute ej with -s args instead of
simulating it within the run() method. This way, init:boot would load
only what it needs.

Furthermore, run_wrapper exits abnormally in case of erjang - even
with correct results. As far as I can see it runs into the catch block
in the run method without any chance to compare results. I will try to
fix this spot
in the next run, too.

Feedback is of course very welcome - it is very possible that I just
did nonsense there :) I've been especially looking for the spot with
the logic to dynamically compile/load a jar-beam when it's yet
unloaded, but couldn't find any. So maybe I have just overseen smth...

rgds
Pavlo
> ...
>
> Erfahren Sie mehr »

Pavlo Baron

unread,
Jan 3, 2011, 1:39:08 PM1/3/11
to Erjang
after having read a little (learned a little :) ), I see that there is
no real mystery in what happens there. What we would need - if we
don't start the run_wrapper using the ej shell, is the simulation of
the application loading taking place in init:do_boot/3 (without
start_em tail call). It just reads in the boot script and runs it.
Currently, in my configuration, only kernel and stdlib are getting
loaded, with the relevant corresponding modules. These are _far_ less
than what I'm loading traversing the lib folder of the Erlang
installation. A very pragmatic/spartanic way could also be to load
only those modules for the tests.
> ...
>
> Erfahren Sie mehr »

Erik Søe Sørensen

unread,
Jan 3, 2011, 3:57:00 PM1/3/11
to erj...@googlegroups.com

A solution I have considered is to add to the relevant modules an attribute listing the modules it depends on. Either the wrapper or the Java part could then ensure that these modules are loaded.

Pavlo Baron

unread,
Jan 3, 2011, 4:16:20 PM1/3/11
to Erjang
I'm not sure an additional static accounting for module dependencies
would be easily maintainable, but maybe I'm wrong. What could be cool
is to find out dynamically what imports and applies are in there and
load those modules, but this is quite a bigger effort :)
Alternatively, we could just do the same thing Erlang does or Java app
servers do - we preload modules/classes which are explicitly
configured.

But hey, whatever it is - it is much better than preloading the
universe like I currently do with the first test :D

On 3 Jan., 21:57, Erik Søe Sørensen <erik...@gmail.com> wrote:
> A solution I have considered is to add to the relevant modules an attribute
> listing the modules it depends on. Either the wrapper or the Java part could
> then ensure that these modules are loaded.
> one for each triq or compiled beam ...
>
> Erfahren Sie mehr »

Erik Søe Sørensen

unread,
Jan 3, 2011, 4:24:46 PM1/3/11
to erj...@googlegroups.com

Installing a suitable function-not-found handler isn't an option? Of course, there may still be services which need starting, but it would be a start.

Pavlo Baron

unread,
Jan 3, 2011, 4:44:46 PM1/3/11
to Erjang
how would this work? when a function call fails, first try to load a
module including this function before definitely failing? I've been
looking for this logic in the code base hoping to find it somewhere...
If it isn't implemented yet, such a logic would be very mighty of
course

On 3 Jan., 22:24, Erik Søe Sørensen <erik...@gmail.com> wrote:
> Installing a suitable function-not-found handler isn't an option? Of course,
> there may still be services which need starting, but it would be a start.
> ...
>
> Erfahren Sie mehr »

Erik Søe Sørensen

unread,
Jan 4, 2011, 8:18:09 PM1/4/11
to erj...@googlegroups.com
I'll see if I can follow the trace...:

* If a function call fails, because the function does not exist, in both
Erlang and Erjang what happens is that
error_handler:undefined_function/3 is called - if it exists.
* In Erjang, this is done in EModuleManager (look for occurrences of
"undefined_function").
* The default error_handler module is in the 'kernel' part of OTP.
undefined_function() calls ensure_loaded(), which checks for the
presence of a 'code_server' process;
if a code server exists, code:ensure_loaded() is called, otherwise
init:ensure_loaded() is called.

We'll probably try to imitate the simpler case, init, and disregard most
of the error handling:
* init:ensure_loaded calls (via load_mod()) first
erl_prim_loader:get_file(), then (via load_mod_code()) erlang:load_module().
Using these two functions, along with some logic to determine the file
name, should be all that's needed to load a module.

Den 03-01-2011 22:44, Pavlo Baron skrev:
> how would this work? when a function call fails, first try to load a
> module including this function before definitely failing? I've been
> looking for this logic in the code base hoping to find it somewhere...
> If it isn't implemented yet, such a logic would be very mighty of
> course
>

> On 3 Jan., 22:24, Erik S�e S�rensen<erik...@gmail.com> wrote:
>> Installing a suitable function-not-found handler isn't an option? Of course,
>> there may still be services which need starting, but it would be a start.
>> Den 03/01/2011 22.16 skrev "Pavlo Baron"<pbit....@googlemail.com>:
>>
>>> I'm not sure an additional static accounting for module dependencies
>>> would be easily maintainable, but maybe I'm wrong. What could be cool
>>> is to find out dynamically what imports and applies are in there and
>>> load those modules, but this is quite a bigger effort :)
>>> Alternatively, we could just do the same thing Erlang does or Java app
>>> servers do - we preload modules/classes which are explicitly
>>> configured.

[snip]

Pavlo Baron

unread,
Jan 5, 2011, 3:36:41 AM1/5/11
to Erjang
got it. Can be done. Would you like to implement it, or should I?

On 5 Jan., 02:18, Erik Søe Sørensen <erik...@gmail.com> wrote:
> I'll see if I can follow the trace...:
>
> * If a function call fails, because the function does not exist, in both
> Erlang and Erjang what happens is that
> error_handler:undefined_function/3 is called - if it exists.
> * In Erjang, this is done in EModuleManager (look for occurrences of
> "undefined_function").
> * The default error_handler module is in the 'kernel' part of OTP.
>    undefined_function() calls ensure_loaded(), which checks for the
> presence of a 'code_server' process;
>    if a code server exists, code:ensure_loaded() is called, otherwise
> init:ensure_loaded() is called.
>
> We'll probably try to imitate the simpler case, init, and disregard most
> of the error handling:
> * init:ensure_loaded calls (via load_mod()) first
> erl_prim_loader:get_file(), then (via load_mod_code()) erlang:load_module().
> Using these two functions, along with some logic to determine the file
> name, should be all that's needed to load a module.
>
> Den 03-01-2011 22:44, Pavlo Baron skrev:
>
> > how would this work? when a function call fails, first try to load a
> > module including this function before definitely failing? I've been
> > looking for this logic in the code base hoping to find it somewhere...
> > If it isn't implemented yet, such a logic would be very mighty of
> > course
>
> > On 3 Jan., 22:24, Erik S�e S�rensen<erik...@gmail.com>  wrote:

Kresten Krab Thorup

unread,
Jan 5, 2011, 3:56:41 AM1/5/11
to erj...@googlegroups.com, eri...@gmail.com, pbit...@googlemail.com
AFAIK this code was written before Erjang was booting OTP, and so it was fairly convoluted becuase it had to emulate much of the error handler stuff that is normally part of OTP. Perhaps now that we're this far, it would make more sense to run these teses somehow in context of Erjang/OTP, and thus so that the normal error_handler module can do it's thing?

Perhaps by somehow generating a .java JUnit test for each .erl test script, which launches ej ?
Just an idea.

Kresten
________________________________________
Fra: erj...@googlegroups.com [erj...@googlegroups.com] P&#229; vegne af Pavlo Baron [pbit...@googlemail.com]
Sendt: 5. januar 2011 09:36
Til: Erjang
Emne: [erjang] Re: Triq.hrl

pbit...@googlemail.com

unread,
Jan 5, 2011, 4:25:32 AM1/5/11
to Kresten Krab Thorup, erj...@googlegroups.com, eri...@gmail.com
Would be the best for the unit tests - I think, this option is somewhere in this thread. Dynamic code loading is what we ended with and is also cool :) I'll try to fix it using ej and collect what it's missing to run the wrapper adequately. Right now, I need 5 min for a simple unit test to run on my quadcore :)
Von meinem drahtlosen BlackBerry®-Handheld gesendet

Erik Søe Sørensen

unread,
Jan 5, 2011, 5:10:25 AM1/5/11
to erj...@googlegroups.com
I'm not sure about booting all of OTP for each test - especially
combined with the "start Erjang afresh for each test" approach.
For one thing, the boot process isn't particularly speedy at the moment.
For another, it makes the tests less unit-ish and less simple -
simplicity is a good thing when it comes to debugging.

Of course, at the moment the predominant part of the testing time is the
compilation tests, which is a different kind of fish iirc. (Not sure if
they are still as relevant they used to be, by the way.)

start.script is interesting to read in this context. error_handler is
the only module which is part of the kernel proper but not preloaded, so
maybe it is enough to just load that one manually.
Otherwise, yes, we can boot OTP, perhaps with timeusing pruned boot script.

Den 05-01-2011 10:25, pbit...@googlemail.com skrev:
> Would be the best for the unit tests - I think, this option is somewhere in this thread. Dynamic code loading is what we ended with and is also cool :) I'll try to fix it using ej and collect what it's missing to run the wrapper adequately. Right now, I need 5 min for a simple unit test to run on my quadcore :)

> Von meinem drahtlosen BlackBerry�-Handheld gesendet


>
> -----Original Message-----
> From: Kresten Krab Thorup<kr...@trifork.com>
> Date: Wed, 5 Jan 2011 09:56:41
> To: erj...@googlegroups.com<erj...@googlegroups.com>
> Cc: eri...@gmail.com<eri...@gmail.com>; pbit...@googlemail.com<pbit...@googlemail.com>
> Subject: SV: [erjang] Re: Triq.hrl
>
> AFAIK this code was written before Erjang was booting OTP, and so it was fairly convoluted becuase it had to emulate much of the error handler stuff that is normally part of OTP. Perhaps now that we're this far, it would make more sense to run these teses somehow in context of Erjang/OTP, and thus so that the normal error_handler module can do it's thing?
>
> Perhaps by somehow generating a .java JUnit test for each .erl test script, which launches ej ?
> Just an idea.
>
> Kresten
> ________________________________________
> Fra: erj...@googlegroups.com [erj...@googlegroups.com] P&#229; vegne af Pavlo Baron [pbit...@googlemail.com]
> Sendt: 5. januar 2011 09:36
> Til: Erjang
> Emne: [erjang] Re: Triq.hrl
>
> got it. Can be done. Would you like to implement it, or should I?
>

pbit...@googlemail.com

unread,
Jan 5, 2011, 5:31:24 AM1/5/11
to erj...@googlegroups.com
I think both is necessary and a bit different. For the triq test it would be sufficient to run erl and ej on command line and compare results. Any optimization which helps reduce startup time of ej and makes it more flexible such as dynamic code loading, alternative start scripts etc does automatically improve it, also for tests
Von meinem drahtlosen BlackBerry®-Handheld gesendet

-----Original Message-----
From: Erik Søe Sørensen <eri...@gmail.com>
Sender: erj...@googlegroups.com
Date: Wed, 05 Jan 2011 11:10:25
To: erj...@googlegroups.com<erj...@googlegroups.com>
Reply-To: erj...@googlegroups.com
Subject: Re: AW: SV: [erjang] Re: Triq.hrl

I'm not sure about booting all of OTP for each test - especially
combined with the "start Erjang afresh for each test" approach.
For one thing, the boot process isn't particularly speedy at the moment.
For another, it makes the tests less unit-ish and less simple -
simplicity is a good thing when it comes to debugging.

Of course, at the moment the predominant part of the testing time is the
compilation tests, which is a different kind of fish iirc. (Not sure if
they are still as relevant they used to be, by the way.)

start.script is interesting to read in this context. error_handler is
the only module which is part of the kernel proper but not preloaded, so
maybe it is enough to just load that one manually.
Otherwise, yes, we can boot OTP, perhaps with timeusing pruned boot script.

Den 05-01-2011 10:25, pbit...@googlemail.com skrev:
> Would be the best for the unit tests - I think, this option is somewhere in this thread. Dynamic code loading is what we ended with and is also cool :) I'll try to fix it using ej and collect what it's missing to run the wrapper adequately. Right now, I need 5 min for a simple unit test to run on my quadcore :)
> Von meinem drahtlosen BlackBerry®-Handheld gesendet
>
> -----Original Message-----
> From: Kresten Krab Thorup<kr...@trifork.com>
> Date: Wed, 5 Jan 2011 09:56:41
> To: erj...@googlegroups.com<erj...@googlegroups.com>
> Cc: eri...@gmail.com<eri...@gmail.com>; pbit...@googlemail.com<pbit...@googlemail.com>
> Subject: SV: [erjang] Re: Triq.hrl
>
> AFAIK this code was written before Erjang was booting OTP, and so it was fairly convoluted becuase it had to emulate much of the error handler stuff that is normally part of OTP. Perhaps now that we're this far, it would make more sense to run these teses somehow in context of Erjang/OTP, and thus so that the normal error_handler module can do it's thing?
>
> Perhaps by somehow generating a .java JUnit test for each .erl test script, which launches ej ?
> Just an idea.
>
> Kresten
> ________________________________________
> Fra: erj...@googlegroups.com [erj...@googlegroups.com] P&#229; vegne af Pavlo Baron [pbit...@googlemail.com]
> Sendt: 5. januar 2011 09:36
> Til: Erjang
> Emne: [erjang] Re: Triq.hrl
>
> got it. Can be done. Would you like to implement it, or should I?
>

Pavlo Baron

unread,
Jan 5, 2011, 4:39:16 PM1/5/11
to Erjang
implementing the call/comparison of erl and ej in TestRunFile now. I
see that both results are different since ej throws undefined
functions. As soon as it's done we can have a look at which functions
these are (for float, maybe some transformations between float and
string etc.)

On 5 Jan., 11:31, pbit....@googlemail.com wrote:
> I think both is necessary and a bit different. For the triq test it would be sufficient to run erl and ej on command line and compare results. Any optimization which helps reduce startup time of ej and makes it more flexible such as dynamic code loading, alternative start scripts etc does automatically improve it, also for tests
> Von meinem drahtlosen BlackBerry®-Handheld gesendet
>
> -----Original Message-----
> From: Erik Søe Sørensen <erik...@gmail.com>
>
> Sender: erj...@googlegroups.com
> Date: Wed, 05 Jan 2011 11:10:25
> To: erj...@googlegroups.com<erj...@googlegroups.com>
> Reply-To: erj...@googlegroups.com
> Subject: Re: AW: SV: [erjang] Re: Triq.hrl
>
> I'm not sure about booting all of OTP for each test - especially
> combined with the "start Erjang afresh for each test" approach.
> For one thing, the boot process isn't particularly speedy at the moment.
> For another, it makes the tests less unit-ish and less simple -
> simplicity is a good thing when it comes to debugging.
>
> Of course, at the moment the predominant part of the testing time is the
> compilation tests, which is a different kind of fish iirc. (Not sure if
> they are still as relevant they used to be, by the way.)
>
> start.script is interesting to read in this context. error_handler is
> the only module which is part of the kernel proper but not preloaded, so
> maybe it is enough to just load that one manually.
> Otherwise, yes, we can boot OTP, perhaps with timeusing pruned boot script.
>
> Den 05-01-2011 10:25, pbit....@googlemail.com skrev:
> > Would be the best for the unit tests - I think, this option is somewhere in this thread. Dynamic code loading is what we ended with and is also cool :) I'll try to fix it using ej and collect what it's missing to run the wrapper adequately. Right now, I need 5 min for a simple unit test to run on my quadcore :)
> > Von meinem drahtlosen BlackBerry®-Handheld gesendet
>
> > -----Original Message-----
> > From: Kresten Krab Thorup<k...@trifork.com>
> > Date: Wed, 5 Jan 2011 09:56:41
> > To: erj...@googlegroups.com<erj...@googlegroups.com>
> > Cc: erik...@gmail.com<erik...@gmail.com>; pbit....@googlemail.com<pbit....@googlemail.com>
> > Subject: SV: [erjang] Re: Triq.hrl
>
> > AFAIK this code was written before Erjang was booting OTP, and so it was fairly convoluted becuase it had to emulate much of the error handler stuff that is normally part of OTP.  Perhaps now that we're this far, it would make more sense to run these teses somehow in context of Erjang/OTP, and thus so that the normal error_handler module can do it's thing?
>
> > Perhaps by somehow generating a .java JUnit test for each .erl test script, which launches ej ?
> >    Just an idea.
>
> > Kresten
> > ________________________________________
> > Fra: erj...@googlegroups.com [erj...@googlegroups.com] P&#229; vegne af Pavlo Baron [pbit....@googlemail.com]

Pavlo Baron

unread,
Jan 6, 2011, 7:25:37 AM1/6/11
to Erjang
implemented and pushed to github. Each .erl test now needs just
seconds to run, and for sure much less PermGen space (going to play
with the settings later)

:)

PS: please do a Unix test - I only did Cygwin yet. Neet to setup the
whole environment on my FreeBSD box or in a VirtualBox... Thx

On 5 Jan., 11:31, pbit....@googlemail.com wrote:
> I think both is necessary and a bit different. For the triq test it would be sufficient to run erl and ej on command line and compare results. Any optimization which helps reduce startup time of ej and makes it more flexible such as dynamic code loading, alternative start scripts etc does automatically improve it, also for tests
> Von meinem drahtlosen BlackBerry®-Handheld gesendet
>
> -----Original Message-----
> From: Erik Søe Sørensen <erik...@gmail.com>
>
> Sender: erj...@googlegroups.com
> Date: Wed, 05 Jan 2011 11:10:25
> To: erj...@googlegroups.com<erj...@googlegroups.com>
> Reply-To: erj...@googlegroups.com
> Subject: Re: AW: SV: [erjang] Re: Triq.hrl
>
> I'm not sure about booting all of OTP for each test - especially
> combined with the "start Erjang afresh for each test" approach.
> For one thing, the boot process isn't particularly speedy at the moment.
> For another, it makes the tests less unit-ish and less simple -
> simplicity is a good thing when it comes to debugging.
>
> Of course, at the moment the predominant part of the testing time is the
> compilation tests, which is a different kind of fish iirc. (Not sure if
> they are still as relevant they used to be, by the way.)
>
> start.script is interesting to read in this context. error_handler is
> the only module which is part of the kernel proper but not preloaded, so
> maybe it is enough to just load that one manually.
> Otherwise, yes, we can boot OTP, perhaps with timeusing pruned boot script.
>
> Den 05-01-2011 10:25, pbit....@googlemail.com skrev:
> > Would be the best for the unit tests - I think, this option is somewhere in this thread. Dynamic code loading is what we ended with and is also cool :) I'll try to fix it using ej and collect what it's missing to run the wrapper adequately. Right now, I need 5 min for a simple unit test to run on my quadcore :)
> > Von meinem drahtlosen BlackBerry®-Handheld gesendet
>
> > -----Original Message-----
> > From: Kresten Krab Thorup<k...@trifork.com>
> > Date: Wed, 5 Jan 2011 09:56:41
> > To: erj...@googlegroups.com<erj...@googlegroups.com>
> > Cc: erik...@gmail.com<erik...@gmail.com>; pbit....@googlemail.com<pbit....@googlemail.com>
> > Subject: SV: [erjang] Re: Triq.hrl
>
> > AFAIK this code was written before Erjang was booting OTP, and so it was fairly convoluted becuase it had to emulate much of the error handler stuff that is normally part of OTP.  Perhaps now that we're this far, it would make more sense to run these teses somehow in context of Erjang/OTP, and thus so that the normal error_handler module can do it's thing?
>
> > Perhaps by somehow generating a .java JUnit test for each .erl test script, which launches ej ?
> >    Just an idea.
>
> > Kresten
> > ________________________________________
> > Fra: erj...@googlegroups.com [erj...@googlegroups.com] P&#229; vegne af Pavlo Baron [pbit....@googlemail.com]

Erik Søe Sørensen

unread,
Jan 18, 2011, 5:31:50 PM1/18/11
to erj...@googlegroups.com, Kresten Krab Thorup
On 05-01-2011 11:31, pbit...@googlemail.com wrote:
[snip]

> Any optimization which helps reduce startup time of ej and makes it more flexible such as dynamic code loading, alternative start scripts etc does automatically improve it, also for tests
Out of curiousity I just tried to time the contribution of the different
parts of the module loading process.

From an empty cache (i.e. compilation needed), the figures say 45% of
the module loading time is compilation; 20% is class loading; and 25% is
module instantiation.

From a populated .erjang cache (no compilation needed) it's 11% class
loading and 88% instantiation.

It is thus rather interesting what's expensive about EModule
instantiation, and whether anything can be done about it.
Only 30% of it is binding, i.e. spent in EModuleManager.setup_module().
Possibly it's classloading of other classes than the EModule
representing the module.

-- Further investigation confirms that much of the time is indeed spent
between the start of the clazz.newInstance() call in EModuleLoader and
the beginning of the static initializer for the module class (the
EModule subclass).
I don't know if the time consumer is a lazy part of the class loading of
the module class or if it's loading of the dependencies (mainly EFun
subclasses).
Some time measurements seem to indicate that it's more related to the
size or the jar file for the module than to the number of classes
therein; at first I thought that that would indicate that it had to do
with loading of the module class, but I'm no longer sure whether you can
conclude that, though, given that decompression of the jar file might
make its size count against loading the EFun subclasses as well.

In any case, I think these measurements mean that we can't cut down much
on boot time unless we can either
- avoid loading the majority of these classes - the ones representing
function objects - eagerly.
- cut down on the classes' size and/or complexity.

(Class files for mobile devices contain type information that reduces
load time, because the bytecode verifier won't have to reconstruct that
info - I wonder if Java SE supports that, and if there's a potential
gain there.)

As for avoiding to load all of the EFun subclasses eagerly, some
possible solutions are:
(1) Keep the singleton fields, but initialize them lazily.
(2) Move the singletons to their respective classes.
(3) Don't have the singletons - create new objects instead as needed.

I think (2) is the most interesting option.

As for cutting down on size and complexity:
It appears to be the case that there is much common/boilerplate code in
the EFun subclasses representing lambdas; collecting this in common
superclasses might help a bit.
And in all the EFun subclasses, the bulk of the code is kilim expansion
of a very simple wrapper; at a glance, the expansion appears to be the
same except for a single call. Would be nice if we could keep the common
code (if it is necessary at all, weaving-wise) in a common superclass
("Template Method", I think) as one would usually do; the difficult part
about that is getting kilim to play along...

/Erik

Pavlo Baron

unread,
Jan 19, 2011, 1:32:21 AM1/19/11
to erj...@googlegroups.com
interesting analysis!

IMHO, when we would touch this spot, we really should consider:

(1) dropping the god ECompiledModule class
(2) moving the static EFun classes out of the god class up to the top
level as _small_single_ classes
(3) as you said, trying to collect as much as possible of the common
code in a common abstraction deriving the EFuns from it
(4) interpreting the jar as compiled module instead since it's a much
more native java concept and is just a container without any obligations
except unzipping, which has already to be done. With some MANIFEST
information if necessary. Well, reading MANIFEST doesn't _really_ spead
up the loading time, so we might avoid it :)
(5) not having a jar at all and have only .class files in the cache.
Module could be a prefix in the file name
(6) working with a very "small" start script, loading as many EFuns as
possible lazily instead

Hm, but this is a sort of revolution compared to now, and for sure a
huge violation of kilim :). But I think the loading time could be
increased or at least we might have more adjustment screws for it...

rgds
Pavlo

Kresten Krab Thorup

unread,
Jan 19, 2011, 2:24:56 AM1/19/11
to erj...@googlegroups.com, erj...@googlegroups.com
I have noticed that the kilim weaver is running as part of start up to create some EFun objects for BIFs. Kilim is pretty slow. Those should also be cached.

Kresten

On 19/01/2011, at 07.31, "Pavlo Baron" <pbit...@googlemail.com> wrote:

> interesting analysis!
>
> IMHO, when we would touch this spot, we really should consider:
>
> (1) dropping the god ECompiledModule class
> (2) moving the static EFun classes out of the god class up to the top
> level as _small_single_ classes
> (3) as you said, trying to collect as much as possible of the common
> code in a common abstraction deriving the EFuns from it
> (4) interpreting the jar as compiled module instead since it's a much
> more native java concept and is just a container without any obligations
> except unzipping, which has already to be done. With some MANIFEST
> information if necessary. Well, reading MANIFEST doesn't _really_ spead
> up the loading time, so we might avoid it :)
> (5) not having a jar at all and have only .class files in the cache.
> Module could be a prefix in the file name
> (6) working with a very "small" start script, loading as many EFuns as
> possible lazily instead
>
> Hm, but this is a sort of revolution compared to now, and for sure a
> huge violation of kilim :). But I think the loading time could be
> increased or at least we might have more adjustment screws for it...
>
> rgds
> Pavlo
>

pbit...@googlemail.com

unread,
Jan 19, 2011, 3:21:00 AM1/19/11
to erj...@googlegroups.com
Concerning my (5)

Since it can be many class files, module name could be used as folder to group classes and thus to group inodes instead
Von meinem drahtlosen BlackBerry®-Handheld gesendet

-----Original Message-----
From: Kresten Krab Thorup <kr...@trifork.com>
Sender: erj...@googlegroups.com
Date: Wed, 19 Jan 2011 08:24:56
To: erj...@googlegroups.com<erj...@googlegroups.com>
Reply-To: erj...@googlegroups.com

Erik Søe Sørensen

unread,
Jan 19, 2011, 5:00:31 AM1/19/11
to erj...@googlegroups.com
Den 19-01-2011 07:32, Pavlo Baron skrev:
> interesting analysis!
>
> IMHO, when we would touch this spot, we really should consider:
>
> (1) dropping the god ECompiledModule class
> (2) moving the static EFun classes out of the god class up to the top
> level as _small_single_ classes
You mean generating the code such that the actual code is generated as
methods of different classes rather than different methods of the same
class?
Apart from breaking the "modules are loaded atomically" semantics of
Erlang, I think this might be detrimental to normal performance (might
break JIT optimizations).
A minor point is that'd still have to have the binding stuff somewhere,
so we'd probably still need to have some class representing the module.

> (3) as you said, trying to collect as much as possible of the common
> code in a common abstraction deriving the EFuns from it

> (4) interpreting the jar as compiled module instead since it's a much
> more native java concept and is just a container without any
> obligations except unzipping, which has already to be done.

Not sure what you mean by this; isn't this what we're already doing?


> With some MANIFEST information if necessary. Well, reading MANIFEST
> doesn't _really_ spead up the loading time, so we might avoid it :)

> (5) not having a jar at all and have only .class files in the cache.
> Module could be a prefix in the file name

I was going to raise the "many files in one directory is bad issue", but
you already addressed this yourself.
However: the current grouping of module classes is nice I think - we
have one module ~ one beam file ~ one jar file; no risk of intra-module
inconsistencies.
More to the point, the amount of I/O would increase significantly. At
present we have about 10MB to load; if I unzip the jar files it becomes
30MB. (For filesystem-independent numbers, it's 10MB vs. 18MB if you
just add the file sizes.)
Decompressing is probably preferable to increasing the amount of I/O.

> (6) working with a very "small" start script, loading as many EFuns as
> possible lazily instead

That's actually two things: Lazy EFun loading on the Erjang level, and
loading less modules on the Erlang level :-)

> Hm, but this is a sort of revolution compared to now, and for sure a
> huge violation of kilim :). But I think the loading time could be
> increased or at least we might have more adjustment screws for it...

Regarding kilim, I've come to the conclusion that what we want in the
modules' EFun classes is near to what kilim should want as a feature
anyway: that wrapper methods are translated into wrapper methods,
without code explosion. Having that feature should benefit kilim
performance in general.
(Only problem as I see it is a technical soundness issue in the case
where wrapper calls wrapper in infinite recursion. This might have to be
handled somehow. Or maybe not - StackOverflowException might save us,
which is a rare occurrence...)

/Erik

pbit...@googlemail.com

unread,
Jan 19, 2011, 5:56:13 AM1/19/11
to erj...@googlegroups.com
What I mean with small classes: no wrapping module class at all. EFun classes as top level, separate classes, which are loaded only when they are needed

What I mean with start script: as far as I see it, kernel and stdlib with many included modules as configured in my Erlang are loaded _immidiately_ in Erjang, EFun singletons are instantiated immidiately. Don't have the code here, don't remember it 100%. I thought you've been speaking of the loading time as an issue, so I've pointed this spot as a candidate for optimization.

I/O: I think this is more of a phylosophical discussion, isn't it? :) Dropping decompression reduces loading time, with drawbacks

What I have suggested - just as an idea - is to have an EFun as a separate class file in a module folder. When I need it, I pick it on function_undefined for the most of funs. Quickly, easily. I think so :)

Well, I'm not that deep in kilim yet, can't say much about it

Pavlo
Von meinem drahtlosen BlackBerry®-Handheld gesendet

-----Original Message-----
From: Erik Søe Sørensen <eri...@gmail.com>
Sender: erj...@googlegroups.com

Erik Søe Sørensen

unread,
Jan 19, 2011, 5:01:51 PM1/19/11
to erj...@googlegroups.com
Disk I/O is expensive, time-wise - more so than decompression.

Realistic numbers for loading OTP:
Reading in all of the jar files in ~/erjang takes here 3.8 seconds;
if I uncompress them and read in all of the resulting files, it takes
14.3 seconds.
(Both tests done from cold file cache.)
This means that I/O is a significant factor.

So replacing the jar system with single-class files is a bet that for
e.g. booting OTP you will need less than a third of the functions.
Which is not impossible, of course; I have little idea how much is
really used.
(I would think, though, that almost all parts of the loaded kernel
modules are used - and that's a good fourth.)

Den 19-01-2011 11:56, pbit...@googlemail.com wrote:
[snip]


> I/O: I think this is more of a phylosophical discussion, isn't it? :) Dropping decompression reduces loading time, with drawbacks
>

> -----Original Message-----
> From: Erik S�e S�rensen<eri...@gmail.com>
> Sender: erj...@googlegroups.com
> Date: Wed, 19 Jan 2011 11:00:31
> To:<erj...@googlegroups.com>
> Reply-To: erj...@googlegroups.com
> Subject: [erjang] Re: [erjang-dev] Module loading time analysis
[snip]
>> (5) not having a jar at all and have only .class files in the cache.
>> Module could be a prefix in the file name
> I was going to raise the "many files in one directory is bad issue", but
> you already addressed this yourself.
> However: the current grouping of module classes is nice I think - we
> have one module ~ one beam file ~ one jar file; no risk of intra-module
> inconsistencies.
> More to the point, the amount of I/O would increase significantly. At
> present we have about 10MB to load; if I unzip the jar files it becomes
> 30MB. (For filesystem-independent numbers, it's 10MB vs. 18MB if you
> just add the file sizes.)
> Decompressing is probably preferable to increasing the amount of I/O.

[snip]

Erik Søe Sørensen

unread,
Jan 19, 2011, 6:10:06 PM1/19/11
to erj...@googlegroups.com
Den 19-01-2011 11:00, Erik S�e S�rensen skrev:
> Regarding kilim, I've come to the conclusion that what we want in the
> modules' EFun classes is near to what kilim should want as a feature
> anyway: that wrapper methods are translated into wrapper methods,
> without code explosion. Having that feature should benefit kilim
> performance in general.

And looking further into it, I realize that kilim actually has reasons
for what it does here:
The expanded function (foo$FN_bar__n.invoke(EProc, EObject1, ...,
EObjectN, kilim.Fiber) is not just a wrapper function, but has
additionally a loop for doing tail call optimization.
This causes it to have state to be saved: The EProc. (This would go away
if the EProc and Fiber arguments were to be merged, which would be nice
in general... if for no other additional reason, then because each stack
frame of a process at present has to contain a reference to the same
EProc instance.)

So as far as code size is concerned, a possible low-hanging fruit is to
move this loop into the common EFun superclasses. I'll work on that.

/Erik

Erik Søe Sørensen

unread,
Jan 20, 2011, 5:18:34 AM1/20/11
to erj...@googlegroups.com
Got it working... it still needs cleanup before being commit-ready, though.
(I should probably run performance tests, too, to ensure that the change doesn't impair normal performance.)

Some numbers:

Cache sizes (sorry about the numbers I gave earlier; they were the cache contents after "ant test" and thus included other stuff than OTP; more than I thought; these numbers are after booting only):
Before: 6.4MB
After shrinking EFun subclasses: 5.5MB

CPU time for booting (./ej < /dev/null):
Before: ~7.4s
After: ~6.5s

So, significant though not radical improvement: 15% reduction on both counts.
Wall-clock time varies a bit too much to give clear results. (It is about 5.5s.)

If we interpret rather than compile, we also get significant results:
CPU time is ~6.6s in this case as well - but wall-clock time decreases from ~5.5s to ~4.4s.
(Of course, these numbers are only possible with multiprocessing; the system in question is dual-core.)

Another thing of interest:
At present we store the pre-weaving version of the module class file in the jar. If we refrain from doing that, cache size decreases further to 4.3MB - but boot time numbers are unaffected. So apart from size, it doesn't pay not to store it; at this stage it is still nice to have for debugging purposes.

/Erik

Kresten Krab Thorup

unread,
Jan 24, 2011, 4:21:53 AM1/24/11
to Erjang
Merging EProc and Fiber args would be great. The easiest way is
probably to use

self = (EProc) Task.getCurrentTask()

where appropriate (this will be inlined by kilim to
((EProc)fiber.task) ... ),

... and then remove EProc self from EFun.invoke signature (but still
have it Pausable of cause).

I think that could slice another chunk off performance because we can
avoid a lot of locals...



For BIFs, ... it is still much faster to have a BIT that takes the
EProc as an explicit argument, than marking
it pausable and then use the above trick.

Kresten

Kresten Krab Thorup

unread,
Jan 24, 2011, 4:43:48 AM1/24/11
to erj...@googlegroups.com
Once we get to Java7 much of this should be possible to translate into usage og MethodHandles. But that is probably too far into the future right now.

The issue with "moving the invoke loop into a superclass" is that what happens in the invoke loop is *special* to that particular EFun. What it does right now is to call a static member in the actual module class (the module:function).

Here's a proposal

One way to have it [the contents of the loop] be non-special would be if the module has a set of functions, one for each arity in use in that module called

invoke0, invoke1, ... invokeN

Then, the first argument in this would be an INTEGER (equivalent to the LABEL of the entry point). So it could look like this:

class my_module extend ECompiledModule {

invoke0(F) throws Pausable {
switch(F) {
case 37: return foo();
case 66: return bar();
}
}

invoke1(F, A1) throws Pausable {
switch(F) {
case 78: return baz(A1);
case 102: return jumbo(A1);
}
}


With this, the EFun objects used to represent exported function from my_module could simply be instantiated as

static EFun0 foo_fun = EXFun0(my_module_instance, 37),

The only real issue with this is that it would increase the stack depth when external calls are involved. It would also involve an additional switch statement in method call, but that in itself is probably not important.

But it could reduce over all code size by what .. ? half? or perhaps even down to 1/3 because we could eliminate *all* the generated EFuns (except for those that represent BIFs).

Kresten

On Jan 20, 2011, at 0:10 , Erik Søe Sørensen wrote:

Kresten Krab Thorup

unread,
Jan 24, 2011, 4:48:15 AM1/24/11
to erj...@googlegroups.com
When reporting performance numbers, it is also very relevant to know the "long-term" implication. Because that is the most important after all, ... once we're all running boot time should not be an issue.

So it may be relevant to compare running fib? Or something else that actually tests performance. Make sure to run it a couple of times in the same JVM to make sure the JIT cicks in properly.

What is an issue though is the code size (and therefore the memory usage) when runninng with all this code generation. Right now, a vanilla BEAM runs in ~3 megs ? A vanilla Erjang in ~ 19 megs. And a lot of that is because of loaded code. [wrote a blog post of this a while back I believe]

Kresten

On Jan 20, 2011, at 11:18 , Erik Søe Sørensen wrote:

Den 20-01-2011 00:10, Erik Søe Sørensen skrev:

Erik Søe Sørensen

unread,
Jan 24, 2011, 8:10:47 AM1/24/11
to erj...@googlegroups.com
Den 24-01-2011 10:48, Kresten Krab Thorup skrev:
> When reporting performance numbers, it is also very relevant to know the "long-term" implication. Because that is the most important after all, ... once we're all running boot time should not be an issue.
>
> So it may be relevant to compare running fib? Or something else that actually tests performance. Make sure to run it a couple of times in the same JVM to make sure the JIT cicks in properly.
Indeed - before committing, I ran estone_SUITE 3 times in the same VM
(and repeated that 3 times) to check that performance hadn't suffered.
I expect this to be a good enough measure? :-)

> What is an issue though is the code size (and therefore the memory usage) when runninng with all this code generation. Right now, a vanilla BEAM runs in ~3 megs ? A vanilla Erjang in ~ 19 megs. And a lot of that is because of loaded code. [wrote a blog post of this a while back I believe]

I tried checking the code-size numbers with
erlang:system_info(allocated_areas), but I'm not sure what to look for...:

Old:
[{'non_heap:PS Perm Gen', 134'217'728, 28'193'960},
{'heap:PS Old Gen', 21'889'024, 10'213'160},
{'heap:PS Survivor Space', 2'490'368, 2'483'328},
{'heap:PS Eden Space', 306'970'624, 30'772'368},
{'non_heap:Code Cache', 4'063'232, 3'870'720}]

New:
[{'non_heap:PS Perm Gen', 134'217'728, 24'755'584},
{'heap:PS Old Gen', 21'889'024, 9'740'280},
{'heap:PS Survivor Space', 6'225'920, 6'221'120},
{'heap:PS Eden Space', 341'508'096, 120'967'864},
{'non_heap:Code Cache', 4'358'144, 4'104'768}]

"PS Perm Gen" is down, but "Code Cache" is up.

/Erik

Kresten Krab Thorup

unread,
Jan 24, 2011, 8:19:55 AM1/24/11
to erj...@googlegroups.com

On Jan 24, 2011, at 14:10 , Erik Søe Sørensen wrote:

> Den 24-01-2011 10:48, Kresten Krab Thorup skrev:
>> When reporting performance numbers, it is also very relevant to know the "long-term" implication. Because that is the most important after all, ... once we're all running boot time should not be an issue.
>>
>> So it may be relevant to compare running fib? Or something else that actually tests performance. Make sure to run it a couple of times in the same JVM to make sure the JIT cicks in properly.
> Indeed - before committing, I ran estone_SUITE 3 times in the same VM
> (and repeated that 3 times) to check that performance hadn't suffered.
> I expect this to be a good enough measure? :-)

Perfect

>
>> What is an issue though is the code size (and therefore the memory usage) when runninng with all this code generation. Right now, a vanilla BEAM runs in ~3 megs ? A vanilla Erjang in ~ 19 megs. And a lot of that is because of loaded code. [wrote a blog post of this a while back I believe]
> I tried checking the code-size numbers with
> erlang:system_info(allocated_areas), but I'm not sure what to look for...:
>
> Old:
> [{'non_heap:PS Perm Gen', 134'217'728, 28'193'960},
> {'heap:PS Old Gen', 21'889'024, 10'213'160},
> {'heap:PS Survivor Space', 2'490'368, 2'483'328},
> {'heap:PS Eden Space', 306'970'624, 30'772'368},
> {'non_heap:Code Cache', 4'063'232, 3'870'720}]
>
> New:
> [{'non_heap:PS Perm Gen', 134'217'728, 24'755'584},
> {'heap:PS Old Gen', 21'889'024, 9'740'280},
> {'heap:PS Survivor Space', 6'225'920, 6'221'120},
> {'heap:PS Eden Space', 341'508'096, 120'967'864},
> {'non_heap:Code Cache', 4'358'144, 4'104'768}]
>
> "PS Perm Gen" is down, but "Code Cache" is up.

That's super. It's perm gen we want to reduce. Code cache is exactly that, just a cache.


Erik Søe Sørensen

unread,
Jan 24, 2011, 3:37:11 PM1/24/11
to erj...@googlegroups.com
Den 24-01-2011 10:43, Kresten Krab Thorup skrev:
> Once we get to Java7 much of this should be possible to translate into usage og MethodHandles. But that is probably too far into the future right now.
>
> The issue with "moving the invoke loop into a superclass" is that what happens in the invoke loop is *special* to that particular EFun. What it does right now is to call a static member in the actual module class (the module:function).
That's where the Template Method pattern enters the picture - it's very
much like the invoke/go separation I took advantage of in the last
change: the superclass method contains a loop and calls a new method in
the subclass, which contains just the static call.

That isn't as radical as doing away with the EFun classes altogether,
which is certainly also worth a try.

> Here's a proposal
>
> One way to have it [the contents of the loop] be non-special would be if the module has a set of functions, one for each arity in use in that module called
>
> invoke0, invoke1, ... invokeN
>
> Then, the first argument in this would be an INTEGER (equivalent to the LABEL of the entry point). So it could look like this:
>
> class my_module extend ECompiledModule {
>
> invoke0(F) throws Pausable {
> switch(F) {
> case 37: return foo();
> case 66: return bar();
> }
> }
>
> invoke1(F, A1) throws Pausable {
> switch(F) {
> case 78: return baz(A1);
> case 102: return jumbo(A1);
> }
> }
>
>
> With this, the EFun objects used to represent exported function from my_module could simply be instantiated as
>
> static EFun0 foo_fun = EXFun0(my_module_instance, 37),
>
> The only real issue with this is that it would increase the stack depth when external calls are involved. It would also involve an additional switch statement in method call, but that in itself is probably not important.
>
> But it could reduce over all code size by what .. ? half? or perhaps even down to 1/3 because we could eliminate *all* the generated EFuns (except for those that represent BIFs).

Doing the stats...
Looks like the EFun classes are currently around 54% of the generated
code size - measured by class file size.

> Kresten
>
>
>
> On Jan 20, 2011, at 0:10 , Erik S�e S�rensen wrote:

Reply all
Reply to author
Forward
0 new messages