andygrove commented on code in PR #6730:
URL: https://github.com/apache/datafusion-comet/pull/6730#discussion_r4211294610


##########
spark/src/test/scala/org/apache/spark/sql/comet/execution/arrow/CometArrowWriterSuite.scala:
##########
@@ -640,4 +656,146 @@ class CometArrowWriterSuite extends AnyFunSuite with 
Matchers {
       }
     }
   }
+
+  // Nested shapes whose unsafe forms take paths of their own: elements 
converted one at a time,
+  // collections inside collections, and a struct wider than one word of null 
bits.
+  private val moreNestedTypes: Seq[DataType] = Seq(

Review Comment:
   Done in 61ec88b771. `moreNestedTypes` now starts with 
`primitiveTypes.map(ArrayType(_))`, which also replaces the boolean, 
decimal(38,10) and binary arrays that were listed by hand. I logged which 
vectors reach the block copy while the suite runs. Before, only `IntVector` and 
`BigIntVector` did. Now all twelve in `unsafeValueWidth` do, including 
`TinyIntVector` and `SmallIntVector`, and `TimeNanoVector` on 4.1.
   



##########
spark/src/main/scala/org/apache/spark/sql/comet/execution/arrow/ArrowWriters.scala:
##########
@@ -1384,16 +1627,59 @@ private[arrow] class TimeNanoWriter(val valueVector: 
TimeNanoVector)
 private[arrow] class ArrayWriter(val valueVector: ListVector, val 
elementWriter: ArrowFieldWriter)
     extends ArrowFieldWriter {
 
+  // Pointed at each unsafe array in turn, rather than allocating a view per 
value.
+  private val elements = new UnsafeArrayData
+
   override def setNull(): Unit = {}
 
   override def setValue(input: SpecializedGetters, ordinal: Int): Unit = {
-    val array = input.getArray(ordinal)
+    input.getArray(ordinal) match {
+      case unsafe: UnsafeArrayData =>
+        writeElements(unsafe)
+      case array =>
+        val numElements = array.numElements()
+        valueVector.startNewValue(count)
+        var i = 0
+        while (i < numElements) {
+          elementWriter.write(array, i)
+          i += 1
+        }
+        valueVector.endValue(count, numElements)
+    }
+  }
+
+  override private[arrow] def writeUnsafeRowField(row: UnsafeRow, ordinal: 
Int): Unit = {

Review Comment:
   I tried this, and it costs more than I expected. As a private method in each 
writer, `writeUnsafe` is bound statically and inlined. In a shared 
`writeArrayElements` and `writeUnsafeRowField` it becomes one virtual call site 
for all three writers, which goes megamorphic once a JVM has converted arrays, 
maps and structs. I warmed every case together and ran four case orders, with 
three alternating JVMs each. The shared class was 2-10% slower on most nested 
shapes, most of all on array<int>, array<struct<int,string>>, array<array<int>> 
and struct<int,string>, and level on flat ones. So I'd rather keep the three 
copies. The differential tests cover each of them, as the three stale-view 
mutations show, so a change that misses one of them fails.
   
   The shared class did win on array<map<string,int>>, at 103 ns per row 
against 120-178, but that turned out to be a separate C2 quirk. When C2 inlines 
`MapWriter.writeEntries` into the loop over the array's maps, that loop is slow 
under a mixed profile, and the shared class only avoided it because its 
megamorphic call stops the inlining. `-XX:CompileCommand=dontinline` on 
`writeEntries` also gives 103, and so does warming only that shape. `main` 
takes 211 on it, so this isn't a regression, and I filed #6757 to dig into it.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to