@@ -12,6 +12,7 @@ var mod_extsprintf = require('extsprintf');
1212var mod_color = require ( 'color' ) ;
1313var mod_dashdash = require ( 'dashdash' ) ;
1414var mod_concatjson = require ( 'concatjson' ) ;
15+ var mod_statemap = require ( '../build/Release/statemap' ) ;
1516
1617var fatal = function ( )
1718{
@@ -47,15 +48,7 @@ var out = function ()
4748
4849var rectWidth = function ( map , index , config )
4950{
50- var etime ;
51-
52- if ( index + 1 < map . length ) {
53- etime = map [ index + 1 ] . time ;
54- } else {
55- etime = config . begin + config . timeWidth ;
56- }
57-
58- return ( ( ( etime - map [ index ] . time ) / config . timeWidth ) *
51+ return ( ( map [ index ] . duration / config . timeWidth ) *
5952 config . pixelWidth ) ;
6053} ;
6154
@@ -104,16 +97,26 @@ var outputMap = function (map, config)
10497 for ( i = 0 ; i < map . length ; i ++ ) {
10598 var w = rectWidth ( map , i , config ) ;
10699 var datum = map [ i ] ;
107- var state = datum . state ;
108- var x , color , idx ;
100+ var state = - 1 ;
101+ var x , color , idx , j ;
109102
110103 if ( w === 0 )
111104 continue ;
112105
113106 x = ( ( ( datum . time - config . begin ) /
114107 config . timeWidth ) * config . pixelWidth ) ;
115108
116- if ( ! config . coalesce || w >= config . coalesceThreshold ) {
109+ for ( j = 0 ; j < datum . states . length ; j ++ ) {
110+ if ( datum . states [ j ] != 0 ) {
111+ if ( state != - 1 )
112+ break ;
113+ state = j ;
114+ }
115+ }
116+
117+ if ( j == datum . states . length ) {
118+ mod_assert ( state != - 1 ) ;
119+
117120 idx = data . length ;
118121
119122 data . push ( {
@@ -130,41 +133,11 @@ var outputMap = function (map, config)
130133 continue ;
131134 }
132135
133- /*
134- * If our width is less than our coalesce threshold, search
135- * forward in states until we reach the threshold.
136- */
137- var widths = { } ;
138-
139- widths [ state ] = w ;
140-
141- while ( w < config . coalesceThreshold && i + 1 < map . length ) {
142- var nextw = rectWidth ( map , i + 1 , config ) ;
143-
144- if ( nextw > config . coalesceThreshold )
145- break ;
146-
147- /*
148- * Our next width is also less than our coalesce
149- * threshold. Add to our total width, increase i,
150- * and keep track of how much time we are in which
151- * state.
152- */
153- w += nextw ;
154-
155- if ( ! widths [ map [ i + 1 ] . state ] )
156- widths [ map [ i + 1 ] . state ] = 0 ;
157-
158- widths [ map [ i + 1 ] . state ] += nextw ;
159- config . coalesced ++ ;
160- i ++ ;
161- }
162-
163136 var max = state ;
164137
165- for ( state in widths ) {
166- if ( widths [ state ] > widths [ max ] )
167- max = state ;
138+ for ( j = 0 ; j < datum . states . length ; j ++ ) {
139+ if ( datum . states [ j ] > datum . states [ state ] )
140+ max = j ;
168141 }
169142
170143 color = config . states [ max ] . color ;
@@ -174,14 +147,18 @@ var outputMap = function (map, config)
174147 s : { }
175148 } ;
176149
177- for ( state in widths ) {
178- d . s [ state ] = widths [ state ] / w ;
150+ for ( j = 0 ; j < datum . states . length ; j ++ ) {
151+ var ratio = 0 ;
179152
180- if ( state == max )
153+ if ( datum . states [ j ] ) {
154+ ratio = datum . states [ j ] / datum . duration ;
155+ d . s [ j ] = Math . round ( ratio * 1000 ) / 1000 ;
156+ }
157+
158+ if ( j == max )
181159 continue ;
182160
183- color = color . mix ( config . states [ state ] . color ,
184- widths [ state ] / w ) ;
161+ color = color . mix ( config . states [ j ] . color , ratio ) ;
185162 }
186163
187164 idx = data . length ;
@@ -389,19 +366,25 @@ var filteredDatum = function (config, datum)
389366
390367var statemap = function ( config , input )
391368{
392- var maps = { } , events = { } , states = { } ;
393- var latest , data , datum ;
369+ var maps = { } , states = { } ;
370+ var latest = undefined , data , datum ;
394371 var state , value ;
395372 var i , j ;
396- var what ;
373+ var sortby = 0 ;
397374
398375 if ( ! config . hasOwnProperty ( 'begin' ) )
399376 config . begin = 0 ;
400377
401378 if ( ! config . hasOwnProperty ( 'end' ) )
402379 config . end = 0 ;
403380
404- var sortby = 'on-cpu' ;
381+ if ( ! config . sortby )
382+ config . sortby = 'on-cpu' ;
383+
384+ for ( i = 0 ; i < input . states . length ; i ++ ) {
385+ if ( input . states [ i ] . name == config . sortby )
386+ sortby = i ;
387+ }
405388
406389 check ( input , 'data' ) ;
407390 check ( input , 'states' ) ;
@@ -448,25 +431,6 @@ var statemap = function (config, input)
448431 for ( i = 0 ; i < data . length ; i ++ ) {
449432 datum = data [ i ] ;
450433
451- /*
452- * We permit entirely empty datum objects.
453- */
454- if ( Object . keys ( datum ) . length === 0 )
455- continue ;
456-
457- if ( ! isDatum ( datum ) ) {
458- var msg = [ ] ;
459-
460- if ( ! datum . entity )
461- msg . push ( 'missing "entity" field' ) ;
462-
463- if ( ! datum . time )
464- msg . push ( 'missing "time" field' ) ;
465-
466- fatal ( 'input.data[%d] is invalid: %s' ,
467- i , msg . join ( ', ' ) ) ;
468- }
469-
470434 if ( ! config . entities [ datum . entity ] )
471435 config . entities [ datum . entity ] = { } ;
472436
@@ -476,57 +440,29 @@ var statemap = function (config, input)
476440 continue ;
477441 }
478442
479- if ( filteredDatum ( config , datum ) )
480- continue ;
481-
482- latest = datum ;
483-
484- if ( datum . event ) {
485- what = events ;
486- } else if ( datum . hasOwnProperty ( 'state' ) ) {
487- what = maps ;
488-
489- if ( ! states [ datum . state ] ) {
490- fatal ( 'input.data[%d] has unknown state %s' ,
491- i , datum . state ) ;
492- }
443+ if ( ! maps [ datum . entity ] ) {
444+ maps [ datum . entity ] = [ datum ] ;
493445 } else {
494- fatal ( 'input.data[%d] is neither an event nor a ' +
495- 'state transition' , i ) ;
446+ maps [ datum . entity ] . push ( datum ) ;
496447 }
497448
498- if ( ! what [ datum . entity ] ) {
499- what [ datum . entity ] = [ datum ] ;
500- } else {
501- what [ datum . entity ] . push ( datum ) ;
449+ if ( ! latest || datum . time + datum . duration >
450+ latest . time + latest . duration ) {
451+ latest = datum ;
502452 }
503453 }
504454
505- var timeWidth = latest . time - config . begin ;
455+ var timeWidth = ( latest . time + latest . duration ) - config . begin ;
506456
507457 var keys = Object . keys ( maps ) ;
508458 var weight = { } ;
509- var all = undefined ;
510-
511- if ( config . autocoalesceTarget )
512- all = [ ] ;
513459
514460 for ( i = 0 ; i < keys . length ; i ++ ) {
515461 var key = keys [ i ] ;
516462 weight [ key ] = 0 ;
517463
518- for ( j = 0 ; j < maps [ key ] . length ; j ++ ) {
519- var etime = j < maps [ key ] . length - 1 ?
520- maps [ key ] [ j + 1 ] . time : timeWidth + config . begin ;
521-
522- datum = maps [ key ] [ j ] ;
523-
524- if ( states [ datum . state ] . name == sortby )
525- weight [ key ] += etime - datum . time ;
526-
527- if ( all )
528- all . push ( etime - datum . time ) ;
529- }
464+ for ( j = 0 ; j < maps [ key ] . length ; j ++ )
465+ weight [ key ] += maps [ key ] [ j ] . states [ sortby ] ;
530466 }
531467
532468 keys . sort ( function ( lhs , rhs ) {
@@ -560,30 +496,6 @@ var statemap = function (config, input)
560496 config . lmargin = lmargin ;
561497 config . tmargin = tmargin ;
562498
563- if ( all && all . length > config . autocoalesceTarget ) {
564- var targ = config . autocoalesceTarget ;
565- var thresh ;
566-
567- all . sort ( function ( lhs , rhs ) {
568- if ( lhs < rhs )
569- return ( 1 ) ;
570-
571- if ( lhs > rhs )
572- return ( - 1 ) ;
573-
574- return ( 0 ) ;
575- } ) ;
576-
577- thresh = ( all [ targ ] / config . timeWidth ) * config . pixelWidth ;
578-
579- if ( thresh < 1.0 )
580- thresh = 1.0 ;
581-
582- config . coalesceThreshold = thresh ;
583- config . coalesce = true ;
584- }
585-
586- config . coalesced = 0 ;
587499 loadLibs ( config ) ;
588500
589501 out ( '<svg x="%dpx" y="%dpx" width="%dpx" height="%dpx">\n' ,
@@ -674,16 +586,14 @@ var parseOffset = function (option, optstr, arg)
674586
675587var main = function ( )
676588{
677- var file , input , stream ;
589+ var file , stream ;
678590
679591 var config = {
680592 begin : 0 ,
681593 end : 0 ,
682594 stripHeight : 10 ,
683595 stripWidth : 1000 ,
684- libs : [ 'statemap-svg.js' ] ,
685- coalesce : false ,
686- autocoalesceTarget : 50000
596+ libs : [ 'statemap-svg.js' ]
687597 } ;
688598
689599 var opts = [ {
@@ -757,13 +667,12 @@ var main = function ()
757667 fatal ( 'must specify a data file' ) ;
758668
759669 if ( opts . coalesce )
760- config . autocoalesceTarget = opts . coalesce ;
670+ config . maxrect = opts . coalesce ;
761671
762672 if ( opts . stripHeight )
763673 config . stripHeight = Math . floor ( opts . stripHeight ) ;
764674
765675 file = opts . _args [ 0 ] ;
766- input = { } ;
767676
768677 stream = mod_fs . createReadStream ( file ) . pipe ( mod_concatjson . parse ( ) ) ;
769678
@@ -772,29 +681,17 @@ var main = function ()
772681 } ) ;
773682
774683 stream . on ( 'data' , function ( obj ) {
775- var f ;
684+ if ( isDatum ( obj ) )
685+ fatal ( 'expected metadata as first payload' ) ;
776686
777- if ( isDatum ( obj ) ) {
778- if ( filteredDatum ( config , obj ) )
779- return ;
687+ obj . data = [ ] ;
780688
781- if ( ! input . data )
782- input . data = [ ] ;
783-
784- input . data . push ( obj ) ;
785- return ;
786- }
787-
788- for ( f in obj ) {
789- if ( input . hasOwnProperty ( f ) )
790- fatal ( 'input contains duplicate "%s" field' , f ) ;
791-
792- input [ f ] = obj [ f ] ;
793- }
794- } ) ;
689+ config . coalesced = mod_statemap . ingest ( file , function ( datum ) {
690+ obj . data . push ( datum ) ;
691+ } , config ) ;
795692
796- stream . on ( 'end' , function ( ) {
797- statemap ( config , input ) ;
693+ statemap ( config , obj ) ;
694+ process . exit ( 0 ) ;
798695 } ) ;
799696} ;
800697
0 commit comments