Commit ee4a0b7
Benchmark Stroke Benchmark functions for the old stroke code, it took 17.6873s to create 5 strokes of the test path.
Changed files (7)
modifiedlibbirdfont/EditPoint.valaaddedlibbirdfont/FastPath.valamodifiedlibbirdfont/Path.valaaddedlibbirdfont/Test.valaaddedlibbirdfont/TestBirdFont.valamodifiedlibbirdfont/TestCases.valadeletedlibbirdfont/TestSupplement.vala
Diff
@@ -1,5 +1,5 @@ /*- Copyright (C) 2012 Johan Mattsson+ Copyright (C) 2012, 2013, 2014 Johan Mattsson This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as new file mode 100644@@ -0,0 +1,138 @@+/*+ Copyright (C) 2014 Johan Mattsson++ This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version.++ This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details.+*/++namespace BirdFont {+ +/** A faster implementation of the Path and EditPoint classes. */+public class FastPath : GLib.Object {+ + /** Control points and control point handles.+ * + * Each point is stored with left handle at index - 2,+ * the point at index, and right handle at index + 2. Both x and y+ * coordinates is stores in this array.+ */+ double* points;+ + /** Point types. */+ uint* types;+ + /** The number of points that can be stored in the point array. */+ int capacity;+ + public static const uint NUMBERS_PER_POINT = 6;++ public static const uint LEFT_HANDLE_POS_X = 0;+ public static const uint LEFT_HANDLE_POS_Y = 1;+ public static const uint POS_X = 2;+ public static const uint POS_Y = 3;+ public static const uint RIGHT_HANDLE_POS_X = 4;+ public static const uint RIGHT_HANDLE_POS_Y = 5;++ /** Various boolean properties */+ uint* flags;++ public static uint ACTIVE = 1 << 0;+ public static uint SELECTED = 1 << 1;+ public static uint DELETED = 1 << 2;+ + public static uint TIE_HANDLES = 1 << 3;+ public static uint REFLECTIVE_HANDLES = 1 << 4;+ + /** Number of control points in this path. */+ int number_of_points = 0;+ + public FastPath () {+ capacity = 1024;+ points = new double[capacity * NUMBERS_PER_POINT];+ types = new uint[capacity];+ }++ ~FastPath () {+ delete points;+ delete types;+ }+ + /** @return number of control points in this path. */+ public int get_length () {+ return number_of_points;+ }+ + /** Get a slow representation for an edipoint. */+ public EditPoint get_editpoint (int index) {+ EditPoint ep = new EditPoint (get_x (index), get_y (index), get_point_type (index));+ ep.get_left_handle ().move_to_coordinate (get_left_handle_x (index), get_left_handle_y (index));+ ep.get_right_handle ().move_to_coordinate (get_right_handle_x (index), get_right_handle_y (index)); + return ep;+ }++ public void set_editpoint (int index, EditPoint ep) {+ points[NUMBERS_PER_POINT * index + POS_X] = ep.x;+ points[NUMBERS_PER_POINT * index + POS_Y] = ep.y;+ points[NUMBERS_PER_POINT * index + LEFT_HANDLE_POS_X] = ep.get_left_handle ().x ();+ points[NUMBERS_PER_POINT * index + LEFT_HANDLE_POS_Y] = ep.get_left_handle ().y ();+ points[NUMBERS_PER_POINT * index + RIGHT_HANDLE_POS_X] = ep.get_right_handle ().x ();+ points[NUMBERS_PER_POINT * index + RIGHT_HANDLE_POS_Y] = ep.get_right_handle ().y ();+ }++ public double get_x (int index) {+ return points[NUMBERS_PER_POINT * index + POS_X];+ }+ + public double get_y (int index) {+ return points[NUMBERS_PER_POINT * index + POS_Y];+ }++ public double get_left_handle_x (int index) {+ return points[NUMBERS_PER_POINT * index + LEFT_HANDLE_POS_X];+ }+ + public double get_left_handle_y (int index) {+ return points[NUMBERS_PER_POINT * index + LEFT_HANDLE_POS_Y];+ }++ public double get_right_handle_x (int index) {+ return points[NUMBERS_PER_POINT * index + RIGHT_HANDLE_POS_X];+ }+ + public double get_right_handle_y (int index) {+ return points[NUMBERS_PER_POINT * index + RIGHT_HANDLE_POS_Y];+ }+ + public PointType get_point_type (int index) {+ return (PointType) types[index];+ }++ public bool is_active (int index) {+ return (flags[index] & ACTIVE) > 0;+ }++ public bool is_selected (int index) {+ return (flags[index] & SELECTED) > 0;+ }++ public bool is_deleted (int index) {+ return (flags[index] & DELETED) > 0;+ }++ public bool has_tied_handles (int index) {+ return (flags[index] & TIE_HANDLES) > 0;+ }++ public bool has_reflective_handles (int index) {+ return (flags[index] & REFLECTIVE_HANDLES) > 0;+ }+}++}@@ -27,8 +27,7 @@ public class Path { public List<EditPoint> points; EditPoint? last_point = null;- EditPoint? second_last_point = null;-+ /** Path boundaries */ public double xmax = double.MIN; public double xmin = double.MAX;@@ -967,7 +966,6 @@ public class Path { } } - second_last_point = last_point; last_point = p; return np;new file mode 100644@@ -0,0 +1,47 @@+/*+ Copyright (C) 2012, 2014 Johan Mattsson++ This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version.++ This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details.+*/++namespace BirdFont {++class Test : Object {+ public Callback callback;+ public string name;+ double time;+ bool benchmark = false;+ + public Test (Callback callback, string name, bool benchmark = false) {+ this.callback = callback;+ this.name = name;+ this.time = 0;+ this.benchmark = benchmark;+ }+ + public void timer_start () {+ time = GLib.get_real_time ();+ }++ public void timer_stop () {+ time = GLib.get_real_time () - time;+ }+ + public double get_time () {+ return time / 1000000.0;+ }+ + public bool is_benchmark () {+ return benchmark;+ }+}++}new file mode 100644@@ -0,0 +1,268 @@+/* + Copyright (C) 2012, 2014 Johan Mattsson + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. +*/ + +namespace BirdFont { + +/** Class for executing tests cases. */ +class TestBirdFont : GLib.Object { + + const int NOT_STARTED = 0; + const int RUNNING = 1; + const int PAUSED = 2; + const int DONE = 3; + + static int state = NOT_STARTED; + + TestCases tests; + + unowned List<Test> test_cases; + unowned List<Test?>? current_case = null; + + unowned List<Test> passed; + unowned List<Test> failed; + unowned List<Test> skipped; + + unowned List<Test> bechmarks; + + static TestBirdFont? singleton = null; + + bool has_failed = false; + bool has_skipped = false; + + static bool slow_test = false; + + string test_cases_to_run; // name of specific test case or all to run all test cases + + public TestBirdFont () { + assert (singleton == null); + tests = new TestCases (); + test_cases = tests.get_test_functions (); + current_case = test_cases.first (); + test_cases_to_run = "All"; + + from_command_line (); + } + + public static bool is_slow_test () { + return slow_test; + } + + public static void set_slow_test (bool s) { + slow_test = s; + } + + public static TestBirdFont get_singleton () { + if (singleton == null) { + singleton = new TestBirdFont (); + } + + return (!) singleton; + } + + private bool has_test_case (string s) { + foreach (var t in test_cases) { + if (t.name == s) return true; + } + + if (s == "" || s == "All") { + print ("No specific tescase given run all test cases.\n"); + return true; + } + + return false; + } + + /** Run only test specified on the command line. */ + private void from_command_line () { + string? stn = BirdFont.get_argument ("--test"); + + if (stn != null) { + string st = (!) stn; + + if (!has_test_case (st)) { + stderr.printf (@"Test case \"$st\" does not exist.\n"); + stderr.printf ("\nAvaliable test cases:\n"); + + foreach (var t in test_cases) { + stderr.printf (t.name); + stderr.printf ("\n"); + } + + Process.exit(1); + } + + if (st == "All" || st == "") { + return; + } else { + stderr.printf (@"Run only test case \"$st\" \n"); + } + + test_cases_to_run = st; + } + } + + public static void log (string? log_domain, LogLevelFlags log_levels, string message) { + Test t = (!)((!)get_singleton ().current_case).data; + + if (log_domain != null) { + stderr.printf ("%s: \n", (!) log_domain); + } + + stderr.printf ("Testcase \"%s\" failed because:\n", t.name); + stderr.printf ("%s\n\n", message); + + get_singleton ().has_failed = true; + + assert (!BirdFont.fatal_wanings); + } + + public static void @continue () { + int s = AtomicInt.get (ref state); + if (s == DONE) { + singleton = null; + } + + TestBirdFont t = get_singleton (); + + LogLevelFlags levels = LogLevelFlags.LEVEL_ERROR | LogLevelFlags.LEVEL_CRITICAL | LogLevelFlags.LEVEL_WARNING; + Log.set_handler (null, levels, log); + + AtomicInt.set (ref state, RUNNING); + t.run_all_tests (); + } + + public static bool is_running () { + int r = AtomicInt.get (ref state); + return (r == RUNNING); + } + + public static void pause () { + AtomicInt.set (ref state, PAUSED); + Log.set_handler (null, LogLevelFlags.LEVEL_MASK, Log.default_handler); + } + + private static void pad (int t) { + for (int i = 0; i < t; i++) { + stdout.printf (" "); + } + } + + public void print_result () { + stdout.printf ("\n"); + stdout.printf ("Test case results:\n"); + + foreach (Test t in skipped) { + stdout.printf ("%s", t.name); + pad (40 - t.name.char_count()); + stdout.printf ("Skipped\n"); + } + + if (skipped.length () > 0) { + stdout.printf ("\n"); + } + + foreach (Test t in passed) { + stdout.printf ("%s", t.name); + pad (40 - t.name.char_count()); + stdout.printf ("Passed\n"); + } + + foreach (Test t in failed) { + stdout.printf ("%s", t.name); + pad (40 - t.name.char_count()); + stdout.printf ("Failed\n"); + } + + foreach (Test t in bechmarks) { + stdout.printf ("%s", t.name); + pad (40 - t.name.char_count()); + stdout.printf (@"$(t.get_time ())s\n"); + } + + stdout.printf ("\n"); + + stdout.printf ("Total %u test cases executed, %u passed and %u failed.\n", (passed.length () + failed.length ()), passed.length (), failed.length ()); + } + + /** Run tests in main loop. */ + public void run_all_tests () { + TimeoutSource idle = new TimeoutSource (20); + MenuTab.new_file (); + + idle.set_callback(() => { + int s = AtomicInt.get (ref state); + + if (s != RUNNING || current_case == null) { + return false; + } + + Test test = (!)((!) current_case).data; + + has_failed = false; + has_skipped = false; + + if (test_cases_to_run != "All" && test_cases_to_run != test.name) { + has_skipped = true; + } else { + if (test.is_benchmark ()) { + test.timer_start (); + test.callback (); + test.timer_stop (); + } else { + test.callback (); + } + } + + if (test.is_benchmark ()) { + bechmarks.append ((!) test); + } else if (has_failed) { + failed.append ((!) test); + + if (BirdFont.has_argument ("--exit")) { + print_result (); + Process.exit (1); + } + + } else if (has_skipped) { + skipped.append ((!) test); + } else { + passed.append ((!) test); + } + + if (unlikely (current_case == test_cases.last ())) { + stdout.printf ("Finished running test suite.\n"); + + AtomicInt.set (ref state, DONE); + Log.set_handler (null, LogLevelFlags.LEVEL_MASK, Log.default_handler); + + print_result (); + + if (BirdFont.has_argument ("--exit")) { + print_result (); + Process.exit ((failed.length () == 0) ? 0 : 1); + } + return false; + } + + current_case = ((!) current_case).next; + + return true; + }); + + idle.attach (null); + } + +} + +} @@ -44,6 +44,12 @@ class TestCases { add (test_preview, "Preview"); add (test_kerning, "Kerning"); add (test_boundaries, "Boundaries");+ + add_bechmark (benchmark_stroke, "Stroke");+ }+ + private void add_bechmark (Callback callback, string name) {+ test_cases.append (new Test (callback, name, true)); } private void add (Callback callback, string name) {@@ -53,6 +59,21 @@ class TestCases { public unowned List<Test> get_test_functions () { return test_cases; }++ public static void benchmark_stroke () {+ Glyph glyph;+ test_open_next_glyph ();+ test_illustrator_import ();+ + glyph = MainWindow.get_current_glyph ();+ for (int i = 0; i < 5; i++) {+ foreach (Path p in glyph.path_list) {+ p.set_stroke (i / 100.0);+ glyph.update_view ();+ Tool.yield ();+ }+ }+ } public static void test_freetype () { StringBuilder? data;deleted file mode 100644@@ -1,260 +0,0 @@-/* - Copyright (C) 2012 Johan Mattsson - - This library is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 3 of the - License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. -*/ - -namespace BirdFont { - -class Test : Object { - public Callback callback; - public string name; - - public Test (Callback callback, string name) { - this.callback = callback; - this.name = name; - } -} - -/** Class for executing tests cases. */ -class TestBirdFont : GLib.Object { - - const int NOT_STARTED = 0; - const int RUNNING = 1; - const int PAUSED = 2; - const int DONE = 3; - - static int state = NOT_STARTED; - - TestCases tests; - - unowned List<Test> test_cases; - unowned List<Test?>? current_case = null; - - unowned List<Test> passed; - unowned List<Test> failed; - unowned List<Test> skipped; - - static TestBirdFont? singleton = null; - - bool has_failed = false; - bool has_skipped = false; - - static bool slow_test = false; - - string test_cases_to_run; // name of specific test case or all to run all test cases - - public TestBirdFont () { - assert (singleton == null); - tests = new TestCases (); - test_cases = tests.get_test_functions (); - current_case = test_cases.first (); - test_cases_to_run = "All"; - - from_command_line (); - } - - public static bool is_slow_test () { - return slow_test; - } - - public static void set_slow_test (bool s) { - slow_test = s; - } - - public static TestBirdFont get_singleton () { - if (singleton == null) { - singleton = new TestBirdFont (); - } - - return (!) singleton; - } - - private bool has_test_case (string s) { - foreach (var t in test_cases) { - if (t.name == s) return true; - } - - if (s == "" || s == "All") { - print ("No specific tescase given run all test cases.\n"); - return true; - } - - return false; - } - - /** Run only test specified on the command line. */ - private void from_command_line () { - string? stn = BirdFont.get_argument ("--test"); - - if (stn != null) { - string st = (!) stn; - - if (!has_test_case (st)) { - stderr.printf (@"Test case \"$st\" does not exist.\n"); - stderr.printf ("\nAvaliable test cases:\n"); - - foreach (var t in test_cases) { - stderr.printf (t.name); - stderr.printf ("\n"); - } - - Process.exit(1); - } - - if (st == "All" || st == "") { - return; - } else { - stderr.printf (@"Run only test case \"$st\" \n"); - } - - test_cases_to_run = st; - } - } - - public static void log (string? log_domain, LogLevelFlags log_levels, string message) { - Test t = (!)((!)get_singleton ().current_case).data; - - if (log_domain != null) { - stderr.printf ("%s: \n", (!) log_domain); - } - - stderr.printf ("Testcase \"%s\" failed because:\n", t.name); - stderr.printf ("%s\n\n", message); - - get_singleton ().has_failed = true; - - assert (!BirdFont.fatal_wanings); - } - - public static void @continue () { - int s = AtomicInt.get (ref state); - if (s == DONE) { - singleton = null; - } - - TestBirdFont t = get_singleton (); - - LogLevelFlags levels = LogLevelFlags.LEVEL_ERROR | LogLevelFlags.LEVEL_CRITICAL | LogLevelFlags.LEVEL_WARNING; - Log.set_handler (null, levels, log); - - AtomicInt.set (ref state, RUNNING); - t.run_all_tests (); - } - - public static bool is_running () { - int r = AtomicInt.get (ref state); - return (r == RUNNING); - } - - public static void pause () { - AtomicInt.set (ref state, PAUSED); - Log.set_handler (null, LogLevelFlags.LEVEL_MASK, Log.default_handler); - } - - private static void pad (int t) { - for (int i = 0; i < t; i++) stdout.printf (" "); - } - - public void print_result () { - stdout.printf ("\n"); - stdout.printf ("Test case results:\n"); - - foreach (var t in skipped) { - stdout.printf ("%s", t.name); - pad (40 - t.name.char_count()); - stdout.printf ("Skipped\n"); - } - - if (skipped.length () > 0) { - stdout.printf ("\n"); - } - - foreach (var t in passed) { - stdout.printf ("%s", t.name); - pad (40 - t.name.char_count()); - stdout.printf ("Passed\n"); - } - - foreach (var t in failed) { - stdout.printf ("%s", t.name); - pad (40 - t.name.char_count()); - stdout.printf ("Failed\n"); - } - - stdout.printf ("\n"); - - stdout.printf ("Total %u test cases executed, %u passed and %u failed.\n", (passed.length () + failed.length ()), passed.length (), failed.length ()); - } - - /** Run tests in main loop. */ - public void run_all_tests () { - TimeoutSource idle = new TimeoutSource (20); - MenuTab.new_file (); - - idle.set_callback(() => { - int s = AtomicInt.get (ref state); - - if (s != RUNNING || current_case == null) { - return false; - } - - Test test = (!)((!) current_case).data; - - has_failed = false; - has_skipped = false; - - if (test_cases_to_run != "All" && test_cases_to_run != test.name) { - has_skipped = true; - } else { - test.callback (); - } - - if (has_failed) { - failed.append ((!) test); - - if (BirdFont.has_argument ("--exit")) { - print_result (); - Process.exit (1); - } - - } else if (has_skipped) { - skipped.append ((!) test); - } else { - passed.append ((!) test); - } - - if (unlikely (current_case == test_cases.last ())) { - stdout.printf ("Finished running test suite.\n"); - - AtomicInt.set (ref state, DONE); - Log.set_handler (null, LogLevelFlags.LEVEL_MASK, Log.default_handler); - - print_result (); - - if (BirdFont.has_argument ("--exit")) { - print_result (); - Process.exit ((failed.length () == 0) ? 0 : 1); - } - return false; - } - - current_case = ((!) current_case).next; - - return true; - }); - - idle.attach (null); - } - -} - -}