Derby
  1. Derby
  2. DERBY-5474

Speed up message splitting in build

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: 10.9.1.0
    • Fix Version/s: 10.9.1.0
    • Component/s: Build tools
    • Labels:
      None

      Description

      On a slow machine I sometimes use to build Derby, running the org.apache.derbyBuild.splitmessages tool takes 30 seconds and accounts for 15% of the total time needed to run "ant -q buildsource" (which builds the engine, the network server and the client, but not the tests or demos). The tool is invoked 15 times, and each time a new Java process is started because the Ant target has specified fork="yes". By changing it to run the splitmessages tool in the same Java process as the one running Ant, the time is reduced to 3-4 seconds on the same machine.

      1. d5474.diff
        2 kB
        Knut Anders Hatlen

        Activity

        Hide
        Knut Anders Hatlen added a comment -

        Attaching a patch that removes the fork attribute from the target so that it uses the default value "no". It also removes the dir attribute, otherwise a warning is printed about the property being ignored (since working directory cannot be changed when fork is "no"). The tool doesn't use any relative path names as far as I can see, so inheriting the working directory from the parent process should be OK.

        Additionally, it turns the initClientMessageIds() method into a static initializer. This isn't strictly necessary, since initClientMessageIds() is idempotent, but it saves a little bit of work when the main() method is invoked multiple times in the same process.

        Show
        Knut Anders Hatlen added a comment - Attaching a patch that removes the fork attribute from the target so that it uses the default value "no". It also removes the dir attribute, otherwise a warning is printed about the property being ignored (since working directory cannot be changed when fork is "no"). The tool doesn't use any relative path names as far as I can see, so inheriting the working directory from the parent process should be OK. Additionally, it turns the initClientMessageIds() method into a static initializer. This isn't strictly necessary, since initClientMessageIds() is idempotent, but it saves a little bit of work when the main() method is invoked multiple times in the same process.
        Hide
        Kristian Waagan added a comment -

        +1, great having the build complete faster!

        Show
        Kristian Waagan added a comment - +1, great having the build complete faster!
        Hide
        Bryan Pendleton added a comment -

        Wow! Years ago (2005-ish?) I did a series of experiments on a different, very complex, build system,
        to see if I could measure the impact of fork=yes vs fork=no. At that time, I couldn't see any difference
        at all; the tens of thousands of process forks that I was doing seemed to add no time at all to the
        build.

        However, that was a completely different build system, a completely different source tree, and a
        completely different set of machines (principally Windows and Linux boxes on fairly fast hardware).

        So I'm pleased that you found a substantial difference, but somewhat surprised.

        Show
        Bryan Pendleton added a comment - Wow! Years ago (2005-ish?) I did a series of experiments on a different, very complex, build system, to see if I could measure the impact of fork=yes vs fork=no. At that time, I couldn't see any difference at all; the tens of thousands of process forks that I was doing seemed to add no time at all to the build. However, that was a completely different build system, a completely different source tree, and a completely different set of machines (principally Windows and Linux boxes on fairly fast hardware). So I'm pleased that you found a substantial difference, but somewhat surprised.
        Hide
        Knut Anders Hatlen added a comment -

        Thanks, Kristian and Bryan.

        All regression tests passed with jars built with the patch.
        Committed revision 1188163.

        The machine where I saw that the 15 invocations of splitmessages took 30 seconds, was a four-year-old laptop running Linux.

        On various desktops running Solaris I've seen that it takes between 3 and 15 seconds, depending on how powerful the machines are. When changing to fork=no, it's reduced to 0-2 seconds on those machines.

        So whereas it's cheaper on the more powerful machines, the cost is still not negligible, even though there are just 15 processes to be started. Bryan, perhaps your experiment ran with processes that were lighter and cheaper to fork than a JVM? Or maybe it was a multi-threaded build system so that other threads could utilize the CPU while one thread was kept up waiting for the forked process to fault in the runtime libraries, or whatever it is that's taking time?

        Show
        Knut Anders Hatlen added a comment - Thanks, Kristian and Bryan. All regression tests passed with jars built with the patch. Committed revision 1188163. The machine where I saw that the 15 invocations of splitmessages took 30 seconds, was a four-year-old laptop running Linux. On various desktops running Solaris I've seen that it takes between 3 and 15 seconds, depending on how powerful the machines are. When changing to fork=no, it's reduced to 0-2 seconds on those machines. So whereas it's cheaper on the more powerful machines, the cost is still not negligible, even though there are just 15 processes to be started. Bryan, perhaps your experiment ran with processes that were lighter and cheaper to fork than a JVM? Or maybe it was a multi-threaded build system so that other threads could utilize the CPU while one thread was kept up waiting for the forked process to fault in the runtime libraries, or whatever it is that's taking time?
        Hide
        Bryan Pendleton added a comment -

        Well, it was <javac> and <java> tasks that we were forking, so I think it was definitely JVM forking.

        But, it was mostly on Linux boxes. I don't think we had a single Solaris machine in that build system.

        Another thing is that our machines tended to be massively over-provisioned with real memory, so that
        might also make forking fast.

        On your laptop, do you have JAVA_OPTS or ANT_OPTS or other parameters that might control the
        virtual memory size of the Ant and/or forked Java processes?

        I rather doubt it's worth pursuing my old memories very far. I see no reason not to remove the forking,
        since as you say it was wholly unnecessary. So it can't hurt, and since it demonstrably helps at least
        some environments, I say full speed ahead!

        Show
        Bryan Pendleton added a comment - Well, it was <javac> and <java> tasks that we were forking, so I think it was definitely JVM forking. But, it was mostly on Linux boxes. I don't think we had a single Solaris machine in that build system. Another thing is that our machines tended to be massively over-provisioned with real memory, so that might also make forking fast. On your laptop, do you have JAVA_OPTS or ANT_OPTS or other parameters that might control the virtual memory size of the Ant and/or forked Java processes? I rather doubt it's worth pursuing my old memories very far. I see no reason not to remove the forking, since as you say it was wholly unnecessary. So it can't hurt, and since it demonstrably helps at least some environments, I say full speed ahead!
        Hide
        Knut Anders Hatlen added a comment -

        I didn't have any JAVA_OPTS or ANT_OPTS set. All the machines I tested on had 4 GB of RAM, which should be sufficient to build Derby, I think.

        The next problem I found, was that the <chmod> tasks in the binscripts target need close to half a second on all the platforms I have tested (Solaris and Linux). There are six of those, so it totals to three seconds, also in incremental builds when there shouldn't be anything to do. I'll file a separate issue for that. I don't understand this either. Executing six chmod commands from a shell script takes a few milliseconds, so I don't see why doing the same from Ant should take three seconds. Oh well...

        For the record, I timed the targets by running Ant with these extra parameters: -logger org.apache.tools.ant.listener.ProfileLogger

        Show
        Knut Anders Hatlen added a comment - I didn't have any JAVA_OPTS or ANT_OPTS set. All the machines I tested on had 4 GB of RAM, which should be sufficient to build Derby, I think. The next problem I found, was that the <chmod> tasks in the binscripts target need close to half a second on all the platforms I have tested (Solaris and Linux). There are six of those, so it totals to three seconds, also in incremental builds when there shouldn't be anything to do. I'll file a separate issue for that. I don't understand this either. Executing six chmod commands from a shell script takes a few milliseconds, so I don't see why doing the same from Ant should take three seconds. Oh well... For the record, I timed the targets by running Ant with these extra parameters: -logger org.apache.tools.ant.listener.ProfileLogger

          People

          • Assignee:
            Knut Anders Hatlen
            Reporter:
            Knut Anders Hatlen
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development