You are here: Foswiki>Tasks Web>Item12319 (05 Jul 2015, GeorgeClark)Edit Attach

Item12319: ASSERTs not eliminated by optimization

pencil
Priority: Urgent
Current State: Closed
Released In: 2.0.0
Target Release: major
Applies To: Engine
Component:
Branches: trunk
Reported By: MichaelDaum
Waiting For:
Last Change By: GeorgeClark
Investigating a 23seconds SEARCH page, I've found out that dummyASSERT() is still called even though the code should be removed by the perl optimizer. Typical code passages look like this:

ASSERT(blabla) if DEBUG;

The DEBUG constant is exported by the Assert module but unfortunately not used to remove the ASSERT() statement from the op code when DEBUG equals zero.

As an experiment, I commented out use Assert; in Meta.pm and replace it with a use constant DEBUG => 0;. It resulted in full 3 seconds being shaved off the test page.

%SEARCH{"1"
  nonoise="on"
  type="query"
  web="TestWeb"
  format="."
  separator=" "
  footer="count=$ntopics"
}%
TestWeb with 17061 topics, almost all having local ACLs, a typical Main with lots of profile pages.

Before dummyASSERT was still called over a million times all over the code. Removing it from Meta.pm alone significantly reduced the amount of calls leaving behind another 203k calls from other locations in the code.

Basically, dummyASSERT() should almost never have been called at all as almost all are guarded by an if DEBUG; Still perl was not able to perform this optimization step.

I don't fully understand under which conditions the code will be eliminated part of an optimization step. Yet I assume that the way DEBUG is constructed within Assert.pm is too complicated for perl to be able to deduce the NOP that the code is in the end.

The shocking fact is that this is time spent on doing nothing other than calling dummyASSERT() over and over again.

-- MichaelDaum - 28 Dec 2012

It's possible the DEBUG can't be checked for constancy at compile time for some reason. In this case, adding a BEGIN { DEBUG; } to Meta.pm should show a similar performance improvement.

-- CrawfordCurrie - 19 Jan 2013

As is often the case with perl, this is not as simple as it appears.

I have tested in various scenarios:
  1. Existing code
  2. With use constant in the module-under-test (MUT)
  3. With sub DEBUG{0} in the MUT
  4. With Assert stripped down to sub DEBUG{0} and not a lot more
  5. With Assert fully functional, but recoded to minimise the overhead of Exporter
There does indeed appear to be a problem with optimising constant functions; even when the function is cirectly in the module, the use constant version is still faster! It took some work, but I managed to get the assert module recoded so that it exports a constant. On my local benchmarks at least, this delivers a significant speedup.

-- CrawfordCurrie - 20 Jan 2013

Strange warnings. The optimizer had a whinge on stuff like this:

   } elseif (DEBUG) {
      ASSERT(0);
   }

Saying "Useless use of a constant (undef) in void context". Umpf.

So after making it a

   } else {
      ASSERT(0) if (DEBUG);
   }

where fine again. I wonder where else this pattern has been used.

-- MichaelDaum - 21 Jan 2013

The fix causes the Fn_SEARCH unit test to fail with a taint error.
Insecure dependency in require while running with -T switch at /var/www/foswiki/trunk/core/lib/Assert.pm line 23.

Reopening to fix.

-- GeorgeClark - 29 Jan 2013

My attempt to fix has failed. use constant DEBUG = $ENV{FOSWIKI_ASSERTS}; is established at compile time. Untainting at runtime is too late.

Reverting my attempts.

-- GeorgeClark - 31 Jan 2013
 
Topic revision: r15 - 05 Jul 2015, GeorgeClark
The copyright of the content on this website is held by the contributing authors, except where stated elsewhere. See Copyright Statement. Creative Commons License    Legal Imprint    Privacy Policy