diff --git a/probing-tools/README.md b/probing-tools/README.md
new file mode 100644
index 000000000..53491d1b9
--- /dev/null
+++ b/probing-tools/README.md
@@ -0,0 +1,172 @@
+# Probing toolset for Encore
+
+These probing tools allows the user to gain insight into how many actors and futures are created, how work stealing occurs, succeeds or fails, and how many messages are sent and more, in a running Encore program.
+
+## Table of contents
+
+* [Installation](#installation)
+ * [Prerequisites](#prerequisites)
+ * [Setup](#setup)
+ * [MacOS 10.11+](#macos-1011)
+ * [Parser](#parser)
+* [Usage](#usage)
+ * [Dtrace](#dtrace)
+ * [SystemTap](#systemtap)
+ * [Parsing](#parsing)
+* [Further work](#further-work)
+* [Authors](#authors)
+
+## Installation
+
+The toolset works only on MacOS, BSD or Linux systems.
+
+### Prerequisites
+
+* DTrace / SystemTap
+* NodeJS (**above version 8**)
+
+### Setup
+
+In order for the probing tools to function, the Encore compiler must first be built with DTrace probes enabled, which can be done with the following command:
+
+```bash
+$ make config=release use=dtrace
+```
+
+#### MacOS 10.11+
+
+Systems running MacOS 10.11 or above, must first disable **System Integrity Protection** (SIP) for DTrace to work. This can be done by booting into recovery mode, and running the following commands in the Terminal:
+
+```bash
+$ csrutil clear
+$ csrutil enable --without dtrace
+```
+
+If it still does not work, you may disable SIP entirely, with the command ``csrutil disable`` (but do this at your own risk).
+
+#### Parser
+
+To setup the parser, just run ``npm install`` in the subdirectory ``probing-tools/parser``.
+
+## Usage
+
+Although the two scripts give the same output, depending on whether you have DTrace or SystemTap on your system, the usage will differ somewhat.
+
+
+
+### DTrace
+
+To probe a program using DTrace, run the following command:
+
+```
+$ dtrace -o ../output.xml -Cs dtrace.d -c ./[target binary] XML
+```
+
+This assumes that the working directory is ``probing-tools/dtrace``, and will produce an XML-file in the parent directory with the output from the DTrace script.
+
+**Note:** If you want the output to be in a human readable format, you can ommit the ``-o`` flag, and replace the ``XML`` argument with an arbitrary argument (you can not leave it empty, though).
+
+**Note:** If you need to pass an argument to the Encore program, you may do that by enclosing the target binary and the arguments in quotation marks, like so:
+
+```
+$ dtrace -o ../output.xml -Cs dtrace.d -c "./[target binary] someArgument" XML
+```
+
+### SystemTap
+
+To probe the program using SystemTap, run the following command:
+
+```
+$ stap systemTapXML.stp -c [target binary] -o ../output.XML
+```
+
+This assumes that the working directory is ``probing-tools/systemtap``, and will produce an XML-file in the parent directory with the output from the SystemTap script.
+
+**Note:** If you want the output to be in a human readable format, you may use the script ``systemTap.stp`` instead.
+
+### Parsing
+
+A simple parser is available to parse the XML output produced by the DTrace / SystemTap scripts.
+
+To parse the XML output, simply run the following command:
+
+```
+node parser/index.js /path/to/output.xml
+```
+
+This assumes that the working directory ``probing-tools``, and will give an organized overview of the data gathered:
+
+```bash
+┌───────────────────────┬────────┐
+│ (index) │ Values │
+├───────────────────────┼────────┤
+│ core-switches │ 2 │
+│ work-steal-failure │ 2 │
+│ work-steal-successful │ 3 │
+│ work-steal-attempt │ 5 │
+│ actor-msg-send │ 27 │
+└───────────────────────┴────────┘
+--------------------------- ACTORS ---------------------------
+┌────────────┬──────────────┬──────────────┬──────────────────────┬─────────────────────┐
+│ (index) │ id │ numberOfGets │ numberOfTimesBlocked │ numberOfTimesStolen │
+├────────────┼──────────────┼──────────────┼──────────────────────┼─────────────────────┤
+│ 4430339584 │ '4430339584' │ 0 │ 0 │ 1 │
+│ 4933481472 │ '4933481472' │ 0 │ 0 │ 2 │
+└────────────┴──────────────┴──────────────┴──────────────────────┴─────────────────────┘
+--------------------------- Schedulers ---------------------------
+┌────────────┬──────────────┬──────────────────┬──────────────┐
+│ (index) │ id │ successfulSteals │ failedSteals │
+├────────────┼──────────────┼──────────────────┼──────────────┤
+│ 4430338432 │ '4430338432' │ 1 │ 1 │
+│ 4430338048 │ '4430338048' │ 2 │ 1 │
+└────────────┴──────────────┴──────────────────┴──────────────┘
+--------------------------- Work steal success ---------------------------
+┌─────────┬──────────────┬──────────────┬───────┐
+│ (index) │ scheduler │ victim │ count │
+├─────────┼──────────────┼──────────────┼───────┤
+│ 0 │ '4430338432' │ '4430338048' │ 1 │
+│ 1 │ '4430338048' │ '4430338432' │ 2 │
+└─────────┴──────────────┴──────────────┴───────┘
+--------------------------- Work steal failure ---------------------------
+┌─────────┬──────────────┬──────────────┬───────┐
+│ (index) │ scheduler │ victim │ count │
+├─────────┼──────────────┼──────────────┼───────┤
+│ 0 │ '4430338048' │ '0' │ 1 │
+│ 1 │ '4430338432' │ '4430338048' │ 1 │
+└─────────┴──────────────┴──────────────┴───────┘
+```
+
+## Further work
+
+While the parser allows for an automated analysis of an Encore program, currently there is no script that does anything fancy with the data.
+
+The data will be collected and accessible through a few properties of the parser, as seen below:
+
+```js
+// index.js
+const parser = new Parser(nodes);
+parser.start(); // Start parsing
+
+const counts = parser.counts; // Holds a bunch of enumerations
+const futures = parser.futures; // Holds info on all futures created
+const futureGets = parser.futureGets; // Holds info on all future gets
+const futureBlocks = parser.blocks; // Holds info on all blocks made
+const actors = parser.actors; // Holds info on all actors
+const schedulers = parser.schedulers; // Holds info on all schedulers
+const workStealSuccess = parser.workStealSuccess; // Holds info on all successful work steals
+const workStealFailure = parser.workStealFailure; // Holds info on all failed work steals
+```
+
+For example, to get the ratio between number of messages sent and number of futures created, you can do the following:
+
+```js
+const counts = parser.counts;
+const ratio = parser.counts['actor-msg-send'] / parser.counts['future-create'];
+
+console.log(ratio);
+```
+
+
+## Authors
+
+The toolset was created by [Ardalan Samimi](https://github.com/pkrll), [Ulf Sigvardsson](https://github.com/ulfsigvardsson) and [Joy van den Eijkhof](https://github.com/elieoaks).
diff --git a/probing-tools/dtrace/dtrace.d b/probing-tools/dtrace/dtrace.d
new file mode 100644
index 000000000..f262e7b25
--- /dev/null
+++ b/probing-tools/dtrace/dtrace.d
@@ -0,0 +1,241 @@
+#pragma D option quiet
+
+typedef struct pony_ctx_t
+{
+ void* scheduler;
+ void* current;
+};
+
+struct actor_info {
+ uint64_t cpu;
+ uint32_t jumps;
+};
+
+struct actor_info cpus[int64_t]; /* declare cpus as an associative array */
+
+pony$target:::actor-msg-send {
+ @counts[probename] = count();
+}
+
+pony$target:::actor-scheduled {
+ cpus[arg1].cpu = cpu; // current CPU of the actor
+}
+
+pony$target:::work-steal-successful {
+ if (cpu != cpus[arg2].cpu) {
+ @counts["core-switches"] = count();
+ }
+
+ @counts[probename] = count();
+ @steal_success_count[arg0] = count();
+ @successful_steal_from_scheduler[arg0, arg1] = count();
+ @stolen_actor[arg2] = count();
+ @counts["work-steal-attempt"] = count();
+}
+
+pony$target:::work-steal-failure {
+ @counts[probename] = count();
+ @steal_fail_count[arg0] = count();
+ @failed_steal_from_scheduler[arg0, arg1] = count();
+ @counts["work-steal-attempt"] = count();
+}
+
+encore$target:::future-create {
+ @counts[probename] = count();
+ // Used in future-destroy to determine lifetime of a future
+ future_create_starttime[arg1] = timestamp;
+}
+
+encore$target:::future-block {
+ // The actor ID is in the context (arg0), so we need to
+ // get it by copying the pony_ctx_t struct into kernel space
+ ctx = (struct pony_ctx_t*)copyin(arg0, sizeof(struct pony_ctx_t));
+ actorPointer = (uintptr_t)ctx->current;
+ @counts[probename] = count();
+ @future_block[arg1] = count();
+ @actor_blocked[actorPointer] = count();
+ @future_blocked_actor[arg1, actorPointer] = count();
+ // Used in future-unblock to determine duration of a block
+ future_block_starttime[arg1, actorPointer] = timestamp;
+}
+
+encore$target:::future-unblock {
+ // The actor ID is in the context (arg0), so we need to
+ // get it by copying the pony_ctx_t struct into kernel space
+ ctx = (struct pony_ctx_t*)copyin(arg0, sizeof(struct pony_ctx_t));
+ actorPointer = (uintptr_t)ctx->current;
+
+ @counts[probename] = count();
+ @future_block_lifetime[arg1, actorPointer] = sum(timestamp - future_block_starttime[arg1, actorPointer]);
+}
+
+encore$target:::future-chaining {
+ @counts[probename] = count();
+ @future_chaining[arg1] = count();
+}
+
+encore$target:::future-fulfil-start {
+ @counts[probename] = count();
+}
+
+encore$target:::future-fulfil-end {
+ @counts[probename] = count();
+}
+
+encore$target:::future-get {
+ // The actor ID is in the context (arg0), so we need to
+ // get it by copying the pony_ctx_t struct into kernel space
+ ctx = (struct pony_ctx_t*)copyin(arg0, sizeof(struct pony_ctx_t));
+ actorPointer = (uintptr_t)ctx->current;
+
+ @future_get[actorPointer, arg1] = count();
+ @counts[probename] = count();
+}
+
+encore$target:::future-destroy {
+ @counts[probename] = count();
+ @future_lifetime[arg1] = sum(timestamp - future_create_starttime[arg1]);
+}
+
+// These probes are disabled for now. If a program uses future chaining,
+// we cannot determine the name of a method in the probe method-exit.
+// The instruction copyinstr (which copies a string from user space) gets
+// an error, for some unknown reason. Though, it works if the program does
+// not chain futures!
+
+// NOTE: When enabling these probes, you need to uncomment their outputs
+// as well below.
+
+// encore$target:::method-entry {
+// ctx = (struct pony_ctx_t*)copyin(arg0, sizeof(struct pony_ctx_t));
+// actorPointer = (uintptr_t)ctx->current;
+// // target pointer == the ctx current actor?
+// if (arg1 == actorPointer) {
+// function_time[arg1, arg2] = timestamp;
+// }
+// }
+//
+// encore$target:::method-exit {
+// ctx = (struct pony_ctx_t*)copyin(arg0, sizeof(struct pony_ctx_t));
+// actorPointer = (uintptr_t)ctx->current;
+// // target pointer == the ctx current actor?
+// if (arg1 == actorPointer) {
+// name = copyinstr(arg2);
+// @function_time[arg1, name] = sum(timestamp - function_time[arg1, arg2]);
+// }
+// }
+
+END {
+ if ($$1 == "XML") {
+ printf("\n");
+ printf("\n");
+ printa("\t<%s count=\"%@u\" />\n", @counts);
+ printf("\n");
+
+ printf("\n");
+ printa("\t\n\t\t%d\n\t\t%@u\n\t\n", @future_lifetime);
+ printf("\n");
+
+ printf("\n");
+ printa("\t\n\t\t%d\n\t\t%d\n\t\t%@u\n\t\n", @future_block_lifetime);
+ printa("\t\n\t\t%d\n\t\t%d\n\t\t%@u\n\t\n", @future_blocked_actor);
+ printa("\t\n\t\t%d\n\t\t%@u\n\t\n", @future_block);
+ printa("\t\n\t\t%d\n\t\t%@u\n\t\n", @actor_blocked);
+ printf("\n");
+
+ printf("\n");
+ printa("\t\n\t\t\n\t\t\t%d\n\t\t\n\t\t\n\t\t\t%d\n\t\t\n\t\t%@u\n\t\n", @future_get);
+ printf("\n");
+
+ printf("\n");
+ printa("\t\n\t\t%d\n\t\t%@u\n\t\n", @future_chaining);
+ printf("\n");
+
+ printf("\n");
+ printa("\t\n\t\t\n\t\t\t%d\n\t\t\n\t\t%@u\n\t\n", @steal_success_count);
+ printf("\n");
+
+ printf("\n");
+ printa("\t\n\t\t\n\t\t\t%d\n\t\t\n\t\t%d\n\t\t%@u\n\t\n", @successful_steal_from_scheduler);
+ printf("\n");
+
+ printf("\n");
+ printa("\t\n\t\t\n\t\t\t%d\n\t\t\n\t\t%@u\n\t\n", @steal_fail_count);
+ printf("\n");
+
+ printf("\n");
+ printa("\t\n\t\t\n\t\t\t%d\n\t\t\n\t\t%d\n\t\t%@u\n\t\n", @failed_steal_from_scheduler);
+ printf("\n");
+
+ printf("\n");
+ printa("\t\n\t\t%d\n\t\t%@u\n\t\n", @stolen_actor);
+ printf("\n");
+
+ // Uncomment these lines when using the method-entry/exit probes
+ // printf("\n");
+ // printa("\t\n\t\t\n\t\t\t%d\n\t\t\n\t\t%s\n\t\t%@u\n\t\n", @function_time);
+ // printf("");
+
+ printf("");
+ } else {
+ printf("--- COUNTS ---\n");
+ printa("%s\t%@1u\n", @counts);
+
+ printf("//---------- FUTURES ------------//\n");
+ printf("\n--- Duration a future is alive ---\n");
+ printf("Future id\t\tLifetime (nanoseconds)\n");
+ printa("%d\t\t%@1u\n", @future_lifetime);
+
+ printf("\n--- Duration a future blocks an actor ---\n");
+ printf("Future id\t\tActor id\t\tLifetime (nanoseconds)\n");
+ printa("%d\t\t%d\t\t%@1u\n", @future_block_lifetime);
+
+ printf("\n--- Number of times an actor is blocked by a future ---\n");
+ printf("Future id\t\tActor id\t\tCount\n");
+ printa("%d\t\t%d\t\t%@2u\n", @future_blocked_actor);
+
+ printf("\n--- Total number of times an actor is blocked ---\n");
+ printf("Actor id\t\tCount\n");
+ printa("%d\t\t%@2u\n", @actor_blocked);
+
+ printf("\n--- Total number of times a future blocks ---\n");
+ printf("Future id\t\tCount\n");
+ printa("%d\t\t%@2u\n", @future_block);
+
+ printf("\n--- Total number of times an actor calls get on a future ---\n");
+ printf("Actor id\t\tFuture id\t\tCount\n");
+ printa("%d\t\t%d\t\t%@u\n", @future_get);
+
+ printf("\n--- Number of times a future is chained ---\n");
+ printf("Future id\t\tCount\n");
+ printa("%d\t\t%@2u\n", @future_chaining);
+
+ printf("\n//---------- STEALS ------------//\n");
+ printf("\n--- Number of times a scheduler successfully steals ---\n");
+ printf("Scheduler id\t\tCount\n");
+ printa("%d\t\t%@2u\n", @steal_success_count);
+
+ printf("\n--- Number of times a scheduler fails to steal ---\n");
+ printf("Scheduler id\t\tCount\n");
+ printa("%d\t\t%@2u\n", @steal_fail_count);
+
+ printf("\n--- Number of times a scheduler steals from another ---\n");
+ printf("Stolen by\t\tStolen from\t\tCount\n");
+ printa("%d\t\t%d\t\t%@2u\n", @successful_steal_from_scheduler);
+
+ printf("\n--- Number of times a scheduelr fails to steal from another ---\n");
+ printf("Attempted by\t\tTarget\t\tCount\n");
+ printa("%d\t\t%d\t\t%@2u\n", @failed_steal_from_scheduler);
+
+ printf("\n--- Number of times an actor is stolen ---\n");
+ printf("Actor id\t\tTimes stolen\n");
+ printa("%d\t\t%@2u\n", @stolen_actor);
+
+ // Uncomment these lines when using the method-entry/exit probes
+ // printf("\n//---------- METHODS ------------//\n");
+ //
+ // printf("\n--- Time spent in methods\n");
+ // printf("Actor id\t\tMethod name\t\tDuration (Nanoseconds)\n");
+ // printa("%d\t\t%s\t\t\t%@u\n", @function_time);
+ }
+}
diff --git a/probing-tools/parser/.gitignore b/probing-tools/parser/.gitignore
new file mode 100644
index 000000000..c2658d7d1
--- /dev/null
+++ b/probing-tools/parser/.gitignore
@@ -0,0 +1 @@
+node_modules/
diff --git a/probing-tools/parser/Classes/Actor.js b/probing-tools/parser/Classes/Actor.js
new file mode 100644
index 000000000..36f990139
--- /dev/null
+++ b/probing-tools/parser/Classes/Actor.js
@@ -0,0 +1,26 @@
+'use strict'
+/**
+ * Represents an Encore Actor
+ *
+ * This class has the ID of an actor, as well as the number of times the
+ * actor is blocked by a future, the number of times the actor calls get
+ * and the number of times a scheduler steals it from another scheduler.
+ *
+ * All these values are integers.
+ *
+ * The actor object also holds references to Method objects, representing
+ * the methods of an actor called.
+ */
+class Actor {
+
+ constructor(id) {
+ this.id = id;
+ this.numberOfTimesBlocked = 0;
+ this.numberOfGets = 0;
+ this.numberOfTimesStolen = 0;
+ this.methods = {};
+ }
+
+}
+
+module.exports = Actor;
diff --git a/probing-tools/parser/Classes/Future.js b/probing-tools/parser/Classes/Future.js
new file mode 100644
index 000000000..d593e1063
--- /dev/null
+++ b/probing-tools/parser/Classes/Future.js
@@ -0,0 +1,28 @@
+'use strict'
+/**
+ * Represents an Encore Future
+ *
+ * This class has the ID of a future, the duration the future is active
+ * as well as the number of actors it has blocked, the total number of
+ * times actors has called a get on it.
+ *
+ * All these values are integers.
+ *
+ * The future object also holds references to FutureBlock objects, representing
+ * a future blocking.
+ */
+class Future {
+
+ constructor(id, duration) {
+ this.id = id;
+ this.duration = duration / 1000000.0;
+ this.blocks = [];
+ this.actorsBlocked = {};
+ this.numberOfGets = 0;
+ this.numberOfBlocks = 0;
+ this.numberOfFutureChainings = 0;
+ }
+
+}
+
+module.exports = Future;
diff --git a/probing-tools/parser/Classes/FutureBlock.js b/probing-tools/parser/Classes/FutureBlock.js
new file mode 100644
index 000000000..75204fddc
--- /dev/null
+++ b/probing-tools/parser/Classes/FutureBlock.js
@@ -0,0 +1,19 @@
+'use strict'
+/**
+ * Represents a block made by a Future.
+ *
+ * This class has the ID of an actor, the ID of a future, the duration of
+ * the block. This object also holds a reference to the Actor object.
+ */
+class FutureBlock {
+
+ constructor(id, actor, duration) {
+ this.futureId = id;
+ this.actor = actor;
+ this.duration = duration / 1000000.0;
+ this.actorId = actor.id;
+ }
+
+}
+
+module.exports = FutureBlock;
diff --git a/probing-tools/parser/Classes/FutureGet.js b/probing-tools/parser/Classes/FutureGet.js
new file mode 100644
index 000000000..51d975a05
--- /dev/null
+++ b/probing-tools/parser/Classes/FutureGet.js
@@ -0,0 +1,20 @@
+'use strict'
+/**
+ * Represents a Future get operation.
+ *
+ * This class has the ID of an actor, the id of a future, and the number
+ * of times it has been called (not necessary?).
+ *
+ * All these values are integers.
+ */
+class FutureGet {
+
+ constructor(actor, future, count) {
+ this.actor = actor;
+ this.future = future;
+ this.count = count;
+ }
+
+}
+
+module.exports = FutureGet;
diff --git a/probing-tools/parser/Classes/Method.js b/probing-tools/parser/Classes/Method.js
new file mode 100644
index 000000000..336d83ad9
--- /dev/null
+++ b/probing-tools/parser/Classes/Method.js
@@ -0,0 +1,18 @@
+'use strict'
+/**
+ * Represents a Method.
+ *
+ * This class has the ID of an actor, as well as the name of the method,
+ * and the total number of milliseconds the method was alive.
+ */
+class Method {
+
+ constructor(actorId, name, duration) {
+ this.actorId = actorId;
+ this.name = name;
+ this.duration = duration / 1000000.0;
+ }
+
+}
+
+module.exports = Method;
diff --git a/probing-tools/parser/Classes/Scheduler.js b/probing-tools/parser/Classes/Scheduler.js
new file mode 100644
index 000000000..6686b0839
--- /dev/null
+++ b/probing-tools/parser/Classes/Scheduler.js
@@ -0,0 +1,21 @@
+'use strict'
+/**
+ * Represents a Scheduler
+ *
+ * This class has the ID of a scheduler, the number of times it has successfully
+ * and unsuccessfully stolen work from another scheduler , as well as the a list
+ * of which schedulers it has stolen or attempted to steal from.
+ */
+class Scheduler {
+
+ constructor(id, successfulSteals, failedSteals) {
+ this.id = id;
+ this.successfulSteals = successfulSteals;
+ this.failedSteals = failedSteals;
+ this.stolenFrom = {};
+ this.failedToStealFrom = {};
+ }
+
+}
+
+module.exports = Scheduler;
diff --git a/probing-tools/parser/Classes/WorkSteal.js b/probing-tools/parser/Classes/WorkSteal.js
new file mode 100644
index 000000000..03e09b67d
--- /dev/null
+++ b/probing-tools/parser/Classes/WorkSteal.js
@@ -0,0 +1,18 @@
+'use strict'
+/**
+ * Represents a schedulers steal.
+ *
+ * This class has the IDs of the schedulers and the number of times the
+ * scheduler has stolen from the other scheduler.
+ */
+class WorkSteal {
+
+ constructor(byId, fromId, count) {
+ this.scheduler = byId;
+ this.victim = fromId;
+ this.count = count;
+ }
+
+}
+
+module.exports = WorkSteal;
diff --git a/probing-tools/parser/index.js b/probing-tools/parser/index.js
new file mode 100644
index 000000000..7bdd5e82e
--- /dev/null
+++ b/probing-tools/parser/index.js
@@ -0,0 +1,73 @@
+'use strict'
+const fs = require('fs');
+const xml2js = new require('xml2js').Parser();
+const Parser = require('./parser');
+const argv = process.argv.slice(2);
+
+if (argv.length == 0) {
+ console.log("No input file given.");
+ process.exit();
+}
+
+fs.readFile(process.cwd() + "/" + argv[0], (err, data) => {
+
+ if (err) {
+ console.log(err);
+ process.exit()
+ }
+
+ xml2js.parseString(data, (err, nodes) => {
+ if (err) {
+ console.log(err);
+ process.exit();
+ }
+
+ const parser = new Parser(nodes);
+ parser.start();
+
+ const counts = parser.counts;
+ const futures = parser.futures;
+ const futureGets = parser.futureGets;
+ const futureBlocks = parser.blocks;
+ const actors = parser.actors;
+ const schedulers = parser.schedulers;
+ const workStealSuccess = parser.workStealSuccess;
+ const workStealFailure = parser.workStealFailure;
+
+ let methods = [];
+
+ for (const key in actors) {
+ for (const method in actors[key].methods) {
+ methods.push(actors[key].methods[method]);
+ }
+ }
+
+ let blocks = [];
+
+ for (const key in futureBlocks) {
+ for (const block in futureBlocks[key]) {
+ blocks.push(futureBlocks[key][block]);
+ }
+ }
+
+ console.table(counts);
+ console.log("--------------------------- ACTORS ---------------------------");
+ console.table(actors, ["id", "numberOfGets", "numberOfTimesBlocked", "numberOfTimesStolen"]);
+ console.log("--------------------------- FUTURES ---------------------------");
+ console.table(futures, ["id", "duration", "numberOfGets", "numberOfBlocks", "numberOfFutureChainings"]);
+ console.log("--------------------------- BLOCKS ---------------------------");
+ console.table(blocks, ["futureId", "actorId", "duration"]);
+ console.log("--------------------------- FUTURE GETS ---------------------------");
+ console.table(futureGets);
+ console.log("--------------------------- Schedulers ---------------------------");
+ console.table(schedulers, ["id", "successfulSteals", "failedSteals"]);
+ console.log("--------------------------- Work steal success ---------------------------");
+ console.table(workStealSuccess);
+ console.log("--------------------------- Work steal failure ---------------------------");
+ console.table(workStealFailure);
+ console.log("--------------------------- Methods ---------------------------");
+ console.table(methods);
+
+ });
+
+});
diff --git a/probing-tools/parser/package-lock.json b/probing-tools/parser/package-lock.json
new file mode 100644
index 000000000..da63c7779
--- /dev/null
+++ b/probing-tools/parser/package-lock.json
@@ -0,0 +1,26 @@
+{
+ "name": "parser",
+ "requires": true,
+ "lockfileVersion": 1,
+ "dependencies": {
+ "sax": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+ },
+ "xml2js": {
+ "version": "0.4.19",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
+ "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
+ "requires": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~9.0.1"
+ }
+ },
+ "xmlbuilder": {
+ "version": "9.0.7",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
+ "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
+ }
+ }
+}
diff --git a/probing-tools/parser/package.json b/probing-tools/parser/package.json
new file mode 100644
index 000000000..5e900fcc6
--- /dev/null
+++ b/probing-tools/parser/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "parser",
+ "dependencies": {
+ "xml2js": "^0.4.19"
+ }
+}
diff --git a/probing-tools/parser/parser.js b/probing-tools/parser/parser.js
new file mode 100644
index 000000000..a6211e22d
--- /dev/null
+++ b/probing-tools/parser/parser.js
@@ -0,0 +1,361 @@
+'use strict';
+
+const Actor = require('./Classes/Actor.js');
+const Method = require('./Classes/Method.js');
+const Future = require('./Classes/Future.js');
+const FutureGet = require('./Classes/FutureGet.js');
+const FutureBlock = require('./Classes/FutureBlock.js');
+const Scheduler = require('./Classes/Scheduler.js');
+const WorkSteal = require('./Classes/WorkSteal.js');
+
+class Parser {
+
+ constructor(nodes) {
+ this.nodes = nodes;
+ this.counts = {};
+ this.blocks = {};
+ this.futures = {};
+ this.actors = {};
+ this.futureGets = [];
+ this.schedulers = {};
+ this.workStealSuccess = [];
+ this.workStealFailure = [];
+ }
+
+ start() {
+ for (const root in this.nodes) {
+ for (const parent in this.nodes[root]) {
+ const elements = this.nodes[root][parent];
+ switch (parent) {
+ case "counts":
+ this.parseCounts(elements);
+ break;
+ case "futures":
+ this.parseFutures(elements);
+ break;
+ case "future-blocks":
+ this.parseFutureBlocks(elements);
+ break;
+ case "future-gets":
+ this.parseFutureGets(elements);
+ break;
+ case "future-chainings":
+ this.parseFutureChaining(elements);
+ break;
+ case "work-steal-successes":
+ this.parseWorkStealSuccess(elements);
+ break;
+ case "work-steal-success-from":
+ this.parseWorkStealSuccessFrom(elements);
+ break;
+ case "work-steal-failures":
+ this.parseWorkStealFailure(elements);
+ break;
+ case "work-steal-failure-from":
+ this.parseWorkStealFailureFrom(elements);
+ break;
+ case "actor-stolen":
+ this.parseActorStolen(elements);
+ break;
+ case "methods":
+ this.parseMethods(elements);
+ break;
+ default:
+ console.log("Error: Unknown tag: " + parent);
+ break;
+ }
+ }
+ }
+ }
+ /**
+ * Parses the element.
+ * @param Object rootNode The root node.
+ */
+ parseCounts(rootNode) {
+ const elements = rootNode[0];
+ for (const key in elements) {
+ const count = elements[key][0]["$"]["count"];
+ this.counts[key] = parseInt(count);
+ }
+ }
+ /**
+ * Parses the element.
+ * @param Object rootNode The root node.
+ */
+ parseFutures(rootNode) {
+ // As there is only one root node for futures
+ // we can just get the first element in the list
+ const elements = rootNode[0]["future"];
+
+ for (const key in elements) {
+ const id = elements[key]['id'][0];
+ const duration = elements[key]['duration'][0];
+ const future = new Future(id, parseInt(duration));
+ this.futures[id] = future;
+ }
+ }
+ /**
+ * Parses the element.
+ * @param Object rootNode The root node.
+ */
+ parseFutureBlocks(rootNode) {
+ const elements = rootNode[0];
+
+ for (const key in elements) {
+ switch (key) {
+ case "future-block-lifetime":
+ this.parseFutureBlockLifetime(elements[key]);
+ break;
+ case "future-block-actor-count":
+ this.parseFutureBlockActorCount(elements[key]);
+ break;
+ case "future-block-count":
+ this.parseFutureBlockCount(elements[key]);
+ break;
+ case "actor-block-count":
+ this.parseActorBlockCount(elements[key]);
+ break;
+ case "0":
+ // Empty tag
+ break;
+ default:
+ console.log("Error: Unknown tag: " + key);
+ break;
+ }
+ }
+ }
+ /**
+ * Parses the element.
+ * @param Object elements The root node.
+ */
+ parseFutureBlockLifetime(elements) {
+ for (let key in elements) {
+ const future = elements[key]["future"][0];
+ const actorElm = elements[key]["actor"][0];
+ const duration = elements[key]["duration"][0];
+ const futureId = future["id"][0];
+ const actorId = actorElm["id"][0];
+ let actor = this.actors[actorId];
+
+ if (actor == null) {
+ actor = new Actor(actorId);
+ this.actors[actorId] = actor;
+ }
+
+ if (!(futureId in this.blocks)) { this.blocks[futureId] = []; }
+
+ const block = new FutureBlock(futureId, actor, parseInt(duration));
+ this.blocks[futureId].push(block);
+
+ if (futureId in this.futures) {
+ this.futures[futureId].blocks.push(block);
+ }
+ }
+ }
+ /**
+ * Parses the elements.
+ * @param Object elements The root node.
+ */
+ parseFutureBlockActorCount(elements) {
+ for (let key in elements) {
+ const futureId = elements[key]["future"][0]['id'][0];
+ const actorId = elements[key]["actor"][0]["id"][0];
+ const count = elements[key]["count"][0];
+ // TODO: If Future has no lifetime, it will not exist here.
+ // Perhaps create the Future object then??
+ if (futureId in this.futures) {
+ let future = this.futures[futureId];
+ future.actorsBlocked[actorId] = parseInt(count);
+ }
+ }
+ }
+ /**
+ * Parses the elements.
+ * @param Object elements The root node.
+ */
+ parseFutureBlockCount(elements) {
+ for (let key in elements) {
+ const id = elements[key]["future"][0]["id"][0];
+ const count = elements[key]['count'][0];
+
+ if (id in this.futures) {
+ let future = this.futures[id];
+ future.numberOfBlocks = parseInt(count);
+ }
+ }
+ }
+ /**
+ * Parses the elements.
+ * @param Object elements The root node.
+ */
+ parseActorBlockCount(elements) {
+ for (let key in elements) {
+ const element = elements[key]['actor'][0];
+ const id = element['id'][0];
+ const count = elements[key]['count'][0];
+
+ if (!(id in this.actors)) {
+ this.actors[id] = new Actor(id);
+ }
+
+ this.actors[id].numberOfTimesBlocked = parseInt(count);
+ }
+ }
+ /**
+ * Parses the elements.
+ * @param Object rootNode The root node.
+ */
+ parseFutureGets(rootNode) {
+ // As there is only one node for future-gets
+ // we can just get the first element in the list
+ const futureGets = rootNode[0]["future-get"];
+
+ for (const key in futureGets) {
+ const actorID = futureGets[key]["actor"][0]["id"][0];
+ const futureID = futureGets[key]["future"][0]["id"][0];
+ const count = futureGets[key]["count"][0];
+
+ if (!(actorID in this.actors)) {
+ this.actors[actorID] = new Actor(actorID);
+ }
+ if (!(futureID in this.futures)) {
+ this.futures[futureID] = new Future(futureID, -1);
+ }
+
+ this.actors[actorID].numberOfGets += parseInt(count);
+ this.futures[futureID].numberOfGets += parseInt(count);
+
+ const futureGet = new FutureGet(actorID, futureID, parseInt(count));
+ this.futureGets.push(futureGet);
+ }
+ }
+ /**
+ * Parses the element.
+ * @param Object rootNode The root node.
+ */
+ parseFutureChaining(rootNode) {
+ const chains = rootNode[0]["future-chaining"];
+
+ for (const key in chains) {
+ const futureID = chains[key]["future"][0]["id"][0];
+ const count = chains[key]["count"][0];
+
+ if (!(futureID in this.futures)) {
+ this.futures[futureID] = new Future(futureID, -1);
+ }
+
+ this.futures[futureID].numberOfFutureChainings += parseInt(count);
+ }
+ }
+ /**
+ * Parses the element.
+ * @param Object rootNode The root node.
+ */
+ parseWorkStealSuccess(rootNode) {
+ const schedulers = rootNode[0]["work-steal-success"];
+ for (const key in schedulers) {
+ const id = schedulers[key]["scheduler"][0]["id"][0];
+ const count = schedulers[key]["count"][0];
+
+ if (!(id in this.schedulers)) {
+ this.schedulers[id] = new Scheduler(id, parseInt(count), 0);
+ } else {
+ this.schedulers[id].successfulSteals = parseInt(count);
+ }
+ }
+ }
+ /**
+ * Parses the element.
+ * @param Object rootNode The root node.
+ */
+ parseWorkStealSuccessFrom(rootNode) {
+ const schedulers = rootNode[0]["work-steal-success"];
+
+ for (const key in schedulers) {
+ const byId = schedulers[key]["scheduler"][0]["id"][0];
+ const fromId = schedulers[key]["victim"][0];
+ const count = schedulers[key]["count"][0];
+
+ if (!(byId in this.schedulers)) {
+ this.schedulers[byId] = new Scheduler(byId, parseInt(count), 0);
+ }
+
+ this.workStealSuccess.push(new WorkSteal(byId, fromId, parseInt(count)));
+ this.schedulers[byId].stolenFrom[fromId] = parseInt(count);
+ }
+ }
+ /**
+ * Parses the element.
+ * @param Object rootNode The root node.
+ */
+ parseWorkStealFailure(rootNode) {
+ const schedulers = rootNode[0]["work-steal-failure"];
+ for (const key in schedulers) {
+ const id = schedulers[key]["scheduler"][0]["id"][0];
+ const count = schedulers[key]["count"][0];
+
+ if (!(id in this.schedulers)) {
+ this.schedulers[id] = new Scheduler(id, 0, parseInt(count));
+ } else {
+ this.schedulers[id].failedSteals = parseInt(count);
+ }
+ }
+ }
+ /**
+ * Parses the element.
+ * @param Object rootNode The root node.
+ */
+ parseWorkStealFailureFrom(rootNode) {
+ const schedulers = rootNode[0]["work-steal-failure"];
+ for (const key in schedulers) {
+ const byId = schedulers[key]["scheduler"][0]["id"][0];
+ const fromId = schedulers[key]["victim"][0];
+ const count = schedulers[key]["count"][0];
+
+ if (!(byId in this.schedulers)) {
+ this.schedulers[byId] = new Scheduler(byId, 0, parseInt(count));
+ }
+
+ this.workStealFailure.push(new WorkSteal(byId, fromId, parseInt(count)));
+ this.schedulers[byId].failedToStealFrom[fromId] = parseInt(count);
+ }
+ }
+ /**
+ * Parses the elements.
+ * @param Object rootNode The root node.
+ */
+ parseActorStolen(rootNode) {
+ const actors = rootNode[0]["actor"];
+ for (const key in actors) {
+ const id = actors[key]["id"][0];
+ const count = actors[key]["count"][0];
+
+ if (!(id in this.actors)) {
+ this.actors[id] = new Actor(id);
+ }
+
+ this.actors[id].numberOfTimesStolen = parseInt(count);
+ }
+ }
+ /**
+ * Parses the element.
+ * @param Object rootNode The root node.
+ */
+ parseMethods(rootNode) {
+ const methods = rootNode[0]["method"];
+ for (const key in methods) {
+ const id = methods[key]["actor"][0]["id"][0];
+ const name = methods[key]["name"][0];
+ const duration = methods[key]["duration"][0];
+
+ if (!(id in this.actors)) {
+ this.actors[id] = new Actor(id);
+ }
+
+ this.actors[id].methods[name] = new Method(id, name, parseInt(duration));
+ }
+ }
+
+}
+
+module.exports = Parser;
diff --git a/probing-tools/systemtap/systemTap.stp b/probing-tools/systemtap/systemTap.stp
new file mode 100644
index 000000000..f47f60c82
--- /dev/null
+++ b/probing-tools/systemtap/systemTap.stp
@@ -0,0 +1,308 @@
+## A systemTap probing tool for Encore that prints human readable data
+## Written by Joy van den EIjkhof, Ardalan Samimi, Ulf Sigvardsson
+## March 2019
+
+#core_switches > core_switches -DONE
+#steal_success_count > steal_success_count -DONE
+#actor_stolen > stolen_actor -DONE
+#scheduler_from_scheduler > successful_steal_from_scheduler -DONE
+#current_sched_core > cpus -DOne
+
+## Counters
+## Contains how many times each probe has been called
+## Uses aggregation
+global actor_msg_send
+global future_create
+global future_block
+global future_destroy
+global future_fulfil_start
+global future_fulfil_end
+global future_get
+global future_unblock
+global future_chaining
+global successful_steals
+global failed_steals
+global total_steals
+
+
+#Lists containing data corresponding to their name
+#Each list corresponds to one foreach-loop in probe end
+
+#List for counting lifetimes
+global list_future_lifetime
+global list_future_block_lifetime
+
+#How many times does an Actor get blocked by any Future
+global actor_block_count
+
+#How many times does what Actor call get() on what future
+global actor_get_future
+
+#How many time does a Future block any actor
+global future_block_count
+
+#How many times is a Future chained at what Actor
+global chained_actor_future_list
+
+#How many time a Scheduler successfully steals work any other Scheduler
+global steal_success_count
+
+#How many times an Actor is stolen from any Scheduler
+global stolen_actor
+
+#How many time a Scheduler fails to steals work any other Scheduler
+global failed_steals_count
+
+#What Future blocks what Future
+global future_block_actor
+
+#What Scheduler steals from what Scheduler sucess/fail
+global successful_steal_from_scheduler
+global scheduler_from_scheduler_fail
+
+#Counts how many core-swites have been made
+global core_switches
+
+#Keeps track of what scheduler is used by what core.
+global cpus
+
+
+
+#messages
+probe process.mark("actor-msg-send") {
+ #Count
+ actor_msg_send <<< 1;
+}
+
+probe process.mark("actor-scheduled") {
+ actor = sprint($arg2)
+ cpus[actor] = cpu()
+}
+
+probe process.mark("work-steal-successful") {
+ #Count
+ successful_steals <<< 1;
+ total_steals <<< 1;
+
+ #Arguments from probe
+ scheduler = sprint($arg1)
+ victim = sprint($arg2)
+ actor = sprint($arg3)
+
+
+ steal_success_count[scheduler] <<< 1
+ stolen_actor[actor] <<< 1
+ successful_steal_from_scheduler[scheduler, victim] <<< 1;
+
+ if (cpu() != cpus[actor]) {
+ core_switches <<< 1;
+ cpus[actor] = cpu()
+ }
+
+}
+
+probe process.mark("work-steal-failure") {
+ #Count
+ failed_steals <<< 1;
+ total_steals <<< 1;
+
+ #Arguments from probe
+ scheduler = sprint($arg1)
+ victim = sprint($arg2)
+
+ failed_steals_count[scheduler] <<< 1
+ scheduler_from_scheduler_fail[scheduler, victim] <<< 1
+
+}
+
+
+probe process.mark("future-create") {
+ #Count
+ future_create <<< 1;
+
+ #Arguments from probe
+ future = sprint($arg2)
+
+ list_future_lifetime[future] = gettimeofday_ns()
+}
+
+
+probe process.mark("future-destroy") {
+ #Count
+ future_destroy <<< 1;
+
+ #Arguments
+ future = sprint($arg2)
+
+ list_future_lifetime[future] = gettimeofday_ns()-list_future_lifetime[future]
+}
+
+probe process.mark("future-block") {
+ #Count
+ future_block <<< 1;
+
+ #Arguments from probe
+ actor = sprint(@cast($arg1, "pony_ctx_t")->current)
+ future = sprint($arg2)
+
+ actor_block_count[actor] <<< 1
+ future_block_actor[future, actor] <<< 1
+ future_block_count[future] <<< 1
+
+ list_future_block_lifetime[future, actor] = gettimeofday_ns()
+
+}
+
+probe process.mark("future-unblock") {
+ #Count
+ future_unblock <<< 1;
+
+ #Arguments from probe
+ actor = sprint(@cast($arg1, "pony_ctx_t")->current)
+ future = sprint($arg2)
+
+ list_future_block_lifetime[future, actor] = gettimeofday_ns()-list_future_block_lifetime[future, actor]
+}
+
+probe process.mark("future-get") {
+ #Count
+ future_get <<< 1;
+
+ #Arguments from probe
+ actor = sprint(@cast($arg1, "pony_ctx_t")->current)
+ future = sprint($arg2)
+
+ actor_get_future[actor, future] <<< 1;
+
+}
+
+probe process.mark("future-fulfil-end"){
+ #Count
+ future_fulfil_end <<< 1;
+}
+
+probe process.mark("future-fulfil-start"){
+ #Count
+ future_fulfil_start <<< 1;
+}
+
+probe process.mark("future-chaining") {
+ #Count
+ future_chaining <<< 1;
+
+ #Arguments from probe
+ future = sprint($arg2)
+
+ chained_actor_future_list[future] <<< 1;
+}
+
+probe end {
+ print("--- DATA FROM PROBING ---")
+ print("\n--- COUNTS ---\n")
+ ams = @count(actor_msg_send)
+ fc = @count(future_create)
+ fb = @count(future_block)
+ ffs = @count(future_fulfil_start)
+ ffe = @count(future_fulfil_end)
+ fd = @count(future_destroy)
+ fg = @count(future_get)
+ fu = @count(future_unblock)
+ fch = @count(future_chaining)
+ ss = @count(successful_steals)
+ fs = @count(failed_steals)
+ ts = @count(total_steals)
+
+ printf("future-chaining\t\t%d\n", fch)
+ printf("future-block\t\t%d\n", fb)
+ printf("future-create\t\t%d\n", fc)
+ printf("future-destroy\t\t%d\n", fd)
+ printf("future-fulfil-start\t%d\n", ffs)
+ printf("future-fulfil-end\t%d\n", ffe)
+ printf("future-get\t\t%d\n", fg)
+ printf("future-unblock\t\t%d\n", fu)
+ printf("actor-msg-send\t\t%d\n", ams)
+ printf("work-steal-failure\t\t%d\n", fs)
+ printf("work-steal-successful\t\t%d\n", ss)
+ printf("work-steal-attempt\t\t%d\n", ts)
+ printf("core-switches:\t%d\n", @count(core_switches))
+
+
+ print("\n--- LIFETIME OF FUTURE ---\n")
+ print("Future Addr\t\tLifetime (nanoseconds)\n")
+ foreach(fut in list_future_lifetime) {
+ printf("%s\t\t%d\n", fut, list_future_lifetime[fut])
+
+ }
+
+
+ print("\n--- LIFETIME OF A FUTURE BLOCK ---\n")
+ print("Future Addr\t\tActor Addr\t\tLifetime (nanoseconds)\n")
+ foreach([fut, act] in list_future_block_lifetime) {
+ printf("%s\t\t%s\t\t%d\n", fut, act, list_future_block_lifetime[fut, act])
+
+ }
+
+ print("\n---NUMBER OF TIMES ACTOR CALLS GET ON FUTURE---\n")
+ print("Actor addr\t\tFuture Addr\t\tCount\n")
+ foreach ([act, fut] in actor_get_future) {
+ printf("%s\t\t%s\t\t%d\n", act, fut, @count(actor_get_future[act, fut]))
+ }
+
+
+ print("\n--- WHAT FUTURE BLOCKED WHAT ACTOR ---\n")
+ print("Future Addr\t\tActorr Addr\t\tCount\n")
+ foreach([fut, actor] in future_block_actor) {
+ printf("%s\t\t%s\t\t%d\n", fut, actor, @count(future_block_actor[fut, actor]))
+ }
+
+
+ print("\n--- NUMBER OF TIMES AN ACTOR IS BLOCKED ---\n")
+ print("Actor Addr\t\tCount\n")
+ foreach(act in actor_block_count) {
+ printf("%s\t\t%d\n", act, @count(actor_block_count[act]))
+ }
+
+
+ print("\n--- NUMBER OF TIMES A FUTURE BLOCKS ---\n")
+ print("Future Addr\t\tCount\n")
+ foreach(fut in future_block_count) {
+ printf("%s\t\t%d\n", fut, @count(future_block_count[fut]))
+ }
+
+ print("\n--- WHAT FUTURES CHAINES AT WHAT ACTOR ---\n")
+ print("Actor Addr\t\tFuture Addr\t\tCount\n")
+ foreach([fut] in chained_actor_future_list) {
+ printf("%s\t\t%s\t\t%d\n",act, fut, @count(chained_actor_future_list[fut]))
+ }
+
+ print("\n---SUCCESSFUL STEALS---\n")
+ print("Scheduler\t\tCount\n")
+ foreach(ssid in steal_success_count) {
+ printf("%s\t\t%d\n", ssid, @count(steal_success_count[ssid]))
+ }
+
+ print("\n---FAILED STEALS---\n")
+ print("Scheduler\t\tCount\n")
+ foreach(fsid in failed_steals_count) {
+ printf("%s\t\t%d\n", fsid, @count(failed_steals_count[fsid]))
+ }
+
+ print("\n---STEALS BETWEEN SCHEDULERS---\n")
+ print("Stolen by\t\tStolen from\t\tCount\n")
+ foreach([steal, victim] in successful_steal_from_scheduler) {
+ printf("%s\t\t%s\t\t%d\n", steal, victim, @count(successful_steal_from_scheduler[steal, victim]))
+ }
+
+ print("\n---FAILS BETWEEN SCHEDULERS---\n")
+ print("Attempted by\t\tTarget\t\t\tCount\n")
+ foreach([steal, victim] in scheduler_from_scheduler_fail) {
+ printf("%s\t\t%s\t\t%d\n", steal, victim, @count(scheduler_from_scheduler_fail[steal, victim]))
+ }
+
+ print("\n---STOLEN ACTORS---\n")
+ print("Actor ID\t\tTimes Stolen\n")
+ foreach(actor in stolen_actor) {
+ printf("%s\t\t%d\n", actor, @count(stolen_actor[actor]))
+ }
+
+}
\ No newline at end of file
diff --git a/probing-tools/systemtap/systemTapXML.stp b/probing-tools/systemtap/systemTapXML.stp
new file mode 100644
index 000000000..5f9d551c9
--- /dev/null
+++ b/probing-tools/systemtap/systemTapXML.stp
@@ -0,0 +1,429 @@
+## A systemTap probing tool for Encore that produces data in XML-format
+## Written by Joy van den Eijkhof in colaboration with Ardalan Samimi, Ulf Sigvardsson
+## March 2019
+
+## Note that some actors are identified by their ctx pointers.
+
+#core_switches > core_switcheses
+#successful_steals_count > steal_success_count
+#actor_stolen > stolen_actor
+#scheduler_from_scheduler > successful_steal_from_scheduler
+#current_sched_core > cpus
+
+
+## Counters
+## Contains how many times each probe has been called
+## Uses aggregation
+
+global actor_msg_send
+global future_create
+global future_block
+global future_destroy
+global future_fulfil_start
+global future_fulfil_end
+global future_get
+global future_unblock
+global future_chaining
+global successful_steals
+global failed_steals
+global total_steals
+
+
+#Lists containing data corresponding to their name
+#Each list corresponds to one foreach-loop in probe end
+
+#List for counting lifetimes
+global list_future_lifetime
+global list_future_block_lifetime
+
+#How many times does an Actor get blocked by any Future
+global actor_block_count
+
+#How many times does what Actor call get() on what future
+global actor_get_future
+
+#How many time does a Future block any actor
+global future_block_count
+
+#How many times is a Future chained at what Actor
+global chained_actor_future_list
+
+#How many time a Scheduler successfully steals work from any other Scheduler
+global steal_success_count
+
+#How many times an Actor is stolen from any Scheduler
+global stolen_actor
+
+#How many time a Scheduler fails to steals work any other Scheduler
+global failed_steals_count
+
+#What Future blocks what Future
+global future_block_actor
+
+#What Scheduler steals from what Scheduler sucess/fail
+global successful_steal_from_scheduler
+global scheduler_from_scheduler_fail
+
+#Counts how many core-swites have been made
+global core_switches
+
+#Keeps track of what scheduler is used by what core.
+global cpus
+
+
+
+#messages
+probe process.mark("actor-msg-send") {
+ #Count
+ actor_msg_send <<< 1;
+}
+
+probe process.mark("actor-scheduled") {
+ actor = sprint($arg2)
+ cpus[actor] = cpu()
+}
+
+probe process.mark("work-steal-successful") {
+ #Count
+ successful_steals <<< 1;
+ total_steals <<< 1;
+
+ #Arguments from probe
+ scheduler = sprint($arg1)
+ victim = sprint($arg2)
+ actor = sprint($arg3)
+
+
+ steal_success_count[scheduler] <<< 1
+ stolen_actor[actor] <<< 1
+ successful_steal_from_scheduler[scheduler, victim] <<< 1;
+
+ if (cpu() != cpus[actor]) {
+ core_switches <<< 1;
+ cpus[actor] = cpu()
+ }
+
+}
+
+probe process.mark("work-steal-failure") {
+ #Count
+ failed_steals <<< 1;
+ total_steals <<< 1;
+
+ #Arguments from probe
+ scheduler = sprint($arg1)
+ victim = sprint($arg2)
+
+ failed_steals_count[scheduler] <<< 1
+ scheduler_from_scheduler_fail[scheduler, victim] <<< 1
+
+}
+
+
+probe process.mark("future-create") {
+ #Count
+ future_create <<< 1;
+
+ #Arguments from probe
+ future = sprint($arg2)
+
+ list_future_lifetime[future] = gettimeofday_ns()
+}
+
+
+probe process.mark("future-destroy") {
+ #Count
+ future_destroy <<< 1;
+
+ #Arguments
+ future = sprint($arg2)
+
+ list_future_lifetime[future] = gettimeofday_ns()-list_future_lifetime[future]
+}
+
+probe process.mark("future-block") {
+ #Count
+ future_block <<< 1;
+
+ #Arguments from probe
+ actor = sprint(@cast($arg1, "pony_ctx_t")->current)
+ future = sprint($arg2)
+
+ actor_block_count[actor] <<< 1
+ future_block_actor[future, actor] <<< 1
+ future_block_count[future] <<< 1
+
+ list_future_block_lifetime[future, actor] = gettimeofday_ns()
+
+}
+
+probe process.mark("future-unblock") {
+ #Count
+ future_unblock <<< 1;
+
+ #Arguments from probe
+ actor = sprint(@cast($arg1, "pony_ctx_t")->current)
+ future = sprint($arg2)
+
+ list_future_block_lifetime[future, actor] = gettimeofday_ns()-list_future_block_lifetime[future, actor]
+}
+
+probe process.mark("future-get") {
+ #Count
+ future_get <<< 1;
+
+ #Arguments from probe
+ actor = sprint(@cast($arg1, "pony_ctx_t")->current)
+ future = sprint($arg2)
+
+ actor_get_future[actor, future] <<< 1;
+
+}
+
+probe process.mark("future-fulfil-end"){
+ #Count
+ future_fulfil_end <<< 1;
+}
+
+probe process.mark("future-fulfil-start"){
+ #Count
+ future_fulfil_start <<< 1;
+}
+
+probe process.mark("future-chaining") {
+ #Count
+ future_chaining <<< 1;
+
+ #Arguments from probe
+ future = sprint($arg2)
+
+ chained_actor_future_list[future] <<< 1;
+}
+
+#Handles all the data all previous probes have accumulated
+#Prints all data in XML format
+
+probe end {
+ ams = @count(actor_msg_send)
+ fc = @count(future_create)
+ fb = @count(future_block)
+ ffs = @count(future_fulfil_start)
+ ffe = @count(future_fulfil_end)
+ fd = @count(future_destroy)
+ fg = @count(future_get)
+ fu = @count(future_unblock)
+ fch = @count(future_chaining)
+ ss = @count(successful_steals)
+ fs = @count(failed_steals)
+ ts = @count(total_steals)
+
+ print("\n")
+ print("\n")
+
+ printf("\t\n", fch)
+ printf("\t\n", fb)
+ printf("\t\n", fc)
+ printf("\t\n", fd)
+ printf("\t\n", ffs)
+ printf("\t\n", ffe)
+ printf("\t\n", fg)
+ printf("\t\n", fu)
+ printf("\t\n", ams)
+ printf("\t\n", fs)
+ printf("\t\n", ss)
+ printf("\t\n", ts)
+ printf("\t\n", @count(core_switches))
+
+ print("\n")
+
+ #--- LIFETIME OF FUTURE ---
+ print("\n")
+ foreach(fut in list_future_lifetime) {
+ print("\t\n")
+ printf("\t\t%s\n", fut)
+ printf("\t\t%d\n", list_future_lifetime[fut])
+ print("\t\n")
+ }
+ print("\n")
+
+ #Future blocking:
+ print("\n") #This has a closure further down
+
+ #--- LIFETIME OF A FUTURE BLOCK ---
+ foreach([fut, act] in list_future_block_lifetime) {
+ print("\t\n")
+
+ print("\t\t\n")
+ printf("\t\t\t%s\n", fut)
+ print("\t\t\n")
+
+ print("\t\t\n")
+ printf("\t\t\t%s\n", act)
+ print("\t\t\n")
+
+ printf("\t\t%d\n", list_future_block_lifetime[fut, act])
+ print("\t\n")
+
+ }
+
+ #--- WHAT FUTURE BLOCKED WHAT ACTOR ---
+ foreach([fut, act] in future_block_actor) {
+ print("\t\n")
+
+ print("\t\t\n")
+ printf("\t\t\t%s\n", fut)
+ print("\t\t\n")
+
+ print("\t\t\n")
+ printf("\t\t\t%s\n", act)
+ print("\t\t\n")
+
+ printf("\t\t%d\n", @count(future_block_actor[fut, act]))
+ print("\t\n")
+
+
+ }
+
+ #--- NUMBER OF TIMES A FUTURE BLOCKS ---
+ foreach(fut in future_block_count) {
+
+ print("\t\n")
+ print("\t\t\n")
+ printf("\t\t\t%s\n", fut)
+ print("\t\t\n")
+
+ printf("\t\t%d\n", @count(future_block_count[fut]))
+ print("\t\n")
+ }
+
+ #--- NUMBER OF TIMES AN ACTOR IS BLOCKED ---
+ foreach(act in actor_block_count) {
+ print("\t\n")
+
+ print("\t\t\n")
+ printf("\t\t\t%s\n", act)
+ print("\t\t\n")
+
+ printf("\t\t%d\n", @count(actor_block_count[act]))
+ print("\t\n")
+ }
+ print("\n") #Here is its closure
+
+ #---NUMBER OF TIMES ACTOR CALLS GET ON FUTURE---
+ print("\n")
+ foreach ([act, fut] in actor_get_future) {
+ print("\t\n")
+
+ print("\t\t\n")
+ printf("\t\t\t%s\n", act)
+ print("\t\t\n")
+
+ print("\t\t\n")
+ printf("\t\t\t%s\n", fut)
+ print("\t\t\n")
+
+ printf("\t\t%d\n", @count(actor_get_future[act, fut]))
+
+ print("\t\n")
+
+ }
+ print("\n")
+
+ #--- WHAT FUTURES CHAINES AT WHAT ACTOR ---
+ print("\n")
+ foreach([fut] in chained_actor_future_list) {
+
+ print("\t\n")
+
+ print("\t\t\n")
+ printf("\t\t\t%s\n", fut)
+ print("\t\t\n")
+
+ printf("\t\t%d\n", @count(chained_actor_future_list[fut]))
+
+ print("\t\n")
+
+ }
+ print("\n")
+
+
+
+ #---SUCCESSFUL STEALS---
+ print("\n")
+ foreach(ssid in steal_success_count) {
+ print("\t\n")
+
+ print("\t\t\n")
+ printf("\t\t\t%s\n", ssid)
+ print("\t\t\n")
+
+ printf("\t\t%d\n", @count(steal_success_count[ssid]))
+
+ print("\t\n")
+ }
+ print("\n")
+
+ #---STEALS BETWEEN SCHEDULERS---
+ print("\n")
+ foreach([steal, victim] in successful_steal_from_scheduler) {
+ print("\t\n")
+
+ print("\t\t\n")
+ printf("\t\t\t%s\n", steal)
+ print("\t\t\n")
+
+ printf("\t\t%s\n", victim)
+
+ printf("\t\t%d\n", @count(successful_steal_from_scheduler[steal, victim]))
+
+ print("\t\n")
+
+ }
+ print("\n")
+
+ #---FAILED STEALS---
+ print("\n")
+ foreach(fsid in failed_steals_count) {
+ print("\t\n")
+
+ print("\t\t\n")
+ printf("\t\t\t%s\n", fsid)
+ print("\t\t\n")
+
+ printf("\t\t%d\n", @count(failed_steals_count[fsid]))
+
+ print("\t\n")
+ }
+ print("\n")
+
+
+
+ #---FAILS BETWEEN SCHEDULERS---
+ print("\n")
+ foreach([steal, victim] in scheduler_from_scheduler_fail) {
+ print("\t\n")
+
+ print("\t\t\n")
+ printf("\t\t\t%s\n", steal)
+ print("\t\t\n")
+
+ printf("\t\t%s\n", victim)
+
+ printf("\t\t%d\n", @count(scheduler_from_scheduler_fail[steal, victim]))
+
+ print("\t\n")
+ }
+ print("\n")
+
+ #---STOLEN ACTORS---
+ print("\n")
+ foreach(act in stolen_actor) {
+ print("\t\n")
+ printf("\t\t%s\n", act)
+ printf("\t\t%d\n", @count(stolen_actor[act]))
+ print("\t\n")
+ }
+ print("\n")
+
+ print("\n")
+}
diff --git a/src/runtime/future/future.c b/src/runtime/future/future.c
index 597aa9bac..9ad07753b 100644
--- a/src/runtime/future/future.c
+++ b/src/runtime/future/future.c
@@ -369,7 +369,7 @@ void future_register_callback(pony_ctx_t **ctx,
future_t *fut,
closure_t *c)
{
- ENC_DTRACE2(FUTURE_REGISTER_CALLBACK, (uintptr_t) *ctx, (uintptr_t) fut);
+// ENC_DTRACE2(FUTURE_REGISTER_CALLBACK, (uintptr_t) *ctx, (uintptr_t) fut);
perr("future_chain_actor");
BLOCK;
diff --git a/src/tests/encore/io/FileTest.tmp b/src/tests/encore/io/FileTest.tmp
new file mode 100644
index 000000000..f28b39131
--- /dev/null
+++ b/src/tests/encore/io/FileTest.tmp
@@ -0,0 +1,2 @@
+Hello World!
+Hello World!
diff --git a/src/tests/stress/savina/21.ParallelQuickSort/Main b/src/tests/stress/savina/21.ParallelQuickSort/Main
new file mode 100755
index 000000000..2b6abe1d2
Binary files /dev/null and b/src/tests/stress/savina/21.ParallelQuickSort/Main differ
diff --git a/src/tests/stress/savina/21.ParallelQuickSort/Main.enc b/src/tests/stress/savina/21.ParallelQuickSort/Main.enc
index 639f0c70f..b49db60fd 100644
--- a/src/tests/stress/savina/21.ParallelQuickSort/Main.enc
+++ b/src/tests/stress/savina/21.ParallelQuickSort/Main.enc
@@ -1,12 +1,16 @@
import Random
import ArrayList
+
typedef Position = int
+
fun left() : Position
-(1)
end
+
fun right() : Position
1
end
+
fun initial() : Position
0
end
@@ -84,18 +88,21 @@ end
fun randomInitialArray(n : int, s : int, m : int) : ArrayList[int]
var result = new ArrayList[int](n)
val r = new Random(s)
- for i <- [0..n - 1] do
- result.add(r.random(m))
+ for i <- [0..size - 1] do
+ result.add(r.random(maxVal))
end
consume result
end
-fun printArray(s : String, a : borrowed ArrayList[int]) : unit
- if a.size() > 0 then
- var result = string_from_int(a.at(0))
+
+fun printArray(s : String, list : borrowed ArrayList[int]) : unit
+ var n = list.size()
+
+ if n > 0 then
+ var result = string_from_int(list.at(0))
var i = 1
- while i < a.size() do
+ while i < n do
result = result.concatenate(", ")
- result = result.concatenate(string_from_int(a.at(i)))
+ result = result.concatenate(string_from_int(list.at(i)))
i = i + 1
end
print("{}: {} \n", s, result)
@@ -103,16 +110,17 @@ fun printArray(s : String, a : borrowed ArrayList[int]) : unit
end
active class QuickSortActor : Id
- var t : int
+ var seqThreshold : int
var parent : QuickSortActor
var result : ArrayList[int]
var numFragments : int
- var myPosition : Position
- def init(parent : QuickSortActor, pos : Position, t : int, n : int) : unit
- this.t = t
+ var myPosition : Position -- The position from the perspective of the parent, left or right part of original list
+
+ def init(parent : QuickSortActor, pos : Position, seqThreshold : int, n : int) : unit
+ this.seqThreshold = seqThreshold
this.parent = parent
this.result = new ArrayList[int](n)
- this.numFragments = 0
+ this.numFragments = 0 -- Number of completed fragments, done when 3
this.myPosition = pos
end
def done(var arr : ArrayList[int], position : Position) : unit
@@ -131,6 +139,7 @@ active class QuickSortActor : Id
end
end
end
+
def notify() : unit
if this.parent != null then
this.parent!done(consume this.result, this.myPosition)
@@ -160,6 +169,7 @@ active class QuickSortActor : Id
end
end
end
+
active class Main
def argToInt(str : String) : int
match str.to_int() with
@@ -172,14 +182,15 @@ active class Main
end
end
+
def main(args : [String]) : unit
let
- n = 100 --1000000
- m = 1152921504606846976 -- 2^60
- t = 2048
- s = 1024
+ numberOfElements = 1000000
+ maxValue = 1152921504606846976 -- 2^60
+ seqThreshold = 2048
+ randomSeed = 1024
in
- (new QuickSortActor(null, initial(), t, n))!sort(randomInitialArray(n, s, m))
+ (new QuickSortActor(null, initial(), seqThreshold, numberOfElements))!sort(randomInitialArray(numberOfElements, randomSeed, maxValue))
println("Done!")
end
end
diff --git a/src/tests/stress/savina/21.ParallelQuickSort/Makefile b/src/tests/stress/savina/21.ParallelQuickSort/Makefile
new file mode 100644
index 000000000..4db58b1e1
--- /dev/null
+++ b/src/tests/stress/savina/21.ParallelQuickSort/Makefile
@@ -0,0 +1,20 @@
+SOURCE=Main
+SCRIPT=trace.d
+
+build:
+ encorec $(SOURCE).enc
+
+compile:
+ cd $(SOURCE)_src && make && mv $(SOURCE) ../
+
+run:
+ sudo dtrace -s $(SCRIPT) -c ./$(SOURCE)
+
+clean:
+ rm $(SOURCE)
+
+list:
+ @sudo dtrace -l -P "pony*" -P "encore*" -c ./$(SOURCE)
+
+gen:
+ ./probes.sh $(SOURCE)
diff --git a/src/tests/stress/savina/21.ParallelQuickSort/trace.d b/src/tests/stress/savina/21.ParallelQuickSort/trace.d
new file mode 100644
index 000000000..81a8fc326
--- /dev/null
+++ b/src/tests/stress/savina/21.ParallelQuickSort/trace.d
@@ -0,0 +1,28 @@
+BEGIN
+{
+ successful_steals = 0;
+ unsuccessful_steals = 0;
+ actors = 0;
+}
+
+pony$target:::actor-alloc
+{
+ actors++;
+}
+pony$target:::work-steal-successful
+{
+ printf("%d stole from %d", arg1, arg2);
+ successful_steals++;
+}
+
+pony$target:::work-steal-failure
+{
+ unsuccessful_steals++;
+}
+
+END
+{
+ printf("\nSuccessful steals: %d\n", successful_steals);
+ printf("Failed steals: %d\n", unsuccessful_steals);
+ printf("Actors created: %d\n", actors);
+}
\ No newline at end of file
diff --git a/src/tests/stress/savina/3.Counting/Count b/src/tests/stress/savina/3.Counting/Count
new file mode 100755
index 000000000..0893ef8be
Binary files /dev/null and b/src/tests/stress/savina/3.Counting/Count differ
diff --git a/src/tests/stress/savina/3.Counting/Count.enc b/src/tests/stress/savina/3.Counting/Count.enc
index b530b89b1..fb0d94553 100644
--- a/src/tests/stress/savina/3.Counting/Count.enc
+++ b/src/tests/stress/savina/3.Counting/Count.enc
@@ -1,38 +1,48 @@
active class Counter
var count : int
+
def init() : unit
this.count = 0
end
+
def increment() : unit
this.count = this.count + 1
end
- def retrieve(p : Producer) : unit
+
+ def query(p : Producer) : unit
p!resultMessage(this.count)
end
end
+
+
active class Producer
var counter : Counter
var iterations : int
+
def init(counter : Counter, iterations : int) : unit
this.counter = counter
this.iterations = iterations
end
+
def increment(max : int) : unit
var i = 0
while i < max do
this.counter!increment()
i = i + 1
end
- this.counter!retrieve(this)
+ this.counter!query(this)
end
+
def resultMessage(count : int) : unit
if this.iterations != count then
- print("ERROR: expected : {}, found: {}", this.iterations, count)
+ print("ERROR: expected : {}, found: {}\n", this.iterations, count)
else
- print("SUCCESS! received: {}", count)
+ print("SUCCESS! received: {}\n", count)
end
end
+
end
+
active class Main
def main(args : [String]) : unit
if |args| != 2 then
diff --git a/src/tests/stress/savina/6.Fib/fib.enc b/src/tests/stress/savina/6.Fib/fib.enc
index 67cad8f36..7473e5dca 100644
--- a/src/tests/stress/savina/6.Fib/fib.enc
+++ b/src/tests/stress/savina/6.Fib/fib.enc
@@ -1,20 +1,26 @@
import Std
+-- Trait used by the Request and Response classes.
+-- Allows for simple message passing
linear trait Action
require var msg : String
require var number : int
+
def getMsg() : String
this.msg
end
+
def setNumber(n : int) : unit
this.number = n
end
+
def getNumber() : int
this.number
end
end
active class Main
+
def main(args : [String]) : unit
if |args| != 2 then
print("input required: number-th of fibo not specified\n")
@@ -27,52 +33,60 @@ active class Main
case Nothing =>
0
end
-
end
in
let
- fjRunner = new FibonacciActor(Nothing)
+ handler = new FibonacciActor(Nothing)
in
- fjRunner!process(new Request(N))
+ handler!process(new Request(N))
end
end
end
end
end
+--
linear class Request : Action
- var msg : String
- var number : int
+ var msg : String -- String identifying the actor as a Request
+ var number : int -- The degree of the Fibonacci number to be computed
+
def init(n : int) : unit
this.msg = "Request"
this.number = n
end
+
def request(n : int) : unit
this.number = n
end
end
linear class Response : Action
- var msg : String
- var number : int
+ var msg : String -- String identifying the actor as a Response
+ var number : int -- The computed Fibonacci number to be returned
+
def init(value : int) : unit
this.msg = "Response"
this.number = value
end
+
def response_one() : unit
this.number = 1
end
end
+--
active class FibonacciActor
var result : int
var respReceived : int
var parent : Maybe[FibonacciActor]
+
def init(parent : Maybe[FibonacciActor]) : unit
this.result = 0
this.respReceived = 0
this.parent = parent
end
+
+ -- Method processing either requests from parents or responses from children
def process(msg : Action) : unit
match msg.getMsg() with
case "Request" =>
@@ -89,6 +103,7 @@ active class FibonacciActor
end
()
end
+
case "Response" =>
this.respReceived = this.respReceived + 1
this.result = this.result + msg.getNumber()
@@ -99,10 +114,12 @@ active class FibonacciActor
end
end
+
+ -- Sends result back to parent or in the case of the root FibonacciActor prints the result
def processResult(var response : Response) : unit
match this.parent with
case Just(p) => { p!process(consume response); (); }
- case Nothing => print(" Result = {}\n", this.result)
+ case Nothing => print("Result = {}\n", this.result)
end
end
end