build-graph 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,98 +0,0 @@
1
-
2
- require 'process/group'
3
- require 'build/files'
4
- require 'build/graph'
5
-
6
- require 'console/event/spawn'
7
-
8
- class ProcessNode < Build::Graph::Node
9
- def initialize(inputs, outputs, block, title: nil)
10
- super(inputs, outputs)
11
-
12
- if title
13
- @title = title
14
- else
15
- @title = block.source_location
16
- end
17
-
18
- @block = block
19
- end
20
-
21
- def == other
22
- super and
23
- @title == other.title and
24
- @block == other.block
25
- end
26
-
27
- def hash
28
- super ^ @title.hash ^ @block.hash
29
- end
30
-
31
- def evaluate(context)
32
- context.instance_eval(&@block)
33
- end
34
-
35
- attr :title
36
- end
37
-
38
- class ProcessTask < Build::Graph::Task
39
- def initialize(walker, node, group)
40
- super(walker, node)
41
-
42
- @group = group
43
- end
44
-
45
- def process(inputs, outputs = :inherit, **options, &block)
46
- inputs = Build::Files::List.coerce(inputs)
47
- outputs = Build::Files::List.coerce(outputs) unless outputs.kind_of? Symbol
48
-
49
- node = ProcessNode.new(inputs, outputs, block, **options)
50
-
51
- self.invoke(node)
52
- end
53
-
54
- def wet?
55
- @node.dirty?
56
- end
57
-
58
- class CommandError < RuntimeError
59
- def initialize(command, status)
60
- @command = command
61
- @status = status
62
-
63
- super "#{command.join(' ')} failed: #{status}!"
64
- end
65
- end
66
-
67
- def run(*arguments, **options)
68
- if wet?
69
- @walker.logger.debug(self) {Console::Event::Spawn.for(*arguments, **options)}
70
-
71
- status = @group.spawn(*arguments, **options)
72
-
73
- if status != 0
74
- raise CommandError.new(arguments, status)
75
- end
76
- end
77
- end
78
-
79
- def mkpath(*args)
80
- return unless wet?
81
-
82
- FileUtils.mkpath(*args)
83
- end
84
-
85
- def install(*args)
86
- return unless wet?
87
-
88
- FileUtils.install(*args)
89
- end
90
-
91
- # This function is called to finish the invocation of the task within the graph.
92
- # There are two possible ways this function can generally proceed.
93
- # 1/ The node this task is running for is clean, and thus no actual processing needs to take place, but children should probably be executed.
94
- # 2/ The node this task is running for is dirty, and the execution of commands should work as expected.
95
- def update
96
- @node.evaluate(self)
97
- end
98
- end
@@ -1,72 +0,0 @@
1
- //
2
- // Benchmark.cpp
3
- // DictionarySort
4
- //
5
- // Created by Samuel Williams on 2/11/11.
6
- // Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
7
- //
8
-
9
- #include "Benchmark.h"
10
-
11
- #include <sys/time.h>
12
-
13
- // A timer class for quickly checking the wall-clock performance of code.
14
- namespace Benchmark
15
- {
16
- static TimeT system_time () {
17
- static struct timeval t;
18
- gettimeofday (&t, (struct timezone*)0);
19
- return ((TimeT)t.tv_sec) + ((TimeT)t.tv_usec / 1000000.0);
20
- }
21
-
22
- WallTime::WallTime () {
23
- this->reset();
24
- }
25
-
26
- void WallTime::reset () {
27
- this->_last = system_time();
28
- this->_total = 0.0;
29
- }
30
-
31
- TimeT WallTime::total () const {
32
- TimeT current = system_time();
33
- this->_total += current - this->_last;
34
- this->_last = current;
35
- return this->_total;
36
- }
37
-
38
- ProcessorTime::ProcessorTime()
39
- {
40
- this->reset();
41
- }
42
-
43
- void ProcessorTime::reset ()
44
- {
45
- this->_last = std::clock();
46
- this->_total = 0;
47
- }
48
-
49
- TimeT ProcessorTime::total () const
50
- {
51
- std::clock_t current = std::clock();
52
- this->_total += std::clock() - this->_last;
53
- this->_last = current;
54
-
55
- return TimeT(this->_total) / TimeT(CLOCKS_PER_SEC);
56
- }
57
-
58
- Timer::Timer()
59
- {
60
- }
61
-
62
- void Timer::reset ()
63
- {
64
- _wall_time.reset();
65
- _processor_time.reset();
66
- }
67
-
68
- Timer::Sample Timer::sample() const
69
- {
70
- return {_wall_time.total(), _processor_time.total()};
71
- }
72
- }
@@ -1 +0,0 @@
1
- Benchmark.cpp.o: Benchmark.cpp Benchmark.h
@@ -1,65 +0,0 @@
1
- //
2
- // Benchmark.h
3
- // DictionarySort
4
- //
5
- // Created by Samuel Williams on 2/11/11.
6
- // Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
7
- //
8
-
9
- #pragma once
10
-
11
- #include <ctime>
12
-
13
- // A timer class for quickly checking the wall-clock performance of code.
14
- namespace Benchmark
15
- {
16
- typedef double TimeT;
17
-
18
- class WallTime {
19
- protected:
20
- mutable TimeT _last, _total;
21
-
22
- public:
23
- WallTime ();
24
-
25
- void reset ();
26
- TimeT total () const;
27
- };
28
-
29
- class ProcessorTime {
30
- protected:
31
- mutable std::clock_t _last, _total;
32
-
33
- public:
34
- ProcessorTime();
35
-
36
- void reset ();
37
- TimeT total () const;
38
- };
39
-
40
- class Timer {
41
- protected:
42
- WallTime _wall_time;
43
- ProcessorTime _processor_time;
44
-
45
- public:
46
- Timer();
47
-
48
- const WallTime & wall_time() const { return _wall_time; }
49
- const ProcessorTime & processor_time() const { return _processor_time; }
50
-
51
- void reset ();
52
-
53
- struct Sample {
54
- TimeT wall_time_total;
55
- TimeT processor_time_total;
56
-
57
- TimeT approximate_processor_usage() const {
58
- return processor_time_total / wall_time_total;
59
- }
60
- };
61
-
62
- Sample sample() const;
63
- };
64
-
65
- }
@@ -1,270 +0,0 @@
1
- //
2
- // DictionarySort.h
3
- // DictionarySort
4
- //
5
- // Created by Samuel Williams on 2/11/11.
6
- // Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
7
- //
8
-
9
- #pragma once
10
-
11
- #include <cmath>
12
- #include <vector>
13
- #include <map>
14
-
15
- #include "ParallelMergeSort.h"
16
-
17
- template <typename AnyT>
18
- struct pointer_less_than
19
- {
20
- bool operator()(const AnyT a, const AnyT b) {
21
- return *a < *b;
22
- }
23
- };
24
-
25
- namespace DictionarySort
26
- {
27
- // Use std::sort
28
- //const int SORT_MODE = -1;
29
- // Use ParallelMergeSort with 2^n threads
30
- const int SORT_MODE = 3; // = n
31
-
32
- typedef std::uint64_t IndexT;
33
-
34
- template <typename CharT, typename MapT>
35
- class Dictionary {
36
- public:
37
- typedef std::vector<CharT> WordT;
38
- typedef std::vector<WordT> WordsT;
39
- typedef std::vector<IndexT> OrderT;
40
-
41
- static const int ORDERED_LT = -1;
42
- static const int ORDERED_EQ = 0;
43
- static const int ORDERED_GT = 1;
44
-
45
- // Compare two order vectors to determine the relative nature of lhs compared to rhs.
46
- // We assume that lhs and rhs have at least one element each.
47
- // ORDERED_LT => (lhs < rhs)
48
- // ORDERED_EQ => (lhs == rhs)
49
- // ORDERED_GT => (lhs > rhs)
50
- static int compare(const OrderT & lhs, const OrderT & rhs)
51
- {
52
- std::size_t offset = 0;
53
-
54
- while (offset < lhs.size() && offset < rhs.size()) {
55
- if (lhs[offset] < rhs[offset])
56
- return ORDERED_LT;
57
- else if (lhs[offset] > rhs[offset])
58
- return ORDERED_GT;
59
-
60
- offset += 1;
61
- }
62
-
63
- if (lhs.size() == rhs.size())
64
- return ORDERED_EQ;
65
-
66
- // lhs was longer,
67
- if (offset < lhs.size())
68
- return ORDERED_GT;
69
-
70
- return ORDERED_LT;
71
- }
72
-
73
- static int compare(Dictionary * dictionary, const WordT & lhs, const WordT & rhs) {
74
- std::size_t offset = 0;
75
-
76
- while (offset < lhs.size() && offset < rhs.size()) {
77
- IndexT left_order = dictionary->_characterOrder[lhs[offset]];
78
- IndexT right_order = dictionary->_characterOrder[rhs[offset]];
79
-
80
- if (left_order < right_order)
81
- return ORDERED_LT;
82
- else if (left_order > right_order)
83
- return ORDERED_GT;
84
-
85
- offset += 1;
86
- }
87
-
88
- if (lhs.size() == rhs.size())
89
- return ORDERED_EQ;
90
-
91
- if (offset < lhs.size())
92
- return ORDERED_GT;
93
-
94
- return ORDERED_LT;
95
- }
96
-
97
- private:
98
- WordT _alphabet;
99
-
100
- MapT _characterOrder;
101
- //int _characterOrder[256];
102
- //std::map<CharT, IndexT> _characterOrder;
103
-
104
- IndexT width;
105
- IndexT characters_per_segment;
106
-
107
- // This is a light weight wrapper over WordT which caches its OrderT, an integer representation of position based on the given dictionary.
108
- struct OrderedWord {
109
- WordT word;
110
-
111
- // We can generate this as part of the sorting process. Because the sort is parallel, generation of word order (which is relatively expensive) is distributed across multiple processors.
112
- mutable OrderT order;
113
-
114
- // The first time this function is called, it must be guaranteed from a single thread.
115
- // After that, it can be called from multiple threads at the same time.
116
- // The parallel merge sort algorithm guarantees this.
117
- const OrderT & fetch_order(Dictionary * dictionary) const {
118
- if (order.size() == 0 && word.size() > 0)
119
- order = dictionary->sum(word);
120
-
121
- return order;
122
- }
123
- };
124
-
125
- struct CompareWordsAscending {
126
- Dictionary * dictionary;
127
-
128
- CompareWordsAscending (Dictionary * _dictionary)
129
- : dictionary(_dictionary)
130
- {
131
- }
132
-
133
- bool operator()(const WordT * a, const WordT * b) const {
134
- return compare(dictionary, a, b) == ORDERED_LT;
135
- }
136
-
137
- bool operator()(const OrderedWord * a, const OrderedWord * b) const {
138
- return compare(a->fetch_order(dictionary), b->fetch_order(dictionary)) == ORDERED_LT;
139
- }
140
- };
141
-
142
- struct UnorderedWord {
143
- WordT word;
144
- Dictionary * dictionary;
145
-
146
- UnorderedWord(const WordT & _word, Dictionary * _dictionary)
147
- : word(_word), dictionary(_dictionary) {
148
-
149
- }
150
-
151
- bool operator<(const UnorderedWord & other) const {
152
- return compare(dictionary, *this, other) == ORDERED_LT;
153
- }
154
- };
155
-
156
- public:
157
- Dictionary(WordT alphabet)
158
- : _alphabet(alphabet)
159
- {
160
- IndexT index = 1;
161
-
162
- // Build up the character order map
163
- for (typename WordT::iterator i = _alphabet.begin(); i != _alphabet.end(); ++i) {
164
- _characterOrder[*i] = index;
165
- index += 1;
166
- }
167
-
168
- width = std::ceil(std::log(alphabet.size()) / std::log(2));
169
-
170
- // Naturally floor the result by integer division/truncation.
171
- characters_per_segment = (sizeof(IndexT) * 8) / width;
172
- }
173
-
174
- OrderT sum(const WordT & word) {
175
- OrderT order;
176
- std::size_t index = 0;
177
-
178
- while (index < word.size()) {
179
- IndexT count = characters_per_segment;
180
- IndexT sum = 0;
181
-
182
- while (index < word.size()) {
183
- count -= 1;
184
-
185
- sum <<= width;
186
- sum += _characterOrder[word[index]];
187
-
188
- index += 1;
189
-
190
- if (count == 0)
191
- break;
192
- }
193
-
194
- // Shift along any remaining count, since we are ordering using the left most significant character.
195
- sum <<= (count * width);
196
- order.push_back(sum);
197
- }
198
-
199
- return order;
200
- }
201
-
202
- // The words will be sorted in-place.
203
- template <typename ToSortT>
204
- void sort (ToSortT & words, int mode = 2)
205
- {
206
- CompareWordsAscending comparator(this);
207
-
208
- Benchmark::Timer sort_timer;
209
-
210
- if (mode == -1) {
211
- // Sort the words using built-in sorting algorithm, for comparison:
212
- std::sort(words.begin(), words.end(), comparator);
213
- } else {
214
- ParallelMergeSort::sort(words, comparator, std::size_t(mode));
215
- }
216
-
217
- auto sample = sort_timer.sample();
218
-
219
- std::cerr << "--- Completed Dictionary Sort ---" << std::endl;
220
- std::cerr << " * Dictionary sort time: " << sample.wall_time_total << std::endl;
221
- std::cerr << " * Processor sort time: " << sample.processor_time_total << std::endl;
222
- std::cerr << " * Approximate processor usage: " << sample.approximate_processor_usage() << std::endl;
223
- }
224
-
225
- // This function can be slow due to the large amount of memory required for large datasets.
226
- uint64_t sort(const WordsT & input, WordsT & output)
227
- {
228
- typedef std::vector<OrderedWord*> OrderedWordsT;
229
-
230
- // Allocate all words in one go:
231
- OrderedWord * allocation = new OrderedWord[input.size()];
232
-
233
- // Copy pointers to intermediate list which will be used for sorting:
234
- OrderedWordsT words(input.size());
235
-
236
- // Calculate order vector for each word in preparation for sort.
237
- for (std::size_t i = 0; i < input.size(); i += 1) {
238
- words[i] = &allocation[i];
239
-
240
- words[i]->word = input[i];
241
-
242
- // We can force generation of the order cache, but performance may be reduced by about 10%.
243
- //words[i]->fetch_order(this);
244
- }
245
-
246
- // Change the mode from -1 for std::sort, to 0..n for ParallelMergeSort where 2^n is the number of threads to use.
247
- sort(words, SORT_MODE);
248
-
249
- // Prepare container for sorted output:
250
- output.reserve(input.size());
251
- output.resize(0);
252
-
253
- uint64_t checksum = 1, offset = 1;
254
- // Copy sorted words to output vector.
255
- for (typename OrderedWordsT::iterator i = words.begin(); i != words.end(); ++i) {
256
- output.push_back((*i)->word);
257
-
258
- // Compute a very simple checksum for verifying sorted order.
259
- const OrderT & order = (*i)->fetch_order(this);
260
- for (typename OrderT::const_iterator j = order.begin(); j != order.end(); ++j) {
261
- checksum ^= *j + (offset++ % checksum);
262
- }
263
- }
264
-
265
- delete[] allocation;
266
-
267
- return checksum;
268
- }
269
- };
270
- }