Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[hail/ptypes] copy based on ptype and requiredeness #7639

Merged
merged 90 commits into from
Jan 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
3e02787
order roundUpAlignment to be the same
akotlar Nov 7, 2019
da6eb1a
wip
akotlar Nov 29, 2019
aeb525f
more efficient checked convert, clarified offset use
akotlar Nov 30, 2019
3532dcd
fix
akotlar Nov 30, 2019
da26541
in case jvm and scala hae different coercion rules
akotlar Nov 30, 2019
d6206e2
wip
akotlar Nov 30, 2019
bca7611
vectorized version over longs
akotlar Nov 30, 2019
adaebe8
factor out the missingness check
akotlar Nov 30, 2019
42d62f3
better type check
akotlar Nov 30, 2019
e0fdd06
wip
akotlar Nov 30, 2019
af058f7
merge
akotlar Nov 30, 2019
69837e9
wip
akotlar Nov 30, 2019
5201abc
move test
akotlar Dec 1, 2019
b23fde9
wip
akotlar Dec 1, 2019
0508371
cleanup
akotlar Dec 1, 2019
0b5eb1f
cleanup
akotlar Dec 1, 2019
125ab0d
cleanup
akotlar Dec 2, 2019
6415b75
cleanup
akotlar Dec 2, 2019
1ac9441
remove read, irrelevant for this pr
akotlar Dec 2, 2019
3b11997
cleanup
akotlar Dec 2, 2019
5bc1f64
merge master
akotlar Dec 2, 2019
d4adb22
fix
akotlar Dec 2, 2019
34abefe
cleanup
akotlar Dec 2, 2019
dcfca5e
merge
akotlar Dec 18, 2019
8e478a8
fix
akotlar Dec 18, 2019
e72ddcb
Merge branch 'master' of github.com:hail-is/hail into ptype-upcast
akotlar Dec 19, 2019
0248b8d
wip
akotlar Dec 19, 2019
0292be5
wip
akotlar Dec 20, 2019
a5d650c
wip
akotlar Dec 20, 2019
faa0fbb
wip
akotlar Dec 21, 2019
e99d6b5
working for PContainer
akotlar Dec 21, 2019
0fa1156
note on deep copy
akotlar Dec 21, 2019
9af2ae3
cleanup
akotlar Dec 21, 2019
26e9169
fix when deepCopy disabled
akotlar Dec 21, 2019
e8ed486
cleanup at some minor cost to efficiency, remove cast to pcontainer
akotlar Dec 21, 2019
8ff741b
cleanup
akotlar Dec 21, 2019
a342552
start implementating copyFromType, move storeShallowAtAddress for non…
akotlar Dec 21, 2019
4810ee3
wip, implement complex and PCanonicalNDArray copyFromType methods. sp…
akotlar Dec 21, 2019
bab7137
trailing newline
akotlar Dec 21, 2019
cbbda64
fix forceDeep
akotlar Dec 22, 2019
f9617d0
partial cleanup of tests with minor comments
akotlar Dec 22, 2019
6331b50
cleanup
akotlar Dec 22, 2019
5b731e8
cleanup tests
akotlar Dec 22, 2019
4160ef7
wip
akotlar Dec 27, 2019
7d0c8e3
wip
akotlar Jan 7, 2020
a85a456
simplify clearMissingBits, setAllMissing
akotlar Jan 8, 2020
187168c
fix
akotlar Jan 8, 2020
5741984
wip
akotlar Jan 8, 2020
5590ed4
merge
akotlar Jan 8, 2020
dec1cf6
Merge branch 'master' of github.com:hail-is/hail into ptype-upcast
akotlar Jan 8, 2020
0935f6c
fix
akotlar Jan 8, 2020
f9b2189
wip
akotlar Jan 9, 2020
6332522
stagedInitialize method
akotlar Jan 9, 2020
83c3898
add non-staged version
akotlar Jan 9, 2020
7552aeb
formatting
akotlar Jan 9, 2020
eea41b3
merge
akotlar Jan 9, 2020
91f2e05
add failing test
akotlar Jan 9, 2020
2ebae40
wip
akotlar Jan 9, 2020
da7f6fb
nearly working test; moved copyFromType back to PBaseStruct
akotlar Jan 10, 2020
a6d62ce
working test, but failing on array nested in struct due to segmentati…
akotlar Jan 10, 2020
00af1bb
merge
akotlar Jan 10, 2020
0978fa7
fixed PContainer test
akotlar Jan 10, 2020
56ad469
working tests, refactored shared copyTest into util package
akotlar Jan 10, 2020
b0c1058
wip
akotlar Jan 10, 2020
4b802ac
move PCanonicalArray implementation to fundamental types
akotlar Jan 10, 2020
f51ab95
refactor
akotlar Jan 10, 2020
492965d
cleanup
akotlar Jan 10, 2020
e28dd16
cleanup
akotlar Jan 10, 2020
157f498
cleanup, remove unnecessary arch changes
akotlar Jan 10, 2020
4a604a6
fix fundamentalType use in PBaseStruct
akotlar Jan 11, 2020
ca3c5b1
rename tests
akotlar Jan 11, 2020
3add474
add string for PCanonicalBinary, vis-a-vis PCanonicalString
akotlar Jan 11, 2020
ba36d89
add dict, set, tuple tests
akotlar Jan 11, 2020
ef4e60a
add PCanonicalNDArray test
akotlar Jan 11, 2020
8884e41
cleanup
akotlar Jan 11, 2020
c3503e6
move PContainerTest back for easier GitHub diff
akotlar Jan 11, 2020
5fbfe42
add interval test
akotlar Jan 11, 2020
c71ac66
add PCallSuite
akotlar Jan 11, 2020
1e2debc
fix placement of assert
akotlar Jan 11, 2020
d4a0f30
move to fundamentalType
akotlar Jan 11, 2020
921c7e8
don't run unnecessary assertion
akotlar Jan 11, 2020
9a83509
improve comment
akotlar Jan 11, 2020
1346f3e
add storeShallowAtOffset to all non-primitives
akotlar Jan 14, 2020
87ce25d
remove downcast, add fast path for equal types
akotlar Jan 15, 2020
cddc0a6
cleanup
akotlar Jan 15, 2020
395d831
cleanup
akotlar Jan 15, 2020
a4ff53e
addressed
akotlar Jan 16, 2020
19df4c9
rename loop function
akotlar Jan 16, 2020
e813488
addressed comments
akotlar Jan 16, 2020
596b9a1
merge master
akotlar Jan 16, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package is.hail.expr.types.physical

import is.hail.annotations.UnsafeOrdering
import is.hail.annotations.{Region, UnsafeOrdering}
import is.hail.asm4s.{Code, MethodBuilder}

abstract class ComplexPType extends PType {
val representation: PType
Expand All @@ -14,4 +15,21 @@ abstract class ComplexPType extends PType {
override def fundamentalType: PType = representation.fundamentalType

override def containsPointers: Boolean = representation.containsPointers

override def storeShallowAtOffset(dstAddress: Code[Long], valueAddress: Code[Long]): Code[Unit] =
this.representation.storeShallowAtOffset(dstAddress, valueAddress)

override def storeShallowAtOffset(dstAddress: Long, valueAddress: Long) {
this.representation.storeShallowAtOffset(dstAddress, valueAddress)
}

override def copyFromType(mb: MethodBuilder, region: Code[Region], srcPType: PType, srcAddress: Code[Long], forceDeep: Boolean): Code[Long] = {
assert(this isOfType srcPType)

val srcRepPType = srcPType.asInstanceOf[ComplexPType].representation

this.representation.copyFromType(mb, region, srcRepPType, srcAddress, forceDeep)
}

override def copyFromType(region: Region, srcPType: PType, srcAddress: Long, forceDeep: Boolean): Long = ???
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package is.hail.expr.types.physical

import is.hail.annotations.{Region, UnsafeOrdering}
import is.hail.asm4s.{Code, MethodBuilder}
import is.hail.asm4s.{???, Code, MethodBuilder}
import is.hail.expr.ir.EmitMethodBuilder

trait PArrayBackedContainer extends PContainer {
Expand Down Expand Up @@ -110,6 +110,9 @@ trait PArrayBackedContainer extends PContainer {
def loadElement(aoff: Long, length: Int, i: Int): Long =
arrayRep.loadElement(aoff, length, i)

def loadElementAddress(aoff: Code[Long], length: Code[Int], i: Code[Int]): Code[Long] =
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needed to be called something other than loadElement, because scala cannot distinguish between Code[Region] and Code[Long] types in the argument list, and besides this (arity, other argument types), this method is identical to loadElement(region: Code[Region] ...), leading to type check errors.

Later on, in the PR corresponding to #7826, the region-bearing methods will go away.
references #7829

arrayRep.loadElementAddress(aoff, length, i)

def loadElement(region: Region, aoff: Long, length: Int, i: Int): Long =
arrayRep.loadElement(region, aoff, length, i)

Expand Down Expand Up @@ -164,7 +167,29 @@ trait PArrayBackedContainer extends PContainer {
def copyFrom(mb: MethodBuilder, region: Code[Region], srcOff: Code[Long]): Code[Long] =
arrayRep.copyFrom(mb, region, srcOff)

override def unsafeOrdering: UnsafeOrdering = unsafeOrdering(this)
override def unsafeOrdering: UnsafeOrdering =
unsafeOrdering(this)

override def unsafeOrdering(rightType: PType): UnsafeOrdering =
arrayRep.unsafeOrdering(rightType)

override def copyFromType(mb: MethodBuilder, region: Code[Region], srcPType: PType, srcAddress: Code[Long], forceDeep: Boolean): Code[Long] = {
assert(srcPType.isInstanceOf[PArrayBackedContainer])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could be more general here, allow copying with a PArray as well.

this.arrayRep.copyFromType(mb, region, srcPType.asInstanceOf[PArrayBackedContainer].arrayRep, srcAddress, forceDeep)
}

override def copyFromType(region: Region, srcPType: PType, srcAddress: Long, forceDeep: Boolean): Long = ???

override def storeShallowAtOffset(dstAddress: Code[Long], valueAddress: Code[Long]): Code[Unit] =
this.arrayRep.storeShallowAtOffset(dstAddress, valueAddress)

override def storeShallowAtOffset(dstAddress: Long, valueAddress: Long) {
this.arrayRep.storeShallowAtOffset(dstAddress, valueAddress)
}

def nextElementAddress(currentOffset: Long) =
arrayRep.nextElementAddress(currentOffset)

override def unsafeOrdering(rightType: PType): UnsafeOrdering = arrayRep.unsafeOrdering(rightType)
def nextElementAddress(currentOffset: Code[Long]) =
arrayRep.nextElementAddress(currentOffset)
}
136 changes: 131 additions & 5 deletions hail/src/main/scala/is/hail/expr/types/physical/PBaseStruct.scala
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ abstract class PBaseStruct extends PType {
}

def identBase: String

def _asIdent: String = {
val sb = new StringBuilder
sb.append(identBase)
Expand Down Expand Up @@ -147,7 +148,30 @@ abstract class PBaseStruct extends PType {
region.allocate(alignment, byteSize)
}

def allocate(region: Code[Region]): Code[Long] = region.allocate(alignment, byteSize)
def allocate(region: Code[Region]): Code[Long] =
region.allocate(alignment, byteSize)

def copyFrom(region: Region, srcAddress: Long): Long = {
val destAddress = this.allocate(region)
this.storeShallowAtOffset(destAddress, srcAddress)
destAddress
}

def copyFrom(mb: MethodBuilder, region: Code[Region], srcAddress: Code[Long]): Code[Long] = {
val destAddress = mb.newField[Long]
Code(
destAddress := this.allocate(region),
this.storeShallowAtOffset(destAddress, srcAddress),
destAddress
)
}

override def storeShallowAtOffset(destAddress: Code[Long], srcAddress: Code[Long]): Code[Unit] =
Region.copyFrom(srcAddress, destAddress, this.byteSize)

override def storeShallowAtOffset(destAddress: Long, srcAddress: Long) {
Region.copyFrom(srcAddress, destAddress, this.byteSize)
}

def initialize(structAddress: Long, setMissing: Boolean = false): Unit = {
if (allFieldsRequired) {
Expand Down Expand Up @@ -217,11 +241,11 @@ abstract class PBaseStruct extends PType {
def setFieldPresent(region: Code[Region], offset: Code[Long], fieldIdx: Int): Code[Unit] =
setFieldPresent(offset, fieldIdx)

def fieldOffset(offset: Long, fieldIdx: Int): Long =
offset + byteOffsets(fieldIdx)
def fieldOffset(structAddress: Long, fieldIdx: Int): Long =
structAddress + byteOffsets(fieldIdx)

def fieldOffset(offset: Code[Long], fieldIdx: Int): Code[Long] =
offset + byteOffsets(fieldIdx)
def fieldOffset(structAddress: Code[Long], fieldIdx: Int): Code[Long] =
structAddress + byteOffsets(fieldIdx)

def loadField(rv: RegionValue, fieldIdx: Int): Long = loadField(rv.region, rv.offset, fieldIdx)

Expand All @@ -248,5 +272,107 @@ abstract class PBaseStruct extends PType {
}
}

def deepCopyFromAddress(mb: MethodBuilder, region: Code[Region], srcStructAddress: Code[Long]): Code[Long] = {
val dstAddress = mb.newField[Long]
Code(
dstAddress := this.copyFrom(mb, region, srcStructAddress),
this.deepPointerCopy(mb, region, dstAddress),
dstAddress
)
}

def deepPointerCopy(mb: MethodBuilder, region: Code[Region], dstStructAddress: Code[Long]): Code[Unit] = {
var c: Code[Unit] = Code._empty

var i = 0
while(i < this.size) {
val dstFieldType = this.fields(i).typ.fundamentalType
if(dstFieldType.containsPointers) {
val dstFieldAddress = mb.newField[Long]
c = Code(
c,
this.isFieldDefined(dstStructAddress, i).orEmpty(
Code(
dstFieldAddress := this.fieldOffset(dstStructAddress, i),
dstFieldType match {
case t@(_: PBinary | _: PArray) =>
t.storeShallowAtOffset(dstFieldAddress, t.copyFromType(mb, region, dstFieldType, Region.loadAddress(dstFieldAddress)))
case t: PBaseStruct =>
t.deepPointerCopy(mb, region, dstFieldAddress)
case t: PType =>
fatal(s"Field type isn't supported ${t}")
}
)
)
)
}
i += 1
}

c
}

override def copyFromType(mb: MethodBuilder, region: Code[Region], srcPType: PType, srcStructAddress: Code[Long],
forceDeep: Boolean): Code[Long] = {
assert(srcPType.isInstanceOf[PBaseStruct])

val sourceType = srcPType.asInstanceOf[PBaseStruct]

assert(sourceType.size == this.size)

val sourceFundamentalTypes = sourceType.fields.map(_.typ.fundamentalType)
if(this.fields.map(_.typ.fundamentalType) == sourceFundamentalTypes) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this check seems insufficient to me. What if there are two different PStruct types with teh same fields? You can't copy the address in this case.

Copy link
Contributor Author

@akotlar akotlar Jan 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would 2 different case classes that happened to have the same attribute values be equal? Meaning PStruct(fields: Seq("1" -> 2)) == PNonCanonicalStruct(fields: Seq("1"->2))? That seems very odd if so, I imagine (I think the equality is hash based), the value that is hashed included the class name (and probably much more metadata)

if(!forceDeep) {
return srcStructAddress
}

return this.deepCopyFromAddress(mb, region, srcStructAddress)
}

val dstStructAddress = mb.newField[Long]
var loop: Code[_] = Code()
var i = 0
while(i < this.size) {
val dstField = this.fields(i)
val srcField = sourceType.fields(i)

assert((dstField.typ.required <= srcField.typ.required) && (dstField.typ isOfType srcField.typ) && (dstField.name == srcField.name) && (dstField.index == srcField.index))

val srcFieldType = srcField.typ.fundamentalType
val dstFieldType = dstField.typ.fundamentalType

val body = srcFieldType.storeShallowAtOffset(
this.fieldOffset(dstStructAddress, dstField.index),
dstFieldType.copyFromType(
mb,
region,
srcFieldType,
sourceType.loadField(srcStructAddress, srcField.index),
forceDeep
)
)

if(!srcFieldType.required) {
loop = Code(loop, sourceType.isFieldMissing(srcStructAddress, srcField.index).mux(
this.setFieldMissing(dstStructAddress, dstField.index),
body
))
} else {
loop = Code(loop, body)
}

i+=1
}

Code(
dstStructAddress := this.allocate(region),
this.stagedInitialize(dstStructAddress),
loop,
dstStructAddress
)
}

override def copyFromType(region: Region, srcPType: PType, srcAddress: Long, forceDeep: Boolean): Long = ???

override def containsPointers: Boolean = types.exists(_.containsPointers)
}
14 changes: 10 additions & 4 deletions hail/src/main/scala/is/hail/expr/types/physical/PBinary.scala
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,19 @@ object PBinary {

def contentByteSize(length: Code[Int]): Code[Long] = PCanonicalBinary.contentByteSize(length)

def loadLength(boff: Long): Int = PCanonicalBinary.loadLength(boff)
def loadLength(bAddress: Long): Int = PCanonicalBinary.loadLength(bAddress)

def loadLength(region: Region, boff: Long): Int = PCanonicalBinary.loadLength(boff)
def loadLength(region: Region, bAddress: Long): Int = PCanonicalBinary.loadLength(bAddress)

def loadLength(boff: Code[Long]): Code[Int] = PCanonicalBinary.loadLength(boff)
def loadLength(bAddress: Code[Long]): Code[Int] = PCanonicalBinary.loadLength(bAddress)

def loadLength(region: Code[Region], boff: Code[Long]): Code[Int] = PCanonicalBinary.loadLength(boff)
def loadLength(region: Code[Region], bAddress: Code[Long]): Code[Int] = PCanonicalBinary.loadLength(bAddress)

def loadBytes(bAddress: Code[Long]): Code[Array[Byte]] =
Region.loadBytes(PBinary.bytesOffset(bAddress), PBinary.loadLength(bAddress))

def loadBytes(bAddress: Long): Array[Byte] =
Region.loadBytes(PBinary.bytesOffset(bAddress), PBinary.loadLength(bAddress))

def storeLength(boff: Long, len: Int): Unit = PCanonicalBinary.storeLength(boff, len)

Expand Down
14 changes: 13 additions & 1 deletion hail/src/main/scala/is/hail/expr/types/physical/PBoolean.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package is.hail.expr.types.physical

import is.hail.annotations.{Region, UnsafeOrdering, _}
import is.hail.asm4s.Code
import is.hail.asm4s.{Code, MethodBuilder}
import is.hail.expr.ir.EmitMethodBuilder
import is.hail.expr.types.virtual.TBoolean

Expand Down Expand Up @@ -34,6 +34,18 @@ class PBoolean(override val required: Boolean) extends PType {
}

override def byteSize: Long = 1

def storeShallowAtOffset(dstAddress: Code[Long], srcAddress: Code[Long]): Code[Unit] =
Region.storeBoolean(dstAddress, Region.loadBoolean(srcAddress))

def storeShallowAtOffset(dstAddress: Long, srcAddress: Long) =
Region.storeBoolean(dstAddress, Region.loadBoolean(srcAddress))

def copyFromType(region: Region, srcPType: PType, srcAddress: Long, forceDeep: Boolean): Long =
srcAddress

def copyFromType(mb: MethodBuilder, region: Code[Region], srcPType: PType, srcAddress: Code[Long], forceDeep: Boolean): Code[Long] =
srcAddress
}

object PBoolean {
Expand Down
Loading