xpflow 0.1b

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.
Files changed (74) hide show
  1. data/bin/xpflow +96 -0
  2. data/lib/colorado.rb +198 -0
  3. data/lib/json/add/core.rb +243 -0
  4. data/lib/json/add/rails.rb +8 -0
  5. data/lib/json/common.rb +423 -0
  6. data/lib/json/editor.rb +1369 -0
  7. data/lib/json/ext.rb +28 -0
  8. data/lib/json/pure/generator.rb +442 -0
  9. data/lib/json/pure/parser.rb +320 -0
  10. data/lib/json/pure.rb +15 -0
  11. data/lib/json/version.rb +8 -0
  12. data/lib/json.rb +62 -0
  13. data/lib/mime/types.rb +881 -0
  14. data/lib/mime-types.rb +3 -0
  15. data/lib/restclient/abstract_response.rb +106 -0
  16. data/lib/restclient/exceptions.rb +193 -0
  17. data/lib/restclient/net_http_ext.rb +55 -0
  18. data/lib/restclient/payload.rb +235 -0
  19. data/lib/restclient/raw_response.rb +34 -0
  20. data/lib/restclient/request.rb +316 -0
  21. data/lib/restclient/resource.rb +169 -0
  22. data/lib/restclient/response.rb +24 -0
  23. data/lib/restclient.rb +174 -0
  24. data/lib/xpflow/bash.rb +341 -0
  25. data/lib/xpflow/bundle.rb +113 -0
  26. data/lib/xpflow/cmdline.rb +249 -0
  27. data/lib/xpflow/collection.rb +122 -0
  28. data/lib/xpflow/concurrency.rb +79 -0
  29. data/lib/xpflow/data.rb +393 -0
  30. data/lib/xpflow/dsl.rb +816 -0
  31. data/lib/xpflow/engine.rb +574 -0
  32. data/lib/xpflow/ensemble.rb +135 -0
  33. data/lib/xpflow/events.rb +56 -0
  34. data/lib/xpflow/experiment.rb +65 -0
  35. data/lib/xpflow/exts/facter.rb +30 -0
  36. data/lib/xpflow/exts/g5k.rb +931 -0
  37. data/lib/xpflow/exts/g5k_use.rb +50 -0
  38. data/lib/xpflow/exts/gui.rb +140 -0
  39. data/lib/xpflow/exts/model.rb +155 -0
  40. data/lib/xpflow/graph.rb +1603 -0
  41. data/lib/xpflow/graph_xpflow.rb +251 -0
  42. data/lib/xpflow/import.rb +196 -0
  43. data/lib/xpflow/library.rb +349 -0
  44. data/lib/xpflow/logging.rb +153 -0
  45. data/lib/xpflow/manager.rb +147 -0
  46. data/lib/xpflow/nodes.rb +1250 -0
  47. data/lib/xpflow/runs.rb +773 -0
  48. data/lib/xpflow/runtime.rb +125 -0
  49. data/lib/xpflow/scope.rb +168 -0
  50. data/lib/xpflow/ssh.rb +186 -0
  51. data/lib/xpflow/stat.rb +50 -0
  52. data/lib/xpflow/stdlib.rb +381 -0
  53. data/lib/xpflow/structs.rb +369 -0
  54. data/lib/xpflow/taktuk.rb +193 -0
  55. data/lib/xpflow/templates/ssh-config.basic +14 -0
  56. data/lib/xpflow/templates/ssh-config.inria +18 -0
  57. data/lib/xpflow/templates/ssh-config.proxy +13 -0
  58. data/lib/xpflow/templates/taktuk +6590 -0
  59. data/lib/xpflow/templates/utils/batch +4 -0
  60. data/lib/xpflow/templates/utils/bootstrap +12 -0
  61. data/lib/xpflow/templates/utils/hostname +3 -0
  62. data/lib/xpflow/templates/utils/ping +3 -0
  63. data/lib/xpflow/templates/utils/rsync +12 -0
  64. data/lib/xpflow/templates/utils/scp +17 -0
  65. data/lib/xpflow/templates/utils/scp_many +8 -0
  66. data/lib/xpflow/templates/utils/ssh +3 -0
  67. data/lib/xpflow/templates/utils/ssh-interactive +4 -0
  68. data/lib/xpflow/templates/utils/taktuk +19 -0
  69. data/lib/xpflow/threads.rb +187 -0
  70. data/lib/xpflow/utils.rb +569 -0
  71. data/lib/xpflow/visual.rb +230 -0
  72. data/lib/xpflow/with_g5k.rb +7 -0
  73. data/lib/xpflow.rb +349 -0
  74. metadata +135 -0
@@ -0,0 +1,122 @@
1
+
2
+ # stuff related to collecting execution results
3
+
4
+ module XPFlow
5
+
6
+ class FileResult
7
+
8
+ attr_reader :filename
9
+ attr_reader :info
10
+
11
+ def initialize(filename, info)
12
+ @filename = filename
13
+ @info = info
14
+ end
15
+
16
+ end
17
+
18
+ class Collection
19
+
20
+ attr_reader :path
21
+
22
+ def initialize(path)
23
+ @results = {}
24
+ @files = {}
25
+ @path = path
26
+ end
27
+
28
+ def create(subdir)
29
+ return Collection.new(File.join(@path, subdir))
30
+ end
31
+
32
+ def create_path()
33
+ if File.directory?(@path)
34
+ FileUtils.remove_entry_secure(@path)
35
+ end
36
+ Dir.mkdir(@path)
37
+ end
38
+
39
+ def collect_result(key, result)
40
+ @results[key] = result
41
+ end
42
+
43
+ def save_all
44
+ index = 0
45
+ @results.each do |key, result|
46
+ prefix = File.join(@path, key.to_s)
47
+ if result.is_a?(ManyExecutionResult)
48
+ files = save_manyresult(result, prefix)
49
+ @files[key] = files
50
+ else
51
+ raise "Can't collect results of type #{result.class}"
52
+ end
53
+ end
54
+ end
55
+
56
+ def save_manyresult(result, prefix)
57
+ summary = "#{prefix}-summary.yaml"
58
+ info = []
59
+ files = []
60
+ pad = result.length.to_s.length
61
+ counter = 1
62
+ result.to_list.each do |r|
63
+ basename = "#{counter.to_s.rjust(pad, '0')}"
64
+ stdout_file = "#{basename}.stdout"
65
+ stderr_file = "#{basename}.stderr"
66
+ stdout_file = "#{prefix}-#{stdout_file}"
67
+ stderr_file = "#{prefix}-#{stderr_file}"
68
+ r.save_stdout(stdout_file)
69
+ r.save_stderr(stderr_file)
70
+ node = r.node
71
+ this_info = {
72
+ # TODO: add more data, e.g., provenance, real paths?
73
+ :stdout => stdout_file,
74
+ :stderr => stderr_file,
75
+ :host => node.host,
76
+ :user => node.user
77
+ }
78
+ info.push(this_info)
79
+ files.push(FileResult.new(stdout_file, this_info))
80
+ counter += 1
81
+ end
82
+ IO.write(summary, info.to_yaml)
83
+ return files
84
+ end
85
+
86
+ end
87
+
88
+ class CollectionLibrary < SyncedActivityLibrary
89
+
90
+ activities :collect_result, :save_all_results,
91
+ :get_files, :transform_to_float,
92
+ :result_collection
93
+
94
+ def setup
95
+
96
+ end
97
+
98
+ def result_collection
99
+ return Scope.current[:__collection__]
100
+ end
101
+
102
+ def collect_result(key, result)
103
+ return result_collection.collect_result(key, result)
104
+ end
105
+
106
+ def save_all_results
107
+ return result_collection().save_all()
108
+ end
109
+
110
+ def transform_to_float(results, script)
111
+ files = @files[results]
112
+ script = $files[script]
113
+ floats = files.map do |r|
114
+ x = proxy.run :"__core__.system", "#{script} #{r.filename}"
115
+ x.to_f
116
+ end
117
+ return ValueData.new(floats)
118
+ end
119
+
120
+ end
121
+
122
+ end
@@ -0,0 +1,79 @@
1
+
2
+ module XPFlow
3
+
4
+ class Semaphore
5
+
6
+ def initialize(n)
7
+ @n = n
8
+ @mutex = Mutex.new
9
+ @cond = ConditionVariable.new
10
+ end
11
+
12
+ def acquire
13
+ @mutex.synchronize do
14
+ while @n == 0
15
+ @cond.wait(@mutex)
16
+ end
17
+ @n -= 1
18
+ end
19
+ end
20
+
21
+ def release
22
+ @mutex.synchronize do
23
+ @n += 1
24
+ @cond.signal
25
+ end
26
+ end
27
+
28
+ def synchronize
29
+ begin
30
+ @mutex.acquire
31
+ yield
32
+ ensure
33
+ @mutex.release
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ class SyncQueue
40
+
41
+ attr_reader :q
42
+
43
+ def initialize
44
+ @q = []
45
+ @elements = Semaphore.new(0)
46
+ @mutex = Mutex.new
47
+ @cv = ConditionVariable.new # empty queue
48
+ end
49
+
50
+ def push(x)
51
+ @mutex.synchronize do
52
+ @q.push(x)
53
+ end
54
+ @elements.release
55
+ end
56
+
57
+ def pop
58
+ @elements.acquire
59
+ return @mutex.synchronize do
60
+ x = @q.shift
61
+ @cv.broadcast if @q.length == 0
62
+ x = yield(x) if block_given?
63
+ x
64
+ end
65
+ end
66
+
67
+ # waits for the queue to be empty
68
+
69
+ def wait_empty
70
+ @mutex.synchronize do
71
+ while @q.length > 0
72
+ @cv.wait(@mutex)
73
+ end
74
+ end
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -0,0 +1,393 @@
1
+ # encoding: UTF-8
2
+
3
+ #
4
+ # Data collection classes.
5
+ #
6
+
7
+ module XPFlow
8
+
9
+ class ValueData
10
+
11
+ attr_reader :values
12
+
13
+ def initialize(vals = nil)
14
+ vals = [] if vals.nil?
15
+ @values = vals
16
+ end
17
+
18
+ def push(x)
19
+ @values.push(x)
20
+ end
21
+
22
+ def ==(x)
23
+ return (@values == x) if x.is_a?(Array)
24
+ return (@values == x.values)
25
+ end
26
+
27
+ def average
28
+ return @values.reduce(:+).to_f / @values.length
29
+ end
30
+
31
+ def average_variance
32
+ raise 'The variance computation for sample with less than 2 elements is impossible' if @values.length < 2
33
+ m = average()
34
+ s = @values.map { |x| (x - m)**2 }.reduce(:+)
35
+ return [ m, s / (@values.length - 1) ]
36
+ end
37
+
38
+ def variance
39
+ return average_variance().last
40
+ end
41
+
42
+ def average_stddev
43
+ m, v = average_variance()
44
+ return m, v ** 0.5
45
+ end
46
+
47
+ def stddev
48
+ return average_stddev().last
49
+ end
50
+
51
+ #Credit for cdf_inverse : http://home.online.no/~pjacklam/notes/invnorm/
52
+ # inverse standard normal cumulative distribution function
53
+ def cdf_inverse(p)
54
+ a = [0, -3.969683028665376e+01, 2.209460984245205e+02, -2.759285104469687e+02, 1.383577518672690e+02, -3.066479806614716e+01, 2.506628277459239e+00]
55
+ b = [0, -5.447609879822406e+01, 1.615858368580409e+02, -1.556989798598866e+02, 6.680131188771972e+01, -1.328068155288572e+01]
56
+ c = [0, -7.784894002430293e-03, -3.223964580411365e-01, -2.400758277161838e+00, -2.549732539343734e+00, 4.374664141464968e+00, 2.938163982698783e+00]
57
+ d = [0, 7.784695709041462e-03, 3.224671290700398e-01, 2.445134137142996e+00, 3.754408661907416e+00]
58
+ #Define break-points.
59
+ p_low = 0.02425
60
+ p_high = 1.0 - p_low
61
+
62
+ x = 0.0
63
+ q = 0.0
64
+ #Rational approximation for lower region.
65
+ if 0.0 < p && p < p_low
66
+ q = Math.sqrt(-2.0*Math.log(p))
67
+ x = (((((c[1]*q+c[2])*q+c[3])*q+c[4])*q+c[5])*q+c[6]) / ((((d[1]*q+d[2])*q+d[3])*q+d[4])*q+1.0)
68
+
69
+ #Rational approximation for central region.
70
+ elsif p_low <= p && p <= p_high
71
+ q = p - 0.5
72
+ r = q*q
73
+ x = (((((a[1]*r+a[2])*r+a[3])*r+a[4])*r+a[5])*r+a[6])*q / (((((b[1]*r+b[2])*r+b[3])*r+b[4])*r+b[5])*r+1.0)
74
+
75
+ #Rational approximation for upper region.
76
+ elsif p_high < p && p < 1.0
77
+ q = Math.sqrt(-2.0*Math.log(1.0-p))
78
+ x = -(((((c[1]*q+c[2])*q+c[3])*q+c[4])*q+c[5])*q+c[6]) / ((((d[1]*q+d[2])*q+d[3])*q+d[4])*q+1.0)
79
+ end
80
+
81
+ #The relative error of the approximation has
82
+ #absolute value less than 1.15 × 10−9. One iteration of
83
+ #Halley’s rational method (third order) gives full machine precision.
84
+ if 0 < p && p < 1
85
+ e = 0.5 * Math.erfc(-x/Math.sqrt(2.0)) - p
86
+ u = e * Math.sqrt(2.0*Math::PI) * Math.exp((x**2.0)/2.0)
87
+ x = x - u/(1.0 + x*u/2.0)
88
+ end
89
+ x
90
+ end
91
+ def minimal_sample_prel(prec,confidance)
92
+ minimal_sample_both(prec,nil,confidance)
93
+ end
94
+ def minimal_sample_pabs(prec,confidance)
95
+ minimal_sample_both(nil,prec,condidance)
96
+ end
97
+ #vectors is values and prec and confidence is in percentage
98
+ def minimal_sample_both(prec_rel,prec,confidence)
99
+ avg = average
100
+ prec = prec_rel.nil? ? prec : avg*prec_rel
101
+ critical_value=cdf_inverse((1-confidence)/2)
102
+ ((critical_value*stddev() / prec) ** 2).to_i + 1
103
+ end
104
+
105
+ TSTUDENT = [
106
+ nil, 12.71, 4.303, 3.182, 2.776, 2.571, 2.447, 2.365, 2.306, 2.262, 2.228,
107
+ 2.201, 2.179, 2.160, 2.145, 2.131, 2.120, 2.110, 2.101, 2.093, 2.086, 2.080,
108
+ 2.074, 2.069, 2.064, 2.060, 2.056, 2.052, 2.048, 2.045, 2.042, 2.021, 2.009,
109
+ 2.000, 1.990, 1.984, 1.980, 1.960 ]
110
+
111
+ def confidence_interval
112
+ if size() >= TSTUDENT.length
113
+ factor = TSTUDENT[-1]
114
+ else
115
+ factor = TSTUDENT[size()]
116
+ end
117
+ m, s = average_stddev()
118
+ d = (factor * s).to_f / (@values.length ** 0.5)
119
+ return [m - d, m + d]
120
+ end
121
+
122
+ def confidence_precision
123
+ a, b = confidence_interval()
124
+ return (b - a) * 0.5
125
+ end
126
+
127
+ def confidence_ratio
128
+ # provides conf. as a percentage around the estimated mean value
129
+ prec = confidence_precision()
130
+ mean = average().abs
131
+ return (prec / mean)
132
+ end
133
+
134
+ def conf_ratio
135
+ return confidence_ratio
136
+ end
137
+
138
+ def map(&block)
139
+ arr = @values.map(&block)
140
+ return ValueData.new(arr)
141
+ end
142
+
143
+ def sort
144
+ return ValueData.new(@values.sort)
145
+ end
146
+
147
+ def to_s
148
+ return "<Data: #{@values.inspect}>"
149
+ end
150
+
151
+ def sum
152
+ return @values.reduce(:+)
153
+ end
154
+
155
+ def size
156
+ return @values.length
157
+ end
158
+
159
+ def length
160
+ return size()
161
+ end
162
+
163
+ def append(x)
164
+ return ValueData.new(self.values + [ x ])
165
+ end
166
+
167
+ end
168
+
169
+ class NamedTuple
170
+
171
+ def initialize(base, array)
172
+ @base = base
173
+ @array = array
174
+ end
175
+
176
+ def [](label)
177
+ label = @base.unlabel(label) unless label.is_a?(Fixnum)
178
+ return @array[label]
179
+ end
180
+
181
+ def value(idx)
182
+ return @array[idx]
183
+ end
184
+
185
+ def values(idxs)
186
+ return idxs.map { |i| @array[i] }
187
+ end
188
+
189
+ def method_missing(name, *args)
190
+ idx = @base.unlabel(name)
191
+ raise NoMethodError.new("undefined method '#{name}'", name) if (idx.nil? or args.length != 0)
192
+ return @array[idx]
193
+ end
194
+
195
+ def to_s
196
+ labels = @base.labels
197
+ s = @array.each_with_index.map { |el, i|
198
+ "#{labels[i]}=#{el}"
199
+ }.join(', ')
200
+ return "<#{s}>"
201
+ end
202
+
203
+ def to_a
204
+ return @array
205
+ end
206
+
207
+ end
208
+
209
+ class NamedTupleBase
210
+
211
+ attr_reader :labels
212
+
213
+ def initialize(labels)
214
+ @labels = labels
215
+ end
216
+
217
+ def build(row)
218
+ return row if row.is_a?(NamedTuple)
219
+ if row.is_a?(Hash)
220
+ row = @labels.map { |l| row[l] }
221
+ elsif row.is_a?(Array)
222
+ else
223
+ raise
224
+ end
225
+ return NamedTuple.new(self, row)
226
+ end
227
+
228
+ def unlabel(label)
229
+ return @labels.index(label)
230
+ end
231
+
232
+ def unlabels(labs)
233
+ return labs.map { |l| unlabel(l) }
234
+ end
235
+
236
+ def split_labels(labs)
237
+ left = []
238
+ right = []
239
+ @labels.each_with_index { |l, i|
240
+ idx = labs.index(l)
241
+ if idx.nil?
242
+ right.push(l)
243
+ else
244
+ left.push([idx, l])
245
+ end
246
+ }
247
+ left = left.sort.map { |x| x.last }
248
+ return [left, right]
249
+ end
250
+
251
+ def to_s
252
+ s = @labels.map { |x| x.to_s }.join(', ')
253
+ return "<Base: #{s}>"
254
+ end
255
+
256
+ end
257
+
258
+ class RowData
259
+
260
+ def initialize(labs, rows = nil)
261
+ rows = [] if rows.nil?
262
+ @base = NamedTupleBase.new(labs)
263
+ @rows = rows
264
+ end
265
+
266
+ def labels
267
+ return @base.labels
268
+ end
269
+
270
+ def duplicate(rows = nil)
271
+ return RowData.new(@base.labels, rows)
272
+ end
273
+
274
+ def length
275
+ return @rows.length
276
+ end
277
+
278
+ def width
279
+ return @base.labels.length
280
+ end
281
+
282
+ def push(row)
283
+ row = @base.build(row)
284
+ @rows.push(row)
285
+ end
286
+
287
+ def append(rows)
288
+ rows.each { |r| push(r) }
289
+ end
290
+
291
+ def column(label)
292
+ values = @rows.map { |row| row[label] }
293
+ return ValueData.new(values)
294
+ end
295
+
296
+ def _group(labs, key_f = nil)
297
+ # groups data by labels; returns hash
298
+ labs = @base.unlabels(labs)
299
+ groups = {}
300
+ @rows.each { |r|
301
+ key = r.values(labs)
302
+ key = key_f.call(key) unless key_f.nil?
303
+ groups[key] = duplicate() unless groups.key?(key)
304
+ groups[key].push(r)
305
+ }
306
+ return groups
307
+ end
308
+
309
+ def _select(labs)
310
+ rows = RowData.new(labs)
311
+ labs = @base.unlabels(labs)
312
+ @rows.each { |row| rows.push(row.values(labs)) }
313
+ return rows
314
+ end
315
+
316
+ def _cluster(labs, key_f = nil)
317
+ groups = _group(labs, key_f)
318
+ left, right = @base.split_labels(labs)
319
+ h = groups.map { |k, v| [ k, v._select(right) ] }
320
+ return Hash[h]
321
+ end
322
+
323
+ def _sort(&block)
324
+ rows = @rows.clone() # shallow copy of the rows
325
+ rows.sort!(&block)
326
+ return duplicate(rows)
327
+ end
328
+
329
+ def _filter(&block)
330
+ rows = @rows.select(&block)
331
+ return duplicate(rows)
332
+ end
333
+
334
+ def _map(&block)
335
+ @rows.map(&block)
336
+ end
337
+
338
+ def _expand(new_labels, &block)
339
+ labs = @base.labels + new_labels
340
+ rows = RowData.new(labs)
341
+ @rows.each { |r|
342
+ ext = block.call(r)
343
+ ext = [ext] unless ext.is_a?(Array)
344
+ rows.push(r.to_a + ext)
345
+ }
346
+ return rows
347
+ end
348
+
349
+ def _discard(old_labels)
350
+ labs = @base.labels - old_labels
351
+ rows = RowData.new(labs)
352
+ idxs = @base.unlabels(labs)
353
+ @rows.each { |r|
354
+ rows.push(r.values(idxs))
355
+ }
356
+ return rows
357
+ end
358
+
359
+ def to_s
360
+ s = @rows.map { |el| el.to_s }.join(", ")
361
+ return "[ #{s} ]"
362
+ end
363
+
364
+ ### USER FRIENDLY PART
365
+
366
+ def self.create(*labs)
367
+ return RowData.new(labs)
368
+ end
369
+
370
+ def collect(*row)
371
+ row = row.first if row.length == 1 and row.first.is_a?(Hash)
372
+ push(row)
373
+ end
374
+
375
+ def table
376
+ return @rows.map { |r| r.to_a }
377
+ end
378
+
379
+ def sort(&block); _sort(&block) end
380
+ def select(*labs); _select(labs) end
381
+ def group(*labs); _group(labs) end
382
+ def group_one(label); _group([label], lambda { |k| k.first }) end
383
+ def cluster(*labs); _cluster(labs) end
384
+ def cluster_one(label); _cluster([label], lambda { |k| k.first }) end
385
+ def filter(&block); _filter(&block) end
386
+ def map(&block); _map(&block) end
387
+ def expand(*labs, &block); _expand(labs, &block) end
388
+ def discard(*labs); _discard(labs) end
389
+
390
+ end
391
+
392
+ end
393
+