1+ /******************************************************************************
2+ *
3+ * Copyright (c) 2017, the Perspective Authors.
4+ *
5+ * This file is part of the Perspective library, distributed under the terms of
6+ * the Apache License 2.0. The full license can be found in the LICENSE file.
7+ *
8+ */
9+
10+ import perspective from "../../src/js/perspective.node.js" ;
11+ const { performance } = require ( 'perf_hooks' ) ;
12+ const fs = require ( "fs" ) ;
13+ const process = require ( 'process' ) ;
14+ const os = require ( 'os' ) ;
15+
16+ const FACTOR = 4 ;
17+
18+ import { histogram } from "d3-array" ;
19+
20+ String . prototype . hashCode = function ( ) {
21+ var hash = 0 ;
22+ if ( this . length == 0 ) return hash ;
23+ for ( let i = 0 ; i < this . length ; i ++ ) {
24+ let char = this . charCodeAt ( i ) ;
25+ hash = ( ( hash << 5 ) - hash ) + char ;
26+ hash = hash & hash ; // Convert to 32bit integer
27+ }
28+ return "" + hash ;
29+ }
30+
31+ function numberWithCommas ( x ) {
32+ return x . toString ( ) . replace ( / \B (? = ( \d { 3 } ) + (? ! \d ) ) / g, "," ) ;
33+ }
34+
35+ function print ( message , append ) {
36+ console . log ( message ) ;
37+ }
38+
39+
40+ function get_csv ( url , callback ) {
41+ callback ( fs . readFileSync ( url ) . toString ( ) ) ;
42+ }
43+
44+ var __tests__ = [ ] ;
45+ var attempt = 1 ;
46+
47+ function test ( iterations , f ) {
48+ __tests__ . push ( [ iterations , f ] ) ;
49+ }
50+
51+ function run_tests ( ) {
52+ print ( "Performance suite initiated." ) ;
53+ print ( os . platform ( ) + " " + os . release ( ) ) ;
54+ print ( os . cpus ( ) [ 0 ] . model ) ;
55+ print ( __tests__ . length + " scenarios found." ) ;
56+ setTimeout ( _run_tests ) ;
57+ }
58+
59+ const RESULTS = [ ] ;
60+
61+ function stddev ( values ) {
62+ var avg = average ( values ) ;
63+
64+ var squareDiffs = values . map ( function ( value ) {
65+ var diff = value - avg ;
66+ var sqrDiff = diff * diff ;
67+ return sqrDiff ;
68+ } ) ;
69+
70+ var avgSquareDiff = average ( squareDiffs ) ;
71+
72+ var stdDev = Math . sqrt ( avgSquareDiff ) ;
73+ return stdDev ;
74+ }
75+
76+ function average ( data ) {
77+ var sum = data . reduce ( function ( sum , value ) {
78+ return sum + value ;
79+ } , 0 ) ;
80+
81+ var avg = sum / data . length ;
82+ return avg ;
83+ }
84+
85+ function stats ( results ) {
86+ const r_avg = average ( results ) ;
87+ const r_std = stddev ( results ) ;
88+ const old_avg = OLD . data [ RESULTS . length ] . avg ;
89+ const old_std = OLD . data [ RESULTS . length ] . std ;
90+ let r_avg_diff = ( ( r_avg - old_avg ) / r_avg ) * 100 ;
91+ let r_std_diff = ( ( r_std - old_std ) / r_std ) * 100 ;
92+ r_avg_diff = ( r_avg_diff < 0 ? "" : "+" ) + r_avg_diff . toFixed ( 2 ) + "%" ;
93+ r_std_diff = ( r_std_diff < 0 ? "" : "+" ) + r_std_diff . toFixed ( 2 ) + "%" ;
94+ return { r_avg, r_std, r_avg_diff, r_std_diff, old_avg, old_std} ;
95+ }
96+
97+ let HTML = "<html><head><script>window.__RESULTS__=RESULTS1;window.__OLD__=OLD1</script><script>SCRIPT</script></head><body></body></html>" ;
98+
99+ const OLD = JSON . parse ( fs . readFileSync ( 'bench/results/results.json' ) ) ;
100+
101+ function _run_tests ( ) {
102+
103+ if ( __tests__ . length === 0 ) {
104+ print ( "Performance suite complete." ) ;
105+ const data = JSON . stringify ( {
106+ data : RESULTS . map ( y => {
107+ let results = y . results ;
108+ let { r_avg, r_std, r_avg_diff, r_std_diff, old_avg, old_std} = y . stats ;
109+ return {
110+ code : y . code ,
111+ bins : histogram ( ) . thresholds ( 100 ) ( results ) . map ( x => ( [ x . x0 , x . length ] ) ) ,
112+ avg : r_avg ,
113+ std : r_std ,
114+ avg_diff : r_avg_diff ,
115+ std_diff : r_std_diff ,
116+ old_avg : old_avg ,
117+ old_std : old_std
118+ } ;
119+ } ) ,
120+ model : os . cpus ( ) [ 0 ] . model ,
121+ release : os . release ( ) ,
122+ platform : os . platform ( )
123+ } ) ;
124+ fs . writeFileSync ( 'build/report.html' , HTML . replace ( "SCRIPT" , fs . readFileSync ( 'build/report.js' ) ) . replace ( "RESULTS1" , data ) . replace ( "OLD1" , JSON . stringify ( OLD ) ) ) ;
125+ fs . writeFileSync ( 'bench/results/results.json' , data ) ;
126+ return ;
127+ }
128+
129+ var f = __tests__ [ 0 ] ;
130+ let iterations = f [ 0 ] ;
131+ f = f [ 1 ] ;
132+ __tests__ = __tests__ . slice ( 1 ) ;
133+ print ( "Running scenario " + attempt + ( __tests__ . length > 0 ? ( " (" + __tests__ . length + " remaining)." ) : "" ) ) ;
134+ attempt ++ ;
135+
136+ print ( indent ( code ( f ) ) ) ;
137+
138+ var x = 0 ;
139+ var results = [ ] ;
140+ var start_all = performance . now ( ) ;
141+ var testcase = function ( ) {
142+ var start = performance . now ( ) ;
143+ new Promise ( f ) . then ( function ( ) {
144+ results . push ( performance . now ( ) - start ) ;
145+ try {
146+ process . stdout . clearLine ( ) ; // clear current text
147+ process . stdout . cursorTo ( 0 ) ;
148+ process . stdout . write ( x + "/" + iterations , false ) ;
149+ } catch ( e ) {
150+
151+ }
152+ if ( x === iterations ) {
153+ print ( "" ) ;
154+ print ( "" ) ;
155+ print ( "Completed in " + numberWithCommas ( ( performance . now ( ) - start_all ) . toFixed ( 3 ) ) + "ms" , false ) ;
156+ const r_stats = stats ( results ) ;
157+ RESULTS . push ( { results : results , code : code ( f ) , stats : r_stats } ) ;
158+ let { r_avg, r_std, r_avg_diff, r_std_diff, old_avg, old_std} = r_stats ;
159+ print ( `avg: ${ r_avg . toFixed ( 2 ) } (${ old_avg . toFixed ( 2 ) } ) ${ r_avg_diff } ` ) ;
160+ print ( `std: ${ r_std . toFixed ( 2 ) } (${ old_std . toFixed ( 2 ) } ) ${ r_std_diff } ` ) ;
161+ print ( "" ) ;
162+ setTimeout ( _run_tests ) ;
163+ } else {
164+ x ++ ;
165+ setTimeout ( testcase , 10 ) ;
166+ }
167+ } ) ;
168+ }
169+ setTimeout ( testcase ) ;
170+
171+ }
172+
173+ function code ( f ) {
174+ var y = f . toString ( ) . match ( / f u n c t i o n [ ^ { ] + \{ ( [ \s \S ] * ) \} $ / ) [ 1 ] . replace ( / \t / g, ' ' ) ;
175+ var indentation = y . split ( '\n' ) [ 1 ] . match ( / ^ [ \s \t ] * / ) [ 0 ] . length ;
176+ var z = y . split ( '\n' ) . map ( function ( q ) { return q . slice ( indentation , q . length ) ; } ) . join ( '\n' )
177+ return z ;
178+ }
179+
180+ function indent ( txt ) {
181+ return txt . split ( '\n' ) . map ( x => " " + x ) . join ( '\n' ) ;
182+ }
183+
184+
185+ get_csv ( 'build/flight_small.csv' , function ( csv ) {
186+
187+ let table = perspective . table ( csv ) ;
188+
189+ test ( 50 * FACTOR , function ( resolve ) {
190+ perspective . table ( csv ) ;
191+ resolve ( ) ;
192+ } ) ;
193+
194+ test ( 500 * FACTOR , function ( resolve ) {
195+ var view = table . view ( {
196+ filter : [ [ "Origin" , "contains" , "P" ] ] ,
197+ aggregate : "count"
198+ } ) ;
199+ view . delete ( ) ;
200+ resolve ( ) ;
201+ } ) ;
202+
203+ test ( 500 * FACTOR , function ( resolve ) {
204+ var view = table . view ( {
205+ filter : [ [ "Origin" , "contains" , "P" ] ] ,
206+ aggregate : "count"
207+ } )
208+ view . to_json ( {
209+ end_row : 10
210+ } ) . then ( function ( ) {
211+ view . delete ( ) ;
212+ resolve ( ) ;
213+ } ) ;
214+ } ) ;
215+
216+ test ( 500 * FACTOR , function ( resolve ) {
217+ var view = table . view ( {
218+ filter : [ [ "Origin" , "contains" , "P" ] ] ,
219+ row_pivot : [ 'Dest' ] ,
220+ aggregate : "count"
221+ } )
222+ view . to_json ( ) . then ( function ( ) {
223+ view . delete ( ) ;
224+ resolve ( ) ;
225+ } ) ;
226+ } ) ;
227+
228+ test ( 150 * FACTOR , function ( resolve ) {
229+ var view = table . view ( {
230+ filter : [ [ "Origin" , "contains" , "P" ] ] ,
231+ aggregate : "count"
232+ } )
233+ view . to_json ( ) . then ( function ( ) {
234+ view . delete ( ) ;
235+ resolve ( ) ;
236+ } )
237+ } ) ;
238+
239+ test ( 150 * FACTOR , function ( resolve ) {
240+ var view = table . view ( {
241+ row_pivot : [ 'Dest' ] ,
242+ aggregate : "count" ,
243+ row_pivot_depth : 1 ,
244+ } )
245+ view . to_json ( ) . then ( function ( ) {
246+ view . delete ( ) ;
247+ resolve ( ) ;
248+ } ) ;
249+ } ) ;
250+
251+ // test(500, function(resolve) {
252+ // var table2 = table.add_computed([
253+ // {column: "Constant",
254+ // type: "number",
255+ // f: () => 0,
256+ // inputs: [],
257+ // }
258+ // ]);
259+ // table2.delete();
260+ // resolve();
261+ // });
262+
263+ // Arithmetic
264+ // test(500, function(resolve) {
265+ // var table2 = table.add_computed([
266+ // {column: "Speed",
267+ // type: "number",
268+ // f: (airtime, distance) => airtime/distance,
269+ // inputs: ["AirTime", "Distance"],
270+ // }
271+ // ]);
272+ // table2.delete();
273+ // resolve();
274+ // });
275+
276+ // // Generate string
277+ // test(500, function(resolve) {
278+ // var table2 = table.add_computed([
279+ // {column: "Day",
280+ // type: "string",
281+ // f: (x) => {
282+ // let days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat'];
283+ // return days[x-1];
284+ // },
285+ // inputs: ["DayOfWeek"],
286+ // }
287+ // ]);
288+ // table2.delete();
289+ // resolve();
290+ // });
291+
292+ run_tests ( ) ;
293+ } ) ;
294+
295+ //});
0 commit comments