summaryrefslogtreecommitdiffstats
path: root/tools/binary_size/template/test-data-generator.html
blob: 9c6790a8f9e636c652c4120a939129b26e2d19de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
<!DOCTYPE html>
<!--
  Copyright 2014 The Chromium Authors. All rights reserved.
  Use of this source code is governed by a BSD-style license that can be
  found in the LICENSE file.
-->
<html>
<head>
<script>
function rnd(max) {
    return Math.round(Math.random()*max);
}

function gen() {
  var dirs1=['usr1', 'etc1', 'var1'];
  var dirs2=['aaa2', 'bbb2', 'ccc2', 'ddd2', 'eee2', 'fff2', 'ggg2', 'hhh2',
             'frobozz2', 'kazaam2', 'shazam2'];
  var dirs3=['iii3', 'jjj3', 'kkk3', 'lll3', 'mmm3', 'nnn3', 'ooo3', 'ppp3',
             'wonderllama3', 'excelsior3', 'src3'];
  var filenames=['awesome.cc', 'rad.h', 'tubular.cxx', 'cool.cc', 'groovy.h',
                 'excellent.c', 'gnarly.h', 'green.C', 'articulate.cc'];
  //All possible types (we only see a subset in practice): 'ABbCDdGgiNpRrSsTtUuVvWw-?';
  var nm_symbol_types = 'trd';
  var minSize = 4;
  var maxSize = 10000;
  var numGen = 300000;
  var text = 'var nm_data=[\n';
  var vtablePercent = 5;
  for (var x=0; x<numGen; x++) {
    var path = '/' +
        dirs1[rnd(dirs1.length - 1)] + '/' +
        dirs2[rnd(dirs2.length - 1)] + '/' +
        dirs3[rnd(dirs3.length - 1)] + '/' +
        filenames[rnd(filenames.length - 1)];
    var isVtable = Math.floor((Math.random()*100)+1) <= vtablePercent;
    var size = rnd(maxSize);
    var symbol_name;
    var type;
    if (!isVtable) {
      symbol_name = 'sym' + x.toString(16);
      type = nm_symbol_types.charAt(rnd(nm_symbol_types.length - 1));
    } else {
      symbol_name = 'vtable for ' + x.toString(16);
      type = '@'
    }
    text = text + "{'n': '" + symbol_name +
        "', 't': '" + type +
        "', 's': " + size +
        ", 'p': '" + path + "'},\n";
  }
  text += '];';

  eval(text);
  var treeified = to_d3_tree(nm_data);
  generateDownloadLink('tree_data=' + JSON.stringify(treeified));
}

function generateDownloadLink(content) {
  var blob = new Blob([content], {type: 'text/plain'});
  var link = document.createElement('a');
  link.download = 'generated-content.txt';
  link.href = window.URL.createObjectURL(blob);
  link.textContent = 'Download ready, click here.';
  link.dataset.downloadurl = ['text/plain', link.download, link.href].join(':');
  link.onclick = function(e) {
    if ('disabled' in this.dataset) { return false; }
    link.dataset.disabled = true;
    setTimeout(function() { window.URL.revokeObjectURL(link.href); }, 1500);
  };
  document.getElementById('linkcontainer').innerHTML = '';
  document.getElementById('linkcontainer').appendChild(link);
}

/**
 * This function takes in an array of nm records and converts them into a
 * hierarchical data structure suitable for use in a d3-base treemap layout.
 * Leaves are individual symbols. The parents of the leaves are logical
 * groupings by common symbol-type (for BSS, read-only data, code, etc).
 * Above this, each node represents part of a filesystem path relative
 * to the parent node. The root node has the name '/', and represents
 * a root (though not necessarily THE root) of a file system traversal.
 * The root node also has a special property, 'maxDepth', to which is bound
 * the deepest level of nesting that was found during conversion: for the
 * record at path /a/b/c/d.foo, the maxDepth will be 6; the file 'd.foo'
 * is at depth 4, the type-bucket is depth 5 and the symbols are depth 6.
 */
function to_d3_tree(records) {
  var result = {'n': '/', 'children': [], 'k': 'p'};
  var maxDepth = 0;
  //{'n': 'symbol1', 't': 'b', 's': 1000, 'p': '/usr/local/foo/foo.cc'},
  for (index in records) {
    var record = records[index];
    var parts = record.p.split("/");
    var node = result;
    var depth = 0;
    // Walk the tree and find the file that is named by the "location"
    // field of the record. We create any intermediate nodes required.
    // This is directly analogous to "mkdir -p".
    while(parts.length > 0) {
      var part = parts.shift();
      if (part.length == 0) continue;
      depth++;
      node = _mk_child(node, part, record.s);
      node.k = 'p'; // p for path
    }
    node.lastPathElement = true;

    // 'node' is now the file node. Find the symbol-type bucket.
    node = _mk_child(node, record.t, record.s);
    node.t = record.t;
    node.k = 'b'; // b for bucket
    depth++;
    // 'node' is now the symbol-type bucket. Make the child entry.
    node = _mk_child(node, record.n, record.s);
    delete node.children;
    node.value = record.s;
    node.t = record.t;
    node.k = 's'; // s for symbol
    depth++;

    maxDepth = Math.max(maxDepth, depth);
  }
  result.maxDepth = maxDepth;
  return result;
}

/**
 * Given a node and a name, return the child within node.children whose
 * name matches the specified name. If necessary, a new child node is
 * created and appended to node.children.
 * If this method creates a new node, the 'name' attribute is set to the
 * specified name and the 'children' attribute is an empty array, and
 * total_size is the specified size. Otherwise, the existing node is
 * returned and its total_size value is incremented by the specified size.
 */
function _mk_child(node, name, size) {
  var child = undefined;
  for (child_index in node.children) {
    if (node.children[child_index].n == name) {
      child = node.children[child_index];
    }
  }
  if (child === undefined) {
    child = {'n': name, 'children': []};
    node.children.push(child);
  }
  return child;
}
</script>
</head>
<body style='white-space: pre; font-family: monospace;'>
This script generates sample data for use in D3SymbolTreeMap, and can be used
for testing.
<input type=button onclick='gen();' value='Generate data'></input>
<div id='linkcontainer'></div>
</body>
</html>