[perf] Update FORMAT docs.

Also update the output from validating a JSON file
to also include the supplied links.

Change-Id: I2953961dc1ad5ca8d82f7a9f9061cbc33b903658
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/540095
Auto-Submit: Joe Gregorio <jcgregorio@google.com>
Commit-Queue: Joe Gregorio <jcgregorio@google.com>
Commit-Queue: Leandro Lovisolo <lovisolo@google.com>
Reviewed-by: Leandro Lovisolo <lovisolo@google.com>
diff --git a/perf/FORMAT.md b/perf/FORMAT.md
index 16373e8..7757903 100644
--- a/perf/FORMAT.md
+++ b/perf/FORMAT.md
@@ -4,38 +4,91 @@
 
 ```
 {
-  "version": 1,
-  "git_hash": "cd5...663",
-  "key": {
-      "config": "8888",
-      "arch": "x86"
-  },
-  "results": [
-      {
-          "key": {
-              "test": "some_test_name"
-          },
-          "measurements": {
-              "ms": [
-                  {
-                      "value": "min",
-                      "measurement": 1.2
-                  },
-                  {
-                      "value": "max",
-                      "measurement": 2.4
-                  },
-                  {
-                      "value": "median",
-                      "measurement": 1.5
-                  }
-              ]
-          }
-      }
-  ]
+    "version": 1,
+    "git_hash": "cd5...663",
+    "key": {
+        "config": "8888",
+        "arch": "x86"
+    },
+    "results": [
+        {
+            "key": {
+                "test": "a_test_with_just_a_single_measurement",
+                "units": "s"
+            },
+            "measurement": 123.4
+        },
+        {
+            "key": {
+                "test": "draw_a_circle",
+                "units": "ms"
+            },
+            "measurements": {
+                "stat": [
+                    {
+                        "value": "min",
+                        "measurement": 1.2
+                    },
+                    {
+                        "value": "max",
+                        "measurement": 2.4
+                    },
+                    {
+                        "value": "median",
+                        "measurement": 1.5
+                    }
+                ]
+            }
+        },
+        {
+            "key": {
+                "test": "draw_my_animation",
+                "units": "Hz"
+            },
+            "measurements": {
+                "stat": [
+                    {
+                        "value": "min",
+                        "measurement": 20
+                    },
+                    {
+                        "value": "max",
+                        "measurement": 30
+                    },
+                    {
+                        "value": "median",
+                        "measurement": 22
+                    }
+                ]
+            }
+        }
+    ],
+    "links": {
+        "details": "https://example.com/a-link-to-details-about-this-test-run"
+    }
 }
 ```
 
+When ingested it will produce the following information:
+
+```
+Hash:
+  cd5...663
+Measurements:
+  ,arch=x86,config=8888,test=a_test_with_just_a_single_measurement,units=s, = 123.4
+  ,arch=x86,config=8888,stat=min,test=draw_a_circle,units=ms, = 1.2
+  ,arch=x86,config=8888,stat=max,test=draw_a_circle,units=ms, = 2.4
+  ,arch=x86,config=8888,stat=median,test=draw_a_circle,units=ms, = 1.5
+  ,arch=x86,config=8888,stat=min,test=draw_my_animation,units=Hz, = 20
+  ,arch=x86,config=8888,stat=max,test=draw_my_animation,units=Hz, = 30
+  ,arch=x86,config=8888,stat=median,test=draw_my_animation,units=Hz, = 22
+Links:
+  details: https://example.com/a-link-to-details-about-this-test-run
+```
+
+You can run the `perf-tool` as described below to parse a file and emit a
+description like the one above.
+
 The format is documented
 [here](https://pkg.go.dev/go.skia.org/infra/perf/go/ingest/format?tab=doc#Format).
 
@@ -83,11 +136,18 @@
 If the format is valid then all the found trace ids and their values
 will be printed out, for example:
 
-    $ perf-tool ingest validate --in=$HOME/valid.json
-    hash: def820637c3674a2bcecd6992a207fa3b9bed737
-    ,arch=arm64,radius=10,test=drawCircle,units=ms, = 1.4800247
-    ,arch=arm64,radius=50,test=drawCircle,units=ms, = 261.58847
-    ,arch=arm64,radius=90,test=drawCircle,units=ms, = 377.3585
+    Hash:
+      cd5...663
+    Measurements:
+      ,arch=x86,config=8888,test=a_test_with_just_a_single_measurement,units=s, = 123.4
+      ,arch=x86,config=8888,stat=min,test=draw_a_circle,units=ms, = 1.2
+      ,arch=x86,config=8888,stat=max,test=draw_a_circle,units=ms, = 2.4
+      ,arch=x86,config=8888,stat=median,test=draw_a_circle,units=ms, = 1.5
+      ,arch=x86,config=8888,stat=min,test=draw_my_animation,units=Hz, = 20
+      ,arch=x86,config=8888,stat=max,test=draw_my_animation,units=Hz, = 30
+      ,arch=x86,config=8888,stat=median,test=draw_my_animation,units=Hz, = 22
+    Links:
+      details: https://example.com/a-link-to-details-about-this-test-run
 
 You can run `perf-tool` over
 [`./go/ingest/parser/testdata/version_1/success.json`](//perf/go/ingest/parser/testdata/version_1/success.json)
diff --git a/perf/go/ingest/format/format.go b/perf/go/ingest/format/format.go
index c076df0..5b3eae0 100644
--- a/perf/go/ingest/format/format.go
+++ b/perf/go/ingest/format/format.go
@@ -95,10 +95,18 @@
 //        "results": [
 //            {
 //                "key": {
-//                    "test": "some_test_name"
+//                    "test": "a_test_with_just_a_single_measurement",
+//                    "units": "s"
+//                },
+//                "measurement": 123.4
+//            },
+//            {
+//                "key": {
+//                    "test": "draw_a_circle",
+//                    "units": "ms"
 //                },
 //                "measurements": {
-//                    "ms": [
+//                    "stat": [
 //                        {
 //                            "value": "min",
 //                            "measurement": 1.2
@@ -113,15 +121,49 @@
 //                        }
 //                    ]
 //                }
+//            },
+//            {
+//                "key": {
+//                    "test": "draw_my_animation",
+//                    "units": "Hz"
+//                },
+//                "measurements": {
+//                    "stat": [
+//                        {
+//                            "value": "min",
+//                            "measurement": 20
+//                        },
+//                        {
+//                            "value": "max",
+//                            "measurement": 30
+//                        },
+//                        {
+//                            "value": "median",
+//                            "measurement": 22
+//                        }
+//                    ]
+//                }
 //            }
-//        ]
+//        ],
+//        "links": {
+//            "details": "https://example.com/a-link-to-details-about-this-test-run"
+//        }
 //    }
 //
 // Will produce this set of trace ids and values:
 //
-//    ,arch=x86,config=8888,ms=min,test=some_test_name,      1.2
-//    ,arch=x86,config=8888,ms=max,test=some_test_name,      2.4
-//    ,arch=x86,config=8888,ms=median,test=some_test_name,   1.5
+//    Hash:
+//      cd5...663
+//    Measurements:
+//      ,arch=x86,config=8888,test=a_test_with_just_a_single_measurement,units=s, = 123.4
+//      ,arch=x86,config=8888,stat=min,test=draw_a_circle,units=ms, = 1.2
+//      ,arch=x86,config=8888,stat=max,test=draw_a_circle,units=ms, = 2.4
+//      ,arch=x86,config=8888,stat=median,test=draw_a_circle,units=ms, = 1.5
+//      ,arch=x86,config=8888,stat=min,test=draw_my_animation,units=Hz, = 20
+//      ,arch=x86,config=8888,stat=max,test=draw_my_animation,units=Hz, = 30
+//      ,arch=x86,config=8888,stat=median,test=draw_my_animation,units=Hz, = 22
+//    Links:
+//      details: https://example.com/a-link-to-details-about-this-test-run
 //
 // Key value pair charactes should come from [0-9a-zA-Z\_], particularly note no
 // spaces or ':' characters.
diff --git a/perf/go/perf-tool/application/application.go b/perf/go/perf-tool/application/application.go
index 08a2301..8269bf6 100644
--- a/perf/go/perf-tool/application/application.go
+++ b/perf/go/perf-tool/application/application.go
@@ -2,6 +2,7 @@
 
 import (
 	"archive/zip"
+	"bytes"
 	"context"
 	"encoding/gob"
 	"encoding/json"
@@ -757,21 +758,41 @@
 		return nil
 	}
 	return util.WithReadFile(inputFile, func(r io.Reader) error {
+		b, err := ioutil.ReadAll(r)
+		if err != nil {
+			return fmt.Errorf("Read Failed: %s", err)
+		}
+		reader := bytes.NewReader(b)
 		f := file.File{
 			Name:     inputFile,
-			Contents: ioutil.NopCloser(r),
+			Contents: ioutil.NopCloser(reader),
 		}
 		p, v, hash, err := parser.New(nil).Parse(f)
 		if err != nil {
 			return fmt.Errorf("Parse Failed: %s", skerr.Unwrap(err))
 		}
-		fmt.Printf("hash: %s\n", hash)
+		fmt.Printf("Hash:\n  %s\n", hash)
+		fmt.Printf("Measurements:\n")
 		for i, params := range p {
 			key, err := query.MakeKeyFast(query.ForceValid(params))
 			if err != nil {
 				return fmt.Errorf("Could not make a valid key from %v: %s ", params, err)
 			}
-			fmt.Printf("%s = %g\n", key, v[i])
+			fmt.Printf("  %s = %g\n", key, v[i])
+		}
+
+		fmt.Printf("Links:\n")
+		var decoded format.Format
+		if err := json.Unmarshal(b, &decoded); err != nil {
+			return fmt.Errorf("Failed to parse: %s", err)
+		}
+		keys := make([]string, 0, len(decoded.Links))
+		for k := range decoded.Links {
+			keys = append(keys, k)
+		}
+		sort.Strings(keys)
+		for _, key := range keys {
+			fmt.Printf("  %s: %s\n", key, decoded.Links[key])
 		}
 		return nil
 	})