1

Given the following code that reads email messages and parses them...

  val inbox = store.getFolder("Inbox")
  inbox.open(Folder.READ_WRITE)
  val messages = inbox.getMessages()
  for (message <- messages) {
    val from = InternetAddress.toString(message.getFrom())
    if (from.contains(sender)) {
      message.getContent() match {
        case content: String => {
          parse(content) match {
            case Some(reading: SiteReading) => {
              readings += reading
              Logger.info(s"Message added. Subject: ${message.getSubject()}");
            }
            case _ => Logger.warn(s"Unable to process message. Ignoring. $content");
          }
          message.setFlag(Flags.Flag.DELETED, true);
        }
        case _ => Logger.error(s"Unknown message type sent from $sender.");
      }
    }
  }

The 7th line, case content: String => is really slow. I was thinking that my parse function was slow, but after profiling it at sub-millisecond it didn't really don on me that the pattern match could be the culprit. The pattern match is taking anywhere from 250-300ms.

Because javax.mail returns an Object from message.getContent(), I have to test for the type.

I'm using Scala 2.10.2.

andyczerwonka
  • 4,230
  • 5
  • 34
  • 57
  • Do you mean "Scala 2.10.2"? – om-nom-nom Oct 18 '13 at 14:33
  • First, what's you're question? Second, how did you profile this? Finally, I'm quite confident that it does not take 250-300ms to check if an object is a string. Try doing something like `val start = System.nanotime()` before the pattern match and `val end = System.nanotime() - start` before you're parse and maybe log the result. If you could create a small example that anyone can run it might be easier to diagnose you're perf problem. – Noah Oct 18 '13 at 15:51
  • That particular kind of `case` clause is nothing but a combination of an `isInstanceOf[Strig]` (to test the criterion) followed by an `asInstanceOf[String]` to create the pattern variable binding. In all likelihood, your profiling did not trigger the JIT compiler to create native version. That or it included the cost of that compilation and / or the cost of class loading. – Randall Schulz Oct 18 '13 at 16:23
  • 2
    without splitting `message.getContent() match` into `val m = message.getContent()` and `m match`, i'm pretty suspicious about blaming the matcher. – Rob Starling Oct 18 '13 at 16:30
  • @Noah that is exactly what I did. I will take the advice here and try it again. – andyczerwonka Oct 18 '13 at 17:37
  • 1
    Randall hinted but didn't say something that you may or may not know already: in Java performance testing, you always should run the operation many times before measuring. JIT-compilation is triggered after the JVM sees that you're serious about using a method. The number of executions varies with environment, but I think 20,000 is a "safe" number at which you can be sure it was jit-compiled. You can reduce it by setting JVM options - especially CompilerThreshold; see http://stackoverflow.com/questions/18345089/what-does-compilethreshold-tier2compilethreshold-tier3compilethreshold-and-tie. – Ed Staub Oct 18 '13 at 18:47

0 Answers0