|
17 | 17 |
|
18 | 18 | package org.apache.spark.sql.execution.metric |
19 | 19 |
|
20 | | -import java.io.{ByteArrayInputStream, ByteArrayOutputStream} |
21 | | - |
22 | | -import scala.collection.mutable |
23 | | - |
24 | | -import org.apache.xbean.asm5._ |
25 | | -import org.apache.xbean.asm5.Opcodes._ |
26 | | - |
27 | 20 | import org.apache.spark.SparkFunSuite |
28 | 21 | import org.apache.spark.sql._ |
29 | 22 | import org.apache.spark.sql.execution.SparkPlanInfo |
30 | 23 | import org.apache.spark.sql.execution.ui.SparkPlanGraph |
31 | 24 | import org.apache.spark.sql.functions._ |
32 | 25 | import org.apache.spark.sql.internal.SQLConf |
33 | 26 | import org.apache.spark.sql.test.SharedSQLContext |
34 | | -import org.apache.spark.util.{AccumulatorContext, JsonProtocol, Utils} |
35 | | - |
| 27 | +import org.apache.spark.util.{AccumulatorContext, JsonProtocol} |
36 | 28 |
|
37 | 29 | class SQLMetricsSuite extends SparkFunSuite with SharedSQLContext { |
38 | 30 | import testImplicits._ |
39 | 31 |
|
40 | | - test("SQLMetric should not box Long") { |
41 | | - val l = SQLMetrics.createMetric(sparkContext, "long") |
42 | | - val f = () => { |
43 | | - l += 1L |
44 | | - l.add(1L) |
45 | | - } |
46 | | - val cl = BoxingFinder.getClassReader(f.getClass) |
47 | | - val boxingFinder = new BoxingFinder() |
48 | | - cl.accept(boxingFinder, 0) |
49 | | - assert(boxingFinder.boxingInvokes.isEmpty, s"Found boxing: ${boxingFinder.boxingInvokes}") |
50 | | - } |
51 | | - |
52 | 32 | /** |
53 | 33 | * Call `df.collect()` and verify if the collected metrics are same as "expectedMetrics". |
54 | 34 | * |
@@ -313,76 +293,3 @@ class SQLMetricsSuite extends SparkFunSuite with SharedSQLContext { |
313 | 293 | } |
314 | 294 |
|
315 | 295 | } |
316 | | - |
317 | | -private case class MethodIdentifier[T](cls: Class[T], name: String, desc: String) |
318 | | - |
319 | | -/** |
320 | | - * If `method` is null, search all methods of this class recursively to find if they do some boxing. |
321 | | - * If `method` is specified, only search this method of the class to speed up the searching. |
322 | | - * |
323 | | - * This method will skip the methods in `visitedMethods` to avoid potential infinite cycles. |
324 | | - */ |
325 | | -private class BoxingFinder( |
326 | | - method: MethodIdentifier[_] = null, |
327 | | - val boxingInvokes: mutable.Set[String] = mutable.Set.empty, |
328 | | - visitedMethods: mutable.Set[MethodIdentifier[_]] = mutable.Set.empty) |
329 | | - extends ClassVisitor(ASM5) { |
330 | | - |
331 | | - private val primitiveBoxingClassName = |
332 | | - Set("java/lang/Long", |
333 | | - "java/lang/Double", |
334 | | - "java/lang/Integer", |
335 | | - "java/lang/Float", |
336 | | - "java/lang/Short", |
337 | | - "java/lang/Character", |
338 | | - "java/lang/Byte", |
339 | | - "java/lang/Boolean") |
340 | | - |
341 | | - override def visitMethod( |
342 | | - access: Int, name: String, desc: String, sig: String, exceptions: Array[String]): |
343 | | - MethodVisitor = { |
344 | | - if (method != null && (method.name != name || method.desc != desc)) { |
345 | | - // If method is specified, skip other methods. |
346 | | - return new MethodVisitor(ASM5) {} |
347 | | - } |
348 | | - |
349 | | - new MethodVisitor(ASM5) { |
350 | | - override def visitMethodInsn( |
351 | | - op: Int, owner: String, name: String, desc: String, itf: Boolean) { |
352 | | - if (op == INVOKESPECIAL && name == "<init>" || op == INVOKESTATIC && name == "valueOf") { |
353 | | - if (primitiveBoxingClassName.contains(owner)) { |
354 | | - // Find boxing methods, e.g, new java.lang.Long(l) or java.lang.Long.valueOf(l) |
355 | | - boxingInvokes.add(s"$owner.$name") |
356 | | - } |
357 | | - } else { |
358 | | - // scalastyle:off classforname |
359 | | - val classOfMethodOwner = Class.forName(owner.replace('/', '.'), false, |
360 | | - Thread.currentThread.getContextClassLoader) |
361 | | - // scalastyle:on classforname |
362 | | - val m = MethodIdentifier(classOfMethodOwner, name, desc) |
363 | | - if (!visitedMethods.contains(m)) { |
364 | | - // Keep track of visited methods to avoid potential infinite cycles |
365 | | - visitedMethods += m |
366 | | - val cl = BoxingFinder.getClassReader(classOfMethodOwner) |
367 | | - visitedMethods += m |
368 | | - cl.accept(new BoxingFinder(m, boxingInvokes, visitedMethods), 0) |
369 | | - } |
370 | | - } |
371 | | - } |
372 | | - } |
373 | | - } |
374 | | -} |
375 | | - |
376 | | -private object BoxingFinder { |
377 | | - |
378 | | - def getClassReader(cls: Class[_]): ClassReader = { |
379 | | - val className = cls.getName.replaceFirst("^.*\\.", "") + ".class" |
380 | | - val resourceStream = cls.getResourceAsStream(className) |
381 | | - val baos = new ByteArrayOutputStream(128) |
382 | | - // Copy data over, before delegating to ClassReader - |
383 | | - // else we can run out of open file handles. |
384 | | - Utils.copyStream(resourceStream, baos, true) |
385 | | - new ClassReader(new ByteArrayInputStream(baos.toByteArray)) |
386 | | - } |
387 | | - |
388 | | -} |
0 commit comments