1 /* 2 * Copyright (C) 2011 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.caliper.runner; 18 19 import static java.util.logging.Level.SEVERE; 20 21 import com.google.caliper.api.ResultProcessor; 22 import com.google.caliper.config.CaliperConfig; 23 import com.google.caliper.config.InvalidConfigurationException; 24 import com.google.caliper.config.ResultProcessorConfig; 25 import com.google.caliper.model.Run; 26 import com.google.caliper.model.Trial; 27 import com.google.caliper.options.CaliperDirectory; 28 import com.google.common.base.Charsets; 29 import com.google.common.base.Optional; 30 import com.google.common.io.Files; 31 import com.google.gson.Gson; 32 import com.google.gson.stream.JsonWriter; 33 34 import org.joda.time.format.ISODateTimeFormat; 35 36 import java.io.File; 37 import java.io.FileOutputStream; 38 import java.io.IOException; 39 import java.io.OutputStreamWriter; 40 import java.util.logging.Logger; 41 42 import javax.inject.Inject; 43 44 /** 45 * {@link ResultProcessor} that dumps the output data to a file in JSON format. By default, the 46 * output will be dumped to a file called 47 * {@code ~/.caliper/results/[benchmark classname].[timestamp].json}; if it exists and is a file, 48 * the file will be overwritten. The location can be overridden as either a file or a directory 49 * using either the {@code file} or {@code dir} options respectively. 50 */ 51 final class OutputFileDumper implements ResultProcessor { 52 private static final Logger logger = Logger.getLogger(OutputFileDumper.class.getName()); 53 54 private final Run run; 55 private final Gson gson; 56 private final File resultFile; 57 private final File workFile; 58 59 private Optional<JsonWriter> writer = Optional.absent(); 60 OutputFileDumper(Run run, BenchmarkClass benchmarkClass, Gson gson, CaliperConfig caliperConfig, @CaliperDirectory File caliperDirectory)61 @Inject OutputFileDumper(Run run, 62 BenchmarkClass benchmarkClass, 63 Gson gson, 64 CaliperConfig caliperConfig, 65 @CaliperDirectory File caliperDirectory) throws InvalidConfigurationException { 66 this.run = run; 67 ResultProcessorConfig config = caliperConfig.getResultProcessorConfig(OutputFileDumper.class); 68 if (config.options().containsKey("file")) { 69 this.resultFile = new File(config.options().get("file")); 70 logger.finer("found an output file in the configuration"); 71 } else if (config.options().containsKey("dir")) { 72 File dir = new File(config.options().get("dir")); 73 if (dir.isFile()) { 74 throw new InvalidConfigurationException("specified a directory, but it's a file"); 75 } 76 this.resultFile = new File(dir, createFileName(benchmarkClass.name())); 77 logger.finer("found an output directory in the configuration"); 78 } else { 79 this.resultFile = 80 new File(new File(caliperDirectory, "results"), createFileName(benchmarkClass.name())); 81 logger.fine("found no configuration"); 82 } 83 logger.fine(String.format("using %s for results", resultFile)); 84 this.gson = gson; 85 this.workFile = new File(resultFile.getPath() + ".tmp"); 86 } 87 createFileName(String benchmarkName)88 private String createFileName(String benchmarkName) { 89 return String.format("%s.%s.json", benchmarkName, createTimestamp()); 90 } 91 createTimestamp()92 private String createTimestamp() { 93 return ISODateTimeFormat.dateTimeNoMillis().print(run.startTime()); 94 } 95 processTrial(Trial trial)96 @Override public void processTrial(Trial trial) { 97 if (!writer.isPresent()) { 98 try { 99 Files.createParentDirs(workFile); 100 JsonWriter writer = 101 new JsonWriter(new OutputStreamWriter(new FileOutputStream(workFile), Charsets.UTF_8)); 102 writer.setIndent(" "); // always pretty print 103 writer.beginArray(); 104 this.writer = Optional.of(writer); 105 } catch (IOException e) { 106 logger.log(SEVERE, String.format( 107 "An error occured writing trial %s. Results in %s will be incomplete.", trial.id(), 108 resultFile), e); 109 } 110 } 111 if (writer.isPresent()) { 112 gson.toJson(trial, Trial.class, writer.get()); 113 } 114 } 115 close()116 @Override public void close() throws IOException { 117 if (writer.isPresent()) { 118 writer.get().endArray().close(); 119 } 120 if (workFile.exists()) { 121 Files.move(workFile, resultFile); 122 } 123 } 124 } 125