Archived
0

Timings submodule refactoring

This commit is contained in:
Daniil
2018-08-07 16:27:44 +07:00
parent 22dbf8caa8
commit 6bd8b60832
10 changed files with 124 additions and 34 deletions

View File

@@ -14,11 +14,11 @@ public class Timings implements AutoCloseable {
} }
public static Timings start() { public static Timings start() {
return TimingsManager.TIMINGS_MANAGER.getCurrentThreadTimings().start(); return TimingsStaticAccessor.getTimingsManager().getCurrentThreadTimings().start();
} }
public static TimingsManager getTimingsManager() { public static TimingsManager getTimingsManager() {
return TimingsManager.TIMINGS_MANAGER; return TimingsStaticAccessor.getTimingsManager();
} }
public int getId() { public int getId() {

View File

@@ -0,0 +1,17 @@
package mc.core.timings;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public enum TimingsEventType {
TIMINGS_START((short) 0),
TIMINGS_END((short) 1),
TIMINGS_FILE_INITIALIZING((short) 2),
TIMINGS_FILE_INITIALIZED((short) 3),
TIMINGS_CHANGE_THREAD_OPTIONS((short) 4),
TIMINGS_FILE_END((short) 5);
@Getter
private final short id;
}

View File

@@ -1,6 +1,11 @@
package mc.core.timings; package mc.core.timings;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import mc.core.timings.io.DefaultWriterFactory;
import mc.core.timings.io.TimingsWriter;
import mc.core.timings.io.TimingsWriterFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -14,30 +19,38 @@ import java.util.concurrent.locks.ReentrantLock;
@Slf4j @Slf4j
public class TimingsManager { public class TimingsManager {
static TimingsManager TIMINGS_MANAGER = new TimingsManager(); // These variables are essential in Timings thread synchronization
private final AtomicBoolean waitForFile = new AtomicBoolean(false); private final AtomicBoolean waitForFile = new AtomicBoolean(false);
private Map<Thread, ThreadTimings> threadTimings = new ConcurrentHashMap<>(); private Map<Thread, ThreadTimings> threadTimings = new ConcurrentHashMap<>();
private TimingsFileWriter writer; private TimingsWriter writer;
private Thread timingsIoThread; private Thread timingsIoThread;
private CountDownLatch ioThreadStopMutex; private CountDownLatch ioThreadStopMutex;
private BlockingQueue<TimingsRecord> queue; private BlockingQueue<TimingsRecord> queue;
private ReentrantLock queueAccessLock = new ReentrantLock(); private ReentrantLock queueAccessLock = new ReentrantLock();
// For modularity purposes
@Autowired
@Setter
private TimingsWriterFactory writerFactory = new DefaultWriterFactory();
public TimingsManager() {
TimingsStaticAccessor.TIMINGS_MANAGER = this;
}
public void startRecording(File file) { public void startRecording(File file) {
synchronized (waitForFile) { synchronized (waitForFile) {
waitForFile.set(true); waitForFile.set(true);
} }
try { try {
writer = new TimingsFileWriter(file); writer = writerFactory.newInstance(file);
writer.writeEvent(0, 0, System.nanoTime(), TimingsFileWriter.TimingsEventType.TIMINGS_FILE_INITIALIZING); writer.writeEvent(0, 0, System.nanoTime(), TimingsEventType.TIMINGS_FILE_INITIALIZING);
// Synchronize current thread state // Synchronize current thread state
for (Map.Entry<Thread, ThreadTimings> pair : threadTimings.entrySet()) { for (Map.Entry<Thread, ThreadTimings> pair : threadTimings.entrySet()) {
writer.writeEvent(pair.getValue().getThreadId(), 0, System.nanoTime(), TimingsFileWriter.TimingsEventType.TIMINGS_CHANGE_THREAD_OPTIONS, "name: " + pair.getKey().getName()); writer.writeEvent(pair.getValue().getThreadId(), 0, System.nanoTime(), TimingsEventType.TIMINGS_CHANGE_THREAD_OPTIONS, "name: " + pair.getKey().getName());
for (Timings timings : pair.getValue().getStack()) { for (Timings timings : pair.getValue().getStack()) {
writer.writeEvent(pair.getValue().getThreadId(), timings.getId(), timings.getAcquireTime(), TimingsFileWriter.TimingsEventType.TIMINGS_START); writer.writeEvent(pair.getValue().getThreadId(), timings.getId(), timings.getAcquireTime(), TimingsEventType.TIMINGS_START);
} }
} }
writer.writeEvent(0, 0, System.nanoTime(), TimingsFileWriter.TimingsEventType.TIMINGS_FILE_INITIALIZED); writer.writeEvent(0, 0, System.nanoTime(), TimingsEventType.TIMINGS_FILE_INITIALIZED);
queue = new ArrayBlockingQueue<>(200); queue = new ArrayBlockingQueue<>(200);
ioThreadStopMutex = new CountDownLatch(1); ioThreadStopMutex = new CountDownLatch(1);
timingsIoThread = new Thread() { timingsIoThread = new Thread() {
@@ -47,6 +60,8 @@ public class TimingsManager {
while (!isInterrupted() && isAlive()) { while (!isInterrupted() && isAlive()) {
TimingsRecord record; TimingsRecord record;
try { try {
if (queue == null)
return;
record = queue.take(); record = queue.take();
} catch (InterruptedException e) { } catch (InterruptedException e) {
return; return;
@@ -58,7 +73,9 @@ public class TimingsManager {
} }
} }
}; };
} catch (IOException e) { timingsIoThread.setName("Timings IO thread");
timingsIoThread.start();
} catch (Exception e) {
log.error("Unable to start timings recording", e); log.error("Unable to start timings recording", e);
} }
synchronized (waitForFile) { synchronized (waitForFile) {
@@ -80,7 +97,7 @@ public class TimingsManager {
log.error("Unable to wait until last record would be written to file", e); log.error("Unable to wait until last record would be written to file", e);
} }
// Write EOF event // Write EOF event
writer.writeEvent(0, 0, System.nanoTime(), TimingsFileWriter.TimingsEventType.TIMINGS_FILE_END); writer.writeEvent(0, 0, System.nanoTime(), TimingsEventType.TIMINGS_FILE_END);
// Unload file // Unload file
try { try {
writer.close(); writer.close();
@@ -100,7 +117,7 @@ public class TimingsManager {
new TimingsRecord(thread.getThreadId(), new TimingsRecord(thread.getThreadId(),
timings.getId(), timings.getId(),
start ? timings.getAcquireTime() : timings.getEndTime(), start ? timings.getAcquireTime() : timings.getEndTime(),
start ? TimingsFileWriter.TimingsEventType.TIMINGS_START : TimingsFileWriter.TimingsEventType.TIMINGS_END start ? TimingsEventType.TIMINGS_START : TimingsEventType.TIMINGS_END
) )
); );
} finally { } finally {

View File

@@ -1,20 +1,22 @@
package mc.core.timings; package mc.core.timings;
public class TimingsRecord { import mc.core.timings.io.TimingsWriter;
class TimingsRecord {
private int threadId; private int threadId;
private int stackId; private int stackId;
private long time; private long time;
private TimingsFileWriter.TimingsEventType eventType; private TimingsEventType eventType;
private String data; private String data;
public TimingsRecord(int threadId, int stackId, long time, TimingsFileWriter.TimingsEventType eventType) { public TimingsRecord(int threadId, int stackId, long time, TimingsEventType eventType) {
this.threadId = threadId; this.threadId = threadId;
this.stackId = stackId; this.stackId = stackId;
this.time = time; this.time = time;
this.eventType = eventType; this.eventType = eventType;
} }
public TimingsRecord(int threadId, int stackId, long time, TimingsFileWriter.TimingsEventType eventType, String data) { public TimingsRecord(int threadId, int stackId, long time, TimingsEventType eventType, String data) {
this.threadId = threadId; this.threadId = threadId;
this.stackId = stackId; this.stackId = stackId;
this.time = time; this.time = time;
@@ -22,7 +24,7 @@ public class TimingsRecord {
this.data = data; this.data = data;
} }
public void writeToFile(TimingsFileWriter fileWriter) { public void writeToFile(TimingsWriter fileWriter) {
if (data == null) if (data == null)
fileWriter.writeEvent(threadId, stackId, time, eventType); fileWriter.writeEvent(threadId, stackId, time, eventType);
else else

View File

@@ -0,0 +1,9 @@
package mc.core.timings;
public class TimingsStaticAccessor {
static TimingsManager TIMINGS_MANAGER;
public static TimingsManager getTimingsManager() {
return TIMINGS_MANAGER != null ? TIMINGS_MANAGER : (TIMINGS_MANAGER = new TimingsManager());
}
}

View File

@@ -0,0 +1,11 @@
package mc.core.timings.io;
import java.io.File;
import java.io.IOException;
public class DefaultWriterFactory implements TimingsWriterFactory {
@Override
public TimingsWriter newInstance(File file) throws IOException {
return new TimingsFileWriter(file);
}
}

View File

@@ -1,9 +1,8 @@
package mc.core.timings; package mc.core.timings.io;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import mc.core.timings.TimingsEventType;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
@@ -13,7 +12,7 @@ import java.util.concurrent.locks.ReentrantLock;
@SuppressWarnings("Duplicates") @SuppressWarnings("Duplicates")
@Slf4j @Slf4j
public class TimingsFileWriter { public class TimingsFileWriter implements TimingsWriter {
private FileOutputStream fileOutputStream; private FileOutputStream fileOutputStream;
private ObjectOutputStream writer; private ObjectOutputStream writer;
private ReentrantLock lock = new ReentrantLock(); private ReentrantLock lock = new ReentrantLock();
@@ -23,6 +22,7 @@ public class TimingsFileWriter {
writer = new ObjectOutputStream(fileOutputStream); writer = new ObjectOutputStream(fileOutputStream);
} }
@Override
public void writeEvent(int threadId, int stackId, long time, TimingsEventType type) { public void writeEvent(int threadId, int stackId, long time, TimingsEventType type) {
lock.lock(); lock.lock();
try { try {
@@ -37,6 +37,7 @@ public class TimingsFileWriter {
} }
} }
@Override
public void writeEvent(int threadId, int stackId, long time, TimingsEventType type, String data) { public void writeEvent(int threadId, int stackId, long time, TimingsEventType type, String data) {
lock.lock(); lock.lock();
try { try {
@@ -52,21 +53,9 @@ public class TimingsFileWriter {
} }
} }
@Override
public void close() throws IOException { public void close() throws IOException {
writer.close(); writer.close();
fileOutputStream.close(); fileOutputStream.close();
} }
@RequiredArgsConstructor
public enum TimingsEventType {
TIMINGS_START((short) 0),
TIMINGS_END((short) 1),
TIMINGS_FILE_INITIALIZING((short) 2),
TIMINGS_FILE_INITIALIZED((short) 3),
TIMINGS_CHANGE_THREAD_OPTIONS((short) 4),
TIMINGS_FILE_END((short) 5);
@Getter
private final short id;
}
} }

View File

@@ -0,0 +1,24 @@
package mc.core.timings.io;
import lombok.extern.slf4j.Slf4j;
import mc.core.timings.TimingsEventType;
import java.io.IOException;
@Slf4j
public class TimingsLogWriter implements TimingsWriter {
@Override
public void writeEvent(int threadId, int stackId, long time, TimingsEventType type) {
log.info("[{}] Thread #{}, Stack #{}: {}", time, threadId, stackId, type.toString());
}
@Override
public void writeEvent(int threadId, int stackId, long time, TimingsEventType type, String data) {
log.info("[{}] Thread #{}, Stack #{}: {} ({})", time, threadId, stackId, type.toString(), data);
}
@Override
public void close() throws IOException {
}
}

View File

@@ -0,0 +1,13 @@
package mc.core.timings.io;
import mc.core.timings.TimingsEventType;
import java.io.IOException;
public interface TimingsWriter {
void writeEvent(int threadId, int stackId, long time, TimingsEventType type);
void writeEvent(int threadId, int stackId, long time, TimingsEventType type, String data);
void close() throws IOException;
}

View File

@@ -0,0 +1,8 @@
package mc.core.timings.io;
import java.io.File;
import java.io.IOException;
public interface TimingsWriterFactory {
TimingsWriter newInstance(File file) throws IOException;
}