Timings submodule refactoring
This commit is contained in:
@@ -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() {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -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 {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user