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

java.io.NotSerializableException - what needs to be serializable? #155

Open
peerden-visier opened this issue Oct 27, 2015 · 1 comment
Open

Comments

@peerden-visier
Copy link

I have a test that fails to complete with the following exception:

[error] Error running separate JVM: java.io.NotSerializableException: com.mycompany.test.utilities.framework.builder.MyClassImpl
[error] Classpath: /usr/bin/activator/activator-1.2.10/activator-launch-1.2.10.jar
java.io.NotSerializableException: com.mycompany.test.utilities.framework.builder.MyClassImpl
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeArray(ObjectOutputStream.java:1378)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at org.scalameter.execution.Main$.saveResult(Main.scala:39)
at org.scalameter.execution.Main$.mainMethod(Main.scala:17)
at org.scalameter.execution.Main$.main(Main.scala:10)
at org.scalameter.execution.Main.main(Main.scala)
[error] Could not run test com.mycompany.mymodule.test.benchmark.PerformanceBenchmarkSuite: java.io.NotSerializableException: com.mycompany.test.utilities.framework.builder.MyClassImpl

In this case, MyClassImpl is part of a set of utilities used to create a fairly large object that is needed for the test. Once the test is completed, this error occurs (preventing subsequent tests in the suite from starting). If I make MyClassImpl serializable, the error just shifts to another class in the same set of utilities. Setting as many as I can to be serializable, I eventually started getting into classes that I don't own and cannot modify. I'm not sure why any of these even need to be serializable.

Here is the general (simplified) structure of my suite:

object PerformanceBenchmarkSuite extends MyBenchmark with MyModuleBenchmarkTest {

  val testAction1 = (o1: Object1, ... ) => createAction(o1, ... ).setStuff(myValue1)

  runBenchmark("Shape Group 1", parameterValue1, shapeGroup1, testAction1)
  runBenchmark("Shape Group 2", parameterValue1, shapeGroup2, testAction1)

  val testAction2 = (o1: Object1, ... ) => createAction(o1, ... ).setStuff(myValue2)

  runBenchmark("Shape Group 1", parameterValue2, shapeGroup1, testAction2)
  runBenchmark("Shape Group 2", parameterValue2, shapeGroup2, testAction2)

}

and the trait it extends:

trait MyBenchmark extends PerformanceTest with MyModule with Serializable {

  case class Shape ( val name: String, 
                     val arg1: Int, ... )

  lazy val shape1 = Shape( "Shape 1",  ... )
  ...

  val shapeGroup1 = Gen.enumeration("Test Shapes Group 1")(
    shape1,
    ...
  )
  ...

  def objectsBasedOnShapes(shapes: Gen[Shape]): Gen[(String, ObjectType1, ObjectType2)] = {
    for {
      shape <- shapes
    } yield getObjectsTuple(shape)
  }

  def getObjectsTuple(shape: Shape): (String, Object1, ... )= {
    val o1 = RandomizedData.build(shape.arg1, ... )
    ...
    return (shape.name, o1, ...)
  }

  //Scalameter Specific Configuration
  def executor = SeparateJvmsExecutor(
    new Executor.Warmer.Default,
    Aggregator.average,
    new CustomMeasure)
  def reporter = new LoggingReporter
  def persistor = Persistor.None

  var benchRuns = exec.benchRuns -> 20
  var independentSamples = exec.independentSamples -> 1
  val warmups = exec.maxWarmupRuns -> 5
  val jvmFlags = exec.jvmflags-> "-Xms8g -Xmx8g -Dscala.collection.parallel.range.manual_optimizations=false"

  def runBenchmark(name: String, parameter: Parameter.Value, shapes: Gen[Shape], action : (Object1, ... ) => Action): Unit = {
    performance of name in {
      measure method parameter.toString in {
        using(objectsBasedOnShapes(shapes)) config (
          benchRuns, independentSamples, warmups, jvmFlags
          ) in { case (name, o1, ... ) =>
          Console.println("Benchmark: " + n + " - " + parameter + ": " + action(o1, ... )
            .setParameterId(parameter)
            .run()
            .getValue())
        }
      }
    }
  }

}

class CustomMeasure extends Measurer with Measurer.IterationBasedValue {
  def name = "Measure.CustomMeasure"

  def measure[T, U](context: org.scalameter.Context, measurements: Int, setup: T => Any,
                    tear: T => Any, regen: () => T, snippet: T => Any): Seq[Double] = {
    val times = ListBuffer[Double]()

    var value: T = null.asInstanceOf[T]
    var obj: Any = null.asInstanceOf[Any]

    // Variation on a memory measurer
    ...

    times
  }
}
@axel22
Copy link
Member

axel22 commented Nov 2, 2015

Hi,

On 10/27/2015 1:12 AM, peerden-visier wrote:

I have a test that fails to complete with the following exception:

[error] Error running separate JVM: java.io.NotSerializableException: com.mycompany.test.utilities.framework.builder.MyClassImpl
[error] Classpath: /usr/bin/activator/activator-1.2.10/activator-launch-1.2.10.jar
java.io.NotSerializableException: com.mycompany.test.utilities.framework.builder.MyClassImpl
...
at org.scalameter.execution.Main.main(Main.scala)
[error] Could not run test com.mycompany.,ymodule.test.benchmark.PerformanceBenchmarkSuite: java.io.NotSerializableException: com.mycompany.test.utilities.framework.builder.MyClassImpl

In this case, MyClassImpl is part of a set of utilities used to create a fairly large object that is needed for the test.
Once the test is completed, this error occurs (preventing subsequent
tests in the suite from starting).
If I make MyClassImpl serializable, the error just shifts to another
class in the same set of utilities.
Setting as many as I can to be serializable, I eventually started
getting into classes that I didn't own and could not modify. I'm not
sure why any of these even need to be serializable.

ScalaMeter needs to serialize the closure with the benchmark code to
send it to another JVM for measurements (in case your using the separate
JVM Executor).
This closure can capture stuff from the environment which is not
serializable.

Make sure that the utils object does not get serialized.
One way to do that is to move the MyClassImpl functionality into a
top-level object.

Alternatively, make the utils object and everything in it serializable.

Third option is to use a LocalExecutor so that the test is run in the
same JVM. If your benchmark is large enough or otherwise not affected by
being run in the same JVM, it should not matter give the same results.

Here is the general (simplified) structure of my suite:
object PerformanceBenchmarkSuite extends MyBenchmark with MyModuleBenchmarkTest {

val testAction1 = (o1: Object1, ... ) => createAction(o1, ... ).setStuff(myValue1)

runBenchmark("Shape Group 1", parameterValue1, shapeGroup1, testAction1)
runBenchmark("Shape Group 2", parameterValue1, shapeGroup2, testAction1)

val testAction2 = (o1: Object1, ... ) => createAction(o1, ... ).setStuff(myValue2)

runBenchmark("Shape Group 1", parameterValue2, shapeGroup1, testAction2)
runBenchmark("Shape Group 2", parameterValue2, shapeGroup2, testAction2)

}

I don't see any MyClassImpl here.

and the trait it extends:
trait MyBenchmark extends PerformanceTest with MyModule with Serializable {

case class Shape ( val name: String,
val arg1: Int, ... )

lazy val shape1 = Shape( "Shape 1", ... )
...

val shapeGroup1 = Gen.enumeration("Test Shapes Group 1")(
shape1,
...
)
...

def objectsBasedOnShapes(shapes: Gen[Shape]): Gen[(String, ObjectType1, ObjectType2)] = {
for {
shape <- shapes
} yield getObjectsTuple(shape)
}

def getObjectsTuple(shape: Shape): (String, Object1, ... )= {
val o1 = RandomizedData.build(shape.arg1, ... )
...
return (shape.name, o1, ...)
}

//Scalameter Specific Configuration
def executor = SeparateJvmsExecutor(
new Executor.Warmer.Default,
Aggregator.average,
new CustomMeasure)
def reporter = new LoggingReporter
def persistor = Persistor.None

var benchRuns = exec.benchRuns -> 20
var independentSamples = exec.independentSamples -> 1
val warmups = exec.maxWarmupRuns -> 5
val jvmFlags = exec.jvmflags-> "-Xms8g -Xmx8g -Dscala.collection.parallel.range.manual_optimizations=false"

def runBenchmark(name: String, parameter: Parameter.Value, shapes: Gen[Shape], action : (Object1, ... ) => Action): Unit = {
performance of name in {
measure method parameter.toString in {
using(objectsBasedOnShapes(shapes)) config (
benchRuns, independentSamples, warmups, jvmFlags
) in { case (name, o1, ... ) =>
Console.println("Benchmark: " + n + " - " + parameter + ": " + action(o1, ... )
.setParameterId(parameter)
.run()
.getValue())
}
}
}
}

}

class CustomMeasure extends Measurer with Measurer.IterationBasedValue {
def name = "Measure.CustomMeasure"

def measure[T, U](context: org.scalameter.Context, measurements: Int, setup: T => Any,
tear: T => Any, regen: %28%29 => T, snippet: T => Any): Seq[Double] = {
val times = ListBufferDouble

 var value: T = null.asInstanceOf[T]
 var obj: Any = null.asInstanceOf[Any]

 // Variation on a memory measurer

...

 times

}
}


Reply to this email directly or view it on GitHub:
#155

Aleksandar Prokopec

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants