View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package chapters.appenders;
15  
16  import java.io.FileWriter;
17  import java.io.IOException;
18  
19  import org.slf4j.Logger;
20  
21  import ch.qos.logback.classic.LoggerContext;
22  import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
23  import ch.qos.logback.classic.spi.ILoggingEvent;
24  import ch.qos.logback.core.FileAppender;
25  import ch.qos.logback.core.util.StatusPrinter;
26  
27  public class IOPerformance extends Thread {
28    static String MSG = "ABCDEGHIJKLMNOPQRSTUVWXYZabcdeghijklmnopqrstuvwxyz1234567890";
29    static String LOG_FILE;
30    public static String PARALLEL_FILE;
31  
32    static int NUM_THREADS = 1;
33    static long l;
34    long len;
35    boolean immediateFlush;
36    Logger logger;
37    LoggerContext context;
38    double throughput;
39  
40    public IOPerformance(boolean _immediateFlush, long _len) {
41      this.len = _len;
42      this.immediateFlush = _immediateFlush;
43      context = new LoggerContext();
44      logger = context.getLogger("logger-" + getName());
45  
46      // A FileAppender is created according to the buffering and
47      // immediate flush setting of this IO instance.
48      FileAppender<ILoggingEvent> fa = new FileAppender<ILoggingEvent>();
49      fa.setName("FILE");
50      PatternLayoutEncoder pa = new PatternLayoutEncoder();
51      pa.setPattern("%r %5p %c [%t] - %m%n");
52      pa.setContext(context);
53      pa.start();
54      fa.setEncoder(pa);
55  
56      fa.setFile(LOG_FILE);
57      fa.setAppend(true);
58      fa.setContext(context);
59      fa.start();
60  
61      ((ch.qos.logback.classic.Logger) logger).addAppender(fa);
62  
63      StatusPrinter.print(context);
64    }
65  
66    public static void main(String[] argv) throws Exception {
67      if (argv.length != 3) {
68        usage("Wrong number of arguments.");
69      }
70  
71      l = Integer.parseInt(argv[0]);
72      LOG_FILE = argv[1];
73      PARALLEL_FILE = argv[2];
74  
75      // ----------------------------------------------------
76      // first test with immediate flushing
77      perfCase(true, l);
78  
79      // ----------------------------------------------------
80      // Second test with no immediate flushing
81      perfCase(false, l);
82  
83      // There is no fourth test as buffered IO and immediate flushing
84      // do not make sense.
85    }
86  
87    static void usage(String msg) {
88      System.err.println(msg);
89      System.err.println("Usage: java " + IOPerformance.class.getName()
90          + " runLength logFile otherFile\n"
91          + "   runLength (integer) the number of logs to generate perthread\n"
92          + "   logFile path to a logFile\n"
93          + "   otherFile path to a second file\n");
94      System.exit(1);
95    }
96  
97    static void perfCase(boolean immediateFlush, long len) throws Exception {
98      IOPerformance[] threads = new IOPerformance[NUM_THREADS];
99      OtherIO otherIOThread = new OtherIO();
100     otherIOThread.start();
101 
102     // First create the threads
103     for (int i = 0; i < NUM_THREADS; i++) {
104       threads[i] = new IOPerformance(immediateFlush, len);
105     }
106 
107     // then start them
108     for (int i = 0; i < NUM_THREADS; i++) {
109       threads[i].start();
110     }
111 
112     // wait for them to stop, compute the average throughput
113     double sum = 0;
114 
115     for (int i = 0; i < NUM_THREADS; i++) {
116       threads[i].join();
117       sum += threads[i].throughput;
118     }
119 
120     // setting the interrupted field will cause counterThread to stop
121     otherIOThread.interrupted = true;
122     otherIOThread.join();
123 
124     System.out.println("On total throughput of " + (sum)
125         + " logs per microsecond.");
126     System.out.println("------------------------------------------------");
127   }
128 
129   public void run() {
130 
131     long before = System.nanoTime();
132 
133     for (int i = 0; i < len; i++) {
134       logger.debug(MSG);
135     }
136 
137     throughput = (len * 1.0) / ((System.nanoTime() - before) / 1000);
138     System.out.println(getName() + ", immediateFlush: " + immediateFlush
139         + ", throughput: " + throughput + " logs per microsecond.");
140   }
141 }
142 
143 class OtherIO extends Thread {
144   public boolean interrupted = false;
145   public int counter = 0;
146 
147   public void run() {
148     long before = System.nanoTime();
149     try {
150       FileWriter fw = new FileWriter(IOPerformance.PARALLEL_FILE, true);
151 
152       while (!interrupted) {
153         counter++;
154         fw.write("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
155         fw.flush();
156       }
157     } catch (IOException e) {
158       e.printStackTrace();
159     }
160 
161     double tput = (counter * 1.0) / (System.nanoTime() - before);
162     System.out.println("Counter thread " + getName()
163         + " incremented counter by " + tput + " per nanosecond.");
164   }
165 }