Support outputting elapsed evaluation time on tasks

Add a debug switch to evaluate task performance. This switch outputs an
elapsed time value on every task indicating how much time it took to
evaluate a task and its subtasks.

Change-Id: I553948b3a269812d34d7c1099110f7f639ed6662
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/Modules.java b/src/main/java/com/googlesource/gerrit/plugins/task/Modules.java
index 05c6849..694206f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/Modules.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/Modules.java
@@ -62,6 +62,9 @@
         usage = "Include only invalid tasks and the tasks referencing them in the output")
     public boolean onlyInvalid = false;
 
+    @Option(name = "--evaluation-time", usage = "Include elapsed evaluation time on each task")
+    boolean evaluationTime = false;
+
     @Option(
         name = "--preview",
         metaVar = "{CHANGE,PATCHSET}",
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java b/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
index 04fc54c..ee40d52 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
@@ -55,6 +55,7 @@
     public String name;
     public Status status;
     public List<TaskAttribute> subTasks;
+    public Long evaluationMilliSeconds;
 
     public TaskAttribute(String name) {
       this.name = name;
@@ -114,6 +115,11 @@
       throws OrmException {
     try {
       Task def = node.definition;
+      TaskAttribute att = new TaskAttribute(def.name);
+      if (options.evaluationTime) {
+        att.evaluationMilliSeconds = millis();
+      }
+
       boolean applicable = match(c, def.applicable);
       if (!def.isVisible) {
         if (!def.isTrusted || (!applicable && !options.onlyApplicable)) {
@@ -123,7 +129,6 @@
       }
 
       if (applicable || !options.onlyApplicable) {
-        TaskAttribute att = new TaskAttribute(def.name);
         att.hasPass = def.pass != null || def.fail != null;
         att.subTasks = getSubTasks(c, node);
         att.status = getStatus(c, def, att);
@@ -142,6 +147,10 @@
             }
             att.hint = getHint(att.status, def);
             att.exported = def.exported;
+
+            if (options.evaluationTime) {
+              att.evaluationMilliSeconds = millis() - att.evaluationMilliSeconds;
+            }
             atts.add(att);
           }
         }
@@ -151,6 +160,10 @@
     }
   }
 
+  protected long millis() {
+    return System.nanoTime() / 1000000;
+  }
+
   protected List<TaskAttribute> getSubTasks(ChangeData c, Node node) throws OrmException {
     List<TaskAttribute> subTasks = new ArrayList<>();
     for (Node subNode : node.getSubNodes()) {
diff --git a/src/main/resources/Documentation/task.md b/src/main/resources/Documentation/task.md
index a642426..62297c5 100644
--- a/src/main/resources/Documentation/task.md
+++ b/src/main/resources/Documentation/task.md
@@ -394,6 +394,12 @@
 not output anything. This switch is particularly useful in combination
 with the **\-\-@PLUGIN@\-\-preview** switch.
 
+**\-\-@PLUGIN@\-\-task\-\-evaluation-time**
+
+This switch is meant as a debug switch to evaluate task performance. This
+switch outputs an elapsed time value on every task indicating how much time
+it took to evaluate a task and its subtasks.
+
 When tasks are appended to changes, they will have a "task" section under
 the plugins section like below: