carray-jit 0.1.0 → 0.1.1

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: 255cd246bcdd06c49b0afd2aeaaa4c3086eb8b9c84f4ad04319129f7415c182f
4
- data.tar.gz: 80fedb1eb6cfcfece4009d69d26251a58a2caa9d5975d1895bb34b9a7fa18ac7
3
+ metadata.gz: 89d3c3c1c950f938ca30658e4d6586bd305b60e6d83083a33e645ea69168d3e3
4
+ data.tar.gz: 6101247a5b517a6f28ce051016ced3674ce26e4400952a3a69eaf2ab8ea7eb40
5
5
  SHA512:
6
- metadata.gz: fa33123ca9012275607181b6808e2497da5e8d1908764bff23200299e9c972dd61e9b9e4d3ab58345b2fbcd5badba39ddd03b214ad9ccadde6413b37a32f3215
7
- data.tar.gz: 45050b058cba426afc373e50f47797e4720968c1e4a26862322364d44a81a4610a991622b0e35d3d20519fb583e654558728a85393064978c9adfc23db5d9f06
6
+ metadata.gz: 6789499fd3fa7bbb2e2342bb48b35cb2eb6c5dbe05a2ef281cc4c9c734c6ef18c37ece9a929623103e5f1c388b656184bcc76e4b457b9c03241ae226c132e49c
7
+ data.tar.gz: 16b2611b901be3ab35fd088309ba4976ac45f3cefd360a472971c95e7f0edcf17e3ebb19abb0bded712012b9b8e3c85cc26aea6787b9caf71741bc7b06b861f5
data/CHANGELOG.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Changelog
2
2
 
3
- Releases are recorded here from 0.1.0, which is the first.
3
+ Releases are recorded here from 0.1.0, which is the first. There is no
4
+ separate NEWS file: this is where to look for what changed between the
5
+ version you have and a newer one.
4
6
 
5
7
  <!-- Newest first, at both levels: a new release section goes above the
6
8
  ones below it, and a new entry goes directly under its own release
@@ -8,6 +10,12 @@ Releases are recorded here from 0.1.0, which is the first.
8
10
  carried by the `- Fix:` / `- Change:` / `- New:` that opens the
9
11
  entry; there are no per-kind subheadings.
10
12
 
13
+ A section is written newest-first while the release is open, and
14
+ sorted into New, Change, Fix when it closes -- in the same commit
15
+ that drops `(unreleased)`. Within Change, the ones that ask the
16
+ reader to change code come first. It is a reading order rather than
17
+ a classification: where it is not obvious, either place will do.
18
+
11
19
  An entry says three things and stops: what changed, what to do about
12
20
  it (the migration, the replacement, the condition under which nothing
13
21
  changes), and what is excluded. It does not say how the code was
@@ -15,10 +23,37 @@ Releases are recorded here from 0.1.0, which is the first.
15
23
  speed came from, or argue the design -- those belong in the commit
16
24
  message. Two to six lines.
17
25
 
26
+ It is written for someone using the library, not someone working on
27
+ it: with no NEWS file, this is what a reader consults before
28
+ upgrading. An entry naming something only a C extension touches says
29
+ so in its opening words.
30
+
31
+ Every entry has to read on its own. Entries are looked at one at a
32
+ time and move about within a section, so none may lean on a
33
+ neighbour ("as well", "the kernel above") or leave unnamed the
34
+ method, class or keyword it is about.
35
+
18
36
  The version here is this gem's own and is not CArray's. Which CArray
19
37
  a release needs is said in the gemspec, and an entry says so only
20
38
  when the answer changes. -->
21
39
 
40
+ ## 0.1.1
41
+
42
+ - Fix: a zero divisor in a `CArray.fuse` expression no longer turns
43
+ compilation off for the rest of the process. `ZeroDivisionError` is raised
44
+ as before; what has gone is the warning that followed it on stderr, and the
45
+ expressions walked rather than compiled from then on. Nothing to do.
46
+ `jit_for`, `jit_each` and `jit_map` were never affected.
47
+
48
+ - Fix: on macOS, a `CArray.fuse` expression holding an integer `/` or `%` is
49
+ compiled rather than walked. The answers were right before and are
50
+ unchanged; this is speed alone. Linux was never affected.
51
+
52
+ - Fix: on Linux, a program that compiles more than one kernel no longer
53
+ crashes -- any two of `jit_for`, `jit_each`, `jit_map`, `jit_stencil`,
54
+ `jit_contract` and `jit_function` reached in the same run. Nothing to do:
55
+ cached kernels are rebuilt on first use. macOS was never affected.
56
+
22
57
  ## 0.1.0
23
58
 
24
59
  - New: `CArray.jit_for`, `CArray.jit_each` and `CArray.jit_map` compile their
@@ -73,9 +108,10 @@ Releases are recorded here from 0.1.0, which is the first.
73
108
  `CARRAY_JIT_NO_CACHE` keeps the cache in a temporary directory that goes
74
109
  away with the process, and `CARRAY_JIT_CC` names a different compiler.
75
110
 
76
- - New: the `carray-jit` command reports and looks after that cache --
77
- `status`, `list`, `show`, `clear`. It loads the compiler and nothing else,
78
- so a cache can be inspected or cleared when CArray itself will not load.
111
+ - New: the `carray-jit` command reports and looks after the on-disk kernel
112
+ cache -- `status`, `list`, `show`, `clear`. It loads the compiler and
113
+ nothing else, so a cache can be inspected or cleared when CArray itself
114
+ will not load.
79
115
 
80
116
  - New: needs CArray 3.0.1 or later in the 3.0 series, and Ruby 3.2 or later.
81
117
  The floor is where `ca_call_cslab_N`, the expression evaluator hook,
data/README.md CHANGED
@@ -8,7 +8,7 @@ The block is read with Prism, translated to C if it falls inside that subset, co
8
8
 
9
9
  ## Status
10
10
 
11
- 0.1.0 is the first release, and it still moves: behaviour can change between releases — see [CHANGELOG.md](CHANGELOG.md). A companion gem to CArray, it follows CArray's surface, which is not settled until CArray 3.1.
11
+ 0.1.1 is the current release, and it still moves: behaviour can change between releases — see [CHANGELOG.md](CHANGELOG.md). A companion gem to CArray, it follows CArray's surface, which is not settled until CArray 3.1.
12
12
 
13
13
  ## Features
14
14
 
@@ -40,7 +40,26 @@ class CArray
40
40
  # being lower was not a decision -- the flag list is the one the first
41
41
  # milestone was scaffolded with, and only the contraction flag beside
42
42
  # it was ever argued for.
43
- FLAGS = ["-O3", "-fPIC", "-shared", "-ffp-contract=off"].freeze
43
+
44
+ # Every generated object exports the same fixed names -- carray_jit_kernel,
45
+ # carray_jit_slab, the border and error helpers -- because each one is a
46
+ # module of its own. Fiddle.dlopen passes RTLD_GLOBAL, so on ELF those
47
+ # names all land in one flat namespace and an intra-module call resolves
48
+ # to the first definition loaded: a later kernel's carray_jit_slab calls
49
+ # an earlier kernel's carray_jit_kernel, which takes a different number
50
+ # of operands, reads past the pointers it was given, and the process
51
+ # segfaults. -Wl,-Bsymbolic binds each object's own definitions before
52
+ # the global scope, which is what one object per kernel assumed all
53
+ # along. Nothing else needs saying so: Mach-O binds within each dylib's
54
+ # own two-level namespace and PE within each DLL, so the flag is named
55
+ # only where it means something -- and Apple's linker rejects it
56
+ # outright, which would trade a Linux crash for a macOS build that never
57
+ # compiles at all.
58
+ SYMBOLIC =
59
+ (RbConfig::CONFIG["host_os"] =~ /darwin|mswin|mingw|cygwin/ ?
60
+ [] : ["-Wl,-Bsymbolic"]).freeze
61
+
62
+ FLAGS = ["-O3", "-fPIC", "-shared", "-ffp-contract=off", *SYMBOLIC].freeze
44
63
 
45
64
  # Kernels retained on disk. Each costs about 17 KB, so the default is
46
65
  # roughly 9 MB -- far more than any real program compiles, but a bound
@@ -16,13 +16,24 @@ class CArray
16
16
  # goes back to CArray, which walks it and arrives at the same answer.
17
17
  class Expression
18
18
 
19
+ # A kernel that can divide by zero calls ca_zerodiv, which the CArray
20
+ # extension defines and this object does not. ELF is content to leave
21
+ # the name undefined and resolve it when the object is loaded, which is
22
+ # what the declaration in #source_for assumes; Mach-O refuses to link at
23
+ # all, so on macOS every expression holding an integer `/` or `%` failed
24
+ # to compile and was silently handed back to CArray to walk. The flag
25
+ # says to look the name up at load time, which is what Ruby builds its
26
+ # own extensions with and the only thing this object leaves undefined.
27
+ DYNAMIC_LOOKUP =
28
+ (RbConfig::CONFIG["host_os"] =~ /darwin/ ? ["-Wl,-undefined,dynamic_lookup"] : []).freeze
29
+
19
30
  # Built the way CArray's own kernels were, since that is what the answer
20
31
  # is being compared against. The Prism front end wants the opposite of
21
32
  # this on one point -- it answers to a Ruby loop, which does not fuse a
22
33
  # multiply and an add into one rounding, so it compiles with
23
34
  # -ffp-contract=off. Here the reference is the eager kernel, which was
24
35
  # built with whatever CArray settled on.
25
- FLAGS = ["-fPIC", "-shared", *CArray::BUILD_FLAGS.split].freeze
36
+ FLAGS = ["-fPIC", "-shared", *CArray::BUILD_FLAGS.split, *DYNAMIC_LOOKUP].freeze
26
37
 
27
38
  C_TYPES = {
28
39
  float64: "double", float32: "float",
@@ -37,7 +48,9 @@ class CArray
37
48
  @kernels = {}
38
49
  end
39
50
 
40
- # Fills `out` and returns true, or writes nothing and returns false.
51
+ # Fills `out` and returns true, or returns false and leaves it to
52
+ # CArray. A decline may have written part of `out` first, which is
53
+ # what walking it over again then settles.
41
54
  def call (plan, out)
42
55
  return false unless C_TYPES.key?(plan.data_type)
43
56
  aliased = plan.leaves.any? { |array| array.equal?(out) }
@@ -51,6 +64,25 @@ class CArray
51
64
  kernel.call(out.elements, *pointers(plan, bases))
52
65
  end
53
66
  true
67
+ rescue ZeroDivisionError
68
+ # A zero divisor is an answer, not a fault: it is what ca_zerodiv --
69
+ # the only thing a kernel here calls out to -- reports, and the same
70
+ # expression walked reaches the same place and raises the same error.
71
+ #
72
+ # CArray cannot tell the two apart, though. It catches whatever an
73
+ # evaluator raises, retires it for the rest of the process and says so
74
+ # on stderr, which is right for an evaluator that is broken and wrong
75
+ # for one that has just met a zero. So this declines instead, and
76
+ # CArray walks the expression and raises it there. Anything else
77
+ # still reaches CArray and still retires this, which is what that net
78
+ # is for.
79
+ #
80
+ # What it costs: a kernel that raised where the walk does not -- over
81
+ # a masked zero, say -- now reads as slow rather than as wrong, since
82
+ # the walk answers and nobody sees the difference. The answer is
83
+ # right either way, and the masked-divisor test asks the evaluator
84
+ # directly for that reason.
85
+ false
54
86
  end
55
87
 
56
88
  private
@@ -1,5 +1,5 @@
1
1
  class CArray
2
2
  module JIT
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.1"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carray-jit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - himotoyoshi
@@ -133,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
133
  - !ruby/object:Gem::Version
134
134
  version: '0'
135
135
  requirements: []
136
- rubygems_version: 4.0.17
136
+ rubygems_version: 4.0.8
137
137
  specification_version: 4
138
138
  summary: JIT compilation of CArray kernels written in Ruby
139
139
  test_files: []