diff --git a/async_pi_estimate/nan/README.md b/async_pi_estimate/nan/README.md new file mode 100755 index 0000000..a11d3f5 --- /dev/null +++ b/async_pi_estimate/nan/README.md @@ -0,0 +1 @@ +In this directory run `node-gyp rebuild` and then `node ./addon.js` \ No newline at end of file diff --git a/async_pi_estimate/nan/addon.cc b/async_pi_estimate/nan/addon.cc new file mode 100755 index 0000000..bf48ccc --- /dev/null +++ b/async_pi_estimate/nan/addon.cc @@ -0,0 +1,23 @@ +#include +#include "sync.h" // NOLINT(build/include) +#include "async.h" // NOLINT(build/include) + +using v8::FunctionTemplate; +using v8::Handle; +using v8::Object; +using v8::String; +using Nan::GetFunction; +using Nan::New; +using Nan::Set; + +// Expose synchronous and asynchronous access to our +// Estimate() function +NAN_MODULE_INIT(InitAll) { + Set(target, New("calculateSync").ToLocalChecked(), + GetFunction(New(CalculateSync)).ToLocalChecked()); + + Set(target, New("calculateAsync").ToLocalChecked(), + GetFunction(New(CalculateAsync)).ToLocalChecked()); +} + +NODE_MODULE(addon, InitAll) \ No newline at end of file diff --git a/async_pi_estimate/nan/addon.js b/async_pi_estimate/nan/addon.js new file mode 100755 index 0000000..f678724 --- /dev/null +++ b/async_pi_estimate/nan/addon.js @@ -0,0 +1,44 @@ +var addon = require('./build/Release/addon'); +var calculations = process.argv[2] || 100000000; + +function printResult(type, pi, ms) { + console.log(type, 'method:'); + console.log('\tπ ≈ ' + pi + + ' (' + Math.abs(pi - Math.PI) + ' away from actual)'); + console.log('\tTook ' + ms + 'ms'); + console.log(); +} + +function runSync() { + var start = Date.now(); + // Estimate() will execute in the current thread, + // the next line won't return until it is finished + var result = addon.calculateSync(calculations); + printResult('Sync', result, Date.now() - start); +} + +function runAsync() { + // how many batches should we split the work in to? + var batches = process.argv[3] || 16; + var ended = 0; + var total = 0; + var start = Date.now(); + + function done (err, result) { + total += result; + + // have all the batches finished executing? + if (++ended === batches) { + printResult('Async', total / batches, Date.now() - start); + } + } + + // for each batch of work, request an async Estimate() for + // a portion of the total number of calculations + for (var i = 0; i < batches; i++) { + addon.calculateAsync(calculations / batches, done); + } +} + +runSync(); +runAsync(); \ No newline at end of file diff --git a/async_pi_estimate/nan/async.cc b/async_pi_estimate/nan/async.cc new file mode 100755 index 0000000..cd76c25 --- /dev/null +++ b/async_pi_estimate/nan/async.cc @@ -0,0 +1,56 @@ +#include +#include "pi_est.h" // NOLINT(build/include) +#include "async.h" // NOLINT(build/include) + +using v8::Function; +using v8::Local; +using v8::Number; +using v8::Value; +using Nan::AsyncQueueWorker; +using Nan::AsyncWorker; +using Nan::Callback; +using Nan::HandleScope; +using Nan::New; +using Nan::Null; +using Nan::To; + +class PiWorker : public AsyncWorker { + public: + PiWorker(Callback *callback, int points) + : AsyncWorker(callback), points(points), estimate(0) {} + ~PiWorker() {} + + // Executed inside the worker-thread. + // It is not safe to access V8, or V8 data structures + // here, so everything we need for input and output + // should go on `this`. + void Execute () { + estimate = Estimate(points); + } + + // Executed when the async work is complete + // this function will be run inside the main event loop + // so it is safe to use V8 again + void HandleOKCallback () { + HandleScope scope; + + Local argv[] = { + Null() + , New(estimate) + }; + + callback->Call(2, argv, async_resource); + } + + private: + int points; + double estimate; +}; + +// Asynchronous access to the `Estimate()` function +NAN_METHOD(CalculateAsync) { + int points = To(info[0]).FromJust(); + Callback *callback = new Callback(To(info[1]).ToLocalChecked()); + + AsyncQueueWorker(new PiWorker(callback, points)); +} diff --git a/async_pi_estimate/nan/async.h b/async_pi_estimate/nan/async.h new file mode 100755 index 0000000..d45615a --- /dev/null +++ b/async_pi_estimate/nan/async.h @@ -0,0 +1,8 @@ +#ifndef EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_ +#define EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_ + +#include + +NAN_METHOD(CalculateAsync); + +#endif // EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_ diff --git a/async_pi_estimate/nan/binding.gyp b/async_pi_estimate/nan/binding.gyp new file mode 100755 index 0000000..32f2925 --- /dev/null +++ b/async_pi_estimate/nan/binding.gyp @@ -0,0 +1,14 @@ +{ + "targets": [ + { + "target_name": "addon", + "sources": [ + "addon.cc", + "pi_est.cc", + "sync.cc", + "async.cc" + ], + "include_dirs": [" +#include "pi_est.h" // NOLINT(build/include) + +/* +Estimate the value of π by using a Monte Carlo method. +Take `points` samples of random x and y values on a +[0,1][0,1] plane. Calculating the length of the diagonal +tells us whether the point lies inside, or outside a +quarter circle running from 0,1 to 1,0. The ratio of the +number of points inside to outside gives us an +approximation of π/4. + +See https://en.wikipedia.org/wiki/File:Pi_30K.gif +for a visualization of how this works. +*/ + +inline int randall(unsigned int *p_seed) { +// windows has thread safe rand() +#ifdef _WIN32 + return rand(); // NOLINT(runtime/threadsafe_fn) +#else + return rand_r(p_seed); +#endif +} + +double Estimate (int points) { + int i = points; + int inside = 0; + unsigned int randseed = 1; + +#ifdef _WIN32 + srand(randseed); +#endif + + // unique seed for each run, for threaded use + unsigned int seed = randall(&randseed); + +#ifdef _WIN32 + srand(seed); +#endif + + while (i-- > 0) { + double x = randall(&seed) / static_cast(RAND_MAX); + double y = randall(&seed) / static_cast(RAND_MAX); + + // x & y and now values between 0 and 1 + // now do a pythagorean diagonal calculation + // `1` represents our 1/4 circle + if ((x * x) + (y * y) <= 1) + inside++; + } + + // calculate ratio and multiply by 4 for π + return (inside / static_cast(points)) * 4; +} diff --git a/async_pi_estimate/nan/pi_est.h b/async_pi_estimate/nan/pi_est.h new file mode 100755 index 0000000..8c35fe8 --- /dev/null +++ b/async_pi_estimate/nan/pi_est.h @@ -0,0 +1,6 @@ +#ifndef EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_ +#define EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_ + +double Estimate(int points); + +#endif // EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_ diff --git a/async_pi_estimate/nan/sync.cc b/async_pi_estimate/nan/sync.cc new file mode 100755 index 0000000..2d22ddd --- /dev/null +++ b/async_pi_estimate/nan/sync.cc @@ -0,0 +1,12 @@ +#include +#include "pi_est.h" // NOLINT(build/include) +#include "sync.h" // NOLINT(build/include) + +// Simple synchronous access to the `Estimate()` function +NAN_METHOD(CalculateSync) { + // expect a number as the first argument + int points = info[0]->Uint32Value(); + double est = Estimate(points); + + info.GetReturnValue().Set(est); +} diff --git a/async_pi_estimate/nan/sync.h b/async_pi_estimate/nan/sync.h new file mode 100755 index 0000000..7321f48 --- /dev/null +++ b/async_pi_estimate/nan/sync.h @@ -0,0 +1,8 @@ +#ifndef EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_ +#define EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_ + +#include + +NAN_METHOD(CalculateSync); + +#endif // EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_ diff --git a/async_pi_estimate/node-addon-api/README.md b/async_pi_estimate/node-addon-api/README.md new file mode 100755 index 0000000..a11d3f5 --- /dev/null +++ b/async_pi_estimate/node-addon-api/README.md @@ -0,0 +1 @@ +In this directory run `node-gyp rebuild` and then `node ./addon.js` \ No newline at end of file diff --git a/async_pi_estimate/node-addon-api/addon.cc b/async_pi_estimate/node-addon-api/addon.cc new file mode 100755 index 0000000..ca8b4ea --- /dev/null +++ b/async_pi_estimate/node-addon-api/addon.cc @@ -0,0 +1,13 @@ +#include +#include "sync.h" // NOLINT(build/include) +#include "async.h" // NOLINT(build/include) + +// Expose synchronous and asynchronous access to our +// Estimate() function +Napi::Object Init(Napi::Env env, Napi::Object exports) { + exports.Set(Napi::String::New(env, "calculateSync"), Napi::Function::New(env, CalculateSync)); + exports.Set(Napi::String::New(env, "calculateAsync"), Napi::Function::New(env, CalculateAsync)); + return exports; +} + +NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init) \ No newline at end of file diff --git a/async_pi_estimate/node-addon-api/addon.js b/async_pi_estimate/node-addon-api/addon.js new file mode 100755 index 0000000..d86178b --- /dev/null +++ b/async_pi_estimate/node-addon-api/addon.js @@ -0,0 +1,44 @@ +var addon = require('bindings')('addon'); +var calculations = process.argv[2] || 100000000; + +function printResult(type, pi, ms) { + console.log(type, 'method:'); + console.log('\tπ ≈ ' + pi + + ' (' + Math.abs(pi - Math.PI) + ' away from actual)'); + console.log('\tTook ' + ms + 'ms'); + console.log(); +} + +function runSync() { + var start = Date.now(); + // Estimate() will execute in the current thread, + // the next line won't return until it is finished + var result = addon.calculateSync(calculations); + printResult('Sync', result, Date.now() - start); +} + +function runAsync() { + // how many batches should we split the work in to? + var batches = process.argv[3] || 16; + var ended = 0; + var total = 0; + var start = Date.now(); + + function done (err, result) { + total += result; + + // have all the batches finished executing? + if (++ended === batches) { + printResult('Async', total / batches, Date.now() - start); + } + } + + // for each batch of work, request an async Estimate() for + // a portion of the total number of calculations + for (var i = 0; i < batches; i++) { + addon.calculateAsync(calculations / batches, done); + } +} + +runSync(); +runAsync(); diff --git a/async_pi_estimate/node-addon-api/async.cc b/async_pi_estimate/node-addon-api/async.cc new file mode 100755 index 0000000..9ae2bdd --- /dev/null +++ b/async_pi_estimate/node-addon-api/async.cc @@ -0,0 +1,39 @@ +#include +#include "pi_est.h" // NOLINT(build/include) +#include "async.h" // NOLINT(build/include) + +class PiWorker : public Napi::AsyncWorker { + public: + PiWorker(Napi::Function& callback, int points) + : Napi::AsyncWorker(callback), points(points), estimate(0) {} + ~PiWorker() {} + + // Executed inside the worker-thread. + // It is not safe to access V8, or V8 data structures + // here, so everything we need for input and output + // should go on `this`. + void Execute () { + estimate = Estimate(points); + } + + // Executed when the async work is complete + // this function will be run inside the main event loop + // so it is safe to use V8 again + void OnOK() { + Napi::HandleScope scope(Env()); + Callback().Call({Env().Undefined(), Napi::Number::New(Env(), estimate)}); + } + + private: + int points; + double estimate; +}; + +// Asynchronous access to the `Estimate()` function +Napi::Value CalculateAsync(const Napi::CallbackInfo& info) { + int points = info[0].As().Uint32Value(); + Napi::Function callback = info[1].As(); + PiWorker* piWorker = new PiWorker(callback, points); + piWorker->Queue(); + return info.Env().Undefined(); +} \ No newline at end of file diff --git a/async_pi_estimate/node-addon-api/async.h b/async_pi_estimate/node-addon-api/async.h new file mode 100755 index 0000000..7ab85ce --- /dev/null +++ b/async_pi_estimate/node-addon-api/async.h @@ -0,0 +1,8 @@ +#ifndef EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_ +#define EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_ + +#include + +Napi::Value CalculateAsync(const Napi::CallbackInfo& info); + +#endif // EXAMPLES_ASYNC_PI_ESTIMATE_ASYNC_H_ diff --git a/async_pi_estimate/node-addon-api/binding.gyp b/async_pi_estimate/node-addon-api/binding.gyp new file mode 100755 index 0000000..e27a001 --- /dev/null +++ b/async_pi_estimate/node-addon-api/binding.gyp @@ -0,0 +1,33 @@ +{ + "targets": [ + { + "target_name": "addon", + "sources": [ + "addon.cc", + "pi_est.cc", + "sync.cc", + "async.cc" + ], + 'cflags!': [ '-fno-exceptions' ], + 'cflags_cc!': [ '-fno-exceptions' ], + 'include_dirs': [" +#include "pi_est.h" // NOLINT(build/include) + +/* +Estimate the value of π by using a Monte Carlo method. +Take `points` samples of random x and y values on a +[0,1][0,1] plane. Calculating the length of the diagonal +tells us whether the point lies inside, or outside a +quarter circle running from 0,1 to 1,0. The ratio of the +number of points inside to outside gives us an +approximation of π/4. + +See https://en.wikipedia.org/wiki/File:Pi_30K.gif +for a visualization of how this works. +*/ + +inline int randall(unsigned int *p_seed) { +// windows has thread safe rand() +#ifdef _WIN32 + return rand(); // NOLINT(runtime/threadsafe_fn) +#else + return rand_r(p_seed); +#endif +} + +double Estimate (int points) { + int i = points; + int inside = 0; + unsigned int randseed = 1; + +#ifdef _WIN32 + srand(randseed); +#endif + + // unique seed for each run, for threaded use + unsigned int seed = randall(&randseed); + +#ifdef _WIN32 + srand(seed); +#endif + + while (i-- > 0) { + double x = randall(&seed) / static_cast(RAND_MAX); + double y = randall(&seed) / static_cast(RAND_MAX); + + // x & y and now values between 0 and 1 + // now do a pythagorean diagonal calculation + // `1` represents our 1/4 circle + if ((x * x) + (y * y) <= 1) + inside++; + } + + // calculate ratio and multiply by 4 for π + return (inside / static_cast(points)) * 4; +} \ No newline at end of file diff --git a/async_pi_estimate/node-addon-api/pi_est.h b/async_pi_estimate/node-addon-api/pi_est.h new file mode 100755 index 0000000..087f2e5 --- /dev/null +++ b/async_pi_estimate/node-addon-api/pi_est.h @@ -0,0 +1,14 @@ +/********************************************************************* + * NAN - Native Abstractions for Node.js + * + * Copyright (c) 2018 NAN contributors + * + * MIT License + ********************************************************************/ + +#ifndef EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_ +#define EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_ + +double Estimate(int points); + +#endif // EXAMPLES_ASYNC_PI_ESTIMATE_PI_EST_H_ diff --git a/async_pi_estimate/node-addon-api/sync.cc b/async_pi_estimate/node-addon-api/sync.cc new file mode 100755 index 0000000..4dabedf --- /dev/null +++ b/async_pi_estimate/node-addon-api/sync.cc @@ -0,0 +1,12 @@ +#include +#include "pi_est.h" // NOLINT(build/include) +#include "sync.h" // NOLINT(build/include) + +// Simple synchronous access to the `Estimate()` function + Napi::Value CalculateSync(const Napi::CallbackInfo& info) { + // expect a number as the first argument + int points = info[0].As().Uint32Value(); + double est = Estimate(points); + + return Napi::Number::New(info.Env(), est); +} diff --git a/async_pi_estimate/node-addon-api/sync.h b/async_pi_estimate/node-addon-api/sync.h new file mode 100755 index 0000000..86b51cc --- /dev/null +++ b/async_pi_estimate/node-addon-api/sync.h @@ -0,0 +1,8 @@ +#ifndef EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_ +#define EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_ + +#include + +Napi::Value CalculateSync(const Napi::CallbackInfo& info); + +#endif // EXAMPLES_ASYNC_PI_ESTIMATE_SYNC_H_