1 /*
  2  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  Used by DemoSupport.gmk:
 26  
 27  - calculate the geomean and stdev of benchmark runs
 28  - write markdown snippets for rendering benchmark results as a chart on GitHub .MD files
 29 
 30 Example:
 31 
 32 helidon-quickstart-se$ tbjava ../lib/GithubMDChart.java < mainline_vs_premain.csv
 33 run,mainline default,mainline custom static CDS,premain custom static CDS only,premain AOT new workflow
 34 1,398,240,175,116
 35 2,380,239,138,110
 36 3,411,287,144,113
 37 4,399,246,147,112
 38 5,402,245,147,110
 39 6,398,242,142,122
 40 7,383,242,146,111
 41 8,388,260,152,108
 42 9,395,250,149,113
 43 10,380,241,143,132
 44 Geomean,393.28,248.84,148.01,114.51
 45 Stdev,9.78,13.91,9.63,6.86
 46 
 47 ```mermaid
 48 gantt
 49     title Elapsed time (ms)
 50     todayMarker off
 51     dateFormat  X
 52     axisFormat %s
 53 
 54     mainline default   : 0, 393.28
 55     mainline custom static CDS   : 0, 248.84
 56     premain custom static CDS only   : 0, 148.01
 57     premain AOT new workflow   : 0, 114.51
 58 ```
 59 
 60 */
 61 
 62 import java.io.PrintWriter;
 63 import java.util.Scanner;
 64 import java.util.ArrayList;
 65 
 66 public class GithubMDChart {
 67     @SuppressWarnings("unchecked")
 68     public static void main(String args[]) throws Exception {
 69         Scanner input = new Scanner(System.in);
 70         String line = input.nextLine();
 71         //System.out.println(line);
 72         String head[] = line.split(",");
 73         Object[] groups = new Object[head.length];
 74         String[] geomeans = new String[head.length];
 75         for (int i = 0; i < head.length; i++) {
 76             groups[i] = new ArrayList<Double>();
 77         }
 78         while (input.hasNext()) {
 79             line = input.nextLine();
 80             //System.out.println(line);
 81             String parts[] = line.split(",");
 82             for (int i = 0; i < head.length; i++) {
 83                 ArrayList<Double> list =  (ArrayList<Double>)(groups[i]);
 84                 list.add(Double.valueOf(Double.parseDouble(parts[i])));
 85             }
 86         }
 87 
 88         for (int i = 0; i < head.length; i++) {
 89             ArrayList<Double> list =  (ArrayList<Double>)(groups[i]);
 90             if (i == 0) {
 91                 System.out.print("Geomean");
 92             } else {
 93                 System.out.print(",");
 94                 geomeans[i] = geomean(list);
 95                 System.out.print(geomeans[i]);
 96             }
 97         }
 98 
 99         System.out.println();
100 
101         for (int i = 0; i < head.length; i++) {
102             ArrayList<Double> list =  (ArrayList<Double>)(groups[i]);
103             if (i == 0) {
104                 System.out.print("Stdev");
105             } else {
106                 System.out.print(",");
107                 System.out.print(stdev(list));
108             }
109         }
110         System.out.println();
111         System.out.println("Markdown snippets in " + args[0]);
112 
113         PrintWriter pw = new PrintWriter(args[0]);
114         pw.println("```mermaid");
115         pw.println("gantt");
116         pw.println("    title Elapsed time (ms, smaller is better)");
117         pw.println("    todayMarker off");
118         pw.println("    dateFormat  X");
119         pw.println("    axisFormat %s");
120         pw.println();
121 
122         for (int i = 1; i < head.length; i++) {
123             pw.println("    " + head[i] + "   : 0, " + geomeans[i]);
124         }
125         pw.println("```");
126         pw.println();
127         pw.println("-----------------Normalized---------------------------------------------");
128 
129         pw.println("```mermaid");
130         pw.println("gantt");
131         pw.println("    title Elapsed time (normalized, smaller is better)");
132         pw.println("    todayMarker off");
133         pw.println("    dateFormat  X");
134         pw.println("    axisFormat %s");
135         pw.println();
136 
137         for (int i = 1; i < head.length; i++) {
138             double base = Double.parseDouble(geomeans[1]);
139             double me   = Double.parseDouble(geomeans[i]);
140             pw.println("    " + head[i] + "   : 0, " + String.format("%.0f", 1000.0 * me / base));
141         }
142         pw.println("```");
143         pw.close();
144     }
145 
146 
147     static String geomean(ArrayList<Double> list) {
148         double log = 0.0d;
149         for (Double d : list) {
150             double v = d.doubleValue();
151             if (v <= 0) {
152                 v = 0.000001;
153             }
154             log += Math.log(v);
155         }
156 
157 	return String.format("%.2f", Math.exp(log / list.size()));
158     }
159 
160     static String stdev(ArrayList<Double> list) {
161         double sum = 0.0;
162         for (Double d : list) {
163             sum += d.doubleValue();
164         }
165 
166         double length = list.size();
167         double mean = sum / length;
168 
169         double stdev = 0.0;
170         for (Double d : list) {
171             stdev += Math.pow(d.doubleValue() - mean, 2);
172         }
173 
174 	return String.format("%.2f", Math.sqrt(stdev / length));
175     }
176 }