Hi, I am trying to implement a method of using a "batteries included" lisp image (ccl, linux, 64bit) which can be used for running a variety of lisp tasks in a batch mode. I chose to pre-load the image because it was just too slow to load the individual fasl files at run time, either via asdf or through a generated load-list.
I'm using ASDF to load a small system at run-time, but finding that even with small system (say, one file), performance is sluggish, over 2 seconds.
It looks like the problem crops up when there are many dependencies. Poking around the asdf code this appears to be because operate always traverses the system dependencies, and pokes the asd files to find if they have changed.
This makes sense for asdf in development mode, since it needs to discover changed systems. Not so good for a deployed system.
ASDF assumes that since the system def file has not changed, the system hasn't been changed either (I know there has been discussion of this assumption.) But lets assume that at least part of the reason for that is because it is very time consuming to check the entire set of files every time the developer wants to recompile and load just a single file.
Why not assume in a deployment mode that NO system will have changed if it is already loaded in memory, and unless the application has asked that it be reloaded? This would be for performance as well as for safety -- we really don't want dependency checking to result in any filesystem checks, etc.
I feel that this problem is really pushing my grokking of asdf, but I'm delving ahead anyway.
I haven't tested it extensively, but I did just waste a perfect sunday morning fiddling with this:
extended module with a slot "up-to-date-p", but surely there is a better name, this I just chose while in early play mode:
added these methods:
(defmethod operation-done-p ((o load-op) (c module)) (module-up-to-date-p c))
(defmethod mark-operation-done ((operation load-op) (c module)) (setf (module-up-to-date-p c) t))
tweaked the operate method so that it exits early if the module has been marked as up-to-date
(if (operation-done-p op system) (return-from operate (values op nil)))
and do-traverse to only collect "kids" if it is not done
(unless (operation-done-p operation c) (while-collecting (internal-collect)
Note that this code goes in the special section of operate for handling modules.
I think that is all that I did.
I found that the time to handle the require for my current project dropped from about 2 1/2 to about 1/2 second.
Thoughts?
Dear Erik,
I am trying to implement a method of using a "batteries included" lisp image (ccl, linux, 64bit) which can be used for running a variety of lisp tasks in a batch mode. I chose to pre-load the image because it was just too slow to load the individual fasl files at run time, either via asdf or through a generated load-list.
At ITA, we also deliver applications as dumped images with lots of systems. But I admit that during incremental development, we recompile files individually with SLIME rather than load entire systems with ASDF.
I'm using ASDF to load a small system at run-time, but finding that even with small system (say, one file), performance is sluggish, over 2 seconds.
First, how big are that small system's dependencies? Because they will all be scanned. Second, how much time is spent in initialize-source-registry? Because if you reset it when dumping an image (which you probably should unless the source is guaranteed to be at the same place at runtime), it will scan all the declared source trees.
It looks like the problem crops up when there are many dependencies. Poking around the asdf code this appears to be because operate always traverses the system dependencies, and pokes the asd files to find if they have changed.
This makes sense for asdf in development mode, since it needs to discover changed systems. Not so good for a deployed system.
Well, what do you propose ASDF should do? Have some option to operate and/or traverse to skip checking some dependencies if they are already loaded, kind of a :force-not complement to :force ? I suppose I'll accept a patch that does it.
ASDF assumes that since the system def file has not changed, the system hasn't been changed either (I know there has been discussion of this assumption.) But lets assume that at least part of the reason for that is because it is very time consuming to check the entire set of files every time the developer wants to recompile and load just a single file.
I don't think that's true, but my head hurts just thinking about it.
Why not assume in a deployment mode that NO system will have changed if it is already loaded in memory, and unless the application has asked that it be reloaded? This would be for performance as well as for safety -- we really don't want dependency checking to result in any filesystem checks, etc.
Because that's wrong? I don't have as many dependencies as you do when I reload a system with asdf, but usually, I do want the dependencies to be reloaded.
I feel that this problem is really pushing my grokking of asdf, but I'm delving ahead anyway.
I haven't tested it extensively, but I did just waste a perfect sunday morning fiddling with this:
extended module with a slot "up-to-date-p", but surely there is a better name, this I just chose while in early play mode:
added these methods:
(defmethod operation-done-p ((o load-op) (c module)) (module-up-to-date-p c))
(defmethod mark-operation-done ((operation load-op) (c module)) (setf (module-up-to-date-p c) t))
tweaked the operate method so that it exits early if the module has been marked as up-to-date
(if (operation-done-p op system) (return-from operate (values op nil)))
and do-traverse to only collect "kids" if it is not done
(unless (operation-done-p operation c) (while-collecting (internal-collect)
I think that's quite wrong. How are you to maintain the up-to-date-ness of your modules?
Note that this code goes in the special section of operate for handling modules.
I think that is all that I did.
I found that the time to handle the require for my current project dropped from about 2 1/2 to about 1/2 second.
I'd rather you implement a :force-not. It sounds cleaner to me.
Thoughts?
I imagine a far future where an XCVB daemon watches changes to the filesystem to detect which registered builds require an update. Not quite there yet.
—♯ƒ • François-René ÐVB Rideau •Reflection&Cybernethics• http://fare.tunes.org The older I grow, the more I distrust the familiar doctrine that age brings wisdom. — H.L. Mencken (Plus je vieillis, moins je crois en l'idée commune que l'age apporte la sagesse.)
On 4/22/12 Apr 22 -3:47 PM, Faré wrote:
Dear Erik,
ASDF assumes that since the system def file has not changed, the system hasn't been changed either (I know there has been discussion of this assumption.) But lets assume that at least part of the reason for that is because it is very time consuming to check the entire set of files every time the developer wants to recompile and load just a single file.
I don't think that's true, but my head hurts just thinking about it.
This is not an accurate understanding. It has come up over and over. The right thing to do would be to check systems recursively, but there are a number of reasons why this does not work with the current state of ASDF. You can look in the archives for explanations; it has been discussed many times [I am not trying to be rude; I just don't have the energy to write up another copy of the explanation. Probably we should put it in as a FAQ in the manual...]
Why not assume in a deployment mode that NO system will have changed if it is already loaded in memory, and unless the application has asked that it be reloaded? This would be for performance as well as for safety -- we really don't want dependency checking to result in any filesystem checks, etc.
Because that's wrong? I don't have as many dependencies as you do when I reload a system with asdf, but usually, I do want the dependencies to be reloaded.
The deployment mode is an edge case and can already be handled very efficiently by dumping an image with the (stable) system you want already loaded (cf. Xach's buildapp, although I know that's for SBCL, rather than CCL; and CCL:SAVE-APPLICATION -- http://ccl.clozure.com/manual/chapter4.9.html#Saving-Applications). In some sense you are right, ASDF is slow for this use case, but it's really not the use case ASDF is looking for.
And ASDF is already too liberal about assuming stability, in a way that breaks a lot of people's development practice (see my earlier remarks); the last thing I would want to do is make it even more likely to miss a change and build an inconsistent system.
Best, r