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();
}