Skip to content

Commit ce00177

Browse files
committed
Update documentation
1 parent fa44b11 commit ce00177

File tree

3 files changed

+79
-19
lines changed

3 files changed

+79
-19
lines changed

docs/ops/doc/WritingYourOwnOpPackage.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,66 @@ class DoubleSizeOp implements Function<double[], Double> {
276276

277277
```
278278

279+
### Defining Op Progress
280+
281+
By adding the `scijava-progress` module, your Op can define and update its progress, providing user value for long-running Ops. To add progress to your Op, you must add the following steps to your Op:
282+
* Before any significant computation, add the line `Progress.defineTotal(long elements)` where `elements` is the number of "discrete packets" of computation.
283+
* At convenient spots within your Op, call `Progress.update()` to denote that one packet of computation has finished.
284+
* **Alternatively**, it may be more convenient or performant to call `Progress.update(long numElements)` to denote `numElements` packets have completed at once.
285+
286+
```java
287+
/**
288+
* A simple summer
289+
*
290+
* @implNote op names="stats.sum"
291+
*/
292+
class DoubleSumOp implements Function<double[], Double> {
293+
public Double apply(final double[] inArray) {
294+
Progress.defineTotal(inArray.length);
295+
double sum = 0;
296+
for (double v : inArray) {
297+
sum += v;
298+
Progress.update();
299+
}
300+
return i;
301+
}
302+
}
303+
```
304+
305+
If your Op defines Op dependencies whose progress you'd like to include in your total progress, you can make the following changes.
306+
* For each Op dependency that you want to track, pass the Hint `"progress.TRACK"` within the `@OpDependency` annotation.
307+
* Replace `Progress.defineTotal(long elements)` with `Progress.defineTotal(long elements, long subTasks)`, where `subTasks` is the **total** number of times you will invoke Op dependencies annotated with `"progress.TRACK"`.
308+
309+
310+
```java
311+
312+
import org.scijava.ops.spi.OpDependency;
313+
314+
/**
315+
* A simple mean calculator
316+
*
317+
* @implNote op names="stats.mean"
318+
*/
319+
class DoubleMeanOp implements Function<double[], Double> {
320+
321+
// This Op will contribute to progress
322+
@OpDependency(name="stats.sum", hints={"progress.TRACK"})
323+
public Function<double[], Double> sumOp;
324+
325+
// This Op will also contribute to progress
326+
@OpDependency(name="stats.size", hints={"progress.TRACK"})
327+
public Function<double[], Double> sizeOp;
328+
329+
public Double apply(final double[] inArray) {
330+
// There's no significant work here, but we do have 2 subtasks.
331+
Progress.defineTotal(0, 2);
332+
final Double sum = sumOp.apply(inArray);
333+
final Double size = sizeOp.apply(inArray);
334+
return sum / size;
335+
}
336+
}
337+
```
338+
279339
### Element-wise Ops
280340

281341
Simple pixel-wise operations like addition, inversion, and more can be written on a single pixel (i.e. `RealType`) - therefore, SciJava Ops Image takes care to automagically adapt pixel-wise Ops across a wide variety of image types. If you would like to write a pixel-wise Op, we recommend the following structure.

scijava-ops-tutorial/src/main/java/org/scijava/ops/tutorial/ReportingProgress.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.List;
3434
import java.util.function.Function;
3535

36+
import org.scijava.ops.api.Hints;
3637
import org.scijava.ops.api.OpEnvironment;
3738
import org.scijava.ops.spi.OpCollection;
3839
import org.scijava.ops.spi.OpField;
@@ -56,14 +57,13 @@
5657
* <p>
5758
* Ops tell the {@link Progress} a few things:
5859
* <ol>
59-
* <li>The number of "stages" of computation, including any "subtasks"</li>
60-
* <li>The number of tasks in each stage</li>
61-
* <li>When each task has been completed</li>
60+
* <li>The number of "elements" in a computation, as well as "subtasks", i.e. dependent Ops</li>
61+
* <li>When each "element" has been completed</li>
6262
* </ol>
6363
* <p>
64-
* Note the difference between a "stage" of computation, and a "subtask"
64+
* Note the difference between an "element" of computation, and a "subtask"
6565
* <ul>
66-
* <li><em>stage</em>s are phases of computation done <b>by the Op</b></li>
66+
* <li><em>elements</em>s are pieces of computation done <b>by the Op</b></li>
6767
* <li><em>subtask</em>s are phases of computation done <b>by other Ops</b></li>
6868
* </ul>
6969
* Users are then notified by the progress of Ops by installing
@@ -87,7 +87,7 @@ public class ReportingProgress implements OpCollection {
8787

8888
// Here, we want to update the progress every time we find a new prime.
8989
// We call no Op dependencies, thus the call looks like:
90-
Progress.defineTotal(numPrimes, 0);
90+
Progress.defineTotal(numPrimes);
9191

9292
// Progress is defined within the range [0, 1],
9393
// where 0 denotes an Op that has not yet started.
@@ -118,6 +118,8 @@ public class ReportingProgress implements OpCollection {
118118

119119
public static void main(String... args) {
120120
OpEnvironment ops = OpEnvironment.build();
121+
// To enable Progress Reporting, you must enable the progress tracking hint!
122+
ops.setDefaultHints(new Hints("progress.TRACK"));
121123

122124
// ProgressListeners consume task updates.
123125
// This ProgressListener simply logs to standard output, but we could print

scijava-progress/src/main/java/org/scijava/progress/Progress.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,7 @@
2929

3030
package org.scijava.progress;
3131

32-
import java.util.ArrayDeque;
33-
import java.util.Collections;
34-
import java.util.List;
35-
import java.util.Map;
36-
import java.util.WeakHashMap;
32+
import java.util.*;
3733
import java.util.concurrent.CopyOnWriteArrayList;
3834

3935
/**
@@ -67,13 +63,17 @@ private Progress() {}
6763
private static final Map<Object, List<ProgressListener>> progressibleListeners =
6864
new WeakHashMap<>();
6965

66+
/** Singleton NOP task */
67+
private static final NOPTask IGNORED = new NOPTask();
68+
7069
/**
7170
* A record of the progressible {@link Object}s running on each
7271
* {@link Thread}.
7372
*/
7473
private static final ThreadLocal<ArrayDeque<Task>> progressibleStack =
7574
new InheritableThreadLocal<>()
7675
{
76+
private final Collection<Task> initialContents = Collections.singleton(IGNORED);
7777

7878
@Override
7979
protected ArrayDeque<Task> childValue(ArrayDeque<Task> parentValue) {
@@ -85,7 +85,7 @@ protected ArrayDeque<Task> childValue(ArrayDeque<Task> parentValue) {
8585

8686
@Override
8787
protected ArrayDeque<Task> initialValue() {
88-
return new ArrayDeque<>();
88+
return new ArrayDeque<>(initialContents);
8989
}
9090
};
9191

@@ -178,7 +178,7 @@ public static void register(final Object progressible,
178178
Task t;
179179
var deque = progressibleStack.get();
180180
var parent = deque.peek();
181-
if (parent == null) {
181+
if (parent == null || parent == IGNORED) {
182182
// completely new execution hierarchy
183183
t = new Task(progressible, description);
184184
}
@@ -213,7 +213,7 @@ private static void pingListeners(Task task) {
213213
for (var l : globalListeners)
214214
l.acknowledgeUpdate(task);
215215
// Ping parent
216-
if (task.parent() != null) {
216+
if (task.isSubTask()) {
217217
pingListeners(task.parent());
218218
}
219219
}
@@ -241,11 +241,11 @@ public static void update() {
241241
* Updates the progress of the current {@link Task}, pinging any interested
242242
* {@link ProgressListener}s.
243243
*
244-
* @param numElements the number of elements completed in the current stage.
244+
* @param elements the number of elements completed in the current stage.
245245
* @see Task#update(long)
246246
*/
247-
public static void update(long numElements) {
248-
update(numElements, currentTask());
247+
public static void update(long elements) {
248+
update(elements, currentTask());
249249
}
250250

251251
/**
@@ -336,6 +336,4 @@ public void defineTotal(final long elements, final long subTasks) {
336336

337337
}
338338

339-
private static final NOPTask IGNORED = new NOPTask();
340-
341339
}

0 commit comments

Comments
 (0)