bio-gemma-wrapper 0.99.3 → 0.99.4

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.
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