scalabreeze

Matrix-vector multiplication prints java version in stdout


The following Code on Scala outputs return java 11 instance.

I'm using openjdk-11 and sbt 1.8.0.

# Main.scala
import breeze.linalg.{DenseMatrix, DenseVector}

object Main  extends App {
    val X = DenseMatrix((1.0, 0.0), (1.0, 1.0), (1.0, 2.0), (1.0, 3.0))
    val Y = DenseVector(0.0, 1.0)

    X * Y
}
# build.sbt
ThisBuild / version := "0.1.0-SNAPSHOT"

ThisBuild / scalaVersion := "2.13.10"

libraryDependencies  ++= Seq(
  "org.scalanlp" %% "breeze" % "2.1.0"
)

What is the reason for this output and how can I avoid this in my projects with Breeze?

Moreover this problem reproduces with other versions of jdk, this code always prints java version from which it was built.


Solution

  • The thing is that for multiplication of dense matrices Breeze uses https://github.com/luhenry/netlib with logger dev.ludovic.netlib.blas.InstanceBuilder

    https://github.com/luhenry/netlib/blob/master/blas/src/main/java/dev/ludovic/netlib/blas/InstanceBuilder.java

    private static JavaBLAS initializeJava() {
      String[] fullVersion = System.getProperty("java.version").split("[+.\\-]+", 2);
      int major = Integer.parseInt(fullVersion[0]);
      if (major >= 16) {
        try {
          System.out.println("trying to return java 16 instance");
          return VectorBLAS.getInstance();
        } catch (Throwable t) {
          log.warning("Failed to load implementation from:" + VectorBLAS.class.getName());
        }
      }
      if (major >= 11) {
        System.out.println("return java 11 instance");
        return Java11BLAS.getInstance();
      } else {
        System.out.println("return java 8 instance");
        return Java8BLAS.getInstance();
      }
    }
    

    All other logging can be switched off with setLevel

    import java.util.logging.{Level, Logger}
    
    val logger = Logger.getLogger("dev.ludovic.netlib.blas.InstanceBuilder")
    
    logger.log(Level.SEVERE, "AAAA!!!") // prints
    
    logger.setLevel(Level.OFF)
    logger.log(Level.SEVERE, "BBBB!!!") // doesn't print
    

    Is there a way to disable java.util.logging and enable it back later?

    Why are the Level.FINE logging messages not showing?

    But return java... messages are printed not with log/doLog but directly with System.out.println in the static initializing block of class InstanceBuilder, so this is executed during initialization of the class InstanceBuilder.

    Static initializing block can be modified only with bytecode manipulation (Javassist, Byte Buddy)

    Over riding the static block of a class in java

    So the easiest is just to modify a print stream

    System.setOut(new java.io.PrintStream(System.out) {
      override def println(s: String): Unit =
        if (Seq("trying to return java", "return java").forall(!s.startsWith(_)))
          super.println(s)
    })
    

    https://scastie.scala-lang.org/DmytroMitin/gk52bU4iSEebHAZPZKhaDw/5