cmd/viewcore: allow to limit 'histogram' output

The histogram command now takes an optional flag --top=N.
If a positive N is supplied, only top-N buckets are printed.

This change registers 'histo' as an alias of 'histogram'.

Change-Id: I372fa733ca2544c4bbdb122dc3748edb52e1a08c
Reviewed-on: https://go-review.googlesource.com/128975
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
diff --git a/cmd/viewcore/main.go b/cmd/viewcore/main.go
index 631ffcc..b122b2f 100644
--- a/cmd/viewcore/main.go
+++ b/cmd/viewcore/main.go
@@ -80,10 +80,14 @@
 	}
 
 	cmdHistogram = &cobra.Command{
-		Use:   "histogram",
-		Short: "print histogram of heap memory use by Go type",
-		Args:  cobra.ExactArgs(0),
-		Run:   runHistogram,
+		Use:     "histogram",
+		Aliases: []string{"histo"},
+		Short:   "print histogram of heap memory use by Go type",
+		Long: "print histogram of heap memory use by Go type.\n" +
+			"If N is specified, it will reports only the top N buckets\n" +
+			"based on the total bytes.",
+		Args: cobra.ExactArgs(0),
+		Run:  runHistogram,
 	}
 
 	cmdBreakdown = &cobra.Command{
@@ -148,8 +152,11 @@
 	cmdRoot.PersistentFlags().StringVar(&cfg.exePath, "exe", "", "main executable file")
 	cmdRoot.PersistentFlags().StringVar(&cfg.cpuprof, "prof", "", "write cpu profile of viewcore to this file for viewcore's developers")
 
+	// subcommand flags
 	cmdHTML.Flags().IntP("port", "p", 8080, "port for http server")
 
+	cmdHistogram.Flags().Int("top", 0, "reports only top N entries if N>0")
+
 	cmdRoot.AddCommand(
 		cmdOverview,
 		cmdMappings,
@@ -426,6 +433,10 @@
 }
 
 func runHistogram(cmd *cobra.Command, args []string) {
+	topN, err := cmd.Flags().GetInt("top")
+	if err != nil {
+		exitf("%v\n", err)
+	}
 	_, c, err := readCore()
 	if err != nil {
 		exitf("%v\n", err)
@@ -452,6 +463,12 @@
 	sort.Slice(buckets, func(i, j int) bool {
 		return buckets[i].size*buckets[i].count > buckets[j].size*buckets[j].count
 	})
+
+	// report only top N if requested
+	if topN > 0 && len(buckets) > topN {
+		buckets = buckets[:topN]
+	}
+
 	t := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', tabwriter.AlignRight)
 	fmt.Fprintf(t, "%s\t%s\t%s\t %s\n", "count", "size", "bytes", "type")
 	for _, e := range buckets {