mirror of
https://github.com/davidalves04/Trabalho-Pratico-SD.git
synced 2026-02-04 05:05:55 +00:00
fix: add micro-throttle for Linux performance parity
Linux runs too fast compared to Windows/Wine, causing vehicle queue backup (~44% completion vs 95% on Windows). Adding microsecond delays via LockSupport.parkNanos() achieves 92% completion. - 50μs delay in SocketConnection send/receive - 100μs delay in CoordinatorProcess vehicle generation
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -8,6 +8,9 @@ logs
|
|||||||
*.md
|
*.md
|
||||||
*.tex
|
*.tex
|
||||||
!README.md
|
!README.md
|
||||||
|
report.aux
|
||||||
|
report.synctex.gz
|
||||||
|
!report.tex
|
||||||
|
|
||||||
# BlueJ files
|
# BlueJ files
|
||||||
*.ctxt
|
*.ctxt
|
||||||
@@ -53,6 +56,7 @@ build/
|
|||||||
# Other
|
# Other
|
||||||
*.swp
|
*.swp
|
||||||
*.pdf
|
*.pdf
|
||||||
|
!report.pdf
|
||||||
|
|
||||||
# JAR built pom file
|
# JAR built pom file
|
||||||
dependency-reduced-pom.xml
|
dependency-reduced-pom.xml
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package sd.coordinator;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.locks.LockSupport;
|
||||||
|
|
||||||
import sd.config.SimulationConfig;
|
import sd.config.SimulationConfig;
|
||||||
import sd.dashboard.DashboardStatistics;
|
import sd.dashboard.DashboardStatistics;
|
||||||
@@ -375,6 +376,7 @@ public class CoordinatorProcess {
|
|||||||
|
|
||||||
String entryIntersection = vehicle.getRoute().get(0);
|
String entryIntersection = vehicle.getRoute().get(0);
|
||||||
sendVehicleToIntersection(vehicle, entryIntersection);
|
sendVehicleToIntersection(vehicle, entryIntersection);
|
||||||
|
LockSupport.parkNanos(100000); // 100us
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.net.Socket;
|
|||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.LockSupport;
|
||||||
|
|
||||||
import sd.serialization.MessageSerializer;
|
import sd.serialization.MessageSerializer;
|
||||||
import sd.serialization.SerializationException;
|
import sd.serialization.SerializationException;
|
||||||
@@ -167,7 +168,8 @@ public class SocketConnection implements Closeable {
|
|||||||
DataOutputStream dataOut = new DataOutputStream(outputStream);
|
DataOutputStream dataOut = new DataOutputStream(outputStream);
|
||||||
dataOut.writeInt(data.length);
|
dataOut.writeInt(data.length);
|
||||||
dataOut.write(data);
|
dataOut.write(data);
|
||||||
dataOut.flush(); // Force transmission immediately
|
dataOut.flush();
|
||||||
|
LockSupport.parkNanos(50000); // 50us
|
||||||
|
|
||||||
} catch (SerializationException e) {
|
} catch (SerializationException e) {
|
||||||
throw new IOException("Failed to serialize message", e);
|
throw new IOException("Failed to serialize message", e);
|
||||||
@@ -202,6 +204,7 @@ public class SocketConnection implements Closeable {
|
|||||||
// Ler dados exatos da mensagem
|
// Ler dados exatos da mensagem
|
||||||
byte[] data = new byte[length];
|
byte[] data = new byte[length];
|
||||||
dataIn.readFully(data);
|
dataIn.readFully(data);
|
||||||
|
LockSupport.parkNanos(50000); // 50us
|
||||||
|
|
||||||
// Deserialize do JSON - força o tipo concreto Message
|
// Deserialize do JSON - força o tipo concreto Message
|
||||||
return serializer.deserialize(data, sd.model.Message.class);
|
return serializer.deserialize(data, sd.model.Message.class);
|
||||||
|
|||||||
BIN
report.pdf
Normal file
BIN
report.pdf
Normal file
Binary file not shown.
176
report.tex
Normal file
176
report.tex
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
\documentclass[a4paper,11pt]{article}
|
||||||
|
|
||||||
|
% codificação
|
||||||
|
\usepackage[utf8]{inputenc}
|
||||||
|
\usepackage[T1]{fontenc}
|
||||||
|
|
||||||
|
% layout
|
||||||
|
\usepackage[top=2.5cm, bottom=2.5cm, left=2.5cm, right=2.5cm]{geometry}
|
||||||
|
\usepackage{parskip} % Espaçamento entre parágrafos sem indentação
|
||||||
|
\usepackage{titlesec} % Personalização de títulos
|
||||||
|
|
||||||
|
% cor/estilo
|
||||||
|
\usepackage{xcolor}
|
||||||
|
\definecolor{navyblue}{RGB}{0, 40, 85}
|
||||||
|
\definecolor{codegray}{rgb}{0.95,0.95,0.95}
|
||||||
|
\definecolor{accent}{RGB}{0, 100, 180}
|
||||||
|
|
||||||
|
% data
|
||||||
|
\renewcommand{\today}{%
|
||||||
|
\number\day\ de %
|
||||||
|
\ifcase\month\or
|
||||||
|
Janeiro\or Fevereiro\or Março\or Abril\or Maio\or Junho\or
|
||||||
|
Julho\or Agosto\or Setembro\or Outubro\or Novembro\or Dezembro%
|
||||||
|
\fi
|
||||||
|
\ de \number\year%
|
||||||
|
}
|
||||||
|
|
||||||
|
% tabelas
|
||||||
|
\usepackage{booktabs}
|
||||||
|
\usepackage{array}
|
||||||
|
|
||||||
|
% conf
|
||||||
|
\usepackage{listings}
|
||||||
|
\lstset{
|
||||||
|
backgroundcolor=\color{codegray},
|
||||||
|
basicstyle=\ttfamily\small,
|
||||||
|
breakatwhitespace=false,
|
||||||
|
breaklines=true,
|
||||||
|
captionpos=b,
|
||||||
|
commentstyle=\color{green!50!black},
|
||||||
|
keywordstyle=\color{blue},
|
||||||
|
stringstyle=\color{red},
|
||||||
|
frame=single,
|
||||||
|
rulecolor=\color{black!20},
|
||||||
|
numbers=left,
|
||||||
|
numberstyle=\tiny\color{gray},
|
||||||
|
stepnumber=1,
|
||||||
|
tabsize=4,
|
||||||
|
showstringspaces=false
|
||||||
|
extendedchars=true,
|
||||||
|
literate={á}{{\'a}}1 {ã}{{\~a}}1 {é}{{\'e}}1 {ç}{{\c{c}}}1 {í}{{\'i}}1 {ó}{{\'o}}1 {õ}{{\~o}}1 {ú}{{\'u}}1 {µ}{{\ensuremath{\mu}}}1 {€}{{\euro}}1,
|
||||||
|
}
|
||||||
|
|
||||||
|
% seccões
|
||||||
|
\titleformat{\section}
|
||||||
|
{\color{navyblue}\normalfont\Large\bfseries}
|
||||||
|
{\thesection}{1em}{}
|
||||||
|
|
||||||
|
\titleformat{\subsection}
|
||||||
|
{\color{navyblue}\normalfont\large\bfseries}
|
||||||
|
{\thesubsection}{1em}{}
|
||||||
|
|
||||||
|
% metadados
|
||||||
|
\title{\textbf{\color{navyblue}Relatório de Correção de Regressão de Desempenho em Linux}}
|
||||||
|
\author{Leandro Afonso}
|
||||||
|
\date{\today}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
|
||||||
|
\maketitle
|
||||||
|
|
||||||
|
\section{Resumo do Problema}
|
||||||
|
A simulação distribuída de tráfego demonstrou uma regressão significativa de desempenho em ambiente Linux nativo quando comparada com a execução em Windows/Wine.
|
||||||
|
|
||||||
|
A tabela abaixo ilustra a discrepância nas taxas de conclusão de veículos dentro da janela de simulação fixa:
|
||||||
|
|
||||||
|
\begin{table}[h]
|
||||||
|
\centering
|
||||||
|
\begin{tabular}{@{}lc@{}}
|
||||||
|
\toprule
|
||||||
|
\textbf{Ambiente} & \textbf{Taxa de Conclusão} \\
|
||||||
|
\midrule
|
||||||
|
Windows / Wine & $\sim 95-100\%$ \\
|
||||||
|
Linux (OpenJDK Nativo) & $\sim 44\%$ \\
|
||||||
|
Linux (com \texttt{strace}) & $\sim 91\%$ \\
|
||||||
|
\bottomrule
|
||||||
|
\end{tabular}
|
||||||
|
\caption{Comparação de desempenho por ambiente.}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
O \textit{insight} crucial surgiu ao descobrir que a execução sob \texttt{strace} recuperava a taxa de conclusão para 91\%. O \texttt{strace} introduz \textit{overhead} em cada \textit{syscall}, o que, paradoxalmente, estabilizou o sistema ao forçar um abrandamento natural (\textit{throttling}).
|
||||||
|
|
||||||
|
\section{Causa Raiz}
|
||||||
|
\textbf{O Linux executa demasiado rápido.}
|
||||||
|
|
||||||
|
O Coordenador gera veículos a uma velocidade superior à capacidade de processamento das interseções distribuídas e da pilha de rede. Em Windows/Wine, o \textit{overhead} inerente à emulação e ao agendador do SO limita naturalmente a taxa de transferência do sistema.
|
||||||
|
|
||||||
|
Em Linux nativo, a execução mais célere provoca uma condição de corrida sistémica:
|
||||||
|
\begin{itemize}
|
||||||
|
\item A geração de veículos excede a capacidade de processamento imediato dos nós.
|
||||||
|
\item As filas de eventos congestionam (\textit{back up}) rapidamente nas interseções.
|
||||||
|
\item Veículos gerados tardiamente não dispõem de tempo de CPU suficiente para concluir o percurso antes do fim da simulação.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\section{Solução Implementada}
|
||||||
|
A correção consistiu na introdução de micro-atrasos (\textit{micro-throttles}) utilizando \texttt{LockSupport.parkNanos()}. Esta abordagem simula o \textit{overhead} natural presente no ambiente Windows, permitindo o escoamento das filas de E/S.
|
||||||
|
|
||||||
|
\subsection{Alterações no Código}
|
||||||
|
|
||||||
|
\textbf{1. Ficheiro: \texttt{SocketConnection.java}} \\
|
||||||
|
Adicionado um atraso de 50$\mu$s após operações de E/S para permitir o processamento da pilha TCP.
|
||||||
|
|
||||||
|
\begin{lstlisting}[language=Java, title={SocketConnection.java (Excerto)}]
|
||||||
|
// Em sendMessage() após o flush:
|
||||||
|
dataOut.flush();
|
||||||
|
LockSupport.parkNanos(50000); // 50 us delay
|
||||||
|
|
||||||
|
// Em receiveMessage() após readFully:
|
||||||
|
dataIn.readFully(data);
|
||||||
|
LockSupport.parkNanos(50000); // 50 us delay
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\textbf{2. Ficheiro: \texttt{CoordinatorProcess.java}} \\
|
||||||
|
Adicionado um atraso de 100$\mu$s na geração de veículos para limitar a taxa de produção.
|
||||||
|
|
||||||
|
\begin{lstlisting}[language=Java, title={CoordinatorProcess.java (Excerto)}]
|
||||||
|
// Em generateAndSendVehicle():
|
||||||
|
sendVehicleToIntersection(vehicle, entryIntersection);
|
||||||
|
LockSupport.parkNanos(100000); // 100 us delay
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\textbf{Nota: \textnormal{Em ambos os ficheiros deve ser importado java.util.concurrent.locks.LockSupport.}}
|
||||||
|
|
||||||
|
\section{Resultados e Validação}
|
||||||
|
|
||||||
|
A aplicação dos atrasos sintéticos restaurou a paridade de desempenho entre os sistemas operativos.
|
||||||
|
|
||||||
|
\begin{table}[h]
|
||||||
|
\centering
|
||||||
|
\begin{tabular}{@{}lcc@{}}
|
||||||
|
\toprule
|
||||||
|
\textbf{Ambiente} & \textbf{Antes da Correção} & \textbf{Após Correção} \\
|
||||||
|
\midrule
|
||||||
|
Linux Nativo & $\sim 44\%$ & $\mathbf{\sim 92\%}$ \\
|
||||||
|
\bottomrule
|
||||||
|
\end{tabular}
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
\subsection{Por que funciona?}
|
||||||
|
\begin{itemize}
|
||||||
|
\item \textbf{Precisão:} \texttt{LockSupport.parkNanos()} oferece um atraso preciso e não bloqueante, com impacto mínimo no agendador do SO, ao contrário de \texttt{Thread.sleep()}.
|
||||||
|
\item \textbf{Ritmo de E/S (50$\mu$s):} Abranda a comunicação via \textit{socket} o suficiente para evitar a saturação dos \textit{buffers} de receção das interseções.
|
||||||
|
\item \textbf{Controlo de Fluxo (100$\mu$s):} Limita a produção do Coordenador, garantindo que o sistema a jusante consegue processar os eventos em tempo útil.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\subsection{Verificação}
|
||||||
|
Para validar a correção no ambiente de desenvolvimento:
|
||||||
|
|
||||||
|
\begin{lstlisting}[language=bash]
|
||||||
|
mvn clean compile
|
||||||
|
mvn javafx:run
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\textbf{Resultado Esperado:} Taxa de conclusão superior a 90\%.
|
||||||
|
|
||||||
|
\section{Abordagens Alternativas (Falhadas)}
|
||||||
|
As seguintes tentativas foram realizadas antes da solução final, sem sucesso:
|
||||||
|
\begin{itemize}
|
||||||
|
\item \textbf{Thread.sleep(1):} Demasiado impreciso (granularidade mínima de $\sim$1ms em Linux), causando atrasos excessivos.
|
||||||
|
\item \textbf{Thread.yield():} Sem efeito prático no agendador CFS do Linux neste contexto.
|
||||||
|
\item \textbf{Garbage Collectors:} A alteração entre G1, Parallel e Shenandoah não surtiu efeito.
|
||||||
|
\item \textbf{Versão Java:} Testes com Java 17 e 25 mostraram o mesmo comportamento.
|
||||||
|
\item \textbf{Prioridade de Threads:} Ajustes de prioridade na JVM foram ignorados pelo SO.
|
||||||
|
\end{itemize}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
Reference in New Issue
Block a user