On 06/21/2010 11:22 AM, strk wrote:
> Not really.
> You're right about additional cost, but I dubt it'll really
> be noticeable. Have some profiles ?

Not directly on geos but testing the same scenario against a trivial
example (attached) gives these results on gcc 4.4.3 :

$ g++ -O0 -o bench bench.cc && ./bench
elapsed: 00:00:24.000799
elapsed: 00:00:27.809378
diff: 00:00:03.808579
added cost: 15.8686%

$ g++ -O2 -o bench bench.cc && ./bench
elapsed: 00:00:13.456086
elapsed: 00:00:14.927550
diff: 00:00:01.471464
added cost: 10.9353%

$ g++ -O3 -o bench bench.cc && ./bench
elapsed: 00:00:01.757662
elapsed: 00:00:02.050734
diff: 00:00:00.293072
added cost: 16.674%


First 'elapsed' is an unsafe access, second is the same access protected
by an if().

It is clearly noticeable in any optimization level.

> We could move the checks in higher level APIs and
> leave internals alone. Note that the C-API says it'd return
> 0 on exception. Isn't asking for an non-existant child 
> an exceptional request ? Should the C-API functions check ?

It is indeed an exceptional request and this is why I find that paying
the cost of this additional safety for exceptional cases is too much.
These methods are typically used in loop-intensive contexts.

Furthermore, they add no safety when used in loops such as :

 for(std::size_t i = 0; i < geom->getNumGeometries(); ++i)
  // ...geom->getGeometryN(i)...

Having a safe and slow API is fine, std::vector has one, but not having
an unsafe bust fast API is bad for those who care about performance.
These functions are quite fundamental and broadly used in geos, this is
going to slow down everything a bit.

As I don't use the C-API I don't know if it should do the test or not.
I'd say that there should also be two functions, unsafe & fast and safe
& slow. By the way, a lot of C code has the 'unsafe & fast' behaviour.
Typically the libc : str{len,cpy,...} functions will segfault if they
are given invalid arguments (NULL pointers, ...). So a C developer
should be used to functions that fail when given invalid arguments.

-- 
Maxime
#include <iostream>
#include <vector>

#include <boost/date_time/posix_time/posix_time.hpp>

boost::posix_time::time_duration elapsed(const boost::posix_time::ptime& start)
{
  boost::posix_time::time_duration duration = boost::posix_time::microsec_clock::local_time() - start;
  std::cout << "elapsed: " << duration << std::endl;
  return duration;
}

void set(std::vector<int>& vect, std::size_t ind, int val)
{
  vect[ind] += val;
}

void safe_set(std::vector<int>& vect, std::size_t ind, int val)
{
  if (ind > vect.size())
    return;

  vect[ind] += val;
}

void safe_set2(std::vector<int>& vect, std::size_t ind, int val)
{
  vect.at(ind) = val;
}

int main(int argc, char* argv[])
{
  std::size_t nb_loops = 1000000000;
  std::vector<int> v(10, 42);

  // Cache
  for (std::size_t i = 0; i < nb_loops; ++i)
    v[i % v.size()] = 42;

  boost::posix_time::time_duration d1, d2;

  // Without if()
  {
    const boost::posix_time::ptime& start = boost::posix_time::microsec_clock::local_time();

    for (std::size_t i = 0; i < nb_loops; ++i)
      set(v, (i + argc) % v.size(), argc);

    d1 = elapsed(start);
  }

  // With if()
  {
    const boost::posix_time::ptime& start = boost::posix_time::microsec_clock::local_time();

    for (std::size_t i = 0; i < nb_loops; ++i)
      safe_set(v, (i + argc) % v.size(), argc);

    d2 = elapsed(start);
  }

  std::cout << "diff: " << d2 - d1 << std::endl
            << "added cost: " << (double) d2.total_microseconds() / (double) d1.total_microseconds() * 100. - 100 << "%" <<  std::endl;
}
_______________________________________________
geos-devel mailing list
geos-devel@lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/geos-devel

Reply via email to