1+ using System ;
2+ using System . IO ;
3+ using System . Reflection ;
4+
5+ using BenchmarkDotNet . Attributes ;
6+ using BenchmarkDotNet . Diagnosers ;
7+ using BenchmarkDotNet . Order ;
8+
9+ namespace MsieJavaScriptEngine . Benchmarks
10+ {
11+ [ MemoryDiagnoser ]
12+ [ Orderer ( SummaryOrderPolicy . Method , MethodOrderPolicy . Declared ) ]
13+ public class JsExecutionBenchmark
14+ {
15+ /// <summary>
16+ /// Name of the file containing library for transliteration of Russian
17+ /// </summary>
18+ private const string LibraryFileName = "russian-translit.js" ;
19+
20+ /// <summary>
21+ /// Name of transliterate function
22+ /// </summary>
23+ private const string FunctionName = "transliterate" ;
24+
25+ /// <summary>
26+ /// Number of transliterated items
27+ /// </summary>
28+ private const int ItemCount = 6 ;
29+
30+ /// <summary>
31+ /// Code of library for transliteration of Russian
32+ /// </summary>
33+ private static string _libraryCode ;
34+
35+ /// <summary>
36+ /// List of transliteration types
37+ /// </summary>
38+ private static string [ ] _inputTypes ;
39+
40+ /// <summary>
41+ /// List of input strings
42+ /// </summary>
43+ private static string [ ] _inputStrings ;
44+
45+ /// <summary>
46+ /// List of target output strings
47+ /// </summary>
48+ private static string [ ] _targetOutputStrings ;
49+
50+
51+ /// <summary>
52+ /// Static constructor
53+ /// </summary>
54+ static JsExecutionBenchmark ( )
55+ {
56+ PopulateTestData ( ) ;
57+ }
58+
59+
60+ /// <summary>
61+ /// Populates a test data
62+ /// </summary>
63+ public static void PopulateTestData ( )
64+ {
65+ Type type = typeof ( JsExecutionBenchmark ) ;
66+ Assembly assembly = type . Assembly ;
67+ string resourceName = type . Namespace + ".Resources." + LibraryFileName ;
68+
69+ using ( Stream stream = assembly . GetManifestResourceStream ( resourceName ) )
70+ using ( StreamReader reader = new StreamReader ( stream ) )
71+ {
72+ _libraryCode = reader . ReadToEnd ( ) ;
73+ }
74+
75+ _inputTypes = new string [ ItemCount ]
76+ {
77+ "basic" , "letters-numbers" , "gost-16876-71" , "gost-7-79-2000" , "police" , "foreign-passport"
78+ } ;
79+ _inputStrings = new string [ ItemCount ]
80+ {
81+ "SOLID — мнемонический акроним, введённый Майклом Фэзерсом для первых пяти принципов, названных " +
82+ "Робертом Мартином в начале 2000-х, которые означали пять основных принципов объектно-ориентированного " +
83+ "программирования и проектирования." ,
84+
85+ "Принцип единственной ответственности (The Single Responsibility Principle). " +
86+ "Каждый класс выполняет лишь одну задачу." ,
87+
88+ "Принцип открытости/закрытости (The Open Closed Principle). " +
89+ "«программные сущности … должны быть открыты для расширения, но закрыты для модификации.»" ,
90+
91+ "Принцип подстановки Барбары Лисков (The Liskov Substitution Principle). " +
92+ "«объекты в программе должны быть заменяемыми на экземпляры их подтипов без изменения правильности выполнения программы.»" ,
93+
94+ "Принцип разделения интерфейса (The Interface Segregation Principle). " +
95+ "«много интерфейсов, специально предназначенных для клиентов, лучше, чем один интерфейс общего назначения.»" ,
96+
97+ "Принцип инверсии зависимостей (The Dependency Inversion Principle). " +
98+ "«Зависимость на Абстракциях. Нет зависимости на что-то конкретное.»"
99+ } ;
100+ _targetOutputStrings = new string [ ItemCount ]
101+ {
102+ "SOLID — mnemonicheskij akronim, vvedjonnyj Majklom Fjezersom dlja pervyh pjati principov, nazvannyh " +
103+ "Robertom Martinom v nachale 2000-h, kotorye oznachali pjat' osnovnyh principov ob#ektno-orientirovannogo " +
104+ "programmirovanija i proektirovanija." ,
105+
106+ "Princip edinstvennoj otvetstvennosti (The Single Responsibility Principle). " +
107+ "Ka#dyj klass vypolnjaet li6' odnu zada4u." ,
108+
109+ "Princip otkrytosti/zakrytosti (The Open Closed Principle). " +
110+ "«programmnye sushhnosti … dolzhny byt' otkryty dlja rasshirenija, no zakryty dlja modifikacii.»" ,
111+
112+ "Princip podstanovki Barbary Liskov (The Liskov Substitution Principle). " +
113+ "«ob\" ekty v programme dolzhny byt' zamenyaemymi na e'kzemplyary ix podtipov bez izmeneniya pravil'nosti " +
114+ "vypolneniya programmy.»" ,
115+
116+ "Printsip razdeleniia interfeisa (The Interface Segregation Principle). " +
117+ "«mnogo interfeisov, spetsialno prednaznachennykh dlia klientov, luchshe, chem odin interfeis obshchego " +
118+ "naznacheniia.»" ,
119+
120+ "Printcip inversii zavisimostei (The Dependency Inversion Principle). " +
121+ "«Zavisimost na Abstraktciiakh. Net zavisimosti na chto-to konkretnoe.»"
122+ } ;
123+ }
124+
125+ /// <summary>
126+ /// Transliterates a strings
127+ /// </summary>
128+ /// <param name="createJsEngine">Delegate for create an instance of the JS engine</param>
129+ /// <param name="withPrecompilation">Flag for whether to allow execution of JS code with pre-compilation</param>
130+ private static void TransliterateStrings ( Func < MsieJsEngine > createJsEngine , bool withPrecompilation )
131+ {
132+ // Arrange
133+ string [ ] outputStrings = new string [ ItemCount ] ;
134+ PrecompiledScript precompiledCode = null ;
135+
136+ // Act
137+ using ( var jsEngine = createJsEngine ( ) )
138+ {
139+ if ( withPrecompilation )
140+ {
141+ if ( ! jsEngine . SupportsScriptPrecompilation )
142+ {
143+ throw new NotSupportedException ( $ "{ jsEngine . Mode } mode does not support precompilation.") ;
144+ }
145+
146+ precompiledCode = jsEngine . Precompile ( _libraryCode , LibraryFileName ) ;
147+ jsEngine . Execute ( precompiledCode ) ;
148+ }
149+ else
150+ {
151+ jsEngine . Execute ( _libraryCode , LibraryFileName ) ;
152+ }
153+
154+ outputStrings [ 0 ] = jsEngine . CallFunction < string > ( FunctionName , _inputStrings [ 0 ] , _inputTypes [ 0 ] ) ;
155+ }
156+
157+ for ( int itemIndex = 1 ; itemIndex < ItemCount ; itemIndex ++ )
158+ {
159+ using ( var jsEngine = createJsEngine ( ) )
160+ {
161+ if ( withPrecompilation )
162+ {
163+ jsEngine . Execute ( precompiledCode ) ;
164+ }
165+ else
166+ {
167+ jsEngine . Execute ( _libraryCode , LibraryFileName ) ;
168+ }
169+ outputStrings [ itemIndex ] = jsEngine . CallFunction < string > ( FunctionName , _inputStrings [ itemIndex ] ,
170+ _inputTypes [ itemIndex ] ) ;
171+ }
172+ }
173+
174+ // Assert
175+ for ( int itemIndex = 1 ; itemIndex < ItemCount ; itemIndex ++ )
176+ {
177+ Assert . Equal ( _targetOutputStrings [ itemIndex ] , outputStrings [ itemIndex ] ) ;
178+ }
179+ }
180+ #if NET46
181+
182+ [ Benchmark ]
183+ public void Classic ( )
184+ {
185+ Func < MsieJsEngine > createJsEngine = ( ) => new MsieJsEngine ( new JsEngineSettings {
186+ EngineMode = JsEngineMode . Classic
187+ } ) ;
188+ TransliterateStrings ( createJsEngine , false ) ;
189+ }
190+
191+ [ Benchmark ]
192+ public void ChakraActiveScript ( )
193+ {
194+ Func < MsieJsEngine > createJsEngine = ( ) => new MsieJsEngine ( new JsEngineSettings
195+ {
196+ EngineMode = JsEngineMode . ChakraActiveScript
197+ } ) ;
198+ TransliterateStrings ( createJsEngine , false ) ;
199+ }
200+ #endif
201+
202+ [ Benchmark ]
203+ [ Arguments ( false ) ]
204+ [ Arguments ( true ) ]
205+ public void ChakraIeJsRt ( bool withPrecompilation )
206+ {
207+ Func < MsieJsEngine > createJsEngine = ( ) => new MsieJsEngine ( new JsEngineSettings
208+ {
209+ EngineMode = JsEngineMode . ChakraIeJsRt
210+ } ) ;
211+ TransliterateStrings ( createJsEngine , withPrecompilation ) ;
212+ }
213+
214+ [ Benchmark ]
215+ [ Arguments ( false ) ]
216+ [ Arguments ( true ) ]
217+ public void ChakraEdgeJsRt ( bool withPrecompilation )
218+ {
219+ Func < MsieJsEngine > createJsEngine = ( ) => new MsieJsEngine ( new JsEngineSettings
220+ {
221+ EngineMode = JsEngineMode . ChakraEdgeJsRt
222+ } ) ;
223+ TransliterateStrings ( createJsEngine , withPrecompilation ) ;
224+ }
225+ }
226+ }
0 commit comments