bio-gemma-wrapper 0.99.3 → 0.99.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0bd37b153e121de9c1758af736cd6904744da2de3540f2a7c547cc423382d8d1
4
- data.tar.gz: 84298a943e7cfe6126653895d9714babc83a7be2bf903c7b61ff9072f1d4e4a8
3
+ metadata.gz: da5f26b8acd9c3782c2b3f5f2a39af965fc7e1785cc820b49faca82924d74e51
4
+ data.tar.gz: 17035ee5fada269ae88dd0ed91d84075b2af88b400de1d0e9829cbdb60d5d0cb
5
5
  SHA512:
6
- metadata.gz: f32d48ec2f194a513e0cf8f15463b05662e1b269fdd22a110e4cdfb9f6bc541238bac7e766cbc31a8b782379891636e4f79fb3e3667d567ab3c610298d4f11c2
7
- data.tar.gz: abc9b3faf8ef2f63d566caa14312bde2b2f438c722a83e90f7da775c55e2415171efbfab385273c82e45398c31e5306fb99437c38e287570652a3b04a5432883
6
+ metadata.gz: eaec3c7dad4fc1bda713765e056bfe11dd69d4ca850333fed5a1a27e344724365a705ddf7845ce63b5af6b35ab6140da10f4bc7067aaa4539e47f6c6f94de1f0
7
+ data.tar.gz: c26b282c0fd7c70a702467e58c3f6ea22f820d91a8a364b335cdab7e807add9cf1079faa25c46a87b89c78e4293990cdea2210427c5f9c3565bd5040fdbef496
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.99.3
1
+ 0.99.4
data/bin/gemma-wrapper CHANGED
@@ -71,6 +71,8 @@ require 'optparse'
71
71
  require 'tempfile'
72
72
  require 'tmpdir'
73
73
 
74
+ require 'lock'
75
+
74
76
  split_at = ARGV.index('--')
75
77
 
76
78
  if split_at
@@ -194,6 +196,7 @@ warning = lambda do |*msg|
194
196
  record[:warnings].push *msg.join("")
195
197
  OUTPUT.print "WARNING: ",*msg,"\n"
196
198
  end
199
+
197
200
  info = lambda do |*msg|
198
201
  record[:debug].push *msg.join("") if options[:json] and options[:debug]
199
202
  OUTPUT.print *msg,"\n" if !options[:quiet]
@@ -215,14 +218,14 @@ GEMMA_K_BANNER = "gemma-wrapper #{version} (Ruby #{RUBY_VERSION}) by Pjotr Prins
215
218
  info.call GEMMA_K_BANNER
216
219
 
217
220
  # Check gemma version
218
- GEMMA_COMMAND=options[:gemma_command]
219
- info.call "NOTE: gemma-wrapper is soon to be replaced by gemma2/lib"
220
-
221
221
  begin
222
- GEMMA_INFO = `#{GEMMA_COMMAND}`
222
+ gemma_command2 = options[:gemma_command]
223
+ info.call "NOTE: gemma-wrapper is soon to be replaced by gemma2/lib"
224
+
225
+ GEMMA_INFO = `#{gemma_command2}`
223
226
  rescue Errno::ENOENT
224
- GEMMA_COMMAND = "gemma" if not GEMMA_COMMAND
225
- error.call "<#{GEMMA_COMMAND}> command not found"
227
+ gemma_command2 = "gemma"
228
+ error.call "<#{gemma_command2}> command not found"
226
229
  end
227
230
 
228
231
  gemma_version_header = GEMMA_INFO.split("\n").grep(/GEMMA|Version/)[0].strip
@@ -329,6 +332,14 @@ end
329
332
  HASH = compute_hash.call()
330
333
  options[:hash] = HASH
331
334
 
335
+ at_exit do
336
+ Lock.release(HASH)
337
+ end
338
+
339
+ Lock.create(HASH) # this will wait for a lock to expire
340
+
341
+ joblog = options[:cache_dir]+"/"+HASH+"-parallel.log"
342
+
332
343
  # Create cache dir
333
344
  FileUtils::mkdir_p options[:cache_dir]
334
345
 
@@ -352,7 +363,7 @@ hashme =
352
363
  debug.call "Options: ",options,"\n" if !options[:quiet]
353
364
 
354
365
  invoke_gemma = lambda do |extra_args, cache_hit = false, chr = "full", permutation = 1|
355
- cmd = "#{GEMMA_COMMAND} #{GEMMA_ARGS.join(' ')} #{extra_args.join(' ')}"
366
+ cmd = "#{gemma_command2} #{GEMMA_ARGS.join(' ')} #{extra_args.join(' ')}"
356
367
  record[:gemma_command] = cmd
357
368
  return if cache_hit
358
369
  if options[:slurm]
@@ -552,15 +563,17 @@ if options[:parallel]
552
563
  cmd = parallel_cmds.join("\\n")
553
564
 
554
565
  cmd = "echo -e \"#{cmd}\""
555
- err = execute.call(cmd+"|parallel") # all jobs in parallel
566
+ err = execute.call(cmd+"|parallel --joblog #{joblog}") # first try optimistically to run all jobs in parallel
556
567
  if err != 0
557
568
  [16,8,4,1].each do |jobs|
558
569
  info.call("Failed to complete parallel run -- retrying with smaller RAM footprint!")
559
- err = execute.call(cmd+"|parallel -j #{jobs}")
570
+ err = execute.call(cmd+"|parallel -j #{jobs} --resume --joblog #{joblog}")
560
571
  break if err == 0
561
572
  end
562
573
  if err != 0
563
574
  info.call("Run failed!")
575
+ # Remove remaining files
576
+ FileUtils.rm_rf("#{tmpdir}/*", secure: true)
564
577
  exit err
565
578
  end
566
579
  end
@@ -6,6 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.authors = ["Pjotr Prins"]
7
7
  s.email = 'pjotr.public01@thebird.nl'
8
8
  s.files = ["bin/gemma-wrapper",
9
+ "lib/lock.rb",
9
10
  "Gemfile",
10
11
  "LICENSE.txt",
11
12
  "README.md",
data/lib/lock.rb ADDED
@@ -0,0 +1,95 @@
1
+ # Locking module for gemma (wrapper)
2
+ #
3
+
4
+ =begin
5
+
6
+ The logic is as follows:
7
+
8
+ 1. a program creates a named lock file (based on a hash of its inputs) with its PID
9
+ 2. on exit it destroys the file
10
+ 3. a new program checks for the lock file
11
+ 4. if it exists and the PID is still in the ps table - wait
12
+ 5. when the pid disappears or the lock file - continue
13
+ 6. a timeout will return an error in 3 minutes
14
+
15
+ Note that there is a theoretical chance the lock file existed, but disappeared. I think I have it covered by ignoring the unlink errors. Also the use of /proc/PID is Linux specific.
16
+
17
+ =end
18
+
19
+
20
+ require 'timeout'
21
+
22
+ module Lock
23
+
24
+ def self.local name
25
+ ENV['HOME']+"/."+name.gsub("/","-")+".lck"
26
+ end
27
+
28
+ def self.lock_pid name
29
+ lockfn = local(name)
30
+ if File.exist?(lockfn)
31
+ File.read(lockfn).to_i
32
+ else
33
+ 0
34
+ end
35
+ end
36
+
37
+ def self.locked? name
38
+ lockfn = local(name)
39
+ pid = lock_pid(name)
40
+ if File.exist?("/proc/#{pid}")
41
+ true
42
+ else
43
+ # the program went away - remove any 'stale' lock
44
+ begin
45
+ File.unlink(lockfn)
46
+ rescue Errno::ENOENT
47
+ # ignore error when the lock file went missing
48
+ end
49
+ false # --> no longer locked
50
+ end
51
+ end
52
+
53
+ def Lock::create name
54
+ wait_for(name)
55
+ lockfn = local(name)
56
+ if File.exist?(lockfn)
57
+ $stderr.print "\nERROR: Can not steal #{lockfn}"
58
+ exit 1
59
+ end
60
+ File.open(lockfn, File::RDWR|File::CREAT, 0644) do |f|
61
+ f.flock(File::LOCK_EX)
62
+ f.print(Process.pid)
63
+ end
64
+ end
65
+
66
+ def Lock::wait_for name
67
+ lockfn = local(name)
68
+ begin
69
+ status = Timeout::timeout(180) { # 3 minutes
70
+ while locked?(name)
71
+ $stderr.print("\nWaiting for lock #{lockfn}...")
72
+ sleep 2
73
+ end
74
+ }
75
+ rescue Timeout::Error
76
+ $stderr.print "\nERROR: Timed out, but I can not steal #{lockfn}"
77
+ exit 1
78
+ end
79
+ # yah! lock is released
80
+ end
81
+
82
+ def Lock::release name
83
+ lockfn = local(name)
84
+ if Process.pid == lock_pid(name)
85
+ begin
86
+ File.unlink(lockfn) # PID expired
87
+ rescue Errno::ENOENT
88
+ # ignore error when the lock file went missing
89
+ end
90
+ else
91
+ $stderr.print "\nERROR: can not release #{lockfn} because it is not owned by me"
92
+ end
93
+ end
94
+
95
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bio-gemma-wrapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.99.3
4
+ version: 0.99.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pjotr Prins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-22 00:00:00.000000000 Z
11
+ date: 2021-11-25 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: GEMMA wrapper adds LOCO and permutation support. Also runs in parallel
14
14
  and caches K between runs with LOCO support
@@ -24,6 +24,7 @@ files:
24
24
  - VERSION
25
25
  - bin/gemma-wrapper
26
26
  - gemma-wrapper.gemspec
27
+ - lib/lock.rb
27
28
  homepage: https://github.com/genetics-statistics/gemma-wrapper
28
29
  licenses:
29
30
  - GPL3
@@ -43,7 +44,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
43
44
  - !ruby/object:Gem::Version
44
45
  version: '0'
45
46
  requirements: []
46
- rubygems_version: 3.2.5
47
+ rubygems_version: 3.1.4
47
48
  signing_key:
48
49
  specification_version: 4
49
50
  summary: GEMMA with LOCO and permutations