package com.ibm.tuningfork.traceGenerationExample; import java.io.File; import java.io.IOException; import com.ibm.tuningfork.tracegen.IBookmarkEvent; import com.ibm.tuningfork.tracegen.IFeedlet; import com.ibm.tuningfork.tracegen.ILogger; import com.ibm.tuningfork.tracegen.ITimerEvent; import com.ibm.tuningfork.tracegen.IValueEvent; import com.ibm.tuningfork.tracegen.LoggerFactory; import com.ibm.tuningfork.tracegen.types.EventAttribute; import com.ibm.tuningfork.tracegen.types.EventType; import com.ibm.tuningfork.tracegen.types.EventTypeSpaceVersion; import com.ibm.tuningfork.tracegen.types.ScalarType; public class InstrumentedClient { /* --------------------- INSTRUMENTATION START ------------------------- */ static ILogger logger = null; static IFeedlet signalFeedlet, activityFeedlet, midiFeedlet; static IBookmarkEvent phaseBookmark; static ITimerEvent activityTimer; static IValueEvent signalET, loudnessET; static EventType midiEventET; static private void instrumentationInit(String fileNameOrPortNumber, int durationSeconds) { // Create a logger EventTypeSpaceVersion[] etsv = new EventTypeSpaceVersion[] { new EventTypeSpaceVersion("com.ibm.tuningfork.music", 1) }; try { try { if (fileNameOrPortNumber.equals("none")) { logger = LoggerFactory.makeNullLogger(); } else { int portNumber = Integer.parseInt(fileNameOrPortNumber); logger = LoggerFactory.makeServerLogger(portNumber, etsv, true, LoggerFactory.NO_PROCESSOR_AFFINITY); } } catch (NumberFormatException exn) { logger = LoggerFactory.makeFileLogger(new File(fileNameOrPortNumber), etsv, true, LoggerFactory.NO_PROCESSOR_AFFINITY); } } catch (IOException ex) { ex.printStackTrace(); System.exit(-1); } // Add some properties logger.addProperty("Program Run Length", durationSeconds + " sec"); // Add some event types - two for each type of threads phaseBookmark = logger.makeBookmarkEvent("Iteration"); activityTimer = logger.makeTimerEvent("Activity"); signalET = logger.makeValueEvent("Signal Value"); loudnessET = logger.makeValueEvent("Loudness"); midiEventET = new EventType("MIDI Events", "MIDI Events", new EventAttribute[] { new EventAttribute("channel", "channel", ScalarType.INT), new EventAttribute("status", "status", ScalarType.INT), new EventAttribute("data1", "data1", ScalarType.INT), new EventAttribute("data2", "data2", ScalarType.INT), }); logger.addEventType(midiEventET); signalFeedlet = logger.makeFeedlet("signal feedlet", "Simulation of some amplitude modulated sine wave"); activityFeedlet = logger.makeFeedlet("activity", "Simulation of a irregular task"); midiFeedlet = logger.makeFeedlet("midi", "midi"); } /* --------------------- INSTRUMENTATION END ------------------------- */ static public void main(String[] args) { /* ------- INSTRUMENTATION MODIFICATION START --------- */ if (args.length != 2) { System.err.println("Usage: Client<'none' or traceFileName or portNumber>"); return; } String duration = args[0]; int durationSeconds = 60; // Default is 60 seconds try { durationSeconds = Integer.parseInt(duration); } catch (NumberFormatException exn) { System.err.println("Could not parse duration argument. Using " + durationSeconds); } String fileNameOrPortNumber = args[1]; // INSRUMENTATION instrumentationInit(fileNameOrPortNumber, durationSeconds); // INSRUMENTATION /* ------- INSTRUMENTATION MODIFICATION END --------- */ // Run 2 threads that make events for some time System.out.println("Running 3 threads for " + durationSeconds + " seconds."); runSignal(durationSeconds); runIntervals(durationSeconds); runMidi(durationSeconds); // This is only an approximation - not synchronized with event-generating threads try { Thread.sleep(durationSeconds * 1000); } catch (InterruptedException ie) { } // Flush buffered data System.out.println("Done."); } static void setSignal(double amplitude, double loudness) { signalET.addValue(amplitude); // ---------------- INSTRUMENTATION ------------------- loudnessET.addValue(loudness); // ---------------- INSTRUMENTATION ------------------- // Do some work related to setting signal - we simulate by sleeping briefly try { Thread.sleep(1); } catch (InterruptedException ie) { } } static void runOneInterval(long timeMs) { activityTimer.start(); // ---------------------- INSTRUMENTATION ------------------- try { Thread.sleep(timeMs); } catch (InterruptedException ie) { } activityTimer.stop(); // --------------------- INSTRUMENTATION ------------------- } static void runMidi(final long durationSec) { new Thread() { public void run() { midiFeedlet.bindToCurrentThread(); // --------------------- INSTRUMENTATION ------------------- // Now make some MIDI events final int pitchOffset = 0x0c; final int startPitch = 0x30; final int endPitch = 0x40; final int onStatus = 0x90; final int offStatus = 0x80; int channel = 0; int status = onStatus; int curPitch = startPitch; // pitch int data2 = 64; // velocity int iteration = 0; long start = System.nanoTime(); while (true) { double timeSec = (System.nanoTime() - start) / 1e9; if (curPitch == startPitch && status == onStatus) { phaseBookmark.addBookmark("Iteration " + (++iteration)); } midiFeedlet.addEvent(midiEventET, new int[] { channel, status, curPitch, data2 }, null, null, null); midiFeedlet.addEvent(midiEventET, new int[] { channel, status, curPitch + pitchOffset, data2 }, null, null, null); if (status == onStatus) { status = offStatus; } else { status = onStatus; if (++curPitch > endPitch) { curPitch = startPitch; } } if (timeSec > durationSec) { break; } try { Thread.sleep(200); } catch (InterruptedException ie) { } } } }.start(); } static void runSignal(final long durationSec) { new Thread() { public void run() { signalFeedlet.bindToCurrentThread(); // --------------------- INSTRUMENTATION ------------------- // Now make some events double pitchFrequency = 5; double loudnessFrequency = 0.5; long start = System.nanoTime(); while (true) { double timeSec = (System.nanoTime() - start) / 1e9; double pitchPosition = timeSec * pitchFrequency * 2 * Math.PI; double loudnessPosition = timeSec * loudnessFrequency * 2 * Math.PI; double loudness = 1 + 0.5 * Math.sin(loudnessPosition); double amplitude = Math.sin(pitchPosition) * loudness; // FIXME: HACK AROUND TIMESERIES y-AXIS SCALING BUG: Multiply real values by 1000. double hackScale = 1000; setSignal(hackScale*amplitude, hackScale*loudness); if (timeSec > durationSec) { break; } } } }.start(); } static void runIntervals(final long durationSec) { new Thread() { public void run() { activityFeedlet.bindToCurrentThread(); // --------------------- INSTRUMENTATION ------------------- double onMaxLenMs = 200; // activity's length is from a uniform distribution from 0 to onMaxLen double offMaxLenMs = 500; // time until next activity is from a uniform distribution from 0 to onMaxLen long start = System.nanoTime(); while (true) { int onLenMs = (int) (onMaxLenMs * Math.random()); int offLenMs = (int) (offMaxLenMs * Math.random()); runOneInterval(onLenMs); try { Thread.sleep(offLenMs); } catch (InterruptedException ie) { } double timeSec = (System.nanoTime() - start) / 1e9; if (timeSec > durationSec) { break; } } } }.start(); }