Specify the include path in the ERL_COMPILER_OPTIONS
variable, and the code path in ~/.erlang .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.
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.
* 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]
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å vegne af Pavlo Baron [pbit...@googlemail.com]
Sendt: 5. januar 2011 09:36
Til: Erjang
Emne: [erjang] Re: Triq.hrl
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å 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?
>
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
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
> (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
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]
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
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
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:
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:
> 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
> 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.
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: