Now that you are tracking `stageToShuffleRead` and `stageToShuffleWrite` in the listener, the `hasShuffleRead` and `hasShuffleWrite` functions are no longer necessary. It would be good to remove those. Then you could write this as follows:

    val shuffleRead =  listener.stageToShuffleRead(s.id) match {
      case 0 => "" 
      case b => Utils.memoryBytesToString(b)
    }