View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * 
4    * Copyright (C) 1999-2006, QOS.ch
5    * 
6    * This library is free software, you can redistribute it and/or modify it under
7    * the terms of the GNU Lesser General Public License as published by the Free
8    * Software Foundation.
9    */
10  
11  package chapter4;
12  
13  import org.slf4j.Logger;
14  
15  import ch.qos.logback.classic.LoggerContext;
16  import ch.qos.logback.classic.PatternLayout;
17  import ch.qos.logback.classic.spi.LoggingEvent;
18  import ch.qos.logback.core.FileAppender;
19  import ch.qos.logback.core.layout.EchoLayout;
20  
21  public class IO extends Thread {
22    static String msgLong = "ABCDEGHIJKLMNOPQRSTUVWXYZabcdeghijklmnopqrstuvwxyz1234567890";
23    static String msgShort = "Hello";
24    static boolean scarceCPU;
25    static int numThreads;
26    static long l;
27    static boolean longMessage;
28    long len;
29    boolean buffered;
30    boolean immediateFlush;
31    Logger logger;
32    LoggerContext context;
33    double throughput;
34  
35    public IO(boolean _buffered, boolean _immediateFlush, long _len) {
36      this.len = _len;
37      this.buffered = _buffered;
38      this.immediateFlush = _immediateFlush;
39      context = new LoggerContext();
40      logger = context.getLogger("logger-" + getName());
41  
42      // A FileAppender is created according to the buffering and
43      // immediate flush setting of this IO instance.
44      FileAppender<LoggingEvent> fa = new FileAppender<LoggingEvent>();
45  
46      if (longMessage) {
47        PatternLayout pa = new PatternLayout();
48        pa.setPattern("%r %5p %c [%t] - %m%n");
49        fa.setLayout(pa);
50      } else {
51        fa.setLayout(new EchoLayout<LoggingEvent>());
52      }
53  
54      fa.setFile(getName() + ".log");
55      fa.setAppend(false);
56      fa.setImmediateFlush(immediateFlush);
57      fa.setBufferedIO(buffered);
58      fa.setContext(context);
59      fa.start();
60      
61    }
62  
63    public static void main(String[] argv) throws Exception {
64      if (argv.length != 4) {
65        usage("Wrong number of arguments.");
66      }
67  
68      l = Integer.parseInt(argv[0]);
69      numThreads = Integer.parseInt(argv[1]);
70      scarceCPU = "true".equalsIgnoreCase(argv[2]);
71      longMessage = "long".equalsIgnoreCase(argv[3]);
72  
73      // ----------------------------------------------------
74      // first test with unbuffered IO and immediate flushing
75      perfCase(false, true, l);
76  
77      // ----------------------------------------------------
78      // Second test with unbuffered IO and no immediate flushing
79      perfCase(false, false, l);
80  
81      // ----------------------------------------------------
82      // Third test with buffered IO and no immediate flushing
83      perfCase(true, false, l);
84  
85      // There is no fourth test as buffered IO and immediate flushing
86      // do not make sense.
87    }
88  
89    static void usage(String msg) {
90      System.err.println(msg);
91      System.err.println("Usage: java " + IO.class.getName() +
92        " runLength numThreads scarceCPU (short|long)\n" +
93        "   runLength (integer) the number of logs to generate perthread\n" +
94        "   numThreads (integer) the number of threads.\n" +
95        "   scarceCPU (boolean) if true an additional CPU intensive thread is created\n" +
96        "   (short|long) length of log messages.");
97      System.exit(1);
98    }
99  
100   static void perfCase(boolean buffered, boolean immediateFlush, long len)
101     throws Exception {
102     IO[] threads = new IO[numThreads];
103     Counter counterThread = null;
104 
105     if (scarceCPU) {
106       counterThread = new Counter();
107       counterThread.start();
108     }
109 
110     // First create the threads 
111     for (int i = 0; i < numThreads; i++) {
112       threads[i] = new IO(buffered, immediateFlush, len);
113     }
114 
115     // then start them
116     for (int i = 0; i < numThreads; i++) {
117       threads[i].start();
118     }
119 
120     // wait for them to stop, compute the average throughputs
121     double sum = 0;
122 
123     for (int i = 0; i < numThreads; i++) {
124       threads[i].join();
125       sum += threads[i].throughput;
126     }
127 
128     if (scarceCPU) {
129       // setting the interrupted field will cause counterThread to stop
130       counterThread.interrupted = true;
131       counterThread.join();
132     }
133 
134     System.out.println("On average throughput of " + (sum / numThreads) +
135       " logs per millisecond.");
136     System.out.println("------------------------------------------------");
137   }
138 
139   public void run() {
140     String msg = msgShort;
141 
142     if (longMessage) {
143       msg = msgLong;
144     }
145 
146     long before = System.currentTimeMillis();
147 
148     for (int i = 0; i < len; i++) {
149       logger.debug(msg);
150     }
151 
152     throughput = (len * 1.0) / (System.currentTimeMillis() - before);
153     System.out.println(getName() + ", buffered: " + buffered +
154       ", immediateFlush: " + immediateFlush + ", throughput: " + throughput +
155       " logs per millisecond.");
156   }
157 }
158 
159 
160 class Counter extends Thread {
161   public boolean interrupted = false;
162   public double counter = 0;
163 
164   public void run() {
165     long before = System.currentTimeMillis();
166 
167     while (!interrupted) {
168       counter += 0.001;
169     }
170 
171     double tput = (counter * 1.0) / (System.currentTimeMillis() - before);
172     System.out.println("Counter thread " + getName() +
173       " incremented counter by " + tput + " per millisecond.");
174   }
175 }