Skip to content

Commit f9faaad

Browse files
committed
TritonDataCenter#18 ingestion could be much faster
1 parent bbeea06 commit f9faaad

File tree

16 files changed

+4433
-162
lines changed

16 files changed

+4433
-162
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#
1414
JSL = ./deps/javascriptlint/build/install/jsl
1515
JSSTYLE = ./deps/jsstyle/jsstyle
16+
CSTYLE = ./tools/cstyle.pl
1617
# md2man-roff can be found at <https://github.com/sunaku/md2man>.
1718
MD2MAN := md2man-roff
1819
NODE = node
@@ -33,6 +34,7 @@ JS_FILES := \
3334

3435
JSL_FILES_NODE = $(JS_FILES)
3536
JSSTYLE_FILES = $(JS_FILES)
37+
CSTYLE_FILES = ./src/statemap.h ./src/statemap.c ./src/avl/avl.c
3638

3739
include Makefile.defs
3840

Makefile.targ

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,13 @@ JSSTYLE_TARGET = $(if $(JSSTYLE_FILES), check-jsstyle)
207207
check-jsstyle: $(JSSTYLE_EXEC)
208208
$(JSSTYLE) $(JSSTYLE_FLAGS) $(JSSTYLE_FILES)
209209

210+
CSTYLE_TARGET = $(if $(CSTYLE_FILES), check-cstyle)
211+
.PHONY: check-cstyle
212+
check-cstyle: $(CSTYLE)
213+
$(CSTYLE) $(CSTYLE_FILES)
214+
210215
.PHONY: check
211-
check:: check-jsl check-json $(JSSTYLE_TARGET) check-bash
216+
check:: check-jsl check-json $(CSTYLE_TARGET) $(JSSTYLE_TARGET) check-bash
212217
@echo check ok
213218

214219
.PHONY: clean

bin/statemap

Lines changed: 57 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ var mod_extsprintf = require('extsprintf');
1212
var mod_color = require('color');
1313
var mod_dashdash = require('dashdash');
1414
var mod_concatjson = require('concatjson');
15+
var mod_statemap = require('../build/Release/statemap');
1516

1617
var fatal = function ()
1718
{
@@ -47,15 +48,7 @@ var out = function ()
4748

4849
var 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

390367
var 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

675587
var 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

binding.gyp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"targets": [ {
3+
"target_name": "statemap",
4+
"sources": [
5+
"./src/glue.cc",
6+
"./src/statemap.c",
7+
"./src/jsmn/jsmn.c",
8+
"./src/avl/avl.c"
9+
]
10+
} ]
11+
}

0 commit comments

Comments
 (0)