· 7 years ago · Jan 27, 2018, 04:46 AM
1// benchx264.cs
2// Copyright (C) 2011 David Rudie
3//
4// This program is free software; you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation; either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program; if not, write to the Free Software
16// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
17
18using System;
19using System.Collections.Generic;
20using System.Text;
21using System.Text.RegularExpressions;
22
23namespace BenchX264
24{
25 public class Process
26 {
27 private static int _samples = 0;
28 private static string _program = string.Empty;
29 private static string _arguments = string.Empty;
30
31 public Process(int samples, string program, string arguments)
32 {
33 _samples = samples;
34 _program = program;
35 _arguments = arguments;
36 }
37
38 ~Process()
39 {
40 _samples = 0;
41 _program = string.Empty;
42 _arguments = string.Empty;
43 }
44
45 public double[] Results { get; set; }
46
47 public void Start()
48 {
49 System.Diagnostics.ProcessStartInfo processStartInfo = new System.Diagnostics.ProcessStartInfo(_program);
50 if (!string.IsNullOrEmpty(_arguments))
51 processStartInfo.Arguments = _arguments;
52 processStartInfo.RedirectStandardOutput = true;
53 processStartInfo.RedirectStandardError = true;
54 processStartInfo.UseShellExecute = false;
55
56 List<double> fpsList = new List<double>();
57
58 for (int i = 0; i < _samples; i++)
59 {
60 System.Diagnostics.Process process;
61 process = System.Diagnostics.Process.Start(processStartInfo);
62 System.IO.StreamReader streamStandardError = process.StandardError;
63 process.WaitForExit();
64
65 if (process.HasExited)
66 {
67 string pattern = @"encoded \d+ frames, (.*) fps";
68 string output = streamStandardError.ReadToEnd();
69
70 Regex regex = new Regex(pattern);
71 Match match = regex.Match(output);
72
73 double fps;
74
75 try
76 {
77 fps = Convert.ToDouble(match.Groups[1].Value);
78 }
79 catch
80 {
81 fps = -1.0f;
82 }
83
84 fpsList.Add(fps);
85 Console.WriteLine("Run {0}: {1}", i + 1, fps);
86 }
87 }
88
89 Results = fpsList.ToArray();
90 }
91 }
92
93 public class Math
94 {
95 private static double Sum(params double[] values)
96 {
97 if (values.Length == 0)
98 return 0.0f;
99
100 double result = 0.0f;
101
102 foreach (double value in values)
103 result += value;
104
105 return result;
106 }
107
108 public static double Average(double[] numbers)
109 {
110 return Sum(numbers) / (double)numbers.Length;
111 }
112
113 public static double StandardDeviation(double[] numbers)
114 {
115 double average = Average(numbers);
116
117 double sumsq = 0.0f;
118
119 foreach (double number in numbers)
120 {
121 double sum = System.Math.Pow((number - average), 2);
122 sumsq += sum;
123 }
124
125 return System.Math.Sqrt(sumsq / (double)numbers.Length);
126 }
127
128 public static List<double> QuartilesIQROutliers(double[] numbers)
129 {
130 double quartile1Split = (double)numbers.Length / 4;
131 double quartile2Split = quartile1Split * 2;
132 double quartile3Split = quartile1Split * 3;
133
134 double quartile1 = 0.0f;
135 double quartile2 = 0.0f;
136 double quartile3 = 0.0f;
137
138 // Q1
139 if (System.Math.Floor(quartile1Split) == quartile1Split)
140 quartile1 = (numbers[(int)quartile1Split - 1] + numbers[(int)quartile1Split]) / 2.0f;
141 else
142 quartile1 = numbers[(int)System.Math.Floor(quartile1Split)];
143
144 // Q2
145 if (System.Math.Floor(quartile2Split) == quartile2Split)
146 quartile2 = (numbers[(int)quartile2Split - 1] + numbers[(int)quartile2Split]) / 2.0f;
147 else
148 quartile2 = numbers[(int)System.Math.Floor(quartile2Split)];
149
150 // Q3
151 if (System.Math.Floor(quartile3Split) == quartile3Split)
152 quartile3 = (numbers[(int)quartile3Split - 1] + numbers[(int)quartile3Split]) / 2.0f;
153 else
154 quartile3 = numbers[(int)System.Math.Floor(quartile3Split)];
155
156 double iqr = quartile3 - quartile1;
157
158 // Mild outlier. For a more extreme outlier, use 3.0f.
159 double outlierLow = quartile1 - (1.5f * iqr);
160 double outlierHigh = quartile3 + (1.5f * iqr);
161
162 List<double> sampleList = new List<double>();
163 foreach (double number in numbers)
164 {
165 if (number >= outlierLow && number <= outlierHigh)
166 {
167 sampleList.Add(number);
168 }
169 }
170
171 return sampleList;
172 }
173 }
174
175 public class Program
176 {
177 static void Main(string[] args)
178 {
179 // Determine which OS platform we are on and set the null device accordingly.
180 int p = (int)System.Environment.OSVersion.Platform;
181 string systemNull = string.Empty;
182 string program = string.Empty;
183 if ((p == 4) || (p == 6) || (p == 128))
184 {
185 systemNull = @"/dev/null";
186 program = @"x264";
187 }
188 else
189 {
190 systemNull = @"NUL";
191 program = @"x264.exe";
192 }
193
194 string[] benchmarkTests =
195 {
196 "faster",
197 "medium",
198 "slower",
199 "placebo"
200 };
201 string input = @"SOCCER_352x288_30_orig_02.yuv";
202 int numThreads = -1;
203 string strThreads = string.Empty;
204 int numTest = 0;
205 int numSamples = 20;
206
207 if (args.Length < 4)
208 {
209 Console.WriteLine("{0} [<x264> <input> <threads> <test> <samples>]", System.AppDomain.CurrentDomain.FriendlyName);
210 Console.WriteLine(" x264 = Path to x264 binary");
211 Console.WriteLine(" input = Path to input video to benchmark");
212 Console.WriteLine(" threads = Amount of threads to use (if <= 0, auto is used)");
213 Console.WriteLine(" test = Test to use, 0 = faster, 1 = medium, 2 = slower, 3 = placebo");
214 Console.WriteLine(" samples = Number of samples to take\n");
215 }
216
217 if (args.Length == 5)
218 {
219 program = args[0];
220 input = args[1];
221 numThreads = Convert.ToInt32(args[2]);
222 numTest = Convert.ToInt32(args[3]);
223 numSamples = Convert.ToInt32(args[4]);
224 }
225
226 if (numThreads >= 1)
227 strThreads = string.Format("{0}", numThreads);
228 else
229 strThreads = "auto";
230
231 string argument = string.Format("{0} --threads {1} --preset {2} --quiet --no-progress --crf 25 --output {3}",
232 input,
233 strThreads,
234 benchmarkTests[numTest],
235 systemNull);
236
237 BenchX264.Process process = new BenchX264.Process(numSamples, program, argument);
238 Console.WriteLine("Starting Benchmark,\n Binary: {0}\n Input: {1}\n Threads: {2}\n Test: {3}\n Samples: {4}\n",
239 program, input, strThreads, benchmarkTests[numTest], numSamples);
240 process.Start();
241
242 double[] fpsArray = process.Results;
243 Array.Sort<double>(fpsArray);
244
245 List<double> sampleList = BenchX264.Math.QuartilesIQROutliers(fpsArray);
246 double[] sampleArray = sampleList.ToArray();
247
248 Console.WriteLine("\nSamples Taken: {0}", numSamples);
249 Console.WriteLine("Samples Used: {0}", sampleArray.Length);
250
251 Console.WriteLine("\nLowest FPS: {0}", sampleArray[0]);
252 Console.WriteLine("Highest FPS: {0}", sampleArray[sampleArray.Length - 1]);
253
254 Console.WriteLine("\nAverage FPS: {0}", System.Math.Round(BenchX264.Math.Average(sampleArray), 2));
255 Console.WriteLine("Standard Deviation FPS: {0}", System.Math.Round(BenchX264.Math.StandardDeviation(sampleArray), 2));
256 }
257 }
258}