From 26bba5fed80c610394db566489c067b22a12ef6c Mon Sep 17 00:00:00 2001 From: Glenn Nagel Date: Fri, 21 Jun 2013 23:16:46 -0400 Subject: [PATCH 01/11] Trying to figure out how to export headers ... --- binding.gyp | 1 + 1 file changed, 1 insertion(+) diff --git a/binding.gyp b/binding.gyp index 6288c43..1e01ed5 100644 --- a/binding.gyp +++ b/binding.gyp @@ -35,6 +35,7 @@ } ] ], + "include_dirs": [], "sources": [ "bindings.cpp", "geohash.cpp", From bcbbff663696611565d468a07e45a9655d6e1122 Mon Sep 17 00:00:00 2001 From: Glenn Nagel Date: Sat, 22 Jun 2013 12:38:46 -0400 Subject: [PATCH 02/11] Updating the layout of the package, added test for seconds_per_call_x_many_times --- binding.gyp | 15 +++-- {cvv8 => includes/cvv8}/ClassCreator.hpp | 0 {cvv8 => includes/cvv8}/Makefile | 0 {cvv8 => includes/cvv8}/NativeToJSMap.hpp | 0 {cvv8 => includes/cvv8}/V8Shell.hpp | 0 {cvv8 => includes/cvv8}/XTo.hpp | 0 {cvv8 => includes/cvv8}/arguments.hpp | 0 {cvv8 => includes/cvv8}/convert.hpp | 0 {cvv8 => includes/cvv8}/detail/Makefile | 0 .../cvv8}/detail/convert_core.hpp | 0 .../cvv8}/detail/doxygen_hack.hpp | 0 .../cvv8}/detail/invocable_core.hpp | 0 .../cvv8}/detail/invocable_generated.hpp | 0 .../cvv8}/detail/signature_core.hpp | 0 .../cvv8}/detail/signature_generated.hpp | 0 {cvv8 => includes/cvv8}/detail/tmp.hpp | 0 .../cvv8}/generator/Signature.hpp | 0 {cvv8 => includes/cvv8}/invocable.hpp | 0 {cvv8 => includes/cvv8}/properties.hpp | 0 {cvv8 => includes/cvv8}/signature.hpp | 0 {cvv8 => includes/cvv8}/v8-convert.hpp | 0 lib/cgeohash_fn.js | 8 +++ lib/cgeohash_fn_repeaters.js | 61 ++++++++++++++++++ lib/cgeohash_obj.js | 10 +++ lib/cgeohash_obj_repeaters.js | 62 +++++++++++++++++++ lib/seconds_per_call_x_many_times.js | 34 ++++++++++ geohash.cpp => src/geohash.cpp | 0 geohash.hpp => src/geohash.hpp | 0 geohash.js => src/geohash.js | 0 .../geohash_node_binding.cpp | 0 .../geohash_node_binding.hpp | 0 .../geohash_node_binding_speed.cpp | 0 .../geohash_node_binding_speed.hpp | 0 geohash_obj.cpp => src/geohash_obj.cpp | 0 geohash_obj.hpp => src/geohash_obj.hpp | 0 tests/seconds_per_call_x_many_times_test.js | 19 ++++++ 36 files changed, 203 insertions(+), 6 deletions(-) rename {cvv8 => includes/cvv8}/ClassCreator.hpp (100%) rename {cvv8 => includes/cvv8}/Makefile (100%) rename {cvv8 => includes/cvv8}/NativeToJSMap.hpp (100%) rename {cvv8 => includes/cvv8}/V8Shell.hpp (100%) rename {cvv8 => includes/cvv8}/XTo.hpp (100%) rename {cvv8 => includes/cvv8}/arguments.hpp (100%) rename {cvv8 => includes/cvv8}/convert.hpp (100%) rename {cvv8 => includes/cvv8}/detail/Makefile (100%) rename {cvv8 => includes/cvv8}/detail/convert_core.hpp (100%) rename {cvv8 => includes/cvv8}/detail/doxygen_hack.hpp (100%) rename {cvv8 => includes/cvv8}/detail/invocable_core.hpp (100%) rename {cvv8 => includes/cvv8}/detail/invocable_generated.hpp (100%) rename {cvv8 => includes/cvv8}/detail/signature_core.hpp (100%) rename {cvv8 => includes/cvv8}/detail/signature_generated.hpp (100%) rename {cvv8 => includes/cvv8}/detail/tmp.hpp (100%) rename {cvv8 => includes/cvv8}/generator/Signature.hpp (100%) rename {cvv8 => includes/cvv8}/invocable.hpp (100%) rename {cvv8 => includes/cvv8}/properties.hpp (100%) rename {cvv8 => includes/cvv8}/signature.hpp (100%) rename {cvv8 => includes/cvv8}/v8-convert.hpp (100%) create mode 100644 lib/cgeohash_fn.js create mode 100644 lib/cgeohash_fn_repeaters.js create mode 100644 lib/cgeohash_obj.js create mode 100644 lib/cgeohash_obj_repeaters.js create mode 100644 lib/seconds_per_call_x_many_times.js rename geohash.cpp => src/geohash.cpp (100%) rename geohash.hpp => src/geohash.hpp (100%) rename geohash.js => src/geohash.js (100%) rename geohash_node_binding.cpp => src/geohash_node_binding.cpp (100%) rename geohash_node_binding.hpp => src/geohash_node_binding.hpp (100%) rename geohash_node_binding_speed.cpp => src/geohash_node_binding_speed.cpp (100%) rename geohash_node_binding_speed.hpp => src/geohash_node_binding_speed.hpp (100%) rename geohash_obj.cpp => src/geohash_obj.cpp (100%) rename geohash_obj.hpp => src/geohash_obj.hpp (100%) create mode 100644 tests/seconds_per_call_x_many_times_test.js diff --git a/binding.gyp b/binding.gyp index 1e01ed5..33808e1 100644 --- a/binding.gyp +++ b/binding.gyp @@ -1,4 +1,5 @@ { +"variables": { "library_files": ["lib/cgeohash_obj.js", "lib/cgeohash_fn.js", "lib/cgeohash_obj_speed_tests.js", "lib/cgeohash_fn_speed_tests.js"] }, "conditions": [ [ "OS=='win'", @@ -35,13 +36,15 @@ } ] ], - "include_dirs": [], + "include_dirs": ["src"], "sources": [ - "bindings.cpp", - "geohash.cpp", - "geohash_node_binding.cpp", - "geohash_node_binding_speed.cpp", - "geohash_obj.cpp" + "src/bindings.cpp", + "src/cgeohash_cpp.cpp", + "src/cgeohash_node_fns.cpp", + "src/cgeohash_node_obj.cpp", + "src/speed_tests/cgeohash_cpp_st.cpp", + "src/speed_tests/cgeohash_node_fns_st.cpp", + "src/speed_tests/cgeohash_node_obj_st.cpp", ], "target_name": "cgeohash" } diff --git a/cvv8/ClassCreator.hpp b/includes/cvv8/ClassCreator.hpp similarity index 100% rename from cvv8/ClassCreator.hpp rename to includes/cvv8/ClassCreator.hpp diff --git a/cvv8/Makefile b/includes/cvv8/Makefile similarity index 100% rename from cvv8/Makefile rename to includes/cvv8/Makefile diff --git a/cvv8/NativeToJSMap.hpp b/includes/cvv8/NativeToJSMap.hpp similarity index 100% rename from cvv8/NativeToJSMap.hpp rename to includes/cvv8/NativeToJSMap.hpp diff --git a/cvv8/V8Shell.hpp b/includes/cvv8/V8Shell.hpp similarity index 100% rename from cvv8/V8Shell.hpp rename to includes/cvv8/V8Shell.hpp diff --git a/cvv8/XTo.hpp b/includes/cvv8/XTo.hpp similarity index 100% rename from cvv8/XTo.hpp rename to includes/cvv8/XTo.hpp diff --git a/cvv8/arguments.hpp b/includes/cvv8/arguments.hpp similarity index 100% rename from cvv8/arguments.hpp rename to includes/cvv8/arguments.hpp diff --git a/cvv8/convert.hpp b/includes/cvv8/convert.hpp similarity index 100% rename from cvv8/convert.hpp rename to includes/cvv8/convert.hpp diff --git a/cvv8/detail/Makefile b/includes/cvv8/detail/Makefile similarity index 100% rename from cvv8/detail/Makefile rename to includes/cvv8/detail/Makefile diff --git a/cvv8/detail/convert_core.hpp b/includes/cvv8/detail/convert_core.hpp similarity index 100% rename from cvv8/detail/convert_core.hpp rename to includes/cvv8/detail/convert_core.hpp diff --git a/cvv8/detail/doxygen_hack.hpp b/includes/cvv8/detail/doxygen_hack.hpp similarity index 100% rename from cvv8/detail/doxygen_hack.hpp rename to includes/cvv8/detail/doxygen_hack.hpp diff --git a/cvv8/detail/invocable_core.hpp b/includes/cvv8/detail/invocable_core.hpp similarity index 100% rename from cvv8/detail/invocable_core.hpp rename to includes/cvv8/detail/invocable_core.hpp diff --git a/cvv8/detail/invocable_generated.hpp b/includes/cvv8/detail/invocable_generated.hpp similarity index 100% rename from cvv8/detail/invocable_generated.hpp rename to includes/cvv8/detail/invocable_generated.hpp diff --git a/cvv8/detail/signature_core.hpp b/includes/cvv8/detail/signature_core.hpp similarity index 100% rename from cvv8/detail/signature_core.hpp rename to includes/cvv8/detail/signature_core.hpp diff --git a/cvv8/detail/signature_generated.hpp b/includes/cvv8/detail/signature_generated.hpp similarity index 100% rename from cvv8/detail/signature_generated.hpp rename to includes/cvv8/detail/signature_generated.hpp diff --git a/cvv8/detail/tmp.hpp b/includes/cvv8/detail/tmp.hpp similarity index 100% rename from cvv8/detail/tmp.hpp rename to includes/cvv8/detail/tmp.hpp diff --git a/cvv8/generator/Signature.hpp b/includes/cvv8/generator/Signature.hpp similarity index 100% rename from cvv8/generator/Signature.hpp rename to includes/cvv8/generator/Signature.hpp diff --git a/cvv8/invocable.hpp b/includes/cvv8/invocable.hpp similarity index 100% rename from cvv8/invocable.hpp rename to includes/cvv8/invocable.hpp diff --git a/cvv8/properties.hpp b/includes/cvv8/properties.hpp similarity index 100% rename from cvv8/properties.hpp rename to includes/cvv8/properties.hpp diff --git a/cvv8/signature.hpp b/includes/cvv8/signature.hpp similarity index 100% rename from cvv8/signature.hpp rename to includes/cvv8/signature.hpp diff --git a/cvv8/v8-convert.hpp b/includes/cvv8/v8-convert.hpp similarity index 100% rename from cvv8/v8-convert.hpp rename to includes/cvv8/v8-convert.hpp diff --git a/lib/cgeohash_fn.js b/lib/cgeohash_fn.js new file mode 100644 index 0000000..8025d12 --- /dev/null +++ b/lib/cgeohash_fn.js @@ -0,0 +1,8 @@ +var cgeohash = require('./build/Release/cgeohash'); + +module.exports = { + encode: cgeohash.encode_fn, + decode: cgeohash.decode_fn, + decode_bbox: cgeohash.decode_bbox_fn, + neighbor: cgeohash.neighbor_fn, +}; diff --git a/lib/cgeohash_fn_repeaters.js b/lib/cgeohash_fn_repeaters.js new file mode 100644 index 0000000..16861da --- /dev/null +++ b/lib/cgeohash_fn_repeaters.js @@ -0,0 +1,61 @@ +// +// Map the cgeohash C++ functions to callbacks to repeat X-Many times +// +// Ex: +// var repeat_in_js = require('cgeohash_fn_repeaters').repeat_in_js +// var repeat_in_cpp = require('cgeohash_fn_repeaters').repeat_in_cpp +// var avg_seconds_per_decode = { +// looping_in_js: repeat_in_js.decode( 1000*1000, 'abcd'), +// looping_in_cpp: repeat_in_cpp.decode(1000*1000, 'abcd'), +// } +// +// console.log('Seconds per call Node <-> C++ = ' + looping_in_js); +// console.log('Seconds per call C++ <-> C++ = ' + looping_in_cpp); +// + +var cgeohash = require('./build/Release/cgeohash'); +var cgeohash_fn = require('./cgeohash_fn'); +var seconds_per_call_x_many_times = require('./seconds_per_call_x_many_times'); + +// Alias the <...>_obj methods to the expected <...> method names +// Loop in JS and record the seconds / call +var cgeohash_fn_repeat_js = { + encode: function(num_times, latitude, longitude, numberOfChars) { + return seconds_per_call_x_many_times(num_times, function() { + return cgeohash_fn.encode(latitude, longitude, numberOfChars); + }); + }; + + decode: function(num_times, hash_string) { + return seconds_per_call_x_many_times(num_times, function() { + return cgeohash_fn.dncode(hash_string); + }); + }; + + decode_bbox: function(num_times, hash_string) { + return seconds_per_call_x_many_times(num_times, function() { + return cgeohash_fn.decode_bbox(hash_string); + }); + }; + + neighbor: function(num_times, hash_string, direction) { + return seconds_per_call_x_many_times(num_times, function() { + return cgeohash_fn.neighbor(hash_string, direction); + }); + }; +}; + +// Alias the <...>_obj methods to the expected <...> method names +// Loop in CPP and record the seconds / call +var cgeohash_fn_repeat_cpp = { + encode: cgeohash.encode_fn_repeat, + decode: cgeohash.decode_fn_repeat, + decode_bbox: cgeohash.decode_bbox_fn_repeat, + neighbor: cgeohash.neighbor_fn_repeat, +}; + + +module.exports = { + repeat_in_js: cgeohash_fn_repeat_js, + repeat_in_cpp: cgeohash_fn_repeat_cpp, +}; diff --git a/lib/cgeohash_obj.js b/lib/cgeohash_obj.js new file mode 100644 index 0000000..5b9e245 --- /dev/null +++ b/lib/cgeohash_obj.js @@ -0,0 +1,10 @@ +var cgeohash = require('./build/Release/cgeohash'); +var cgeohash_obj = new cgeohash.GeoHashObject(); + +// Alias the <...>_obj methods to the expected <...> method names +module.exports = { + encode: cgeohash_obj.encode_obj, + decode: cgeohash_obj.decode_obj, + decode_bbox: cgeohash_obj.decode_bbox_obj, + neighbor: cgeohash_obj.neighbor_obj, +}; diff --git a/lib/cgeohash_obj_repeaters.js b/lib/cgeohash_obj_repeaters.js new file mode 100644 index 0000000..8e87161 --- /dev/null +++ b/lib/cgeohash_obj_repeaters.js @@ -0,0 +1,62 @@ +// +// Map the cgeohash C++ Object to callbacks to repeat X-Many times +// +// Ex: +// var repeat_in_js = require('cgeohash_obj_repeaters').repeat_in_js +// var repeat_in_cpp = require('cgeohash_obj_repeaters').repeat_in_cpp +// var avg_seconds_per_decode = { +// looping_in_js: repeat_in_js.decode( 1000*1000, 'abcd'), +// looping_in_cpp: repeat_in_cpp.decode(1000*1000, 'abcd'), +// } +// +// console.log('Seconds per call Node <-> C++ = ' + looping_in_js); +// console.log('Seconds per call C++ <-> C++ = ' + looping_in_cpp); +// + +var cgeohash = require('./build/Release/cgeohash'); +var cgeohash_obj = require('./cgeohash_obj'); +var cgeohash_obj_repeater = new cgeohash.GeoHashObjectRepeater(); +var seconds_per_call_x_many_times = require('./seconds_per_call_x_many_times'); + +// Alias the <...>_obj methods to the expected <...> method names +// Loop in JS and record the seconds / call +var cgeohash_fn_repeat_js = { + encode: function(num_times, latitude, longitude, numberOfChars) { + return seconds_per_call_x_many_times(num_times, function() { + return cgeohash_obj.encode(latitude, longitude, numberOfChars); + }); + }; + + decode: function(num_times, hash_string) { + return seconds_per_call_x_many_times(num_times, function() { + return cgeohash_obj.dncode(hash_string); + }); + }; + + decode_bbox: function(num_times, hash_string) { + return seconds_per_call_x_many_times(num_times, function() { + return cgeohash_obj.decode_bbox(hash_string); + }); + }; + + neighbor: function(num_times, hash_string, direction) { + return seconds_per_call_x_many_times(num_times, function() { + return cgeohash_obj.neighbor(hash_string, direction); + }); + }; +}; + +// Alias the <...>_obj methods to the expected <...> method names +// Loop in CPP and record the seconds / call +var cgeohash_fn_repeat_cpp = { + encode: cgeohash_obj_repeater.encode_obj_repeat, + decode: cgeohash_obj_repeater.decode_obj_repeat, + decode_bbox: cgeohash_obj_repeater.decode_bbox_obj_repeat, + neighbor: cgeohash_obj_repeater.neighbor_obj_repeat, +}; + + +module.exports = { + repeat_in_js: cgeohash_fn_repeat_js, + repeat_in_cpp: cgeohash_fn_repeat_cpp, +}; diff --git a/lib/seconds_per_call_x_many_times.js b/lib/seconds_per_call_x_many_times.js new file mode 100644 index 0000000..83c530d --- /dev/null +++ b/lib/seconds_per_call_x_many_times.js @@ -0,0 +1,34 @@ +// +// Execute the callback X-Many times and return the "Seconds / Call" +// +// Ex: +// var repeater = require('./seconds_per_call_x_many_times'); +// var counter = 0; +// var num_times = 1000*1000*1000; +// var callback = function() { Math.sqrt(++counter); }; +// var sec_per_call = repeater(num_times, callback); +// +// /* Make sure the callback was called */ +// counter.should.equal(num_times); +// +// /* Log the avg time per call */ +// console.log("Calculating Math.sqrt " + counter + " times took " + sec_per_call + " (s) / call"); +// + +var NANOSECONDS_TO_SECONDS = 1000 * 1000 * 1000; + +module.exports = function(num_times, callback) { + // Start + var time = process.hrtime(); + + // Execute + for (var i = 0; i < num_times; ++i) { + last = callback(); + } + + // Stop + var diff = process.hrtime(time); + var seconds = diff[0].valueOf() + diff[1].valueOf() / (NANOSECONDS_TO_SECONDS); + + return seconds / num_times; +}; diff --git a/geohash.cpp b/src/geohash.cpp similarity index 100% rename from geohash.cpp rename to src/geohash.cpp diff --git a/geohash.hpp b/src/geohash.hpp similarity index 100% rename from geohash.hpp rename to src/geohash.hpp diff --git a/geohash.js b/src/geohash.js similarity index 100% rename from geohash.js rename to src/geohash.js diff --git a/geohash_node_binding.cpp b/src/geohash_node_binding.cpp similarity index 100% rename from geohash_node_binding.cpp rename to src/geohash_node_binding.cpp diff --git a/geohash_node_binding.hpp b/src/geohash_node_binding.hpp similarity index 100% rename from geohash_node_binding.hpp rename to src/geohash_node_binding.hpp diff --git a/geohash_node_binding_speed.cpp b/src/geohash_node_binding_speed.cpp similarity index 100% rename from geohash_node_binding_speed.cpp rename to src/geohash_node_binding_speed.cpp diff --git a/geohash_node_binding_speed.hpp b/src/geohash_node_binding_speed.hpp similarity index 100% rename from geohash_node_binding_speed.hpp rename to src/geohash_node_binding_speed.hpp diff --git a/geohash_obj.cpp b/src/geohash_obj.cpp similarity index 100% rename from geohash_obj.cpp rename to src/geohash_obj.cpp diff --git a/geohash_obj.hpp b/src/geohash_obj.hpp similarity index 100% rename from geohash_obj.hpp rename to src/geohash_obj.hpp diff --git a/tests/seconds_per_call_x_many_times_test.js b/tests/seconds_per_call_x_many_times_test.js new file mode 100644 index 0000000..e76c6f4 --- /dev/null +++ b/tests/seconds_per_call_x_many_times_test.js @@ -0,0 +1,19 @@ +var path = require('path'); +var mocha = require('mocha'); +var chai = require('chai'); +var should = chai.should(); +var repeater = require('../lib/seconds_per_call_x_many_times'); + +describe('Record Avg Seconds per call', function() { + var counter = 0; + var num_times = 1000 * 1000 * 1000; + var callback = function() { + Math.sqrt(++counter); + }; + var sec_per_call = repeater(num_times, callback); + + /* Make sure the callback was called */ + it('Counter should equal num_times', function() { + counter.should.equal(num_times); + }); +}); From 7327f6bfc46130c83cb0f91417493717604cad32 Mon Sep 17 00:00:00 2001 From: Glenn Nagel Date: Sat, 22 Jun 2013 12:48:00 -0400 Subject: [PATCH 03/11] Adding new headers for re-named functions and objects --- src/cgeohash.hpp | 41 ++++++++++++++++++++++++++++++++++ src/cgeohash_fn.hpp | 20 +++++++++++++++++ src/cgeohash_fn_repeaters.hpp | 20 +++++++++++++++++ src/cgeohash_obj.hpp | 25 +++++++++++++++++++++ src/cgeohash_obj_repeaters.hpp | 27 ++++++++++++++++++++++ 5 files changed, 133 insertions(+) create mode 100644 src/cgeohash.hpp create mode 100644 src/cgeohash_fn.hpp create mode 100644 src/cgeohash_fn_repeaters.hpp create mode 100644 src/cgeohash_obj.hpp create mode 100644 src/cgeohash_obj_repeaters.hpp diff --git a/src/cgeohash.hpp b/src/cgeohash.hpp new file mode 100644 index 0000000..2caad72 --- /dev/null +++ b/src/cgeohash.hpp @@ -0,0 +1,41 @@ +#ifndef _NODE_CGEOHASH_HPP +#define _NODE_CGEOHASH_HPP + +#include +#include + +namespace cgeohash { + +struct DecodedBBox { + double minlat, minlon, maxlat, maxlon; +}; + +struct DecodedHash { + double latitude; + double longitude; + + double latitude_err; + double longitude_err; +}; + +// Compute nanoseconds at current time +uint64_t nanoseconds(); + +// Encode a pair of latitude and longitude into geohash +std::string encode(const double latitude, const double longitude, const unsigned long precision); + +// Decode a hash string into pair of latitude and longitude +DecodedHash decode(const std::string & hash_string); + +// Decode hashstring into a bound box matches it +DecodedBBox decode_bbox(const std::string & hash_string); + +// Find neighbor of a geohash string in certain direction. +// Direction is a two-element array: +// Ex: [ 1, 0] == north +// Ex: [-1,-1] == southwest +std::string neighbor(const std::string & hash_string, const int direction []); + +} // end namespace cgeohash + +#endif /* end hpp */ diff --git a/src/cgeohash_fn.hpp b/src/cgeohash_fn.hpp new file mode 100644 index 0000000..b855b36 --- /dev/null +++ b/src/cgeohash_fn.hpp @@ -0,0 +1,20 @@ +#ifndef _NODE_CGEOHASH_FN_HPP +#define _NODE_CGEOHASH_FN_HPP + +#include +#include + +namespace cgeohash { + +// Node.JS Hooks to GeoHash encoding +v8::Handle encode_fn(const v8::Arguments& args); +v8::Handle decode_fn(const v8::Arguments& args); +v8::Handle decode_bbox_fn(const v8::Arguments& args); +v8::Handle neighbor_fn(const v8::Arguments& args); + +// Register the above methods with node +v8::Handle register_node_fns(v8::Handle target); + +} + +#endif /* end hpp */ diff --git a/src/cgeohash_fn_repeaters.hpp b/src/cgeohash_fn_repeaters.hpp new file mode 100644 index 0000000..8e505a0 --- /dev/null +++ b/src/cgeohash_fn_repeaters.hpp @@ -0,0 +1,20 @@ +#ifndef _NODE_CGEOHASH_FN_REPEATERS_HPP +#define _NODE_CGEOHASH_FN_REPEATERS_HPP + +#include +#include + +namespace cgeohash { + +// Node.JS Hooks to GeoHash encoding +v8::Handle encode_fn_repeater(const v8::Arguments& args); +v8::Handle decode_fn_repeater(const v8::Arguments& args); +v8::Handle decode_bbox_fn_repeater(const v8::Arguments& args); +v8::Handle neighbor_fn_repeater(const v8::Arguments& args); + +// Register the above methods with node +v8::Handle register_node_fn_repeaters(v8::Handle target); + +} + +#endif /* end hpp */ diff --git a/src/cgeohash_obj.hpp b/src/cgeohash_obj.hpp new file mode 100644 index 0000000..79ca207 --- /dev/null +++ b/src/cgeohash_obj.hpp @@ -0,0 +1,25 @@ +#ifndef _NODE_CGEOHASH_OBJ_HPP +#define _NODE_CGEOHASH_OBJ_HPP + +#include +#include + +namespace cgeohash { + +class GeoHashObject : public node::ObjectWrap { +public: + static v8::Persistent constructor; + static void Init(v8::Handle target); + +protected: + GeoHashObject(); + + static v8::Handle New(const v8::Arguments& args); + static v8::Handle Encode(const v8::Arguments& args); + static v8::Handle Decode(const v8::Arguments& args); + static v8::Handle DecodeBBox(const v8::Arguments& args); + static v8::Handle Neighbor(const v8::Arguments& args); + }; +} + +#endif /* geohash.hpp */ diff --git a/src/cgeohash_obj_repeaters.hpp b/src/cgeohash_obj_repeaters.hpp new file mode 100644 index 0000000..b97ae06 --- /dev/null +++ b/src/cgeohash_obj_repeaters.hpp @@ -0,0 +1,27 @@ +#ifndef _NODE_CGEOHASH_OBJ_REPEATERS_HPP +#define _NODE_CGEOHASH_OBJ_REPEATERS_HPP + +#include +#include + +namespace cgeohash { + +class GeoHashObjectRepeater : public node::ObjectWrap { +public: + static v8::Persistent constructor; + static void Init(v8::Handle target); + +protected: + GeoHashObject(); + + static v8::Handle New(const v8::Arguments& args); + static v8::Handle Encode(const v8::Arguments& args); + static v8::Handle Decode(const v8::Arguments& args); + static v8::Handle DecodeBBox(const v8::Arguments& args); + static v8::Handle Neighbor(const v8::Arguments& args); + + }; + +} + +#endif /* geohash.hpp */ From de02c08f58bc21f4dc6b59c0b387a2540cfc1c8f Mon Sep 17 00:00:00 2001 From: Glenn Nagel Date: Sat, 22 Jun 2013 13:19:22 -0400 Subject: [PATCH 04/11] Updated C++ code --- binding.gyp | 13 +- bindings.cpp | 15 --- src/{geohash.cpp => cgeohash.cpp} | 43 ++----- src/cgeohash.hpp | 3 - src/cgeohash_bindings.cpp | 17 +++ ...ohash_node_binding.cpp => cgeohash_fn.cpp} | 30 ++--- src/cgeohash_fn.hpp | 2 +- src/cgeohash_fn_repeaters.cpp | 121 ++++++++++++++++++ src/cgeohash_fn_repeaters.hpp | 2 +- src/cgeohash_nanoseconds.cpp | 52 ++++++++ src/cgeohash_nanoseconds.hpp | 16 +++ src/cgeohash_obj.cpp | 77 +++++++++++ src/cgeohash_obj_repeaters.cpp | 74 +++++++++++ src/cgeohash_obj_repeaters.hpp | 2 +- src/geohash.hpp | 44 ------- src/geohash.js | 18 --- src/geohash_node_binding.hpp | 18 --- src/geohash_node_binding_speed.cpp | 116 ----------------- src/geohash_node_binding_speed.hpp | 19 --- src/geohash_obj.cpp | 105 --------------- src/geohash_obj.hpp | 27 ---- 21 files changed, 389 insertions(+), 425 deletions(-) delete mode 100644 bindings.cpp rename src/{geohash.cpp => cgeohash.cpp} (79%) create mode 100644 src/cgeohash_bindings.cpp rename src/{geohash_node_binding.cpp => cgeohash_fn.cpp} (82%) create mode 100644 src/cgeohash_fn_repeaters.cpp create mode 100644 src/cgeohash_nanoseconds.cpp create mode 100644 src/cgeohash_nanoseconds.hpp create mode 100644 src/cgeohash_obj.cpp create mode 100644 src/cgeohash_obj_repeaters.cpp delete mode 100644 src/geohash.hpp delete mode 100644 src/geohash.js delete mode 100644 src/geohash_node_binding.hpp delete mode 100644 src/geohash_node_binding_speed.cpp delete mode 100644 src/geohash_node_binding_speed.hpp delete mode 100644 src/geohash_obj.cpp delete mode 100644 src/geohash_obj.hpp diff --git a/binding.gyp b/binding.gyp index 33808e1..4d8f14a 100644 --- a/binding.gyp +++ b/binding.gyp @@ -38,13 +38,12 @@ ], "include_dirs": ["src"], "sources": [ - "src/bindings.cpp", - "src/cgeohash_cpp.cpp", - "src/cgeohash_node_fns.cpp", - "src/cgeohash_node_obj.cpp", - "src/speed_tests/cgeohash_cpp_st.cpp", - "src/speed_tests/cgeohash_node_fns_st.cpp", - "src/speed_tests/cgeohash_node_obj_st.cpp", + "src/cgeohash_bindings.cpp", + "src/cgeohash.cpp", + "src/cgeohash_fn.cpp", + "src/cgeohash_fn_repeaters.cpp", + "src/cgeohash_obj.cpp", + "src/cgeohash_nanoseconds.cpp" ], "target_name": "cgeohash" } diff --git a/bindings.cpp b/bindings.cpp deleted file mode 100644 index ebaedc6..0000000 --- a/bindings.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include - -#include "geohash.hpp" -#include "geohash_node_binding.hpp" -#include "geohash_node_binding_speed.hpp" -#include "geohash_obj.hpp" - -void RegisterModule(v8::Handle target) { - GeoHashObject::Init(target); - geohash_Init(target); - geohash::test1m_Init(target); -} - -NODE_MODULE(cgeohash, RegisterModule); diff --git a/src/geohash.cpp b/src/cgeohash.cpp similarity index 79% rename from src/geohash.cpp rename to src/cgeohash.cpp index a1c5a94..149a127 100644 --- a/src/geohash.cpp +++ b/src/cgeohash.cpp @@ -7,39 +7,12 @@ #include #include -#include "geohash.hpp" - -// http://stackoverflow.com/a/17112198 -#ifdef __MACH__ -#include -#define CLOCK_REALTIME 0 -#define CLOCK_MONOTONIC 0 -int clock_gettime(int clk_id, struct timespec *t){ - mach_timebase_info_data_t timebase; - mach_timebase_info(&timebase); - uint64_t time; - time = mach_absolute_time(); - double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom); - double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9); - t->tv_sec = seconds; - t->tv_nsec = nseconds; - return 0; -} -#else -#include -#endif - -namespace geohash { -#undef NANOSEC -#define NANOSEC ((uint64_t) 1e9) - - uint64_t nanoseconds() { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); - } - -std::string encode(const double latitude, const double longitude, unsigned long numberOfChars) { +#include "cgeohash.hpp" + + +namespace cgeohash { + +std::string encode(const double latitude, const double longitude, unsigned long precision) { // DecodedBBox for the lat/lon + errors DecodedBBox bbox; bbox.maxlat = 90; @@ -54,7 +27,7 @@ std::string encode(const double latitude, const double longitude, unsigned long std::string hash_string; - while(hash_string.length() < numberOfChars) { + while(hash_string.length() < precision) { if (islon) { mid = (bbox.maxlon + bbox.minlon) / 2; if(longitude > mid) { @@ -155,4 +128,4 @@ std::string neighbor(const std::string & hash_string, const int direction []) { hash_string.length()); } -} // end namespace geohash +} // end namespace cgeohash diff --git a/src/cgeohash.hpp b/src/cgeohash.hpp index 2caad72..83c85c1 100644 --- a/src/cgeohash.hpp +++ b/src/cgeohash.hpp @@ -18,9 +18,6 @@ struct DecodedHash { double longitude_err; }; -// Compute nanoseconds at current time -uint64_t nanoseconds(); - // Encode a pair of latitude and longitude into geohash std::string encode(const double latitude, const double longitude, const unsigned long precision); diff --git a/src/cgeohash_bindings.cpp b/src/cgeohash_bindings.cpp new file mode 100644 index 0000000..d9a764d --- /dev/null +++ b/src/cgeohash_bindings.cpp @@ -0,0 +1,17 @@ +#include +#include + +#include "cgeohash.hpp" +#include "cgeohash_fn.hpp" +#include "cgeohash_fn_repeaters.hpp" +#include "cgeohash_obj.hpp" +#include "cgeohash_obj_repeaters.hpp" + +void RegisterModule(v8::Handle target) { + cgeohash::GeoHashObject::Init(target); + cgeohash::GeoHashObjectRepeater::Init(target); + cgeohash::register_node_fns(target); + cgeohash::register_node_fn_repeaters(target); +} + +NODE_MODULE(cgeohash, RegisterModule); diff --git a/src/geohash_node_binding.cpp b/src/cgeohash_fn.cpp similarity index 82% rename from src/geohash_node_binding.cpp rename to src/cgeohash_fn.cpp index bead322..e093fb6 100644 --- a/src/geohash_node_binding.cpp +++ b/src/cgeohash_fn.cpp @@ -1,17 +1,16 @@ #include #include -#include "cvv8/detail/convert_core.hpp" +#include "../includes/cvv8/detail/convert_core.hpp" -#include "geohash.hpp" -#include "geohash_node_binding.hpp" +#include "cgeohash.hpp" +#include "cgeohash_fn.hpp" #define _THROW_NODE_ERROR(MSG) ThrowException(v8::Exception::Error(v8::String::New(MSG))); - -namespace geohash { +namespace cgeohash { // Node.JS Hooks to GeoHash encoding - v8::Handle encode_js(const v8::Arguments& args) { + v8::Handle encode_fn(const v8::Arguments& args) { v8::HandleScope scope; if (args.Length() < 2) { @@ -28,7 +27,7 @@ namespace geohash { return scope.Close(cvv8::CastToJS(hash_string)); } - v8::Handle decode_js(const v8::Arguments& args) { + v8::Handle decode_fn(const v8::Arguments& args) { v8::HandleScope scope; if (args.Length() < 1) { @@ -60,7 +59,7 @@ namespace geohash { return scope.Close(output); } - v8::Handle decode_bbox_js(const v8::Arguments& args) { + v8::Handle decode_bbox_fn(const v8::Arguments& args) { v8::HandleScope scope; if (args.Length() < 1) { @@ -82,7 +81,7 @@ namespace geohash { return scope.Close(cvv8::CastToJS< std::list >(list)); } - v8::Handle neighbor_js(const v8::Arguments& args) { + v8::Handle neighbor_fn(const v8::Arguments& args) { v8::HandleScope scope; if (args.Length() < 2) { @@ -107,12 +106,13 @@ namespace geohash { return scope.Close(cvv8::CastToJS(neighbor_string)); } -} +void register_node_fns(v8::Handle target) { + node::SetMethod(target, "encode_fn", encode_fn); + node::SetMethod(target, "decode_fn", decode_fn); + node::SetMethod(target, "decode_bbox_fn", decode_bbox_fn); + node::SetMethod(target, "neighbor_fn", neighbor_fn); +} -void geohash_Init(v8::Handle target) { - node::SetMethod(target, "encode_js", geohash::encode_js); - node::SetMethod(target, "decode_js", geohash::decode_js); - node::SetMethod(target, "decode_bbox_js", geohash::decode_bbox_js); - node::SetMethod(target, "neighbor_js", geohash::neighbor_js); } + diff --git a/src/cgeohash_fn.hpp b/src/cgeohash_fn.hpp index b855b36..673ed9f 100644 --- a/src/cgeohash_fn.hpp +++ b/src/cgeohash_fn.hpp @@ -13,7 +13,7 @@ v8::Handle decode_bbox_fn(const v8::Arguments& args); v8::Handle neighbor_fn(const v8::Arguments& args); // Register the above methods with node -v8::Handle register_node_fns(v8::Handle target); +void register_node_fns(v8::Handle target); } diff --git a/src/cgeohash_fn_repeaters.cpp b/src/cgeohash_fn_repeaters.cpp new file mode 100644 index 0000000..19b75cd --- /dev/null +++ b/src/cgeohash_fn_repeaters.cpp @@ -0,0 +1,121 @@ +#include +#include +#include "../includes/cvv8/detail/convert_core.hpp" + +#include "cgeohash.hpp" +#include "cgeohash_fn_repeaters.hpp" +#include "cgeohash_nanoseconds.hpp" + +#define _THROW_NODE_ERROR(MSG) ThrowException(v8::Exception::Error(v8::String::New(MSG))); + + +namespace cgeohash { + + // Node.JS Hooks to GeoHash encoding + v8::Handle encode_fn_repeater(const v8::Arguments& args) { + v8::HandleScope scope; + + if (args.Length() < 3) { + return _THROW_NODE_ERROR("Takes 4 parameters: num_times, latitude, longitude, and precision"); + } + + int i = 0; + const int num_times = cvv8::CastFromJS< int >(args[i++]); + const double latitude = cvv8::CastFromJS< double >(args[i++]); + const double longitude = cvv8::CastFromJS< double >(args[i++]); + const uint32_t precision = args.Length() == 3 + ? cvv8::CastFromJS< uint32_t >(args[i++]) + : 9; // Default input + + const uint64_t _nanoseconds = nanoseconds(); + for(int i = 0; i < num_times; i++) { + encode(latitude, longitude, precision); + } + const double _seconds = seconds_differience_of_nanoseconds(_nanoseconds) / num_times; + return scope.Close(cvv8::CastToJS(_seconds)); + } + + v8::Handle decode_fn_repeater(const v8::Arguments& args) { + v8::HandleScope scope; + + if (args.Length() < 2) { + return _THROW_NODE_ERROR("Takes 1 parameters: num_times, hash_string"); + } + + int i = 0; + const int num_times = cvv8::CastFromJS< int >(args[i++]); + const std::string hash_string = cvv8::CastFromJS(args[i++]); + if (hash_string.empty()) { + return _THROW_NODE_ERROR("Parameter 0 must be a valid string"); + } + + const uint64_t _nanoseconds = nanoseconds(); + for(int i = 0; i < num_times; i++) { + decode(hash_string); + } + const double _seconds = seconds_differience_of_nanoseconds(_nanoseconds) / num_times; + return scope.Close(cvv8::CastToJS(_seconds)); + } + + v8::Handle decode_bbox_fn_repeater(const v8::Arguments& args) { + v8::HandleScope scope; + + if (args.Length() < 2) { + return _THROW_NODE_ERROR("Takes 1 parameters: num_times, hash_string"); + } + + int i = 0; + const int num_times = cvv8::CastFromJS< int >(args[i++]); + const std::string hash_string = cvv8::CastFromJS(args[i++]); + if (hash_string.empty()) { + return _THROW_NODE_ERROR("Parameter 1 must be a valid string"); + } + + const uint64_t _nanoseconds = nanoseconds(); + for(int i = 0; i < num_times; i++) { + decode_bbox(hash_string); + } + const double _seconds = seconds_differience_of_nanoseconds(_nanoseconds) / num_times; + return scope.Close(cvv8::CastToJS(_seconds)); + } + + v8::Handle neighbor_fn_repeater(const v8::Arguments& args) { + v8::HandleScope scope; + + if (args.Length() < 3) { + return _THROW_NODE_ERROR("Takes 3 parameters: num_times, hash_string, and direction []"); + } + + int i = 0; + const int num_times = cvv8::CastFromJS< int >(args[i++]); + const std::string hash_string = cvv8::CastFromJS(args[i++]); + if (hash_string.empty()) { + return _THROW_NODE_ERROR("Parameter 1 must be a valid string"); + } + + const std::list directions = cvv8::CastFromJS< std::list >(args[1]); + if (directions.size() != 2) { + return _THROW_NODE_ERROR("Parameter 1 must be an array with 2 numbers"); + } + + const int directions_array [] = { + directions.front(), // Only 2 elements + directions.back() // Only 2 elements + }; + + const uint64_t _nanoseconds = nanoseconds(); + for(int i = 0; i < num_times; i++) { + neighbor(hash_string, directions_array); + } + const double _seconds = seconds_differience_of_nanoseconds(_nanoseconds) / num_times; + return scope.Close(cvv8::CastToJS(_seconds)); + } + + void register_node_fn_repeaters(v8::Handle target) { + node::SetMethod(target, "encode_fn_repeater", encode_fn_repeater); + node::SetMethod(target, "decode_fn_repeater", decode_fn_repeater); + node::SetMethod(target, "decode_bbox_fn_repeater", decode_bbox_fn_repeater); + node::SetMethod(target, "neighbor_fn_repeater", neighbor_fn_repeater); + } + +} diff --git a/src/cgeohash_fn_repeaters.hpp b/src/cgeohash_fn_repeaters.hpp index 8e505a0..96afbdc 100644 --- a/src/cgeohash_fn_repeaters.hpp +++ b/src/cgeohash_fn_repeaters.hpp @@ -13,7 +13,7 @@ v8::Handle decode_bbox_fn_repeater(const v8::Arguments& args); v8::Handle neighbor_fn_repeater(const v8::Arguments& args); // Register the above methods with node -v8::Handle register_node_fn_repeaters(v8::Handle target); +void register_node_fn_repeaters(v8::Handle target); } diff --git a/src/cgeohash_nanoseconds.cpp b/src/cgeohash_nanoseconds.cpp new file mode 100644 index 0000000..58a6b30 --- /dev/null +++ b/src/cgeohash_nanoseconds.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cgeohash_nanoseconds.hpp" + +// http://stackoverflow.com/a/17112198 +#ifdef __MACH__ +#include + +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 0 +int clock_gettime(int clk_id, struct timespec *t){ + mach_timebase_info_data_t timebase; + mach_timebase_info(&timebase); + uint64_t time; + time = mach_absolute_time(); + double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom); + double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9); + t->tv_sec = seconds; + t->tv_nsec = nseconds; + return 0; +} + +#else + +#include + +#endif + +namespace cgeohash { +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + + uint64_t nanoseconds() { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); + } + + double seconds_differience_of_nanoseconds(const uint64_t _nanoseconds) { + const uint64_t _diff = nanoseconds() - _nanoseconds; + const double _seconds = ((double) _diff) / ((double) NANOSEC); + return _seconds; + } + +} // end namespace cgeohash diff --git a/src/cgeohash_nanoseconds.hpp b/src/cgeohash_nanoseconds.hpp new file mode 100644 index 0000000..258dcb5 --- /dev/null +++ b/src/cgeohash_nanoseconds.hpp @@ -0,0 +1,16 @@ +#ifndef _NODE_CGEOHASH_NANOSECONDS_HPP +#define _NODE_CGEOHASH_NANOSECONDS_HPP + +#include +#include + +namespace cgeohash { + +// Compute nanoseconds at current time +uint64_t nanoseconds(); + +double seconds_differience_of_nanoseconds(const uint64_t _nanoseconds); + +} // end namespace cgeohash + +#endif /* end hpp */ diff --git a/src/cgeohash_obj.cpp b/src/cgeohash_obj.cpp new file mode 100644 index 0000000..adede58 --- /dev/null +++ b/src/cgeohash_obj.cpp @@ -0,0 +1,77 @@ +#include +#include + +#include "cgeohash_fn.hpp" +#include "cgeohash_obj.hpp" + +#define _THROW_NODE_ERROR(MSG) ThrowException(v8::Exception::Error(v8::String::New(MSG))); + +namespace cgeohash { + +v8::Persistent GeoHashObject::constructor; + + +void GeoHashObject::Init(v8::Handle target) { + v8::HandleScope scope; + + v8::Local tpl = v8::FunctionTemplate::New(New); + v8::Local name = v8::String::NewSymbol("GeoHashObject"); + + constructor = v8::Persistent::New(tpl); + + // ObjectWrap uses the first internal field to store the wrapped pointer. + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(name); + + // Add all prototype methods, getters and setters here. + NODE_SET_PROTOTYPE_METHOD(constructor, "encode_obj", Encode); + NODE_SET_PROTOTYPE_METHOD(constructor, "decode_obj", Decode); + NODE_SET_PROTOTYPE_METHOD(constructor, "decode_bbox_obj", DecodeBBox); + NODE_SET_PROTOTYPE_METHOD(constructor, "neighbor_obj", Neighbor); + + + // This has to be last, otherwise the properties won't show up on the + // object in JavaScript. + target->Set(name, constructor->GetFunction()); +} + + +GeoHashObject::GeoHashObject() : node::ObjectWrap() { +} + + +v8::Handle GeoHashObject::New(const v8::Arguments& args) { + v8::HandleScope scope; + + if (!args.IsConstructCall()) { + return _THROW_NODE_ERROR("Use the new operator to create instances of this object."); + } + + // Creates a new instance object of this type and wraps it. + GeoHashObject* obj = new GeoHashObject(); + obj->Wrap(args.This()); + + return args.This(); +} + + +v8::Handle GeoHashObject::Encode(const v8::Arguments& args) { + return encode_fn(args); +} + + +v8::Handle GeoHashObject::Decode(const v8::Arguments& args) { + return decode_fn(args); +} + + +v8::Handle GeoHashObject::DecodeBBox(const v8::Arguments& args) { + return decode_bbox_fn(args); +} + + +v8::Handle GeoHashObject::Neighbor(const v8::Arguments& args) { + return neighbor_fn(args); +} + +} \ No newline at end of file diff --git a/src/cgeohash_obj_repeaters.cpp b/src/cgeohash_obj_repeaters.cpp new file mode 100644 index 0000000..1d16773 --- /dev/null +++ b/src/cgeohash_obj_repeaters.cpp @@ -0,0 +1,74 @@ +#include +#include + +#include "cgeohash_obj_repeaters.hpp" +#include "cgeohash_fn_repeaters.hpp" + +#define _THROW_NODE_ERROR(MSG) ThrowException(v8::Exception::Error(v8::String::New(MSG))); + +namespace cgeohash { + +v8::Persistent GeoHashObjectRepeater::constructor; + + +void GeoHashObjectRepeater::Init(v8::Handle target) { + v8::HandleScope scope; + + v8::Local tpl = v8::FunctionTemplate::New(New); + v8::Local name = v8::String::NewSymbol("GeoHashObjectRepeater"); + + constructor = v8::Persistent::New(tpl); + + // ObjectWrap uses the first internal field to store the wrapped pointer. + constructor->InstanceTemplate()->SetInternalFieldCount(1); + constructor->SetClassName(name); + + // Add all prototype methods, getters and setters here. + NODE_SET_PROTOTYPE_METHOD(constructor, "encode_obj_repeater", Encode); + NODE_SET_PROTOTYPE_METHOD(constructor, "decode_obj_repeater", Decode); + NODE_SET_PROTOTYPE_METHOD(constructor, "decode_bbox_obj_repeater", DecodeBBox); + NODE_SET_PROTOTYPE_METHOD(constructor, "neighbor_obj_repeater", Neighbor); + + // This has to be last, otherwise the properties won't show up on the + // object in JavaScript. + target->Set(name, constructor->GetFunction()); +} + + +GeoHashObjectRepeater::GeoHashObjectRepeater() : node::ObjectWrap() { +} + + +v8::Handle GeoHashObjectRepeater::New(const v8::Arguments& args) { + v8::HandleScope scope; + + if (!args.IsConstructCall()) { + return _THROW_NODE_ERROR("Use the new operator to create instances of this object."); + } + + // Creates a new instance object of this type and wraps it. + GeoHashObjectRepeater* obj = new GeoHashObjectRepeater(); + obj->Wrap(args.This()); + + return args.This(); +} + + +v8::Handle GeoHashObjectRepeater::Encode(const v8::Arguments& args) { + return geohash::encode_fn_repeater(args); +} + + +v8::Handle GeoHashObjectRepeater::Decode(const v8::Arguments& args) { + return geohash::decode_fn_repeater(args); +} + + +v8::Handle GeoHashObjectRepeater::DecodeBBox(const v8::Arguments& args) { + return geohash::decode_bbox_fn_repeater(args); +} + + +v8::Handle GeoHashObjectRepeater::Neighbor(const v8::Arguments& args) { + return geohash::neighbor_fn_repeater(args); +} diff --git a/src/cgeohash_obj_repeaters.hpp b/src/cgeohash_obj_repeaters.hpp index b97ae06..a7998d6 100644 --- a/src/cgeohash_obj_repeaters.hpp +++ b/src/cgeohash_obj_repeaters.hpp @@ -12,7 +12,7 @@ class GeoHashObjectRepeater : public node::ObjectWrap { static void Init(v8::Handle target); protected: - GeoHashObject(); + GeoHashObjectRepeater(); static v8::Handle New(const v8::Arguments& args); static v8::Handle Encode(const v8::Arguments& args); diff --git a/src/geohash.hpp b/src/geohash.hpp deleted file mode 100644 index 86ac9a3..0000000 --- a/src/geohash.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _NODE_GEOHASH_HPP -#define _NODE_GEOHASH_HPP - -#include -#include - -namespace geohash { -struct DecodedBBox { - double minlat, minlon, maxlat, maxlon; -}; - -struct DecodedHash { - double latitude; - double longitude; - - double latitude_err; - double longitude_err; -}; - -uint64_t nanoseconds(); - -std::string encode(const double latitude, const double longitude, const unsigned long numberOfChars); - -DecodedHash decode(const std::string & hash_string); - -DecodedBBox decode_bbox(const std::string & hash_string); - - -/** - * direction [lat, lon], i.e. - * [1,0] - north - * [1,1] - northeast - * ... - */ -std::string neighbor(const std::string & hash_string, const int direction []); - -// Node.JS Hooks to GeoHash encoding -v8::Handle encode_js(const v8::Arguments& args); -v8::Handle decode_js(const v8::Arguments& args); -v8::Handle decode_bbox_js(const v8::Arguments& args); -v8::Handle neighbor_js(const v8::Arguments& args); -} - -#endif /* geohash.hpp */ diff --git a/src/geohash.js b/src/geohash.js deleted file mode 100644 index 083ada0..0000000 --- a/src/geohash.js +++ /dev/null @@ -1,18 +0,0 @@ -var cgeohash = require('./build/Release/cgeohash'); - -var GeoHashObject = new cgeohash.GeoHashObject(); - -module.exports = { - encode: cgeohash.encode_js, - decode: cgeohash.decode_js, - decode_bbox: cgeohash.decode_bbox_js, - neighbor: cgeohash.neighbor_js, - - test1m_encode: cgeohash.test1m_encode_js, - test1m_decode: cgeohash.test1m_decode_js, - test1m_decode_bbox: cgeohash.test1m_decode_bbox_js, - test1m_neighbor: cgeohash.test1m_neighbor_js, - - geohash_object: GeoHashObject, -} - diff --git a/src/geohash_node_binding.hpp b/src/geohash_node_binding.hpp deleted file mode 100644 index ff3766f..0000000 --- a/src/geohash_node_binding.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _NODE_GEOHASH_NODE_BINDINGS_HPP -#define _NODE_GEOHASH_NODE_BINDINGS_HPP - -#include -#include - -// Node.JS Hooks to GeoHash encoding -namespace geohash { -v8::Handle encode_js(const v8::Arguments& args); -v8::Handle decode_js(const v8::Arguments& args); -v8::Handle decode_bbox_js(const v8::Arguments& args); -v8::Handle neighbor_js(const v8::Arguments& args); - -} - -void geohash_Init(v8::Handle target); - -#endif /* geohash.hpp */ diff --git a/src/geohash_node_binding_speed.cpp b/src/geohash_node_binding_speed.cpp deleted file mode 100644 index 759fe94..0000000 --- a/src/geohash_node_binding_speed.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include -#include -#include "cvv8/detail/convert_core.hpp" - -#include "geohash.hpp" -#include "geohash_node_binding.hpp" - -#define _THROW_NODE_ERROR(MSG) ThrowException(v8::Exception::Error(v8::String::New(MSG))); - - -namespace geohash { - - // Node.JS Hooks to GeoHash encoding - v8::Handle test1m_encode_js(const v8::Arguments& args) { - v8::HandleScope scope; - - if (args.Length() < 2) { - return _THROW_NODE_ERROR("Takes 3 parameters: latitude, longitude, and numberOfChars"); - } - - const double latitude = cvv8::CastFromJS< double >(args[0]); - const double longitude = cvv8::CastFromJS< double >(args[1]); - const uint32_t numberOfChars = args.Length() == 3 - ? cvv8::CastFromJS< uint32_t >(args[2]) - : 9; // Default input - - const uint64_t _nanoseconds = nanoseconds(); - for(int i = 0, max = 1000*1000; i < max; i++) { - encode(latitude, longitude, numberOfChars); - } - const uint64_t _diff = nanoseconds() - _nanoseconds; - const double _seconds = ((double) _diff) / ((uint64_t) 1e9); - return scope.Close(cvv8::CastToJS(_seconds)); - } - - v8::Handle test1m_decode_js(const v8::Arguments& args) { - v8::HandleScope scope; - - if (args.Length() < 1) { - return _THROW_NODE_ERROR("Takes 1 parameters: hash_string"); - } - - const std::string hash_string = cvv8::CastFromJS(args[0]); - if (hash_string.empty()) { - return _THROW_NODE_ERROR("Parameter 0 must be a valid string"); - } - - const uint64_t _nanoseconds = nanoseconds(); - for(int i = 0, max = 1000*1000; i < max; i++) { - decode(hash_string); - } - const uint64_t _diff = nanoseconds() - _nanoseconds; - const double _seconds = ((double) _diff) / ((uint64_t) 1e9); - return scope.Close(cvv8::CastToJS(_seconds)); - } - - v8::Handle test1m_decode_bbox_js(const v8::Arguments& args) { - v8::HandleScope scope; - - if (args.Length() < 1) { - return _THROW_NODE_ERROR("Takes 1 parameters: hash_string"); - } - - const std::string hash_string = cvv8::CastFromJS(args[0]); - if (hash_string.empty()) { - return _THROW_NODE_ERROR("Parameter 0 must be a valid string"); - } - - const uint64_t _nanoseconds = nanoseconds(); - for(int i = 0, max = 1000*1000; i < max; i++) { - decode_bbox(hash_string); - } - const uint64_t _diff = nanoseconds() - _nanoseconds; - const double _seconds = ((double) _diff) / ((uint64_t) 1e9); - return scope.Close(cvv8::CastToJS(_seconds)); - } - - v8::Handle test1m_neighbor_js(const v8::Arguments& args) { - v8::HandleScope scope; - - if (args.Length() < 2) { - return _THROW_NODE_ERROR("Takes 2 parameters: hash_string, and direction []"); - } - - const std::string hash_string = cvv8::CastFromJS(args[0]); - if (hash_string.empty()) { - return _THROW_NODE_ERROR("Parameter 0 must be a valid string"); - } - - const std::list directions = cvv8::CastFromJS< std::list >(args[1]); - if (directions.size() != 2) { - return _THROW_NODE_ERROR("Parameter 1 must be an array with 2 numbers"); - } - - const int directions_array [] = { - directions.front(), // Only 2 elements - directions.back() // Only 2 elements - }; - - const uint64_t _nanoseconds = nanoseconds(); - for(int i = 0, max = 1000*1000; i < max; i++) { - neighbor(hash_string, directions_array); - } - const uint64_t _diff = nanoseconds() - _nanoseconds; - const double _seconds = ((double) _diff) / ((uint64_t) 1e9); - return scope.Close(cvv8::CastToJS(_seconds)); - } - - void test1m_Init(v8::Handle target) { - node::SetMethod(target, "test1m_encode_js", geohash::test1m_encode_js); - node::SetMethod(target, "test1m_decode_js", geohash::test1m_decode_js); - node::SetMethod(target, "test1m_decode_bbox_js", geohash::test1m_decode_bbox_js); - node::SetMethod(target, "test1m_neighbor_js", geohash::test1m_neighbor_js); - } - -} diff --git a/src/geohash_node_binding_speed.hpp b/src/geohash_node_binding_speed.hpp deleted file mode 100644 index c452b78..0000000 --- a/src/geohash_node_binding_speed.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _NODE_GEOHASH_BINDING_SPEED_HPP -#define _NODE_GEOHASH_BINDING_SPEED_HPP - -#include -#include - -// Node.JS Hooks to GeoHash encoding -namespace geohash { -// Used for performance testing!! -v8::Handle test1m_encode_js(const v8::Arguments& args); -v8::Handle test1m_decode_js(const v8::Arguments& args); -v8::Handle test1m_decode_bbox_js(const v8::Arguments& args); -v8::Handle test1m_neighbor_js(const v8::Arguments& args); - -void test1m_Init(v8::Handle target); - -} - -#endif /* geohash.hpp */ diff --git a/src/geohash_obj.cpp b/src/geohash_obj.cpp deleted file mode 100644 index 63cd6a4..0000000 --- a/src/geohash_obj.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include -#include -#include "geohash_obj.hpp" - -#include "geohash.hpp" -#include "geohash_node_binding.hpp" -#include "geohash_node_binding_speed.hpp" - - -v8::Persistent GeoHashObject::constructor; - - -void GeoHashObject::Init(v8::Handle target) { - v8::HandleScope scope; - - v8::Local tpl = v8::FunctionTemplate::New(New); - v8::Local name = v8::String::NewSymbol("GeoHashObject"); - - constructor = v8::Persistent::New(tpl); - - // ObjectWrap uses the first internal field to store the wrapped pointer. - constructor->InstanceTemplate()->SetInternalFieldCount(1); - constructor->SetClassName(name); - - // Add all prototype methods, getters and setters here. - NODE_SET_PROTOTYPE_METHOD(constructor, "encode", Encode); - NODE_SET_PROTOTYPE_METHOD(constructor, "decode", Decode); - NODE_SET_PROTOTYPE_METHOD(constructor, "decode_bbox", DecodeBBox); - NODE_SET_PROTOTYPE_METHOD(constructor, "neighbor", Neighbor); - - // Used for performance testing!! - NODE_SET_PROTOTYPE_METHOD(constructor, "test1m_encode", Test1M_Encode); - NODE_SET_PROTOTYPE_METHOD(constructor, "test1m_decode", Test1M_Decode); - NODE_SET_PROTOTYPE_METHOD(constructor, "test1m_decode_bbox", Test1M_DecodeBBox); - NODE_SET_PROTOTYPE_METHOD(constructor, "test1m_neighbor", Test1M_Neighbor); - - - // This has to be last, otherwise the properties won't show up on the - // object in JavaScript. - target->Set(name, constructor->GetFunction()); -} - - -GeoHashObject::GeoHashObject() : node::ObjectWrap() { -} - - -v8::Handle GeoHashObject::New(const v8::Arguments& args) { - v8::HandleScope scope; - - if (!args.IsConstructCall()) { - return ThrowException( - v8::Exception::TypeError( - v8::String::New("Use the new operator to create instances of this object.")) - ); - } - - // Creates a new instance object of this type and wraps it. - GeoHashObject* obj = new GeoHashObject(); - obj->Wrap(args.This()); - - return args.This(); -} - - -v8::Handle GeoHashObject::Encode(const v8::Arguments& args) { - return geohash::encode_js(args); -} - - -v8::Handle GeoHashObject::Decode(const v8::Arguments& args) { - return geohash::decode_js(args); -} - - -v8::Handle GeoHashObject::DecodeBBox(const v8::Arguments& args) { - return geohash::decode_bbox_js(args); -} - - -v8::Handle GeoHashObject::Neighbor(const v8::Arguments& args) { - return geohash::neighbor_js(args); -} - - - -// Used for performance testing!! -v8::Handle GeoHashObject::Test1M_Encode(const v8::Arguments& args) { - return geohash::test1m_encode_js(args); -} - - -v8::Handle GeoHashObject::Test1M_Decode(const v8::Arguments& args) { - return geohash::test1m_decode_js(args); -} - - -v8::Handle GeoHashObject::Test1M_DecodeBBox(const v8::Arguments& args) { - return geohash::test1m_decode_bbox_js(args); -} - - -v8::Handle GeoHashObject::Test1M_Neighbor(const v8::Arguments& args) { - return geohash::test1m_neighbor_js(args); -} diff --git a/src/geohash_obj.hpp b/src/geohash_obj.hpp deleted file mode 100644 index 716d614..0000000 --- a/src/geohash_obj.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _NODE_GEOHASH_OBJ_HPP -#define _NODE_GEOHASH_OBJ_HPP - -#include - -class GeoHashObject : public node::ObjectWrap { -public: - static v8::Persistent constructor; - static void Init(v8::Handle target); - -protected: - GeoHashObject(); - - static v8::Handle New(const v8::Arguments& args); - static v8::Handle Encode(const v8::Arguments& args); - static v8::Handle Decode(const v8::Arguments& args); - static v8::Handle DecodeBBox(const v8::Arguments& args); - static v8::Handle Neighbor(const v8::Arguments& args); - - // Used for performance testing!! - static v8::Handle Test1M_Encode(const v8::Arguments& args); - static v8::Handle Test1M_Decode(const v8::Arguments& args); - static v8::Handle Test1M_DecodeBBox(const v8::Arguments& args); - static v8::Handle Test1M_Neighbor(const v8::Arguments& args); - }; - -#endif From e92a1209405e2c3e1585f9cb63538fce6eb06cfe Mon Sep 17 00:00:00 2001 From: Glenn Nagel Date: Sat, 22 Jun 2013 13:28:48 -0400 Subject: [PATCH 05/11] Updating specs --- binding.gyp | 1 + lib/cgeohash_fn.js | 2 +- lib/cgeohash_fn_repeaters.js | 2 +- lib/cgeohash_obj.js | 2 +- lib/cgeohash_obj_repeaters.js | 2 +- src/cgeohash_obj_repeaters.cpp | 10 ++-- tests/cgeohash_fn_test.js | 4 ++ tests/cgeohash_obj_test.js | 4 ++ tests/geohash_js_test.js | 4 -- tests/geohash_obj_test.js | 4 -- tests/geohash_original_test.js | 54 +++++++++---------- tests/geohash_speed_test.js | 6 +++ ...{geohash_shared_spec.js => shared_spec.js} | 0 13 files changed, 52 insertions(+), 43 deletions(-) create mode 100644 tests/cgeohash_fn_test.js create mode 100644 tests/cgeohash_obj_test.js delete mode 100644 tests/geohash_js_test.js delete mode 100644 tests/geohash_obj_test.js rename tests/{geohash_shared_spec.js => shared_spec.js} (100%) diff --git a/binding.gyp b/binding.gyp index 4d8f14a..5fa5930 100644 --- a/binding.gyp +++ b/binding.gyp @@ -43,6 +43,7 @@ "src/cgeohash_fn.cpp", "src/cgeohash_fn_repeaters.cpp", "src/cgeohash_obj.cpp", + "src/cgeohash_obj_repeaters.cpp", "src/cgeohash_nanoseconds.cpp" ], "target_name": "cgeohash" diff --git a/lib/cgeohash_fn.js b/lib/cgeohash_fn.js index 8025d12..2bc2e75 100644 --- a/lib/cgeohash_fn.js +++ b/lib/cgeohash_fn.js @@ -1,4 +1,4 @@ -var cgeohash = require('./build/Release/cgeohash'); +var cgeohash = require('../build/Release/cgeohash'); module.exports = { encode: cgeohash.encode_fn, diff --git a/lib/cgeohash_fn_repeaters.js b/lib/cgeohash_fn_repeaters.js index 16861da..4e27ba2 100644 --- a/lib/cgeohash_fn_repeaters.js +++ b/lib/cgeohash_fn_repeaters.js @@ -13,7 +13,7 @@ // console.log('Seconds per call C++ <-> C++ = ' + looping_in_cpp); // -var cgeohash = require('./build/Release/cgeohash'); +var cgeohash = require('../build/Release/cgeohash'); var cgeohash_fn = require('./cgeohash_fn'); var seconds_per_call_x_many_times = require('./seconds_per_call_x_many_times'); diff --git a/lib/cgeohash_obj.js b/lib/cgeohash_obj.js index 5b9e245..bea9379 100644 --- a/lib/cgeohash_obj.js +++ b/lib/cgeohash_obj.js @@ -1,4 +1,4 @@ -var cgeohash = require('./build/Release/cgeohash'); +var cgeohash = require('../build/Release/cgeohash'); var cgeohash_obj = new cgeohash.GeoHashObject(); // Alias the <...>_obj methods to the expected <...> method names diff --git a/lib/cgeohash_obj_repeaters.js b/lib/cgeohash_obj_repeaters.js index 8e87161..23bb948 100644 --- a/lib/cgeohash_obj_repeaters.js +++ b/lib/cgeohash_obj_repeaters.js @@ -13,7 +13,7 @@ // console.log('Seconds per call C++ <-> C++ = ' + looping_in_cpp); // -var cgeohash = require('./build/Release/cgeohash'); +var cgeohash = require('../build/Release/cgeohash'); var cgeohash_obj = require('./cgeohash_obj'); var cgeohash_obj_repeater = new cgeohash.GeoHashObjectRepeater(); var seconds_per_call_x_many_times = require('./seconds_per_call_x_many_times'); diff --git a/src/cgeohash_obj_repeaters.cpp b/src/cgeohash_obj_repeaters.cpp index 1d16773..279536d 100644 --- a/src/cgeohash_obj_repeaters.cpp +++ b/src/cgeohash_obj_repeaters.cpp @@ -55,20 +55,22 @@ v8::Handle GeoHashObjectRepeater::New(const v8::Arguments& args) { v8::Handle GeoHashObjectRepeater::Encode(const v8::Arguments& args) { - return geohash::encode_fn_repeater(args); + return encode_fn_repeater(args); } v8::Handle GeoHashObjectRepeater::Decode(const v8::Arguments& args) { - return geohash::decode_fn_repeater(args); + return decode_fn_repeater(args); } v8::Handle GeoHashObjectRepeater::DecodeBBox(const v8::Arguments& args) { - return geohash::decode_bbox_fn_repeater(args); + return decode_bbox_fn_repeater(args); } v8::Handle GeoHashObjectRepeater::Neighbor(const v8::Arguments& args) { - return geohash::neighbor_fn_repeater(args); + return neighbor_fn_repeater(args); } + +} \ No newline at end of file diff --git a/tests/cgeohash_fn_test.js b/tests/cgeohash_fn_test.js new file mode 100644 index 0000000..516fac0 --- /dev/null +++ b/tests/cgeohash_fn_test.js @@ -0,0 +1,4 @@ +var shared_spec = require('./shared_spec'); +var cgeohash_fn = require('../lib/cgeohash_fn.js'); + +shared_spec('GeoHash Functions in C++', cgeohash_fn); diff --git a/tests/cgeohash_obj_test.js b/tests/cgeohash_obj_test.js new file mode 100644 index 0000000..7d6cecb --- /dev/null +++ b/tests/cgeohash_obj_test.js @@ -0,0 +1,4 @@ +var cgeohash_shared_spec = require('./shared_spec'); +var cgeohash_obj = new require('../lib/cgeohash_obj.js'); + +cgeohash_shared_spec('GeoHash Object in C++', cgeohash_obj); diff --git a/tests/geohash_js_test.js b/tests/geohash_js_test.js deleted file mode 100644 index 201b3e5..0000000 --- a/tests/geohash_js_test.js +++ /dev/null @@ -1,4 +0,0 @@ -var geohash_shared_spec = require('./geohash_shared_spec'); -var geohash = require('../geohash.js'); - -geohash_shared_spec('GeoHash Functions in C++', geohash); diff --git a/tests/geohash_obj_test.js b/tests/geohash_obj_test.js deleted file mode 100644 index 2699928..0000000 --- a/tests/geohash_obj_test.js +++ /dev/null @@ -1,4 +0,0 @@ -var geohash_shared_spec = require('./geohash_shared_spec'); -var geohash = new require('../geohash.js').geohash_object; - -geohash_shared_spec('GeoHash Object in C++', geohash); diff --git a/tests/geohash_original_test.js b/tests/geohash_original_test.js index e37d13a..591fcff 100644 --- a/tests/geohash_original_test.js +++ b/tests/geohash_original_test.js @@ -1,30 +1,30 @@ -var geohash_shared_spec = require('./geohash_shared_spec'); -var geohash = require('./geohash_original.js'); +var shared_spec = require('./shared_spec'); +var geohash_js = require('./geohash_original.js'); +// +// geohash.test1m_encode = function(a, b, c) { +// var last = undefined; +// for(var i = 0, max = 1000*1000; i < max; i++) { +// last = geohash.encode(a, b, c); +// } +// return last; +// } +// +// geohash.test1m_decode = function(a) { +// var last = undefined; +// for(var i = 0, max = 1000*1000; i < max; i++) { +// last = geohash.decode(a); +// } +// return last; +// } +// +// geohash.test1m_neighbor = function(a, b) { +// var last = undefined; +// for(var i = 0, max = 1000*1000; i < max; i++) { +// last = geohash.neighbor(a, b); +// } +// return last; +// } -geohash.test1m_encode = function(a, b, c) { - var last = undefined; - for(var i = 0, max = 1000*1000; i < max; i++) { - last = geohash.encode(a, b, c); - } - return last; -} -geohash.test1m_decode = function(a) { - var last = undefined; - for(var i = 0, max = 1000*1000; i < max; i++) { - last = geohash.decode(a); - } - return last; -} - -geohash.test1m_neighbor = function(a, b) { - var last = undefined; - for(var i = 0, max = 1000*1000; i < max; i++) { - last = geohash.neighbor(a, b); - } - return last; -} - - -geohash_shared_spec('GeoHash Functions in C++', geohash); +shared_spec('GeoHash Functions in C++', geohash_js); diff --git a/tests/geohash_speed_test.js b/tests/geohash_speed_test.js index ea8f1ab..106949e 100644 --- a/tests/geohash_speed_test.js +++ b/tests/geohash_speed_test.js @@ -70,6 +70,12 @@ function x_faster(new_time, old_time) { // // Geo Hash Libraries for testing // +var cgeohash_fn = require('../lib/cgeohash_fn.js'); +var cgeohash_fn_repeaters = require('../lib/cgeohash_fn_repeaters.js'); +var cgeohash_obj = require('../lib/cgeohash_obj.js'); +var cgeohash_obj_repeaters = require('../lib/cgeohash_obj_repeaters.js'); + + var geohash_c_object = new require('../geohash.js') .geohash_object; var geohash_c_functions = require('../geohash.js'); diff --git a/tests/geohash_shared_spec.js b/tests/shared_spec.js similarity index 100% rename from tests/geohash_shared_spec.js rename to tests/shared_spec.js From 7b1f0b46e1c1e291d52dc18af4934c625adca4fe Mon Sep 17 00:00:00 2001 From: Glenn Nagel Date: Sat, 22 Jun 2013 15:35:00 -0400 Subject: [PATCH 06/11] Making a mess of the encoder ... --- lib/cgeohash_fn_repeaters.js | 18 +- lib/cgeohash_obj_repeaters.js | 18 +- .../cgeohash_original.js | 0 lib/cgeohash_original_repeaters.js | 47 ++++ lib/seconds_per_call_x_many_times.js | 3 +- src/cgeohash_fn_repeaters.cpp | 36 +++- src/cgeohash_nanoseconds.cpp | 41 +++- tests/geohash_speed_test.js | 201 ------------------ tests/speed_test.js | 148 +++++++++++++ 9 files changed, 279 insertions(+), 233 deletions(-) rename tests/geohash_original.js => lib/cgeohash_original.js (100%) create mode 100644 lib/cgeohash_original_repeaters.js delete mode 100644 tests/geohash_speed_test.js create mode 100644 tests/speed_test.js diff --git a/lib/cgeohash_fn_repeaters.js b/lib/cgeohash_fn_repeaters.js index 4e27ba2..ac64716 100644 --- a/lib/cgeohash_fn_repeaters.js +++ b/lib/cgeohash_fn_repeaters.js @@ -24,34 +24,34 @@ var cgeohash_fn_repeat_js = { return seconds_per_call_x_many_times(num_times, function() { return cgeohash_fn.encode(latitude, longitude, numberOfChars); }); - }; + }, decode: function(num_times, hash_string) { return seconds_per_call_x_many_times(num_times, function() { - return cgeohash_fn.dncode(hash_string); + return cgeohash_fn.decode(hash_string); }); - }; + }, decode_bbox: function(num_times, hash_string) { return seconds_per_call_x_many_times(num_times, function() { return cgeohash_fn.decode_bbox(hash_string); }); - }; + }, neighbor: function(num_times, hash_string, direction) { return seconds_per_call_x_many_times(num_times, function() { return cgeohash_fn.neighbor(hash_string, direction); }); - }; + }, }; // Alias the <...>_obj methods to the expected <...> method names // Loop in CPP and record the seconds / call var cgeohash_fn_repeat_cpp = { - encode: cgeohash.encode_fn_repeat, - decode: cgeohash.decode_fn_repeat, - decode_bbox: cgeohash.decode_bbox_fn_repeat, - neighbor: cgeohash.neighbor_fn_repeat, + encode: cgeohash.encode_fn_repeater, + decode: cgeohash.decode_fn_repeater, + decode_bbox: cgeohash.decode_bbox_fn_repeater, + neighbor: cgeohash.neighbor_fn_repeater, }; diff --git a/lib/cgeohash_obj_repeaters.js b/lib/cgeohash_obj_repeaters.js index 23bb948..41b1c18 100644 --- a/lib/cgeohash_obj_repeaters.js +++ b/lib/cgeohash_obj_repeaters.js @@ -25,34 +25,34 @@ var cgeohash_fn_repeat_js = { return seconds_per_call_x_many_times(num_times, function() { return cgeohash_obj.encode(latitude, longitude, numberOfChars); }); - }; + }, decode: function(num_times, hash_string) { return seconds_per_call_x_many_times(num_times, function() { - return cgeohash_obj.dncode(hash_string); + return cgeohash_obj.decode(hash_string); }); - }; + }, decode_bbox: function(num_times, hash_string) { return seconds_per_call_x_many_times(num_times, function() { return cgeohash_obj.decode_bbox(hash_string); }); - }; + }, neighbor: function(num_times, hash_string, direction) { return seconds_per_call_x_many_times(num_times, function() { return cgeohash_obj.neighbor(hash_string, direction); }); - }; + }, }; // Alias the <...>_obj methods to the expected <...> method names // Loop in CPP and record the seconds / call var cgeohash_fn_repeat_cpp = { - encode: cgeohash_obj_repeater.encode_obj_repeat, - decode: cgeohash_obj_repeater.decode_obj_repeat, - decode_bbox: cgeohash_obj_repeater.decode_bbox_obj_repeat, - neighbor: cgeohash_obj_repeater.neighbor_obj_repeat, + encode: cgeohash_obj_repeater.encode_obj_repeater, + decode: cgeohash_obj_repeater.decode_obj_repeater, + decode_bbox: cgeohash_obj_repeater.decode_bbox_obj_repeater, + neighbor: cgeohash_obj_repeater.neighbor_obj_repeater, }; diff --git a/tests/geohash_original.js b/lib/cgeohash_original.js similarity index 100% rename from tests/geohash_original.js rename to lib/cgeohash_original.js diff --git a/lib/cgeohash_original_repeaters.js b/lib/cgeohash_original_repeaters.js new file mode 100644 index 0000000..c400a8e --- /dev/null +++ b/lib/cgeohash_original_repeaters.js @@ -0,0 +1,47 @@ +// +// Map the originan node-geohash JavaScript functions to callbacks to repeat X-Many times +// +// Ex: +// var repeat_in_js = require('geohash_original_repeaters').repeat_in_js +// var avg_seconds_per_decode = { +// looping_in_js: repeat_in_js.decode( 1000*1000, 'abcd'), +// } +// +// console.log('Seconds per call Node <-> JS = ' + looping_in_js); +// + +var cgeohash_original = require('./cgeohash_original'); +var seconds_per_call_x_many_times = require('./seconds_per_call_x_many_times'); + +// Alias the <...>_obj methods to the expected <...> method names +// Loop in JS and record the seconds / call +var cgeohash_original_repeat_js = { + encode: function(num_times, latitude, longitude, numberOfChars) { + return seconds_per_call_x_many_times(num_times, function() { + return cgeohash_original.encode(latitude, longitude, numberOfChars); + }); + }, + + decode: function(num_times, hash_string) { + return seconds_per_call_x_many_times(num_times, function() { + return cgeohash_original.decode(hash_string); + }); + }, + + decode_bbox: function(num_times, hash_string) { + return seconds_per_call_x_many_times(num_times, function() { + return cgeohash_original.decode_bbox(hash_string); + }); + }, + + neighbor: function(num_times, hash_string, direction) { + return seconds_per_call_x_many_times(num_times, function() { + return cgeohash_original.neighbor(hash_string, direction); + }); + }, +}; + +module.exports = { + repeat_in_js: cgeohash_original_repeat_js, + repeat_in_cpp: undefined, // Not available +}; diff --git a/lib/seconds_per_call_x_many_times.js b/lib/seconds_per_call_x_many_times.js index 83c530d..76c8e73 100644 --- a/lib/seconds_per_call_x_many_times.js +++ b/lib/seconds_per_call_x_many_times.js @@ -28,7 +28,8 @@ module.exports = function(num_times, callback) { // Stop var diff = process.hrtime(time); - var seconds = diff[0].valueOf() + diff[1].valueOf() / (NANOSECONDS_TO_SECONDS); + console.log(diff[0] + ',' + diff[1]); + var seconds = diff[0].valueOf() * NANOSECONDS_TO_SECONDS + diff[1].valueOf(); return seconds / num_times; }; diff --git a/src/cgeohash_fn_repeaters.cpp b/src/cgeohash_fn_repeaters.cpp index 19b75cd..059b42a 100644 --- a/src/cgeohash_fn_repeaters.cpp +++ b/src/cgeohash_fn_repeaters.cpp @@ -6,6 +6,8 @@ #include "cgeohash_fn_repeaters.hpp" #include "cgeohash_nanoseconds.hpp" +#include + #define _THROW_NODE_ERROR(MSG) ThrowException(v8::Exception::Error(v8::String::New(MSG))); @@ -29,10 +31,18 @@ namespace cgeohash { const uint64_t _nanoseconds = nanoseconds(); for(int i = 0; i < num_times; i++) { + // std::cout << __FILE__ << ':' << __LINE__ << '=' << i << std::endl; encode(latitude, longitude, precision); } - const double _seconds = seconds_differience_of_nanoseconds(_nanoseconds) / num_times; - return scope.Close(cvv8::CastToJS(_seconds)); + // const double _seconds = seconds_differience_of_nanoseconds(_nanoseconds) / num_times; + + return scope.Close(cvv8::CastToJS((nanoseconds() - _nanoseconds) / num_times)); + // const uint64_t _diff = (nanoseconds() - _nanoseconds) / num_times; + + // const double _seconds = ((double) _diff) / ((uint64_t) 1e9) ; + + // std::cout << __FILE__ << ':' << __LINE__ << " encode = " << _seconds << ", diff = " << _diff << ", runs = " << num_times << std::endl; + // return scope.Close(cvv8::CastToJS(_seconds)); } v8::Handle decode_fn_repeater(const v8::Arguments& args) { @@ -51,10 +61,12 @@ namespace cgeohash { const uint64_t _nanoseconds = nanoseconds(); for(int i = 0; i < num_times; i++) { + // std::cout << __FILE__ << ':' << __LINE__ << '=' << i << std::endl; decode(hash_string); } - const double _seconds = seconds_differience_of_nanoseconds(_nanoseconds) / num_times; - return scope.Close(cvv8::CastToJS(_seconds)); + return scope.Close(cvv8::CastToJS((nanoseconds() - _nanoseconds) / num_times)); + // const double _seconds = seconds_differience_of_nanoseconds(_nanoseconds) / num_times; + // return scope.Close(cvv8::CastToJS(_seconds)); } v8::Handle decode_bbox_fn_repeater(const v8::Arguments& args) { @@ -73,10 +85,12 @@ namespace cgeohash { const uint64_t _nanoseconds = nanoseconds(); for(int i = 0; i < num_times; i++) { + // std::cout << __FILE__ << ':' << __LINE__ << '=' << i << std::endl; decode_bbox(hash_string); } - const double _seconds = seconds_differience_of_nanoseconds(_nanoseconds) / num_times; - return scope.Close(cvv8::CastToJS(_seconds)); + return scope.Close(cvv8::CastToJS((nanoseconds() - _nanoseconds) / num_times)); + // const double _seconds = seconds_differience_of_nanoseconds(_nanoseconds) / num_times; + // return scope.Close(cvv8::CastToJS(_seconds)); } v8::Handle neighbor_fn_repeater(const v8::Arguments& args) { @@ -93,9 +107,9 @@ namespace cgeohash { return _THROW_NODE_ERROR("Parameter 1 must be a valid string"); } - const std::list directions = cvv8::CastFromJS< std::list >(args[1]); + const std::list directions = cvv8::CastFromJS< std::list >(args[i++]); if (directions.size() != 2) { - return _THROW_NODE_ERROR("Parameter 1 must be an array with 2 numbers"); + return _THROW_NODE_ERROR("Parameter 2 must be an array with 2 numbers"); } const int directions_array [] = { @@ -105,10 +119,12 @@ namespace cgeohash { const uint64_t _nanoseconds = nanoseconds(); for(int i = 0; i < num_times; i++) { + // std::cout << __FILE__ << ':' << __LINE__ << '=' << i << std::endl; neighbor(hash_string, directions_array); } - const double _seconds = seconds_differience_of_nanoseconds(_nanoseconds) / num_times; - return scope.Close(cvv8::CastToJS(_seconds)); + return scope.Close(cvv8::CastToJS((nanoseconds() - _nanoseconds) / num_times)); + // const double _seconds = seconds_differience_of_nanoseconds(_nanoseconds) / num_times; + // return scope.Close(cvv8::CastToJS(_seconds)); } void register_node_fn_repeaters(v8::Handle target) { diff --git a/src/cgeohash_nanoseconds.cpp b/src/cgeohash_nanoseconds.cpp index 58a6b30..123b73e 100644 --- a/src/cgeohash_nanoseconds.cpp +++ b/src/cgeohash_nanoseconds.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -33,14 +34,48 @@ int clock_gettime(int clk_id, struct timespec *t){ #endif + +// #if TARGET_OS_IPHONE +// /* see: http://developer.apple.com/library/mac/#qa/qa1398/_index.html */ +// uint64_t uv_hrtime() { +// uint64_t time; +// uint64_t enano; +// static mach_timebase_info_data_t sTimebaseInfo; +// +// time = mach_absolute_time(); +// +// if (0 == sTimebaseInfo.denom) { +// (void)mach_timebase_info(&sTimebaseInfo); +// } +// +// enano = time * sTimebaseInfo.numer / sTimebaseInfo.denom; +// +// return enano; +// } +// #else +// uint64_t uv_hrtime() { +// uint64_t time; +// Nanoseconds enano; +// time = mach_absolute_time(); +// enano = AbsoluteToNanoseconds(*(AbsoluteTime *)&time); +// return (*(uint64_t *)&enano); +// } +// #endif +// + + + + + namespace cgeohash { #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) uint64_t nanoseconds() { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); + return uv_hrtime(); + // struct timespec ts; + // clock_gettime(CLOCK_MONOTONIC, &ts); + // return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec); } double seconds_differience_of_nanoseconds(const uint64_t _nanoseconds) { diff --git a/tests/geohash_speed_test.js b/tests/geohash_speed_test.js deleted file mode 100644 index 106949e..0000000 --- a/tests/geohash_speed_test.js +++ /dev/null @@ -1,201 +0,0 @@ -// -// Required Libraries -// -var path = require('path'); -var mocha = require('mocha'); -var chai = require('chai'); -var should = chai.should(); - -// -// Constants -// -var longitude = 112.5584; -var latitude = 37.8324; -var geostr = 'ww8p1r4t8'; - -// -// Helpers -// -function seconds_per_call(callback) { - var time = process.hrtime(); // Start - callback(); // Execute - var diff = process.hrtime(time); // Stop - var seconds = diff[0].valueOf() + diff[1].valueOf() / (1000 * 1000 * 1000); - - return seconds / (1000 * 1000); -}; - -function wrap_loop_1M_in_js(callback, validates) { - return function() { - var last = null; - for (var i = 0, max = 1000 * 1000; i < max; i++) { - last = callback(); - } - return validates(last); - }; -} - -function seconds_per_call_loop_1M(callback, validates) { - return seconds_per_call(wrap_loop_1M_in_js(callback, validates)); -} - -function encode_latitude_and_longitude_as_string(geohash) { - return geohash.encode(latitude, longitude, 9); -} - -function decodes_string_to_latitude(geohash) { - return geohash.decode(geostr) - .latitude; -} - -function decodes_string_to_longitude(geohash) { - return geohash.decode(geostr) - .longitude; -} - -function finds_neighbor_to_the_north(geohash) { - return geohash.neighbor('dqcjq', [1, 0]); -} - -function finds_neighbor_to_the_south_west(geohash) { - return geohash.neighbor('dqcjq', [-1, - 1]); -} - -// How many times faster is the new vs old times? -function x_faster(new_time, old_time) { - return Math.round((old_time / new_time) * 100) / 100; -}; - - -// -// Geo Hash Libraries for testing -// -var cgeohash_fn = require('../lib/cgeohash_fn.js'); -var cgeohash_fn_repeaters = require('../lib/cgeohash_fn_repeaters.js'); -var cgeohash_obj = require('../lib/cgeohash_obj.js'); -var cgeohash_obj_repeaters = require('../lib/cgeohash_obj_repeaters.js'); - - -var geohash_c_object = new require('../geohash.js') - .geohash_object; -var geohash_c_functions = require('../geohash.js'); -var geohash_original = require('./geohash_original.js'); - -geohash_original.test1m_encode = function(a, b, c) { - var last = undefined; - for (var i = 0, max = 1000 * 1000; i < max; i++) { - last = geohash_original.encode(a, b, c); - } - return last; -} - -geohash_original.test1m_decode = function(a) { - var last = undefined; - for (var i = 0, max = 1000 * 1000; i < max; i++) { - last = geohash_original.decode(a); - } - return last; -} - -geohash_original.test1m_neighbor = function(a, b) { - var last = undefined; - for (var i = 0, max = 1000 * 1000; i < max; i++) { - last = geohash_original.neighbor(a, b); - } - return last; -} - -// -// Test Suite -// -describe('Speed Tests', function() { - this.timeout(0); - - function compare_ratios(tag, src, js, cpp, validates) { - describe(tag, function() { - var seconds = { - // Javascript <-> Javascript (original version) - js_vs_src: seconds_per_call_loop_1M(src, validates), - // Javascript <-> C++ Function - js_vs_c_function: seconds_per_call_loop_1M(js, validates), - // Javascript <-> C++ Object - js_vs_c_object: seconds_per_call(cpp), - // C++ Only - cpp_vs_c_object: cpp(), - }; - var times_faster = { - js_vs_src: 1.0, // Ratio to self is always 1 - js_vs_c_function: x_faster(seconds.js_vs_c_function , seconds.js_vs_src), - js_vs_c_object: x_faster(seconds.js_vs_c_object , seconds.js_vs_src), - cpp_vs_c_object: x_faster(seconds.cpp_vs_c_object , seconds.js_vs_src), - } - - var seconds_s = JSON.stringify(seconds); - var times_faster_to_s = JSON.stringify(times_faster); - if (process.env.VERBOSE) { - console.log(tag + ': times_faster=' + times_faster_to_s); - console.log(tag + ': seconds=' + seconds_s); - } - - describe('[X times Faster]', function() { - it('JS <-> JS Original Version compared to self should be 1.0', function() { - chai.assert.ok(times_faster.js_vs_src == 1.0, times_faster_to_s); - }); - - it('JS <-> Node Function Wrapping-C++ is slower than Original Version', function() { - chai.assert.ok(Math.round(times_faster.js_vs_c_function) <= 1, times_faster_to_s); - }); - - it('JS <-> Node Object Wrapping-C++ is slower than Original Version', function() { - chai.assert.ok(Math.round(times_faster.js_vs_c_object) <= 1, times_faster_to_s); - }); - - // seconds.cpp_vs_c_object is null if it was too fast to measure - it('Pure-C++ function is 100x+ faster than JS Original Version', function() { - if (seconds.cpp_vs_c_object) { - chai.assert.ok(Math.round(times_faster.cpp_vs_c_object) > 100, times_faster_to_s); - } - }); - }); - - }); - }; - - compare_ratios('encodes latitude & longitude as string', - function() { return encode_latitude_and_longitude_as_string(geohash_original); }, - function() { return encode_latitude_and_longitude_as_string(geohash_c_functions); }, - function() { return geohash_c_object.test1m_encode(latitude, longitude, 9) / 1000000000; }, - function(data) { data.should.equal(geostr); }); - - compare_ratios('decodes string to latitude', - function() { return decodes_string_to_latitude(geohash_original); }, - function() { return decodes_string_to_latitude(geohash_c_functions); }, - function() { return geohash_c_object.test1m_decode(geostr) / 1000000000; }, - function(data) { - var diff = Math.abs(latitude - data) < 0.0001 - var msg = 'Expected ' + latitude + '-' + data + ' to be very close' - chai.assert.ok(diff, msg); - }); - - compare_ratios('decodes string to longitude', - function() { return decodes_string_to_longitude(geohash_original); }, - function() { return decodes_string_to_longitude(geohash_c_functions); }, - function() { return geohash_original.test1m_decode(geostr) / 1000000000; }, - function(data) { - var diff = Math.abs(longitude - data) < 0.0001 - var msg = 'Expected ' + longitude + '-' + data + ' to be very close' - chai.assert.ok(diff, msg); - }); - - compare_ratios('finds neighbor to the north', - function() { return finds_neighbor_to_the_north(geohash_original); }, - function() { return finds_neighbor_to_the_north(geohash_c_functions); }, - function() { return geohash_c_object.test1m_neighbor('dqcjq', [1, 0]) / 1000000000; }, - function(data) { data.should.equal('dqcjw'); }); - - compare_ratios('finds neighbor to the south-west', - function() { return finds_neighbor_to_the_south_west(geohash_original); }, - function() { return finds_neighbor_to_the_south_west(geohash_c_functions); }, - function() { return geohash_c_object.test1m_neighbor('dqcjq', [-1, - 1]) / 1000000000; }, - function(data) { data.should.equal('dqcjj'); }); -}); diff --git a/tests/speed_test.js b/tests/speed_test.js new file mode 100644 index 0000000..7253f5a --- /dev/null +++ b/tests/speed_test.js @@ -0,0 +1,148 @@ +// +// Required Libraries +// +var path = require('path'); +var mocha = require('mocha'); +var chai = require('chai'); +var should = chai.should(); + +// +// Helpers +// + +// How many times faster is the new vs old times? +function x_faster(new_time, old_time) { + return Math.round((old_time / new_time) * 100) / 100; +}; + +function compare_ratios(tag, timings) { + describe(tag, function() { + var seconds = { + original_in_js: timings.original_in_js(), + obj_in_js: timings.obj_in_js(), + obj_in_cpp: timings.obj_in_cpp(), + fn_in_js: timings.fn_in_js(), + fn_in_cpp: timings.fn_in_cpp(), + }; + console.log("seconds=" + JSON.stringify(seconds, undefined, 2)); + + // var times_faster = {}; + // var diff = {}; + // + // // // Javascript <-> Javascript (original version) + // // seconds.js_vs_src = src(); + // // times_faster.js_vs_src = 1; // src() / src() ==> 1 + // // diff.js_vs_src = 0; + // // + // // // Javascript <-> C++ Function + // // seconds.js_vs_cpp_function = js(); + // // diff.js_vs_cpp_function = seconds.js_vs_cpp_function - seconds.js_vs_src; + // // times_faster.js_vs_cpp_function = x_faster( + // // seconds.js_vs_cpp_function, + // // seconds.js_vs_src); + // + // // C++ Only + // seconds.cpp_vs_cpp_object = cpp(); + // diff.cpp_vs_cpp_object = seconds.cpp_vs_cpp_object - seconds.js_vs_src; + // times_faster.cpp_vs_cpp_object = x_faster( + // seconds.cpp_vs_cpp_object, + // seconds.js_vs_src); + // + // // Used for logging and errors + // var seconds_s = JSON.stringify(seconds, undefined, 2); + // var diff_s = JSON.stringify(diff, undefined, 2); + // var times_faster_to_s = JSON.stringify(times_faster, undefined, 2); + // // if (process.env.VERBOSE) { + // console.log(tag + ': times_faster=' + times_faster_to_s); + // console.log(tag + ': diff=' + seconds_s); + // console.log(tag + ': seconds=' + seconds_s); + // // } + // + // describe('[X times Faster]', function() { + // it('JS <-> JS Original Version compared to self should be 1.0', function() { + // chai.assert.ok(times_faster.js_vs_src == 1.0, times_faster_to_s); + // }); + // + // // it('JS <-> Node Function Wrapping-C++ is slower than Original Version', function() { + // // chai.assert.ok(Math.round(times_faster.js_vs_cpp_function) <= 1, times_faster_to_s); + // // }); + // + // // seconds.cpp_vs_cpp_object is null if it was too fast to measure + // it('Pure-C++ function is 100x+ faster than JS Original Version', function() { + // if (seconds.cpp_vs_cpp_object) { + // chai.assert.ok(Math.round(times_faster.cpp_vs_cpp_object) > 100, times_faster_to_s); + // } + // }); + // }); + + }); +}; + + +// +// Geo Hash Libraries for testing +// +var fn_repeaters = require('../lib/cgeohash_fn_repeaters.js'); +var obj_repeaters = require('../lib/cgeohash_obj_repeaters.js'); +var orig_repeaters = require('../lib/cgeohash_original_repeaters.js'); + + +// +// Test Suite +// +describe('Speed Tests', function() { + this.timeout(0); + + var num_runs = 1000*1000; + + compare_ratios('encodes latitude & longitude as string', { + original_in_js: function() { + return orig_repeaters.repeat_in_js.encode(num_runs, 37.8324, 112.5584, 9); + }, + obj_in_js: function() { + return obj_repeaters.repeat_in_js.encode(num_runs, 37.8324, 112.5584, 9); + }, + obj_in_cpp: function() { + return obj_repeaters.repeat_in_cpp.encode(num_runs, 37.8324, 112.5584, 9); + }, + fn_in_js: function() { + return fn_repeaters.repeat_in_js.encode(num_runs, 37.8324, 112.5584, 9); + }, + fn_in_cpp: function() { + return fn_repeaters.repeat_in_cpp.encode(num_runs, 37.8324, 112.5584, 9); + }, + }); + + // compare_ratios('decodes string to latitude & longitude', + // function() { + // return orig_repeaters.decode(num_runs, 'ww8p1r4t8'); + // }, + // function() { + // return obj_repeaters.decode(num_runs, 'ww8p1r4t8'); + // }, + // function() { + // return fn_repeaters.decode(num_runs, 'ww8p1r4t8'); + // }); + // + // compare_ratios('finds neighbor to the north', + // function() { + // return orig_repeaters.neighbor(num_runs, 'dqcjq', [1, 0]); + // }, + // function() { + // return obj_repeaters.neighbor(num_runs, 'dqcjq', [1, 0]); + // }, + // function() { + // return fn_repeaters.neighbor(num_runs, 'dqcjq', [1, 0]); + // }); + // + // compare_ratios('finds neighbor to the south-west', + // function() { + // return orig_repeaters.neighbor(num_runs, 'dqcjq', [-1, - 1]); + // }, + // function() { + // return obj_repeaters.neighbor(num_runs, 'dqcjq', [-1, - 1]); + // }, + // function() { + // return fn_repeaters.neighbor(num_runs, 'dqcjq', [-1, - 1]); + // }); +}); From 42a8a703cd8b2a1df65a7888dd7740a853b33ae1 Mon Sep 17 00:00:00 2001 From: Glenn Nagel Date: Sat, 22 Jun 2013 15:48:36 -0400 Subject: [PATCH 07/11] Moved logging --- lib/seconds_per_call_x_many_times.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/seconds_per_call_x_many_times.js b/lib/seconds_per_call_x_many_times.js index 76c8e73..f7fe216 100644 --- a/lib/seconds_per_call_x_many_times.js +++ b/lib/seconds_per_call_x_many_times.js @@ -28,8 +28,9 @@ module.exports = function(num_times, callback) { // Stop var diff = process.hrtime(time); - console.log(diff[0] + ',' + diff[1]); var seconds = diff[0].valueOf() * NANOSECONDS_TO_SECONDS + diff[1].valueOf(); + console.log(seconds); + return seconds / num_times; }; From d2df7bc9ce2952f884e9c65d342afbeb4460d8a7 Mon Sep 17 00:00:00 2001 From: Glenn Nagel Date: Sun, 23 Jun 2013 14:01:35 -0400 Subject: [PATCH 08/11] Updating speed tests ... --- package.json | 3 +- tests/geohash_original_test.js | 2 +- tests/speed_test.js | 178 +++++++++++++++------------------ 3 files changed, 84 insertions(+), 99 deletions(-) diff --git a/package.json b/package.json index 34d79ad..4e939a4 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "chai": "1.6.1", "mocha": "1.11.0", "ngeohash": "0.2.0", - "sprintf": "*" + "sprintf": "*", + "v8-profiler-table": "*" }, "engines": { "node": ">=v0.8.14" diff --git a/tests/geohash_original_test.js b/tests/geohash_original_test.js index 591fcff..5b3bb60 100644 --- a/tests/geohash_original_test.js +++ b/tests/geohash_original_test.js @@ -1,5 +1,5 @@ var shared_spec = require('./shared_spec'); -var geohash_js = require('./geohash_original.js'); +var geohash_js = require('../lib/cgeohash_original'); // // geohash.test1m_encode = function(a, b, c) { diff --git a/tests/speed_test.js b/tests/speed_test.js index 7253f5a..3bbbf6f 100644 --- a/tests/speed_test.js +++ b/tests/speed_test.js @@ -1,80 +1,42 @@ // // Required Libraries // -var path = require('path'); -var mocha = require('mocha'); -var chai = require('chai'); -var should = chai.should(); +var path = require('path'); +var mocha = require('mocha'); +var chai = require('chai'); +var should = chai.should(); +var v8_profiler_table = require('v8-profiler-table'); // // Helpers // -// How many times faster is the new vs old times? -function x_faster(new_time, old_time) { - return Math.round((old_time / new_time) * 100) / 100; -}; - function compare_ratios(tag, timings) { describe(tag, function() { - var seconds = { - original_in_js: timings.original_in_js(), - obj_in_js: timings.obj_in_js(), - obj_in_cpp: timings.obj_in_cpp(), - fn_in_js: timings.fn_in_js(), - fn_in_cpp: timings.fn_in_cpp(), - }; - console.log("seconds=" + JSON.stringify(seconds, undefined, 2)); + // Clear the profiles + v8_profiler_table.reset_profiles(); + + v8_profiler_table.record_profile('Original JS Version', timings.original_in_js); + v8_profiler_table.record_profile('All C++ Version', timings.fn_in_cpp); - // var times_faster = {}; - // var diff = {}; - // - // // // Javascript <-> Javascript (original version) - // // seconds.js_vs_src = src(); - // // times_faster.js_vs_src = 1; // src() / src() ==> 1 - // // diff.js_vs_src = 0; - // // - // // // Javascript <-> C++ Function - // // seconds.js_vs_cpp_function = js(); - // // diff.js_vs_cpp_function = seconds.js_vs_cpp_function - seconds.js_vs_src; - // // times_faster.js_vs_cpp_function = x_faster( - // // seconds.js_vs_cpp_function, - // // seconds.js_vs_src); - // - // // C++ Only - // seconds.cpp_vs_cpp_object = cpp(); - // diff.cpp_vs_cpp_object = seconds.cpp_vs_cpp_object - seconds.js_vs_src; - // times_faster.cpp_vs_cpp_object = x_faster( - // seconds.cpp_vs_cpp_object, - // seconds.js_vs_src); - // - // // Used for logging and errors - // var seconds_s = JSON.stringify(seconds, undefined, 2); - // var diff_s = JSON.stringify(diff, undefined, 2); - // var times_faster_to_s = JSON.stringify(times_faster, undefined, 2); - // // if (process.env.VERBOSE) { - // console.log(tag + ': times_faster=' + times_faster_to_s); - // console.log(tag + ': diff=' + seconds_s); - // console.log(tag + ': seconds=' + seconds_s); - // // } - // - // describe('[X times Faster]', function() { - // it('JS <-> JS Original Version compared to self should be 1.0', function() { - // chai.assert.ok(times_faster.js_vs_src == 1.0, times_faster_to_s); - // }); - // - // // it('JS <-> Node Function Wrapping-C++ is slower than Original Version', function() { - // // chai.assert.ok(Math.round(times_faster.js_vs_cpp_function) <= 1, times_faster_to_s); - // // }); - // - // // seconds.cpp_vs_cpp_object is null if it was too fast to measure - // it('Pure-C++ function is 100x+ faster than JS Original Version', function() { - // if (seconds.cpp_vs_cpp_object) { - // chai.assert.ok(Math.round(times_faster.cpp_vs_cpp_object) > 100, times_faster_to_s); - // } - // }); - // }); + console.log(v8_profiler_table.stringify()); + it ('Original JS Version', function() { + var profile = v8_profiler_table.profiles()['Original JS Version']; + + // Sanity checks + profile.title.should.equal('Original JS Version'); + profile.ratio_to_base.should.equal(1); + }); + + it ('All C++ Version', function() { + var profile = v8_profiler_table.profiles()['All C++ Version']; + + // Sanity checks + profile.title.should.equal('All C++ Version'); + chai.assert.ok(profile.ratio_to_base >= 1.0, JSON.stringify(profile, undefined, 2)); + chai.assert.ok(profile.total_seconds <= 0.5, JSON.stringify(profile, undefined, 2)); + }); }); }; @@ -113,36 +75,58 @@ describe('Speed Tests', function() { }, }); - // compare_ratios('decodes string to latitude & longitude', - // function() { - // return orig_repeaters.decode(num_runs, 'ww8p1r4t8'); - // }, - // function() { - // return obj_repeaters.decode(num_runs, 'ww8p1r4t8'); - // }, - // function() { - // return fn_repeaters.decode(num_runs, 'ww8p1r4t8'); - // }); - // - // compare_ratios('finds neighbor to the north', - // function() { - // return orig_repeaters.neighbor(num_runs, 'dqcjq', [1, 0]); - // }, - // function() { - // return obj_repeaters.neighbor(num_runs, 'dqcjq', [1, 0]); - // }, - // function() { - // return fn_repeaters.neighbor(num_runs, 'dqcjq', [1, 0]); - // }); - // - // compare_ratios('finds neighbor to the south-west', - // function() { - // return orig_repeaters.neighbor(num_runs, 'dqcjq', [-1, - 1]); - // }, - // function() { - // return obj_repeaters.neighbor(num_runs, 'dqcjq', [-1, - 1]); - // }, - // function() { - // return fn_repeaters.neighbor(num_runs, 'dqcjq', [-1, - 1]); - // }); + compare_ratios('decodes string to latitude & longitude', { + original_in_js: function() { + return orig_repeaters.repeat_in_js.decode(num_runs, 'ww8p1r4t8'); + }, + obj_in_js: function() { + return obj_repeaters.repeat_in_js.decode(num_runs, 'ww8p1r4t8'); + }, + obj_in_cpp: function() { + return obj_repeaters.repeat_in_cpp.decode(num_runs, 'ww8p1r4t8'); + }, + fn_in_js: function() { + return fn_repeaters.repeat_in_js.decode(num_runs, 'ww8p1r4t8'); + }, + fn_in_cpp: function() { + return fn_repeaters.repeat_in_cpp.decode(num_runs, 'ww8p1r4t8'); + }, + }); + + compare_ratios('finds neighbor to the north', { + original_in_js: function() { + return orig_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [1, 0]); + }, + obj_in_js: function() { + return obj_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [1, 0]); + }, + obj_in_cpp: function() { + return obj_repeaters.repeat_in_cpp.neighbor(num_runs, 'dqcjq', [1, 0]); + }, + fn_in_js: function() { + return fn_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [1, 0]); + }, + fn_in_cpp: function() { + return fn_repeaters.repeat_in_cpp.neighbor(num_runs, 'dqcjq', [1, 0]); + }, + }); + + compare_ratios('finds neighbor to the south-west', { + original_in_js: function() { + return orig_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [-1, - 1]); + }, + obj_in_js: function() { + return obj_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [-1, - 1]); + }, + obj_in_cpp: function() { + return obj_repeaters.repeat_in_cpp.neighbor(num_runs, 'dqcjq', [-1, - 1]); + }, + fn_in_js: function() { + return fn_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [-1, - 1]); + }, + fn_in_cpp: function() { + return fn_repeaters.repeat_in_cpp.neighbor(num_runs, 'dqcjq', [-1, - 1]); + }, + }); + }); From f0b07b6054665a105349ffe760f451881607f93d Mon Sep 17 00:00:00 2001 From: Glenn Nagel Date: Sun, 23 Jun 2013 14:38:00 -0400 Subject: [PATCH 09/11] Cleaning up C++ strings and adding tests --- src/cgeohash.cpp | 85 ++++++++++++++++++++++++++++++---- src/cgeohash_fn.cpp | 2 +- tests/geohash_original_test.js | 26 ----------- tests/shared_spec.js | 25 ++++++++++ 4 files changed, 102 insertions(+), 36 deletions(-) diff --git a/src/cgeohash.cpp b/src/cgeohash.cpp index 149a127..c9dfadb 100644 --- a/src/cgeohash.cpp +++ b/src/cgeohash.cpp @@ -6,12 +6,73 @@ #include #include #include +#include #include "cgeohash.hpp" namespace cgeohash { + // Static array of 0-9, a-z + const char base32_codes[] = { + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'j', + 'k', + 'm', + 'n', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z'}; + + // Build a map of characters -> index position from the above array + const std::map build_base32_indexes(); + const std::map base32_indexes = build_base32_indexes(); + + // Reverse map of characters --> index position + const std::map build_base32_indexes() { + std::map output; + + for(int i = 0, max = 36; i < max; i++) { + output.insert( std::pair(base32_codes[i], i) ); + } + + return output; + } + + // Convert the index position to the character in the array + char base32_codes_value_of(int index) { + return base32_codes[index]; + } + + // Convert the character to the index position in the array + int base32_codes_index_of(char c) { + return base32_indexes.find(c)->second; + } + std::string encode(const double latitude, const double longitude, unsigned long precision) { // DecodedBBox for the lat/lon + errors DecodedBBox bbox; @@ -23,11 +84,12 @@ std::string encode(const double latitude, const double longitude, unsigned long bool islon = true; int num_bits = 0; int hash_index = 0; - const std::string base32_codes = "0123456789bcdefghjkmnpqrstuvwxyz"; - std::string hash_string; + // Pre-Allocate the hash string + std::string hash_string(precision, ' '); + unsigned int hash_string_length = 0; - while(hash_string.length() < precision) { + while(hash_string_length< precision) { if (islon) { mid = (bbox.maxlon + bbox.minlon) / 2; if(longitude > mid) { @@ -51,9 +113,15 @@ std::string encode(const double latitude, const double longitude, unsigned long ++num_bits; if (5 == num_bits) { - hash_string += base32_codes[hash_index]; - num_bits = 0; - hash_index = 0; + // Append the character to the pre-allocated string + // This gives us roughly a 2x speed boost + hash_string[hash_string_length] = base32_codes_value_of(hash_index); + + // std::cout << hash_string[hash_string_length] << " <- " << hash_index << std::endl; + + hash_string_length++; + num_bits = 0; + hash_index = 0; } } @@ -76,12 +144,11 @@ DecodedBBox decode_bbox(const std::string & _hash_string) { output.minlat = -90; output.minlon = -180; - int char_index = 0; bool islon = true; - const std::string base32_codes = "0123456789bcdefghjkmnpqrstuvwxyz"; for(int i = 0, max = hash_string.length(); i < max; i++) { - char_index = base32_codes.find( hash_string[i] ); + int char_index = base32_codes_index_of(hash_string[i]); + // std::cout << hash_string[i] << " -> " << char_index << std::endl; for (int bits = 4; bits >= 0; --bits) { int bit = (char_index >> bits) & 1; diff --git a/src/cgeohash_fn.cpp b/src/cgeohash_fn.cpp index e093fb6..5a1bf1f 100644 --- a/src/cgeohash_fn.cpp +++ b/src/cgeohash_fn.cpp @@ -72,7 +72,7 @@ namespace cgeohash { } DecodedBBox decoded_bbox = decode_bbox(hash_string); - std::list list(4); + std::list list; list.push_back(decoded_bbox.minlat); list.push_back(decoded_bbox.minlon); list.push_back(decoded_bbox.maxlat); diff --git a/tests/geohash_original_test.js b/tests/geohash_original_test.js index 5b3bb60..2924d5f 100644 --- a/tests/geohash_original_test.js +++ b/tests/geohash_original_test.js @@ -1,30 +1,4 @@ var shared_spec = require('./shared_spec'); var geohash_js = require('../lib/cgeohash_original'); -// -// geohash.test1m_encode = function(a, b, c) { -// var last = undefined; -// for(var i = 0, max = 1000*1000; i < max; i++) { -// last = geohash.encode(a, b, c); -// } -// return last; -// } -// -// geohash.test1m_decode = function(a) { -// var last = undefined; -// for(var i = 0, max = 1000*1000; i < max; i++) { -// last = geohash.decode(a); -// } -// return last; -// } -// -// geohash.test1m_neighbor = function(a, b) { -// var last = undefined; -// for(var i = 0, max = 1000*1000; i < max; i++) { -// last = geohash.neighbor(a, b); -// } -// return last; -// } - - shared_spec('GeoHash Functions in C++', geohash_js); diff --git a/tests/shared_spec.js b/tests/shared_spec.js index 29601c8..3db9b6d 100644 --- a/tests/shared_spec.js +++ b/tests/shared_spec.js @@ -39,6 +39,10 @@ function encode_latitude_and_longitude_as_string(geohash) { return geohash.encode(latitude, longitude, 9); } +function decodes_string_to_bounded_box(geohash) { + return geohash.decode_bbox('ww8p1r4t8'); +} + function decodes_string_to_latitude(geohash) { return geohash.decode(geostr) .latitude; @@ -65,6 +69,27 @@ module.exports = function(tag, geohash) { .should.equal(geostr); }); + it('decodes string to bounded box', function() { + var expected = [ + 37.83236503601074, + 112.55836486816406, + 37.83240795135498, + 112.5584077835083]; + + var bbox = decodes_string_to_bounded_box(geohash); + + // Round the numbers to integers and compare them + var rounding_match = function(a, b) { + Math.round(a) + .should.equal( + Math.round(b), "expected=" + JSON.stringify(expected, undefined, 2) + ", bbox=" + JSON.stringify(bbox, undefined, 2)); + } + rounding_match(bbox[0], expected[0]); + rounding_match(bbox[1], expected[1]); + rounding_match(bbox[2], expected[2]); + rounding_match(bbox[3], expected[3]); + }); + it('decodes string to latitude', function() { var latlon_latitude = decodes_string_to_latitude(geohash); var diff = Math.abs(latitude - latlon_latitude) < 0.0001 From a47a1564e573d6cd21a94364886827c2b2d97338 Mon Sep 17 00:00:00 2001 From: Glenn Nagel Date: Sun, 23 Jun 2013 14:50:56 -0400 Subject: [PATCH 10/11] Working on speed tests ... --- lib/cgeohash_fn_repeaters.js | 18 ++- lib/cgeohash_obj_repeaters.js | 10 +- lib/cgeohash_original_repeaters.js | 10 +- lib/seconds_per_call_x_many_times.js | 36 ----- package.json | 2 +- src/cgeohash.cpp | 140 ++++++++++---------- src/cgeohash_fn_repeaters.cpp | 42 +++--- tests/seconds_per_call_x_many_times_test.js | 19 --- tests/speed_test.js | 3 +- 9 files changed, 112 insertions(+), 168 deletions(-) delete mode 100644 lib/seconds_per_call_x_many_times.js delete mode 100644 tests/seconds_per_call_x_many_times_test.js diff --git a/lib/cgeohash_fn_repeaters.js b/lib/cgeohash_fn_repeaters.js index ac64716..db49197 100644 --- a/lib/cgeohash_fn_repeaters.js +++ b/lib/cgeohash_fn_repeaters.js @@ -15,31 +15,37 @@ var cgeohash = require('../build/Release/cgeohash'); var cgeohash_fn = require('./cgeohash_fn'); -var seconds_per_call_x_many_times = require('./seconds_per_call_x_many_times'); +var repeats_callback = require('v8-profiler-table').repeats_callback; // Alias the <...>_obj methods to the expected <...> method names // Loop in JS and record the seconds / call var cgeohash_fn_repeat_js = { encode: function(num_times, latitude, longitude, numberOfChars) { - return seconds_per_call_x_many_times(num_times, function() { + var callback = function() { return cgeohash_fn.encode(latitude, longitude, numberOfChars); - }); + }; + + return function() { + var last = undefined; + for(var i = 0; i < num_loops; i++) { last = callback(); } + return last; + }; }, decode: function(num_times, hash_string) { - return seconds_per_call_x_many_times(num_times, function() { + return repeats_callback(num_times, function() { return cgeohash_fn.decode(hash_string); }); }, decode_bbox: function(num_times, hash_string) { - return seconds_per_call_x_many_times(num_times, function() { + return repeats_callback(num_times, function() { return cgeohash_fn.decode_bbox(hash_string); }); }, neighbor: function(num_times, hash_string, direction) { - return seconds_per_call_x_many_times(num_times, function() { + return repeats_callback(num_times, function() { return cgeohash_fn.neighbor(hash_string, direction); }); }, diff --git a/lib/cgeohash_obj_repeaters.js b/lib/cgeohash_obj_repeaters.js index 41b1c18..fe086d4 100644 --- a/lib/cgeohash_obj_repeaters.js +++ b/lib/cgeohash_obj_repeaters.js @@ -16,31 +16,31 @@ var cgeohash = require('../build/Release/cgeohash'); var cgeohash_obj = require('./cgeohash_obj'); var cgeohash_obj_repeater = new cgeohash.GeoHashObjectRepeater(); -var seconds_per_call_x_many_times = require('./seconds_per_call_x_many_times'); +var repeats_callback = require('v8-profiler-table').repeats_callback; // Alias the <...>_obj methods to the expected <...> method names // Loop in JS and record the seconds / call var cgeohash_fn_repeat_js = { encode: function(num_times, latitude, longitude, numberOfChars) { - return seconds_per_call_x_many_times(num_times, function() { + return repeats_callback(num_times, function() { return cgeohash_obj.encode(latitude, longitude, numberOfChars); }); }, decode: function(num_times, hash_string) { - return seconds_per_call_x_many_times(num_times, function() { + return repeats_callback(num_times, function() { return cgeohash_obj.decode(hash_string); }); }, decode_bbox: function(num_times, hash_string) { - return seconds_per_call_x_many_times(num_times, function() { + return repeats_callback(num_times, function() { return cgeohash_obj.decode_bbox(hash_string); }); }, neighbor: function(num_times, hash_string, direction) { - return seconds_per_call_x_many_times(num_times, function() { + return repeats_callback(num_times, function() { return cgeohash_obj.neighbor(hash_string, direction); }); }, diff --git a/lib/cgeohash_original_repeaters.js b/lib/cgeohash_original_repeaters.js index c400a8e..38e2fdb 100644 --- a/lib/cgeohash_original_repeaters.js +++ b/lib/cgeohash_original_repeaters.js @@ -11,31 +11,31 @@ // var cgeohash_original = require('./cgeohash_original'); -var seconds_per_call_x_many_times = require('./seconds_per_call_x_many_times'); +var repeats_callback = require('v8-profiler-table').repeats_callback; // Alias the <...>_obj methods to the expected <...> method names // Loop in JS and record the seconds / call var cgeohash_original_repeat_js = { encode: function(num_times, latitude, longitude, numberOfChars) { - return seconds_per_call_x_many_times(num_times, function() { + return repeats_callback(num_times, function() { return cgeohash_original.encode(latitude, longitude, numberOfChars); }); }, decode: function(num_times, hash_string) { - return seconds_per_call_x_many_times(num_times, function() { + return repeats_callback(num_times, function() { return cgeohash_original.decode(hash_string); }); }, decode_bbox: function(num_times, hash_string) { - return seconds_per_call_x_many_times(num_times, function() { + return repeats_callback(num_times, function() { return cgeohash_original.decode_bbox(hash_string); }); }, neighbor: function(num_times, hash_string, direction) { - return seconds_per_call_x_many_times(num_times, function() { + return repeats_callback(num_times, function() { return cgeohash_original.neighbor(hash_string, direction); }); }, diff --git a/lib/seconds_per_call_x_many_times.js b/lib/seconds_per_call_x_many_times.js deleted file mode 100644 index f7fe216..0000000 --- a/lib/seconds_per_call_x_many_times.js +++ /dev/null @@ -1,36 +0,0 @@ -// -// Execute the callback X-Many times and return the "Seconds / Call" -// -// Ex: -// var repeater = require('./seconds_per_call_x_many_times'); -// var counter = 0; -// var num_times = 1000*1000*1000; -// var callback = function() { Math.sqrt(++counter); }; -// var sec_per_call = repeater(num_times, callback); -// -// /* Make sure the callback was called */ -// counter.should.equal(num_times); -// -// /* Log the avg time per call */ -// console.log("Calculating Math.sqrt " + counter + " times took " + sec_per_call + " (s) / call"); -// - -var NANOSECONDS_TO_SECONDS = 1000 * 1000 * 1000; - -module.exports = function(num_times, callback) { - // Start - var time = process.hrtime(); - - // Execute - for (var i = 0; i < num_times; ++i) { - last = callback(); - } - - // Stop - var diff = process.hrtime(time); - var seconds = diff[0].valueOf() * NANOSECONDS_TO_SECONDS + diff[1].valueOf(); - - console.log(seconds); - - return seconds / num_times; -}; diff --git a/package.json b/package.json index 4e939a4..e694e21 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "mocha": "1.11.0", "ngeohash": "0.2.0", "sprintf": "*", - "v8-profiler-table": "*" + "v8-profiler-table": ">=1.1.0" }, "engines": { "node": ">=v0.8.14" diff --git a/src/cgeohash.cpp b/src/cgeohash.cpp index c9dfadb..dff0780 100644 --- a/src/cgeohash.cpp +++ b/src/cgeohash.cpp @@ -13,65 +13,66 @@ namespace cgeohash { - // Static array of 0-9, a-z - const char base32_codes[] = { - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - 'b', - 'c', - 'd', - 'e', - 'f', - 'g', - 'h', - 'j', - 'k', - 'm', - 'n', - 'p', - 'q', - 'r', - 's', - 't', - 'u', - 'v', - 'w', - 'x', - 'y', - 'z'}; - - // Build a map of characters -> index position from the above array - const std::map build_base32_indexes(); - const std::map base32_indexes = build_base32_indexes(); - - // Reverse map of characters --> index position - const std::map build_base32_indexes() { - std::map output; - - for(int i = 0, max = 36; i < max; i++) { - output.insert( std::pair(base32_codes[i], i) ); - } - - return output; - } - - // Convert the index position to the character in the array - char base32_codes_value_of(int index) { - return base32_codes[index]; - } - - // Convert the character to the index position in the array - int base32_codes_index_of(char c) { - return base32_indexes.find(c)->second; - } +// Static array of 0-9, a-z +const char base32_codes[] = { + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'j', + 'k', + 'm', + 'n', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z' +}; + +// Build a map of characters -> index position from the above array +const std::map build_base32_indexes(); +const std::map base32_indexes = build_base32_indexes(); + +// Reverse map of characters --> index position +const std::map build_base32_indexes() { + std::map output; + + for(int i = 0, max = 36; i < max; i++) { + output.insert( std::pair(base32_codes[i], i) ); + } + + return output; +} + +// Convert the index position to the character in the array +char base32_codes_value_of(int index) { + return base32_codes[index]; +} + +// Convert the character to the index position in the array +int base32_codes_index_of(char c) { + return base32_indexes.find(c)->second; +} std::string encode(const double latitude, const double longitude, unsigned long precision) { // DecodedBBox for the lat/lon + errors @@ -85,9 +86,9 @@ std::string encode(const double latitude, const double longitude, unsigned long int num_bits = 0; int hash_index = 0; - // Pre-Allocate the hash string + // Pre-Allocate the hash string std::string hash_string(precision, ' '); - unsigned int hash_string_length = 0; + unsigned int hash_string_length = 0; while(hash_string_length< precision) { if (islon) { @@ -113,15 +114,13 @@ std::string encode(const double latitude, const double longitude, unsigned long ++num_bits; if (5 == num_bits) { - // Append the character to the pre-allocated string - // This gives us roughly a 2x speed boost - hash_string[hash_string_length] = base32_codes_value_of(hash_index); - - // std::cout << hash_string[hash_string_length] << " <- " << hash_index << std::endl; - - hash_string_length++; - num_bits = 0; - hash_index = 0; + // Append the character to the pre-allocated string + // This gives us roughly a 2x speed boost + // hash_string[hash_string_length] = base32_codes_value_of(hash_index); + + hash_string_length++; + num_bits = 0; + hash_index = 0; } } @@ -148,7 +147,6 @@ DecodedBBox decode_bbox(const std::string & _hash_string) { for(int i = 0, max = hash_string.length(); i < max; i++) { int char_index = base32_codes_index_of(hash_string[i]); - // std::cout << hash_string[i] << " -> " << char_index << std::endl; for (int bits = 4; bits >= 0; --bits) { int bit = (char_index >> bits) & 1; diff --git a/src/cgeohash_fn_repeaters.cpp b/src/cgeohash_fn_repeaters.cpp index 059b42a..53a81f7 100644 --- a/src/cgeohash_fn_repeaters.cpp +++ b/src/cgeohash_fn_repeaters.cpp @@ -17,32 +17,26 @@ namespace cgeohash { v8::Handle encode_fn_repeater(const v8::Arguments& args) { v8::HandleScope scope; - if (args.Length() < 3) { - return _THROW_NODE_ERROR("Takes 4 parameters: num_times, latitude, longitude, and precision"); - } - - int i = 0; - const int num_times = cvv8::CastFromJS< int >(args[i++]); - const double latitude = cvv8::CastFromJS< double >(args[i++]); - const double longitude = cvv8::CastFromJS< double >(args[i++]); - const uint32_t precision = args.Length() == 3 - ? cvv8::CastFromJS< uint32_t >(args[i++]) - : 9; // Default input - - const uint64_t _nanoseconds = nanoseconds(); - for(int i = 0; i < num_times; i++) { - // std::cout << __FILE__ << ':' << __LINE__ << '=' << i << std::endl; - encode(latitude, longitude, precision); + // if (args.Length() < 3) { + // return _THROW_NODE_ERROR("Takes 4 parameters: num_times, latitude, longitude, and precision"); + // } + + // int i = 0; + // const int num_times = cvv8::CastFromJS< int >(args[i++]); + // const double latitude = cvv8::CastFromJS< double >(args[i++]); + // const double longitude = cvv8::CastFromJS< double >(args[i++]); + // const uint32_t precision = args.Length() == 3 + // ? cvv8::CastFromJS< uint32_t >(args[i++]) + // : 9; // Default input + + // const uint64_t _nanoseconds = nanoseconds(); + for(int i = 0; i < 1e6; i++) { + // encode(latitude, longitude, precision); + encode(37.8324, 112.5584, 9); } - // const double _seconds = seconds_differience_of_nanoseconds(_nanoseconds) / num_times; - return scope.Close(cvv8::CastToJS((nanoseconds() - _nanoseconds) / num_times)); - // const uint64_t _diff = (nanoseconds() - _nanoseconds) / num_times; - - // const double _seconds = ((double) _diff) / ((uint64_t) 1e9) ; - - // std::cout << __FILE__ << ':' << __LINE__ << " encode = " << _seconds << ", diff = " << _diff << ", runs = " << num_times << std::endl; - // return scope.Close(cvv8::CastToJS(_seconds)); + // return scope.Close(cvv8::CastToJS((nanoseconds() - _nanoseconds) / num_times)); + return scope.Close(v8::Undefined()); } v8::Handle decode_fn_repeater(const v8::Arguments& args) { diff --git a/tests/seconds_per_call_x_many_times_test.js b/tests/seconds_per_call_x_many_times_test.js deleted file mode 100644 index e76c6f4..0000000 --- a/tests/seconds_per_call_x_many_times_test.js +++ /dev/null @@ -1,19 +0,0 @@ -var path = require('path'); -var mocha = require('mocha'); -var chai = require('chai'); -var should = chai.should(); -var repeater = require('../lib/seconds_per_call_x_many_times'); - -describe('Record Avg Seconds per call', function() { - var counter = 0; - var num_times = 1000 * 1000 * 1000; - var callback = function() { - Math.sqrt(++counter); - }; - var sec_per_call = repeater(num_times, callback); - - /* Make sure the callback was called */ - it('Counter should equal num_times', function() { - counter.should.equal(num_times); - }); -}); diff --git a/tests/speed_test.js b/tests/speed_test.js index 3bbbf6f..e98ae5f 100644 --- a/tests/speed_test.js +++ b/tests/speed_test.js @@ -15,7 +15,8 @@ function compare_ratios(tag, timings) { describe(tag, function() { // Clear the profiles v8_profiler_table.reset_profiles(); - + + // Log the run-times of the Original and C++ versions v8_profiler_table.record_profile('Original JS Version', timings.original_in_js); v8_profiler_table.record_profile('All C++ Version', timings.fn_in_cpp); From 64883b7a84c3f78e32aa9bd3721b45534ffe34f4 Mon Sep 17 00:00:00 2001 From: Glenn Nagel Date: Sun, 23 Jun 2013 15:08:19 -0400 Subject: [PATCH 11/11] Updated speed tests for all methods --- lib/cgeohash_fn_repeaters.js | 26 +++++----- lib/cgeohash_obj_repeaters.js | 20 +++++--- lib/cgeohash_original_repeaters.js | 16 +++--- package.json | 2 +- src/cgeohash.cpp | 4 +- src/cgeohash_fn_repeaters.cpp | 15 ------ tests/speed_test.js | 81 +++++++++++++++--------------- 7 files changed, 78 insertions(+), 86 deletions(-) diff --git a/lib/cgeohash_fn_repeaters.js b/lib/cgeohash_fn_repeaters.js index db49197..749d49e 100644 --- a/lib/cgeohash_fn_repeaters.js +++ b/lib/cgeohash_fn_repeaters.js @@ -13,41 +13,39 @@ // console.log('Seconds per call C++ <-> C++ = ' + looping_in_cpp); // -var cgeohash = require('../build/Release/cgeohash'); -var cgeohash_fn = require('./cgeohash_fn'); -var repeats_callback = require('v8-profiler-table').repeats_callback; +var cgeohash = require('../build/Release/cgeohash'); +var cgeohash_fn = require('./cgeohash_fn'); +var repeats_callback_wrapper = require('v8-profiler-table').repeats_callback_wrapper; // Alias the <...>_obj methods to the expected <...> method names // Loop in JS and record the seconds / call var cgeohash_fn_repeat_js = { encode: function(num_times, latitude, longitude, numberOfChars) { - var callback = function() { + var loop = repeats_callback_wrapper(num_times, function() { return cgeohash_fn.encode(latitude, longitude, numberOfChars); - }; - - return function() { - var last = undefined; - for(var i = 0; i < num_loops; i++) { last = callback(); } - return last; - }; + }); + return loop(); }, decode: function(num_times, hash_string) { - return repeats_callback(num_times, function() { + var loop = repeats_callback_wrapper(num_times, function() { return cgeohash_fn.decode(hash_string); }); + return loop(); }, decode_bbox: function(num_times, hash_string) { - return repeats_callback(num_times, function() { + var loop = repeats_callback_wrapper(num_times, function() { return cgeohash_fn.decode_bbox(hash_string); }); + return loop(); }, neighbor: function(num_times, hash_string, direction) { - return repeats_callback(num_times, function() { + var loop = repeats_callback_wrapper(num_times, function() { return cgeohash_fn.neighbor(hash_string, direction); }); + return loop(); }, }; diff --git a/lib/cgeohash_obj_repeaters.js b/lib/cgeohash_obj_repeaters.js index fe086d4..6ca889a 100644 --- a/lib/cgeohash_obj_repeaters.js +++ b/lib/cgeohash_obj_repeaters.js @@ -13,36 +13,40 @@ // console.log('Seconds per call C++ <-> C++ = ' + looping_in_cpp); // -var cgeohash = require('../build/Release/cgeohash'); -var cgeohash_obj = require('./cgeohash_obj'); -var cgeohash_obj_repeater = new cgeohash.GeoHashObjectRepeater(); -var repeats_callback = require('v8-profiler-table').repeats_callback; +var cgeohash = require('../build/Release/cgeohash'); +var cgeohash_obj = require('./cgeohash_obj'); +var cgeohash_obj_repeater = new cgeohash.GeoHashObjectRepeater(); +var repeats_callback_wrapper = require('v8-profiler-table').repeats_callback_wrapper; // Alias the <...>_obj methods to the expected <...> method names // Loop in JS and record the seconds / call var cgeohash_fn_repeat_js = { encode: function(num_times, latitude, longitude, numberOfChars) { - return repeats_callback(num_times, function() { + var loop = repeats_callback_wrapper(num_times, function() { return cgeohash_obj.encode(latitude, longitude, numberOfChars); }); + return loop(); }, decode: function(num_times, hash_string) { - return repeats_callback(num_times, function() { + var loop = repeats_callback_wrapper(num_times, function() { return cgeohash_obj.decode(hash_string); }); + return loop(); }, decode_bbox: function(num_times, hash_string) { - return repeats_callback(num_times, function() { + var loop = repeats_callback_wrapper(num_times, function() { return cgeohash_obj.decode_bbox(hash_string); }); + return loop(); }, neighbor: function(num_times, hash_string, direction) { - return repeats_callback(num_times, function() { + var loop = repeats_callback_wrapper(num_times, function() { return cgeohash_obj.neighbor(hash_string, direction); }); + return loop(); }, }; diff --git a/lib/cgeohash_original_repeaters.js b/lib/cgeohash_original_repeaters.js index 38e2fdb..37b97e2 100644 --- a/lib/cgeohash_original_repeaters.js +++ b/lib/cgeohash_original_repeaters.js @@ -10,34 +10,38 @@ // console.log('Seconds per call Node <-> JS = ' + looping_in_js); // -var cgeohash_original = require('./cgeohash_original'); -var repeats_callback = require('v8-profiler-table').repeats_callback; +var cgeohash_original = require('./cgeohash_original'); +var repeats_callback_wrapper = require('v8-profiler-table').repeats_callback_wrapper; // Alias the <...>_obj methods to the expected <...> method names // Loop in JS and record the seconds / call var cgeohash_original_repeat_js = { encode: function(num_times, latitude, longitude, numberOfChars) { - return repeats_callback(num_times, function() { + var loop = repeats_callback_wrapper(num_times, function() { return cgeohash_original.encode(latitude, longitude, numberOfChars); }); + return loop(); }, decode: function(num_times, hash_string) { - return repeats_callback(num_times, function() { + var loop = repeats_callback_wrapper(num_times, function() { return cgeohash_original.decode(hash_string); }); + return loop(); }, decode_bbox: function(num_times, hash_string) { - return repeats_callback(num_times, function() { + var loop = repeats_callback_wrapper(num_times, function() { return cgeohash_original.decode_bbox(hash_string); }); + return loop(); }, neighbor: function(num_times, hash_string, direction) { - return repeats_callback(num_times, function() { + var loop = repeats_callback_wrapper(num_times, function() { return cgeohash_original.neighbor(hash_string, direction); }); + return loop(); }, }; diff --git a/package.json b/package.json index e694e21..5f0063a 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "mocha": "1.11.0", "ngeohash": "0.2.0", "sprintf": "*", - "v8-profiler-table": ">=1.1.0" + "v8-profiler-table": ">=1.2.0" }, "engines": { "node": ">=v0.8.14" diff --git a/src/cgeohash.cpp b/src/cgeohash.cpp index dff0780..f37ce20 100644 --- a/src/cgeohash.cpp +++ b/src/cgeohash.cpp @@ -90,7 +90,7 @@ std::string encode(const double latitude, const double longitude, unsigned long std::string hash_string(precision, ' '); unsigned int hash_string_length = 0; - while(hash_string_length< precision) { + while(hash_string_length < precision) { if (islon) { mid = (bbox.maxlon + bbox.minlon) / 2; if(longitude > mid) { @@ -116,7 +116,7 @@ std::string encode(const double latitude, const double longitude, unsigned long if (5 == num_bits) { // Append the character to the pre-allocated string // This gives us roughly a 2x speed boost - // hash_string[hash_string_length] = base32_codes_value_of(hash_index); + hash_string[hash_string_length] = base32_codes[hash_index]; hash_string_length++; num_bits = 0; diff --git a/src/cgeohash_fn_repeaters.cpp b/src/cgeohash_fn_repeaters.cpp index 53a81f7..c39dd0f 100644 --- a/src/cgeohash_fn_repeaters.cpp +++ b/src/cgeohash_fn_repeaters.cpp @@ -17,25 +17,10 @@ namespace cgeohash { v8::Handle encode_fn_repeater(const v8::Arguments& args) { v8::HandleScope scope; - // if (args.Length() < 3) { - // return _THROW_NODE_ERROR("Takes 4 parameters: num_times, latitude, longitude, and precision"); - // } - - // int i = 0; - // const int num_times = cvv8::CastFromJS< int >(args[i++]); - // const double latitude = cvv8::CastFromJS< double >(args[i++]); - // const double longitude = cvv8::CastFromJS< double >(args[i++]); - // const uint32_t precision = args.Length() == 3 - // ? cvv8::CastFromJS< uint32_t >(args[i++]) - // : 9; // Default input - - // const uint64_t _nanoseconds = nanoseconds(); for(int i = 0; i < 1e6; i++) { - // encode(latitude, longitude, precision); encode(37.8324, 112.5584, 9); } - // return scope.Close(cvv8::CastToJS((nanoseconds() - _nanoseconds) / num_times)); return scope.Close(v8::Undefined()); } diff --git a/tests/speed_test.js b/tests/speed_test.js index e98ae5f..139174c 100644 --- a/tests/speed_test.js +++ b/tests/speed_test.js @@ -28,15 +28,16 @@ function compare_ratios(tag, timings) { // Sanity checks profile.title.should.equal('Original JS Version'); profile.ratio_to_base.should.equal(1); + chai.assert.ok(profile.total_seconds <= 1.00, JSON.stringify(profile, undefined, 2)); }); - it ('All C++ Version', function() { + it ('All C++ Version is at least 1.5x as fast', function() { var profile = v8_profiler_table.profiles()['All C++ Version']; // Sanity checks profile.title.should.equal('All C++ Version'); - chai.assert.ok(profile.ratio_to_base >= 1.0, JSON.stringify(profile, undefined, 2)); - chai.assert.ok(profile.total_seconds <= 0.5, JSON.stringify(profile, undefined, 2)); + chai.assert.ok(profile.ratio_to_base >= 1.50, JSON.stringify(profile, undefined, 2)); + chai.assert.ok(profile.total_seconds <= 0.50, JSON.stringify(profile, undefined, 2)); }); }); }; @@ -62,72 +63,72 @@ describe('Speed Tests', function() { original_in_js: function() { return orig_repeaters.repeat_in_js.encode(num_runs, 37.8324, 112.5584, 9); }, - obj_in_js: function() { - return obj_repeaters.repeat_in_js.encode(num_runs, 37.8324, 112.5584, 9); - }, - obj_in_cpp: function() { - return obj_repeaters.repeat_in_cpp.encode(num_runs, 37.8324, 112.5584, 9); - }, - fn_in_js: function() { - return fn_repeaters.repeat_in_js.encode(num_runs, 37.8324, 112.5584, 9); - }, fn_in_cpp: function() { return fn_repeaters.repeat_in_cpp.encode(num_runs, 37.8324, 112.5584, 9); }, + // obj_in_js: function() { + // return obj_repeaters.repeat_in_js.encode(num_runs, 37.8324, 112.5584, 9); + // }, + // obj_in_cpp: function() { + // return obj_repeaters.repeat_in_cpp.encode(num_runs, 37.8324, 112.5584, 9); + // }, + // fn_in_js: function() { + // return fn_repeaters.repeat_in_js.encode(num_runs, 37.8324, 112.5584, 9); + // }, }); - + compare_ratios('decodes string to latitude & longitude', { original_in_js: function() { return orig_repeaters.repeat_in_js.decode(num_runs, 'ww8p1r4t8'); }, - obj_in_js: function() { - return obj_repeaters.repeat_in_js.decode(num_runs, 'ww8p1r4t8'); - }, - obj_in_cpp: function() { - return obj_repeaters.repeat_in_cpp.decode(num_runs, 'ww8p1r4t8'); - }, - fn_in_js: function() { - return fn_repeaters.repeat_in_js.decode(num_runs, 'ww8p1r4t8'); - }, fn_in_cpp: function() { return fn_repeaters.repeat_in_cpp.decode(num_runs, 'ww8p1r4t8'); }, + // obj_in_js: function() { + // return obj_repeaters.repeat_in_js.decode(num_runs, 'ww8p1r4t8'); + // }, + // obj_in_cpp: function() { + // return obj_repeaters.repeat_in_cpp.decode(num_runs, 'ww8p1r4t8'); + // }, + // fn_in_js: function() { + // return fn_repeaters.repeat_in_js.decode(num_runs, 'ww8p1r4t8'); + // }, }); compare_ratios('finds neighbor to the north', { original_in_js: function() { return orig_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [1, 0]); }, - obj_in_js: function() { - return obj_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [1, 0]); - }, - obj_in_cpp: function() { - return obj_repeaters.repeat_in_cpp.neighbor(num_runs, 'dqcjq', [1, 0]); - }, - fn_in_js: function() { - return fn_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [1, 0]); - }, fn_in_cpp: function() { return fn_repeaters.repeat_in_cpp.neighbor(num_runs, 'dqcjq', [1, 0]); }, + // obj_in_js: function() { + // return obj_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [1, 0]); + // }, + // obj_in_cpp: function() { + // return obj_repeaters.repeat_in_cpp.neighbor(num_runs, 'dqcjq', [1, 0]); + // }, + // fn_in_js: function() { + // return fn_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [1, 0]); + // }, }); compare_ratios('finds neighbor to the south-west', { original_in_js: function() { return orig_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [-1, - 1]); }, - obj_in_js: function() { - return obj_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [-1, - 1]); - }, - obj_in_cpp: function() { - return obj_repeaters.repeat_in_cpp.neighbor(num_runs, 'dqcjq', [-1, - 1]); - }, - fn_in_js: function() { - return fn_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [-1, - 1]); - }, fn_in_cpp: function() { return fn_repeaters.repeat_in_cpp.neighbor(num_runs, 'dqcjq', [-1, - 1]); }, + // obj_in_js: function() { + // return obj_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [-1, - 1]); + // }, + // obj_in_cpp: function() { + // return obj_repeaters.repeat_in_cpp.neighbor(num_runs, 'dqcjq', [-1, - 1]); + // }, + // fn_in_js: function() { + // return fn_repeaters.repeat_in_js.neighbor(num_runs, 'dqcjq', [-1, - 1]); + // }, }); });