xpflow 0.1b

Sign up to get free protection for your applications and to get access to all the features.
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
+