I continue to explore in a large legacy project, hoping to puzzle out something more about unit dependency cycles. Specifically, the problem is in trying to find which units are actually causing the issue, and which are simply along for the ride.

I continue to explore in a large legacy project, hoping to puzzle out something more about unit dependency cycles. Specifically, the problem is in trying to find which units are actually causing the issue, and which are simply along for the ride.

There is a very good reason to want to find this. The problem is in getting buy-in to proceed, when after hours of work, there is little measurable benefit. Yes, I can document the number of such cycles removed, but the real issue is impact on build time, and if I can't show a significant improvement, then the casual of cost/benefit is rather negative.

Comments

  1. Jeroen Wiert Pluimers
    Also, there is Lattix, which seems to pick up where MMX left off. They acknowledge their roots in the MMX analyzer which was at one time open source, apparently. But Lattix is expensive, and from their demos, I still do not see that it does much to help find the most effective areas in which to work.

    ReplyDelete
  2. Some months ago we drastically improved compilation time in FlexCel (about 1800 unts) by removing cycles. Sadly I am always meaning to write a blog post (which I have already started) but never get the time to finish it. And if I wait too long, I might even forget how I did it! ;)

    Anyway, the idea was as follows:
    1)Run dcc32 in the project (not msbuild because it won't show the line numbers), redirecting the output to a file. I used a C# app which would parse the lines of output, and use FlexCel to generate an Excel file with the time each line was written and the line itself. It could have been a delphi app the same, but I happened to have Visual Studio open when I coded the app.

    2)Then in the generated file, search for gaps. For example, this is an actual file I got:

    23:20:32 _UExpressions.TFormulaConverterTokenToInternal.pas(72)
    23:20:32 _UExpressions.TFormulaConverterTokenToInternal.pas(73)
    23:20:32 _UExpressions.TFormulaConverterTokenToInternal.pas(74)
    23:20:32 _UExpressions.TFormulaConverterTokenToInternal.pas(75)
    23:20:41 _UExpressions.TFormulaConverterTokenToInternal.pas(76)
    23:20:41 _UExpressions.TFormulaConverterTokenToInternal.pas(77)

    As you can see, compilation goes smooth up to 23:20:32,, and suddenly it spends 9 seconds (!) to compile the line 74 of _UExpressions.TFormulaConverterTokenToInternal.pas

    This is the start of the thread you need to follow. If you go and look at line 74, you'll see the unit that is causing trouble. We have one unit per line, if you have more you might have to separate all used units in line 74 one per line and recompile.

    Then, if you look at the unit used in line 74 you will end up in a cycle that comes back to the original file. This is the cycle you need to break.

    It isn't a funny thing to do (to not say it is awfully boring) but results can be incredible. The delphi compiler degrades exponentially when there are large cycles of units and can become really slow. You don't also need to break all the cycles, but the large ones (small cycles are fast enough)

    Well, I wish I could say more but I don't really have time right now (and for the coming months) to expand on it. I hope this is enough to get you started. And yes, if workload even goes down, I should finish the blog post! :)

    ReplyDelete
  3. Adrian Gallero
    Excellent!! I had actually started down that path some months ago, but was uncertain of what I was seeing. Time to reopen that old project.

    ReplyDelete

Post a Comment