PDA

View Full Version : QAbstractProxyModel::mapToSource performance issues



maximAL
10th January 2008, 16:48
hi,
sorry for opening a second thread in one day, i'm really stumbling from one pitfall into another here :(

the situation is like this:
i got a QStandardItemModel subclass presenting a tree of data.
this includes a list of EVENTs, who have about 4-5 sub-elements each.

onto this model, i want to set a proxy model, subclassed from QAbstractProxyModel, to map the EVENTs into a table-like model.
eg. an EVENT has an NOTE attribute (sub-item in the tree) with value 10, so some of it's information should be used in row 10 in the proxy.

as you can imagine, danymic mapping in the mapToSource function is rather expensive because every time i have to search through all the EVENTs and try to find one that fits the current row.

but i underastimated HOW expansive it really is.
so, the proxy displays a 4 * 128 table, there is only one EVENT in the source model.
but nevertheless it takes several seconds to build up the proxy (on an 5200 dual core!), making scrolling etc. just impossible. adding more scenes should have linear complexity, making it event more unusable.

i really can't see the performance drain here. initially displaying the proxy results in ~800 calls of mapToSource - how can that take so long? are the model - functions like data(), index etc. such performance hogs?

code:

QModelIndex NewScriptModelEventTableProxy::mapToSource(
const QModelIndex &i_ProxyIndex) const
{
// is lightning fast, so rest rest of the function is the cause
//return QModelIndex();

static int p_iCalls = 0;

++p_iCalls;
// about 800 calls for initial display
qDebug() << "calls : " << p_iCalls;

int p_iNote = i_ProxyIndex.row();
int p_iColumn = i_ProxyIndex.column();

QString p_State;

if(p_iColumn == this->ColOnAction || p_iColumn == this->ColOnCondition)
p_State = "on";
else
p_State = "off";

QModelIndex p_EventTable = this->sourceModel()->index(0, 0);

// will only be 1 in my test case
int p_iNumEvents = this->sourceModel()->rowCount(p_EventTable);

for(
int i = 0;
i < p_iNumEvents;
++i)
{
QModelIndex p_Event = this->sourceModel()->index(i, 0, p_EventTable);
// about 4
int p_iNumAttributes = this->sourceModel()->rowCount(p_Event);

int p_EventNote;
int p_EventTrack;
QString p_EventState;
QModelIndex p_Action;
QModelIndex p_Condition;

for(
int j = 0;
j < p_iNumAttributes;
++j)
{
QModelIndex p_AttributeIndex = p_Event.child(j, 0);
QModelIndex p_ValueIndex = p_Event.child(j, 1);
QString p_AttributeName = p_AttributeIndex.data().toString();

if(p_AttributeName == "note")
p_EventNote = p_ValueIndex.data().toString().toInt();
else if(p_AttributeName == "track")
p_EventTrack = p_ValueIndex.data().toString().toInt();
else if(p_AttributeName == "state")
p_EventState = p_ValueIndex.data().toString();
else if(p_AttributeName == "action")
p_Action = p_ValueIndex;
else if(p_AttributeName == "condition")
p_Condition = p_ValueIndex;
}

if(
p_EventNote == p_iNote &&
p_EventTrack == this->m_iTrack &&
p_EventState == p_State)
{
switch(p_iColumn)
{
case this->ColOnAction:
case this->ColOffAction:
return p_Action;
default:
return p_Condition;
}
}
}

return QModelIndex();
}

jacek
10th January 2008, 18:43
800 calls takes few seconds? Have you tried using a profiler to obtain more specific data?

maximAL
14th January 2008, 22:48
oh well, the source models data-function was mostly the cause, because there was some really inefficient code hidden. but even getting rid of it, the solution turned out to be too slow, when using more than a few dozend EVENT elements. i finally got a solution running, that caches the data on every dataChanged etc. event