Merge pull request #3337 from lightmare/normalize-angle

speed up util::normalize_angle for large values
This commit is contained in:
lightmare 2018-07-12 19:30:37 +02:00 committed by GitHub
commit 187c1df332
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 111 additions and 42 deletions

View file

@ -18,40 +18,19 @@ test_env.Append(CPPDEFINES = env['LIBMAPNIK_DEFINES'])
if test_env['HAS_CAIRO']: if test_env['HAS_CAIRO']:
test_env.PrependUnique(CPPPATH=test_env['CAIRO_CPPPATHS']) test_env.PrependUnique(CPPPATH=test_env['CAIRO_CPPPATHS'])
test_env.Append(CPPDEFINES = '-DHAVE_CAIRO') test_env.Append(CPPDEFINES = '-DHAVE_CAIRO')
test_env.PrependUnique(CPPPATH='include', delete_existing=True)
test_env['LINKFLAGS'] = copy(test_env['LIBMAPNIK_LINKFLAGS']) test_env['LINKFLAGS'] = copy(test_env['LIBMAPNIK_LINKFLAGS'])
if env['PLATFORM'] == 'Darwin': if env['PLATFORM'] == 'Darwin':
test_env.Append(LINKFLAGS='-F/ -framework CoreFoundation') test_env.Append(LINKFLAGS='-F/ -framework CoreFoundation')
test_env_local = test_env.Clone() test_env_local = test_env.Clone()
#benchmarks = glob.glob('test*cpp') benchmarks = glob.glob("src/*.cpp")
benchmarks = [
#"test_array_allocation.cpp", for src in benchmarks:
#"test_png_encoding1.cpp", name, ext = os.path.splitext(os.path.basename(src))
#"test_png_encoding2.cpp", out = os.path.join("out", name)
#"test_to_string1.cpp", test_program = test_env_local.Program(out, source=[src])
#"test_to_string2.cpp",
#"test_to_bool.cpp",
#"test_to_double.cpp",
#"test_to_int.cpp",
#"test_utf_encoding.cpp"
"test_polygon_clipping.cpp",
#"test_polygon_clipping_rendering.cpp",
"test_proj_transform1.cpp",
"test_expression_parse.cpp",
"test_face_ptr_creation.cpp",
"test_font_registration.cpp",
"test_rendering.cpp",
"test_rendering_shared_map.cpp",
"test_offset_converter.cpp",
"test_marker_cache.cpp",
"test_quad_tree.cpp",
"test_noop_rendering.cpp",
"test_getline.cpp",
# "test_numeric_cast_vs_static_cast.cpp",
]
for cpp_test in benchmarks:
test_program = test_env_local.Program('out/'+cpp_test.replace('.cpp',''), source=[cpp_test])
if 'install' in COMMAND_LINE_TARGETS: if 'install' in COMMAND_LINE_TARGETS:
env.Alias('install',test_program) env.Alias('install',test_program)
#Depends(test_program, env.subst('../src/%s' % env['MAPNIK_LIB_NAME'])) #Depends(test_program, env.subst('../src/%s' % env['MAPNIK_LIB_NAME']))

View file

@ -12,6 +12,7 @@
#include <chrono> #include <chrono>
#include <cmath> // log10, round #include <cmath> // log10, round
#include <cstdio> // snprintf #include <cstdio> // snprintf
#include <iomanip>
#include <iostream> #include <iostream>
#include <set> #include <set>
#include <sstream> #include <sstream>
@ -239,14 +240,19 @@ int run(T const& test_runner, std::string const& name)
big_number_fmt itersf(4, total_iters); big_number_fmt itersf(4, total_iters);
big_number_fmt ips(5, total_iters / seconds<double>(elapsed_nonzero).count()); big_number_fmt ips(5, total_iters / seconds<double>(elapsed_nonzero).count());
std::clog << std::left << std::setw(43) << name;
std::clog << std::resetiosflags(std::ios::adjustfield);
if (num_threads > 0) {
std::clog << ' ' << std::setw(3) << num_threads
<< " worker" << (num_threads > 1 ? "s" : " ");
}
else {
std::clog << " main thread";
}
std::snprintf(msg, sizeof(msg), std::snprintf(msg, sizeof(msg),
"%-43s %3zu thread(s) %*.0f%s iters %6.0f milliseconds %*.0f%s i/s\n", " %*.0f%s iters %6.0f milliseconds %*.0f%s i/t/s\n",
name.c_str(), itersf.w, itersf.v, itersf.u, dur_total,
num_threads, ips.w, ips.v, ips.u);
itersf.w, itersf.v, itersf.u,
dur_total,
ips.w, ips.v, ips.u
);
std::clog << msg; std::clog << msg;
return 0; return 0;
} }

View file

@ -10,7 +10,7 @@ function run {
local threads="$2" local threads="$2"
local iters="$3" local iters="$3"
shift 3 shift 3
$runner --threads 1 --iterations $iters "$@" $runner --threads 0 --iterations $iters "$@"
if test $threads -gt 0; then if test $threads -gt 0; then
$runner --threads $threads --iterations $((iters/threads)) "$@" $runner --threads $threads --iterations $((iters/threads)) "$@"
fi fi
@ -28,6 +28,7 @@ run test_expression_parse 10 10000
run test_face_ptr_creation 10 1000 run test_face_ptr_creation 10 1000
run test_font_registration 10 100 run test_font_registration 10 100
run test_offset_converter 10 1000 run test_offset_converter 10 1000
#run normalize_angle 0 1000000 --min-duration=0.2
# commented since this is really slow on travis # commented since this is really slow on travis
: ' : '

View file

@ -0,0 +1,69 @@
#include "bench_framework.hpp"
#include <mapnik/util/math.hpp>
template <typename T>
struct bench_func : benchmark::test_case
{
T (* const func_)(T);
T const value_;
bench_func(mapnik::parameters const& params, T (*func)(T), T value)
: test_case(params), func_(func), value_(value) {}
bool validate() const { return true; }
bool operator() () const
{
for (auto i = this->iterations_; i-- > 0; )
{
func_(value_);
}
return true;
}
};
#define BENCH_FUNC1(func, value) \
run<bench_func<double>>(#func "(" #value ")", func, value)
int main(int argc, char** argv)
{
return benchmark::sequencer(argc, argv)
.BENCH_FUNC1(mapnik::util::normalize_angle, +3)
.BENCH_FUNC1(mapnik::util::normalize_angle, +6)
.BENCH_FUNC1(mapnik::util::normalize_angle, +9)
.BENCH_FUNC1(mapnik::util::normalize_angle, +12)
.BENCH_FUNC1(mapnik::util::normalize_angle, +15)
.BENCH_FUNC1(mapnik::util::normalize_angle, +20)
.BENCH_FUNC1(mapnik::util::normalize_angle, +30)
.BENCH_FUNC1(mapnik::util::normalize_angle, +40)
.BENCH_FUNC1(mapnik::util::normalize_angle, +50)
.BENCH_FUNC1(mapnik::util::normalize_angle, +70)
.BENCH_FUNC1(mapnik::util::normalize_angle, +90)
.BENCH_FUNC1(mapnik::util::normalize_angle, +110)
.BENCH_FUNC1(mapnik::util::normalize_angle, +130)
.BENCH_FUNC1(mapnik::util::normalize_angle, +157)
.BENCH_FUNC1(mapnik::util::normalize_angle, +209)
.BENCH_FUNC1(mapnik::util::normalize_angle, +314)
.BENCH_FUNC1(mapnik::util::normalize_angle, +628)
.BENCH_FUNC1(mapnik::util::normalize_angle, +942)
.BENCH_FUNC1(mapnik::util::normalize_angle, -3)
.BENCH_FUNC1(mapnik::util::normalize_angle, -6)
.BENCH_FUNC1(mapnik::util::normalize_angle, -9)
.BENCH_FUNC1(mapnik::util::normalize_angle, -12)
.BENCH_FUNC1(mapnik::util::normalize_angle, -15)
.BENCH_FUNC1(mapnik::util::normalize_angle, -20)
.BENCH_FUNC1(mapnik::util::normalize_angle, -30)
.BENCH_FUNC1(mapnik::util::normalize_angle, -40)
.BENCH_FUNC1(mapnik::util::normalize_angle, -50)
.BENCH_FUNC1(mapnik::util::normalize_angle, -70)
.BENCH_FUNC1(mapnik::util::normalize_angle, -90)
.BENCH_FUNC1(mapnik::util::normalize_angle, -110)
.BENCH_FUNC1(mapnik::util::normalize_angle, -130)
.BENCH_FUNC1(mapnik::util::normalize_angle, -157)
.BENCH_FUNC1(mapnik::util::normalize_angle, -209)
.BENCH_FUNC1(mapnik::util::normalize_angle, -314)
.BENCH_FUNC1(mapnik::util::normalize_angle, -628)
.BENCH_FUNC1(mapnik::util::normalize_angle, -942)
.done();
}

View file

@ -27,9 +27,11 @@
namespace mapnik { namespace util { namespace mapnik { namespace util {
constexpr double pi = 3.1415926535897932384626433832795;
constexpr double tau = 6.283185307179586476925286766559;
MAPNIK_DECL double normalize_angle(double angle); MAPNIK_DECL double normalize_angle(double angle);
}} }}
#endif #endif

View file

@ -22,7 +22,6 @@
// mapnik // mapnik
#include <mapnik/util/math.hpp> #include <mapnik/util/math.hpp>
#include <mapnik/global.hpp>
// stl // stl
#include <cmath> #include <cmath>
@ -33,13 +32,26 @@ namespace util {
double normalize_angle(double angle) double normalize_angle(double angle)
{ {
while (angle >= M_PI) if (angle > pi)
{ {
angle -= 2.0 * M_PI; if (angle > 16 * tau)
{
// the angle is too large; better compute the remainder
// directly to avoid subtracting circles ad infinitum
return std::remainder(angle, tau);
} }
while (angle < -M_PI) // std::remainder would take longer than a few subtractions
while ((angle -= tau) > pi)
;
}
else if (angle < -pi)
{ {
angle += 2.0 * M_PI; if (angle < -16 * tau)
{
return std::remainder(angle, tau);
}
while ((angle += tau) < -pi)
;
} }
return angle; return angle;
} }