Debugger: Performance fixes for conditional breakpoints

This commit is contained in:
Souryo 2017-03-03 21:03:20 -05:00
parent 51afb5ae3f
commit 4f6776f30b
7 changed files with 85 additions and 55 deletions

View file

@ -911,7 +911,7 @@ CartridgeState BaseMapper::GetState()
state.PrgPageSize = InternalGetPrgPageSize();
state.ChrPageCount = GetCHRPageCount();
state.ChrPageSize = InternalGetChrPageSize();
for(int i = 0; i < 64; i++) {
for(int i = 0, max = 0x8000 / state.PrgPageSize; i < max; i++) {
if(_prgPageNumbers[i] != 0xEEEEEEEE) {
int16_t pageNumber = (int16_t)_prgPageNumbers[i];
state.PrgSelectedPages[i] = pageNumber < 0 ? state.PrgPageCount + pageNumber : pageNumber;
@ -920,7 +920,7 @@ CartridgeState BaseMapper::GetState()
}
}
for(int i = 0; i < 64; i++) {
for(int i = 0, max = 0x2000 / state.ChrPageSize; i < max; i++) {
if(_chrPageNumbers[i] != 0xEEEEEEEE) {
int16_t pageNumber = (int16_t)_chrPageNumbers[i];
state.ChrSelectedPages[i] = pageNumber < 0 ? state.ChrPageCount + pageNumber : pageNumber;

View file

@ -46,6 +46,11 @@ string Breakpoint::GetCondition()
return _condition;
}
bool Breakpoint::HasCondition()
{
return _condition[0] != 0;
}
void Breakpoint::ClearCondition()
{
memset(_condition, 0, sizeof(_condition));

View file

@ -32,6 +32,7 @@ public:
bool Matches(uint32_t memoryAddr, uint32_t absoluteAddr);
bool HasBreakpointType(BreakpointType type);
string GetCondition();
bool HasCondition();
void ClearCondition();
private:

View file

@ -200,6 +200,7 @@ void Debugger::UpdateBreakpoints()
for(int i = 0; i < Debugger::BreakpointTypeCount; i++) {
_breakpoints[i].clear();
_breakpointRpnList[i].clear();
_hasBreakpoint[i] = false;
}
@ -208,6 +209,7 @@ void Debugger::UpdateBreakpoints()
for(int i = 0; i < Debugger::BreakpointTypeCount; i++) {
if(bp.HasBreakpointType((BreakpointType)i)) {
_breakpoints[i].push_back(bp);
_breakpointRpnList[i].push_back(expEval.GetRpnList(bp.GetCondition()));
_hasBreakpoint[i] = true;
}
}
@ -225,20 +227,25 @@ bool Debugger::HasMatchingBreakpoint(BreakpointType type, uint32_t addr, int16_t
vector<Breakpoint> &breakpoints = _breakpoints[(int)type];
bool needState = true;
EvalResultType resultType;
for(size_t i = 0, len = breakpoints.size(); i < len; i++) {
Breakpoint &breakpoint = breakpoints[i];
if(type == BreakpointType::Global || breakpoint.Matches(addr, absoluteAddr)) {
string condition = breakpoint.GetCondition();
if(condition.empty()) {
if(!breakpoint.HasCondition()) {
return true;
} else {
ExpressionEvaluator expEval(this);
if(needState) {
GetState(&_debugState);
GetState(&_debugState, false);
needState = false;
}
if(expEval.Evaluate(condition, _debugState, value, addr) != 0) {
return true;
if(_breakpointRpnList[(int)type][i]) {
if(_bpExpEval.Evaluate(_breakpointRpnList[(int)type][i], _debugState, resultType, value, addr) != 0) {
return true;
}
} else {
if(_bpExpEval.Evaluate(breakpoint.GetCondition(), _debugState, resultType, value, addr) != 0) {
return true;
}
}
}
}
@ -249,12 +256,9 @@ bool Debugger::HasMatchingBreakpoint(BreakpointType type, uint32_t addr, int16_t
int32_t Debugger::EvaluateExpression(string expression, EvalResultType &resultType)
{
ExpressionEvaluator expEval(this);
DebugState state;
GetState(&state);
return expEval.Evaluate(expression, state, resultType);
return _watchExpEval.Evaluate(expression, state, resultType);
}
void Debugger::UpdateCallstack(uint32_t addr)
@ -461,11 +465,13 @@ void Debugger::PrivateProcessVramOperation(MemoryOperationType type, uint16_t ad
}
}
void Debugger::GetState(DebugState *state)
void Debugger::GetState(DebugState *state, bool includeMapperInfo)
{
state->CPU = _cpu->GetState();
state->PPU = _ppu->GetState();
state->Cartridge = _mapper->GetState();
if(includeMapperInfo) {
state->Cartridge = _mapper->GetState();
}
}
void Debugger::SetState(DebugState state)

View file

@ -54,6 +54,7 @@ private:
atomic<int32_t> _suspendCount;
vector<Breakpoint> _newBreakpoints;
vector<Breakpoint> _breakpoints[BreakpointTypeCount];
vector<vector<int>*> _breakpointRpnList[BreakpointTypeCount];
bool _hasBreakpoint[BreakpointTypeCount] = {};
vector<uint8_t> _frozenAddresses;
@ -63,6 +64,8 @@ private:
unordered_set<uint32_t> _functionEntryPoints;
ExpressionEvaluator _watchExpEval = ExpressionEvaluator(this);
ExpressionEvaluator _bpExpEval = ExpressionEvaluator(this);
DebugState _debugState;
SimpleLock _breakLock;
@ -117,7 +120,7 @@ public:
void GetFunctionEntryPoints(int32_t* entryPoints);
void GetCallstack(int32_t* callstackAbsolute, int32_t* callstackRelative);
void GetState(DebugState *state);
void GetState(DebugState *state, bool includeMapperInfo = true);
void SetState(DebugState state);
void Suspend();

View file

@ -10,6 +10,11 @@
std::unordered_map<string, std::vector<int>, StringHasher> ExpressionEvaluator::_outputCache;
SimpleLock ExpressionEvaluator::_cacheLock;
const vector<string> ExpressionEvaluator::_binaryOperators = { { "*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||" } };
const vector<int> ExpressionEvaluator::_binaryPrecedence = { { 10, 10, 10, 9, 9, 8, 8, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1 } };
const vector<string> ExpressionEvaluator::_unaryOperators = { { "+", "-", "!", "~" } };
const vector<int> ExpressionEvaluator::_unaryPrecedence = { { 11, 11, 11, 11 } };
bool ExpressionEvaluator::IsOperator(string token, int &precedence, bool unaryOperator)
{
if(unaryOperator) {
@ -257,7 +262,11 @@ bool ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
return false;
}
} else {
outputQueue.push_back(std::stoi(token));
if(token[0] < '0' || token[0] > '9') {
return false;
} else {
outputQueue.push_back(std::stoi(token));
}
}
}
@ -274,16 +283,15 @@ bool ExpressionEvaluator::ToRpn(string expression, vector<int> &outputQueue)
return true;
}
int32_t ExpressionEvaluator::EvaluateExpression(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
int32_t ExpressionEvaluator::Evaluate(vector<int> *rpnList, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
{
int pos = 0;
int right = 0;
int left = 0;
int operandStack[1000];
resultType = EvalResultType::Numeric;
for(size_t i = 0, len = outputQueue->size(); i < len; i++) {
int token = (*outputQueue)[i];
for(size_t i = 0, len = rpnList->size(); i < len; i++) {
int token = (*rpnList)[i];
if(token >= EvalValues::RegA) {
//Replace value with a special value
@ -291,12 +299,12 @@ int32_t ExpressionEvaluator::EvaluateExpression(vector<int> *outputQueue, DebugS
case EvalValues::RegA: token = state.CPU.A; break;
case EvalValues::RegX: token = state.CPU.X; break;
case EvalValues::RegY: token = state.CPU.Y; break;
case EvalValues::RegPS: token = state.CPU.PS; break;
case EvalValues::RegSP: token = state.CPU.SP; break;
case EvalValues::Irq: token = state.CPU.IRQFlag; break;
case EvalValues::Nmi: token = state.CPU.NMIFlag; break;
case EvalValues::RegPS: token = state.CPU.PS; break;
case EvalValues::PpuCycle: token = state.PPU.Cycle; break;
case EvalValues::PpuScanline: token = state.PPU.Scanline; break;
case EvalValues::Nmi: token = state.CPU.NMIFlag; break;
case EvalValues::Irq: token = state.CPU.IRQFlag; break;
case EvalValues::Value: token = memoryValue; break;
case EvalValues::Address: token = memoryAddr; break;
case EvalValues::AbsoluteAddress: token = _debugger->GetAbsoluteAddress(memoryAddr); break;
@ -330,12 +338,12 @@ int32_t ExpressionEvaluator::EvaluateExpression(vector<int> *outputQueue, DebugS
case EvalOperators::LogicalOr: token = left || right; resultType = EvalResultType::Boolean; break;
//Unary operators
case EvalOperators::Bracket: token = _debugger->GetMemoryValue(right); break;
case EvalOperators::Braces: token = _debugger->GetMemoryValue(right) | (_debugger->GetMemoryValue(right+1) << 8); break;
case EvalOperators::Plus: token = right; break;
case EvalOperators::Minus: token = -right; break;
case EvalOperators::BinaryNot: token = ~right; break;
case EvalOperators::LogicalNot: token = !right; break;
case EvalOperators::Bracket: token = _debugger->GetMemoryValue(right); break;
case EvalOperators::Braces: token = _debugger->GetMemoryValue(right) | (_debugger->GetMemoryValue(right+1) << 8); break;
default: throw std::runtime_error("Invalid operator");
}
}
@ -349,12 +357,16 @@ ExpressionEvaluator::ExpressionEvaluator(Debugger* debugger)
_debugger = debugger;
}
int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr, bool& success)
vector<int>* ExpressionEvaluator::GetRpnList(string expression)
{
success = true;
vector<int> output;
vector<int> *outputQueue = nullptr;
bool success;
return GetRpnList(expression, output, success);
}
vector<int>* ExpressionEvaluator::GetRpnList(string expression, vector<int> &output, bool& success)
{
vector<int> *outputQueue = nullptr;
{
LockHandler lock = _cacheLock.AcquireSafe();
@ -363,36 +375,37 @@ int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &stat
outputQueue = &(cacheOutputQueue->second);
}
}
if(outputQueue == nullptr && output.empty()) {
if(outputQueue == nullptr) {
string fixedExp = expression;
fixedExp.erase(std::remove(fixedExp.begin(), fixedExp.end(), ' '), fixedExp.end());
success = ToRpn(fixedExp, output);
if(success) {
if(_containsCustomLabels) {
outputQueue = &output;
} else {
LockHandler lock = _cacheLock.AcquireSafe();
_outputCache[expression] = output;
outputQueue = &_outputCache[expression];
}
} else {
return 0;
if(success && !_containsCustomLabels) {
LockHandler lock = _cacheLock.AcquireSafe();
_outputCache[expression] = output;
outputQueue = &_outputCache[expression];
}
}
if(outputQueue) {
return EvaluateExpression(outputQueue, state, resultType, memoryValue, memoryAddr);
} else {
return EvaluateExpression(&output, state, resultType, memoryValue, memoryAddr);
}
return outputQueue;
}
int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, int16_t memoryValue, uint32_t memoryAddr)
int32_t ExpressionEvaluator::PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr, bool& success)
{
EvalResultType resultType;
return Evaluate(expression, state, resultType, memoryValue, memoryAddr);
success = true;
vector<int> output;
vector<int> *rpnList = GetRpnList(expression, output, success);
if(!success) {
return 0;
}
if(!rpnList) {
rpnList = &output;
}
return Evaluate(rpnList, state, resultType, memoryValue, memoryAddr);
}
int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr)
@ -407,7 +420,6 @@ int32_t ExpressionEvaluator::Evaluate(string expression, DebugState &state, Eval
}
resultType = EvalResultType::Invalid;
return 0;
}
bool ExpressionEvaluator::Validate(string expression)

View file

@ -80,14 +80,15 @@ public:
class ExpressionEvaluator
{
private:
const vector<string> _binaryOperators = { { "*", "/", "%", "+", "-", "<<", ">>", "<", "<=", ">", ">=", "==", "!=", "&", "^", "|", "&&", "||" } };
const vector<int> _binaryPrecedence = { { 10, 10, 10, 9, 9, 8, 8, 7, 7, 7, 7, 6, 6, 5, 4, 3, 2, 1 } };
const vector<string> _unaryOperators = { { "+", "-", "!", "~" } };
const vector<int> _unaryPrecedence = { { 11, 11, 11, 11 } };
static const vector<string> _binaryOperators;
static const vector<int> _binaryPrecedence;
static const vector<string> _unaryOperators;
static const vector<int> _unaryPrecedence;
static std::unordered_map<string, std::vector<int>, StringHasher> _outputCache;
static SimpleLock _cacheLock;
int operandStack[1000];
Debugger* _debugger;
bool _containsCustomLabels = false;
@ -97,13 +98,15 @@ private:
string GetNextToken(string expression, size_t &pos);
bool ProcessSpecialOperator(EvalOperators evalOp, std::stack<EvalOperators> &opStack, vector<int> &outputQueue);
bool ToRpn(string expression, vector<int> &outputQueue);
int32_t EvaluateExpression(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr);
int32_t PrivateEvaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue, uint32_t memoryAddr, bool &success);
vector<int>* GetRpnList(string expression, vector<int> &output, bool& success);
public:
ExpressionEvaluator(Debugger* debugger);
int32_t Evaluate(string expression, DebugState &state, int16_t memoryValue = 0, uint32_t memoryAddr = 0);
int32_t Evaluate(vector<int> *outputQueue, DebugState &state, EvalResultType &resultType, int16_t memoryValue = 0, uint32_t memoryAddr = 0);
int32_t Evaluate(string expression, DebugState &state, EvalResultType &resultType, int16_t memoryValue = 0, uint32_t memoryAddr = 0);
vector<int>* GetRpnList(string expression);
bool Validate(string expression);
};