• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdesdk API Reference
  • KDE Home
  • Contact Us
 

kcachegrind

  • sources
  • kde-4.12
  • kdesdk
  • kcachegrind
  • libviews
sourceview.cpp
Go to the documentation of this file.
1 /* This file is part of KCachegrind.
2  Copyright (C) 2011 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
3 
4  KCachegrind is free software; you can redistribute it and/or
5  modify it under the terms of the GNU General Public
6  License as published by the Free Software Foundation, version 2.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; see the file COPYING. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 */
18 
19 /*
20  * Source View
21  */
22 
23 #include "sourceview.h"
24 
25 #include <QDebug>
26 #include <QDir>
27 #include <QFile>
28 #include <QFileInfo>
29 #include <QAction>
30 #include <QMenu>
31 #include <QScrollBar>
32 #include <QHeaderView>
33 #include <QKeyEvent>
34 
35 #include "globalconfig.h"
36 #include "sourceitem.h"
37 
38 
39 
40 //
41 // SourceView
42 //
43 
44 
45 SourceView::SourceView(TraceItemView* parentView,
46  QWidget* parent)
47  : QTreeWidget(parent), TraceItemView(parentView)
48 {
49  _inSelectionUpdate = false;
50 
51  _arrowLevels = 0;
52 
53 
54  setColumnCount(5);
55  setRootIsDecorated(false);
56  setAllColumnsShowFocus(true);
57  setUniformRowHeights(true);
58  // collapsing call/jump lines by double-click is confusing
59  setExpandsOnDoubleClick(false);
60 
61  QStringList headerLabels;
62  headerLabels << tr( "#" )
63  << tr( "Cost" )
64  << tr( "Cost 2" )
65  << ""
66  << tr( "Source (unknown)");
67  setHeaderLabels(headerLabels);
68 
69  // sorting will be enabled after refresh()
70  sortByColumn(0, Qt::AscendingOrder);
71  header()->setSortIndicatorShown(false);
72  this->setItemDelegate(new SourceItemDelegate(this));
73  this->setWhatsThis( whatsThis());
74 
75  connect( this,
76  SIGNAL( currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
77  SLOT( selectedSlot(QTreeWidgetItem*,QTreeWidgetItem*) ) );
78 
79  setContextMenuPolicy(Qt::CustomContextMenu);
80  connect( this,
81  SIGNAL(customContextMenuRequested(const QPoint &) ),
82  SLOT(context(const QPoint &)));
83 
84  connect(this,
85  SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
86  SLOT(activatedSlot(QTreeWidgetItem*,int)));
87 
88  connect(header(), SIGNAL(sectionClicked(int)),
89  this, SLOT(headerClicked(int)));
90 }
91 
92 QString SourceView::whatsThis() const
93 {
94  return tr( "<b>Annotated Source</b>"
95  "<p>The annotated source list shows the "
96  "source lines of the current selected function "
97  "together with (self) cost spent while executing the "
98  "code of this source line. If there was a call "
99  "in a source line, lines with details on the "
100  "call happening are inserted into the source: "
101  "the cost spent inside of the call, the "
102  "number of calls happening, and the call destination.</p>"
103  "<p>Select a inserted call information line to "
104  "make the destination function current.</p>");
105 }
106 
107 void SourceView::context(const QPoint & p)
108 {
109  int c = columnAt(p.x());
110  QTreeWidgetItem* i = itemAt(p);
111  QMenu popup;
112 
113  TraceLineCall* lc = i ? ((SourceItem*) i)->lineCall() : 0;
114  TraceLineJump* lj = i ? ((SourceItem*) i)->lineJump() : 0;
115  TraceFunction* f = lc ? lc->call()->called() : 0;
116  TraceLine* line = lj ? lj->lineTo() : 0;
117 
118  QAction* activateFunctionAction = 0;
119  QAction* activateLineAction = 0;
120  if (f) {
121  QString menuText = tr("Go to '%1'").arg(GlobalConfig::shortenSymbol(f->prettyName()));
122  activateFunctionAction = popup.addAction(menuText);
123  popup.addSeparator();
124  }
125  else if (line) {
126  QString menuText = tr("Go to Line %1").arg(line->name());
127  activateLineAction = popup.addAction(menuText);
128  popup.addSeparator();
129  }
130 
131  if ((c == 1) || (c == 2)) {
132  addEventTypeMenu(&popup);
133  popup.addSeparator();
134  }
135  addGoMenu(&popup);
136 
137  QAction* a = popup.exec(mapToGlobal(p + QPoint(0,header()->height())));
138  if (a == activateFunctionAction)
139  TraceItemView::activated(f);
140  else if (a == activateLineAction)
141  TraceItemView::activated(line);
142 }
143 
144 
145 void SourceView::selectedSlot(QTreeWidgetItem *i, QTreeWidgetItem *)
146 {
147  if (!i) return;
148  // programatically selected items are not signalled
149  if (_inSelectionUpdate) return;
150 
151  TraceLineCall* lc = ((SourceItem*) i)->lineCall();
152  TraceLineJump* lj = ((SourceItem*) i)->lineJump();
153 
154  if (!lc && !lj) {
155  TraceLine* l = ((SourceItem*) i)->line();
156  if (l) {
157  _selectedItem = l;
158  selected(l);
159  }
160  return;
161  }
162 
163  TraceFunction* f = lc ? lc->call()->called() : 0;
164  if (f) {
165  _selectedItem = f;
166  selected(f);
167  }
168  else {
169  TraceLine* line = lj ? lj->lineTo() : 0;
170  if (line) {
171  _selectedItem = line;
172  selected(line);
173  }
174  }
175 }
176 
177 void SourceView::activatedSlot(QTreeWidgetItem* i, int)
178 {
179  if (!i) return;
180 
181  TraceLineCall* lc = ((SourceItem*) i)->lineCall();
182  TraceLineJump* lj = ((SourceItem*) i)->lineJump();
183 
184  if (!lc && !lj) {
185  TraceLine* l = ((SourceItem*) i)->line();
186  if (l) TraceItemView::activated(l);
187  return;
188  }
189 
190  TraceFunction* f = lc ? lc->call()->called() : 0;
191  if (f) TraceItemView::activated(f);
192  else {
193  TraceLine* line = lj ? lj->lineTo() : 0;
194  if (line) TraceItemView::activated(line);
195  }
196 }
197 
198 void SourceView::keyPressEvent(QKeyEvent* event)
199 {
200  QTreeWidgetItem *item = currentItem();
201  if (item && ((event->key() == Qt::Key_Return) ||
202  (event->key() == Qt::Key_Space)))
203  {
204  activatedSlot(item, 0);
205  }
206  QTreeView::keyPressEvent(event);
207 }
208 
209 CostItem* SourceView::canShow(CostItem* i)
210 {
211  ProfileContext::Type t = i ? i->type() : ProfileContext::InvalidType;
212  TraceFunction* f = 0;
213 
214  switch(t) {
215  case ProfileContext::Function:
216  f = (TraceFunction*) i;
217  break;
218 
219  case ProfileContext::Instr:
220  f = ((TraceInstr*)i)->function();
221  select(i);
222  break;
223 
224  case ProfileContext::Line:
225  f = ((TraceLine*)i)->functionSource()->function();
226  select(i);
227  break;
228 
229  default:
230  break;
231  }
232 
233  return f;
234 }
235 
236 void SourceView::doUpdate(int changeType, bool)
237 {
238  // Special case ?
239  if (changeType == selectedItemChanged) {
240 
241  if (!_selectedItem) {
242  clearSelection();
243  return;
244  }
245 
246  TraceLine* sLine = 0;
247  if (_selectedItem->type() == ProfileContext::Line)
248  sLine = (TraceLine*) _selectedItem;
249  if (_selectedItem->type() == ProfileContext::Instr)
250  sLine = ((TraceInstr*)_selectedItem)->line();
251  if (!sLine)
252  return;
253 
254  QList<QTreeWidgetItem*> items = selectedItems();
255  SourceItem* si = (items.count() > 0) ? (SourceItem*)items[0] : 0;
256  if (si) {
257  if (si->line() == sLine) return;
258  if (si->lineCall() &&
259  (si->lineCall()->call()->called() == _selectedItem)) return;
260  }
261 
262  QTreeWidgetItem *item, *item2;
263  for (int i=0; i<topLevelItemCount(); i++) {
264  item = topLevelItem(i);
265  si = (SourceItem*)item;
266  if (si->line() == sLine) {
267  scrollToItem(item);
268  _inSelectionUpdate = true;
269  setCurrentItem(item);
270  _inSelectionUpdate = false;
271  break;
272  }
273  item2 = 0;
274  for (int j=0; i<item->childCount(); j++) {
275  item2 = item->child(j);
276  si = (SourceItem*)item2;
277  if (!si->lineCall()) continue;
278  if (si->lineCall()->call()->called() == _selectedItem) {
279  scrollToItem(item2);
280  _inSelectionUpdate = true;
281  setCurrentItem(item2);
282  _inSelectionUpdate = false;
283  break;
284  }
285  }
286  if (item2) break;
287  }
288  return;
289  }
290 
291  if (changeType == groupTypeChanged) {
292  // update group colors for call lines
293  QTreeWidgetItem *item, *item2;
294  for (int i=0; i<topLevelItemCount(); i++) {
295  item = topLevelItem(i);
296  for (int j=0; i<item->childCount(); i++) {
297  item2 = item->child(j);
298  ((SourceItem*)item2)->updateGroup();
299  }
300  }
301  return;
302  }
303 
304  // On eventTypeChanged, we can not just change the costs shown in
305  // already existing items, as costs of 0 should make the line to not
306  // be shown at all. So we do a full refresh.
307 
308  refresh();
309 }
310 
311 void SourceView::refresh()
312 {
313  int originalPosition = verticalScrollBar()->value();
314  clear();
315  setColumnWidth(0, 20);
316  setColumnWidth(1, 50);
317  setColumnWidth(2, _eventType2 ? 50:0);
318  setColumnWidth(3, 0); // arrows, defaults to invisible
319  if (_eventType)
320  headerItem()->setText(1, _eventType->name());
321  if (_eventType2)
322  headerItem()->setText(2, _eventType2->name());
323 
324  _arrowLevels = 0;
325  if (!_data || !_activeItem) {
326  headerItem()->setText(4, tr("(No Source)"));
327  return;
328  }
329 
330  ProfileContext::Type t = _activeItem->type();
331  TraceFunction* f = 0;
332  if (t == ProfileContext::Function) f = (TraceFunction*) _activeItem;
333  if (t == ProfileContext::Instr) {
334  f = ((TraceInstr*)_activeItem)->function();
335  if (!_selectedItem) _selectedItem = _activeItem;
336  }
337  if (t == ProfileContext::Line) {
338  f = ((TraceLine*)_activeItem)->functionSource()->function();
339  if (!_selectedItem) _selectedItem = _activeItem;
340  }
341 
342  if (!f) return;
343 
344  TraceFunctionSource* mainSF = f->sourceFile();
345 
346  // skip first source if there is no debug info and there are more sources
347  // (this is for a bug in GCC 2.95.x giving unknown source for prologs)
348  if (mainSF &&
349  (mainSF->firstLineno() == 0) &&
350  (mainSF->lastLineno() == 0) &&
351  (f->sourceFiles().count()>1) ) {
352  // skip
353  }
354  else
355  fillSourceFile(mainSF, 0);
356 
357  int fileno = 0;
358  foreach(TraceFunctionSource* sf, f->sourceFiles()) {
359  fileno++;
360  if (sf != mainSF)
361  fillSourceFile(sf, fileno);
362  }
363 
364  if (!_eventType2) {
365 #if QT_VERSION >= 0x050000
366  header()->setSectionResizeMode(2, QHeaderView::Interactive);
367 #else
368  header()->setResizeMode(2, QHeaderView::Interactive);
369 #endif
370  setColumnWidth(2, 0);
371  }
372  // reset to the original position - this is useful when the view
373  // is refreshed just because we change between relative/absolute
374  verticalScrollBar()->setValue(originalPosition);
375 }
376 
377 
378 /* Helper for fillSourceList:
379  * search recursive for a file, starting from a base dir
380  * If found, returns true and <dir> is set to the file path.
381  */
382 static bool searchFileRecursive(QString& dir, const QString& name)
383 {
384  // we leave this in...
385  qDebug("Checking %s/%s", qPrintable(dir), qPrintable(name));
386 
387  if (QFile::exists(dir + '/' + name)) return true;
388 
389  // check in subdirectories
390  QDir d(dir);
391  d.setFilter( QDir::Dirs | QDir::NoSymLinks );
392  d.setSorting( QDir::Unsorted );
393  QStringList subdirs = d.entryList();
394  QStringList::const_iterator it =subdirs.constBegin();
395  for(; it != subdirs.constEnd(); ++it ) {
396  if (*it == "." || *it == ".." || *it == "CVS") continue;
397 
398  dir = d.filePath(*it);
399  if (searchFileRecursive(dir, name)) return true;
400  }
401  return false;
402 }
403 
404 /* Search for a source file in different places.
405  * If found, returns true and <dir> is set to the file path.
406  */
407 bool SourceView::searchFile(QString& dir,
408  TraceFunctionSource* sf)
409 {
410  QString name = sf->file()->shortName();
411 
412  if (QDir::isAbsolutePath(dir)) {
413  if (QFile::exists(dir + '/' + name)) return true;
414  }
415  else {
416  /* Directory is relative. Check
417  * - relative to cwd
418  * - relative to path of data file
419  */
420  QString base = QDir::currentPath() + '/' + dir;
421  if (QFile::exists(base + '/' + name)) {
422  dir = base;
423  return true;
424  }
425 
426  TracePart* firstPart = _data->parts().first();
427  if (firstPart) {
428  QFileInfo partFile(firstPart->name());
429  if (QFileInfo(partFile.absolutePath(), name).exists()) {
430  dir = partFile.absolutePath();
431  return true;
432  }
433  }
434  }
435 
436  QStringList list = GlobalConfig::sourceDirs(_data,
437  sf->function()->object());
438  QStringList::const_iterator it;
439  for ( it = list.constBegin(); it != list.constEnd(); ++it ) {
440  dir = *it;
441  if (searchFileRecursive(dir, name)) return true;
442  }
443 
444  return false;
445 }
446 
447 
448 void SourceView::updateJumpArray(uint lineno, SourceItem* si,
449  bool ignoreFrom, bool ignoreTo)
450 {
451  uint lowLineno, highLineno;
452  int iEnd = -1, iStart = -1;
453 
454  if (0) qDebug("updateJumpArray(line %d, jump to %s)",
455  lineno,
456  si->lineJump()
457  ? qPrintable(si->lineJump()->lineTo()->name()) : "?" );
458 
459  while(_lowListIter != _lowList.end()) {
460  TraceLineJump* lj= *_lowListIter;
461  lowLineno = lj->lineFrom()->lineno();
462  if (lj->lineTo()->lineno() < lowLineno)
463  lowLineno = lj->lineTo()->lineno();
464 
465  if (lowLineno > lineno) break;
466 
467  if (ignoreFrom && (lowLineno < lj->lineTo()->lineno())) break;
468  if (ignoreTo && (lowLineno < lj->lineFrom()->lineno())) break;
469 
470  if (si->lineJump() && (lj != si->lineJump())) break;
471 
472  int asize = (int)_jump.size();
473 #if 0
474  for(iStart=0;iStart<asize;iStart++)
475  if (_jump[iStart] &&
476  (_jump[iStart]->lineTo() == lj->lineTo())) break;
477 #else
478  iStart = asize;
479 #endif
480 
481  if (iStart == asize) {
482  for(iStart=0;iStart<asize;iStart++)
483  if (_jump[iStart] == 0) break;
484 
485  if (iStart== asize) {
486  asize++;
487  _jump.resize(asize);
488  if (asize > _arrowLevels) _arrowLevels = asize;
489  }
490 
491  if (0) qDebug(" start %d (%s to %s)",
492  iStart,
493  qPrintable(lj->lineFrom()->name()),
494  qPrintable(lj->lineTo()->name()));
495 
496  _jump[iStart] = lj;
497  }
498  _lowListIter++;
499  }
500 
501  si->setJumpArray(_jump);
502 
503  while(_highListIter != _highList.end()) {
504  TraceLineJump* lj= *_highListIter;
505  highLineno = lj->lineFrom()->lineno();
506  if (lj->lineTo()->lineno() > highLineno) {
507  highLineno = lj->lineTo()->lineno();
508  if (ignoreTo) break;
509  }
510  else if (ignoreFrom) break;
511 
512  if (highLineno > lineno) break;
513 
514  for(iEnd=0;iEnd< (int)_jump.size();iEnd++)
515  if (_jump[iEnd] == lj) break;
516  if (iEnd == (int)_jump.size()) {
517  qDebug("LineView: no jump start for end at %x ?", highLineno);
518  iEnd = -1;
519  }
520 
521  if (0 && (iEnd>=0))
522  qDebug(" end %d (%s to %s)",
523  iEnd,
524  qPrintable(_jump[iEnd]->lineFrom()->name()),
525  qPrintable(_jump[iEnd]->lineTo()->name()));
526 
527  if (0 && lj) qDebug("next end: %s to %s",
528  qPrintable(lj->lineFrom()->name()),
529  qPrintable(lj->lineTo()->name()));
530 
531  _highListIter++;
532 
533  if (highLineno > lineno)
534  break;
535  else {
536  if (iEnd>=0) _jump[iEnd] = 0;
537  iEnd = -1;
538  }
539  }
540  if (iEnd>=0) _jump[iEnd] = 0;
541 }
542 
543 
544 // compare functions for jump arrow drawing
545 
546 void getJumpLines(const TraceLineJump* jump, uint& low, uint& high)
547 {
548  low = jump->lineFrom()->lineno();
549  high = jump->lineTo()->lineno();
550 
551  if (low > high) {
552  uint t = low;
553  low = high;
554  high = t;
555  }
556 }
557 
558 // sort jumps according to lower line number
559 bool lineJumpLowLessThan(const TraceLineJump* jump1,
560  const TraceLineJump* jump2)
561 {
562  uint line1Low, line1High, line2Low, line2High;
563 
564  getJumpLines(jump1, line1Low, line1High);
565  getJumpLines(jump2, line2Low, line2High);
566 
567  if (line1Low != line2Low) return (line1Low < line2Low);
568  // jump ends come before jump starts
569  if (line1Low == jump1->lineTo()->lineno()) return true;
570  if (line2Low == jump2->lineTo()->lineno()) return false;
571  return (line1High < line2High);
572 }
573 
574 // sort jumps according to higher line number
575 bool lineJumpHighLessThan(const TraceLineJump* jump1,
576  const TraceLineJump* jump2)
577 {
578  uint line1Low, line1High, line2Low, line2High;
579 
580  getJumpLines(jump1, line1Low, line1High);
581  getJumpLines(jump2, line2Low, line2High);
582 
583  if (line1High != line2High) return (line1High < line2High);
584  // jump ends come before jump starts
585  if (line1High == jump1->lineTo()->lineno()) return true;
586  if (line2High == jump2->lineTo()->lineno()) return false;
587  return (line1Low < line2Low);
588 }
589 
590 /* If sourceList is empty we set the source file name into the header,
591  * else this code is of a inlined function, and we add "inlined from..."
592  */
593 void SourceView::fillSourceFile(TraceFunctionSource* sf, int fileno)
594 {
595  if (!sf) return;
596 
597  if (0) qDebug("Selected Item %s",
598  _selectedItem ? qPrintable(_selectedItem->name()) : "(none)");
599 
600  TraceLineMap::Iterator lineIt, lineItEnd;
601  int nextCostLineno = 0, lastCostLineno = 0;
602 
603  bool validSourceFile = (!sf->file()->name().isEmpty());
604 
605  TraceLine* sLine = 0;
606  if (_selectedItem) {
607  if (_selectedItem->type() == ProfileContext::Line)
608  sLine = (TraceLine*) _selectedItem;
609  if (_selectedItem->type() == ProfileContext::Instr)
610  sLine = ((TraceInstr*)_selectedItem)->line();
611  }
612 
613  if (validSourceFile) {
614  TraceLineMap* lineMap = sf->lineMap();
615  if (lineMap) {
616  lineIt = lineMap->begin();
617  lineItEnd = lineMap->end();
618  // get first line with cost of selected type
619  while(lineIt != lineItEnd) {
620  if (&(*lineIt) == sLine) break;
621  if ((*lineIt).hasCost(_eventType)) break;
622  if (_eventType2 && (*lineIt).hasCost(_eventType2)) break;
623  ++lineIt;
624  }
625 
626  nextCostLineno = (lineIt == lineItEnd) ? 0 : (*lineIt).lineno();
627  if (nextCostLineno<0) {
628  qDebug() << "SourceView::fillSourceFile: Negative line number "
629  << nextCostLineno;
630  qDebug() << " Function '" << sf->function()->name() << "'";
631  qDebug() << " File '" << sf->file()->name() << "'";
632  nextCostLineno = 0;
633  }
634 
635  }
636 
637  if (nextCostLineno == 0) {
638  new SourceItem(this, this, fileno, 1, false,
639  tr("There is no cost of current selected type associated"));
640  new SourceItem(this, this, fileno, 2, false,
641  tr("with any source line of this function in file"));
642  new SourceItem(this, this, fileno, 3, false,
643  QString(" '%1'").arg(sf->file()->prettyName()));
644  new SourceItem(this, this, fileno, 4, false,
645  tr("Thus, no annotated source can be shown."));
646  return;
647  }
648  }
649 
650  QString filename = sf->file()->shortName();
651  QString dir = sf->file()->directory();
652  if (!dir.isEmpty())
653  filename = dir + '/' + filename;
654 
655  if (nextCostLineno>0) {
656  // we have debug info... search for source file
657  if (searchFile(dir, sf)) {
658  filename = dir + '/' + sf->file()->shortName();
659  // no need to search again
660  sf->file()->setDirectory(dir);
661  }
662  else
663  nextCostLineno = 0;
664  }
665 
666  // do it here, because the source directory could have been set before
667  if (topLevelItemCount()==0) {
668  headerItem()->setText(4, validSourceFile ?
669  tr("Source ('%1')").arg(filename) :
670  tr("Source (unknown)"));
671  }
672  else {
673  new SourceItem(this, this, fileno, 0, true,
674  validSourceFile ?
675  tr("--- Inlined from '%1' ---").arg(filename) :
676  tr("--- Inlined from unknown source ---"));
677  }
678 
679  if (nextCostLineno == 0) {
680  new SourceItem(this, this, fileno, 1, false,
681  tr("There is no source available for the following function:"));
682  new SourceItem(this, this, fileno, 2, false,
683  QString(" '%1'").arg(sf->function()->prettyName()));
684  if (sf->file()->name().isEmpty()) {
685  new SourceItem(this, this, fileno, 3, false,
686  tr("This is because no debug information is present."));
687  new SourceItem(this, this, fileno, 4, false,
688  tr("Recompile source and redo the profile run."));
689  if (sf->function()->object()) {
690  new SourceItem(this, this, fileno, 5, false,
691  tr("The function is located in this ELF object:"));
692  new SourceItem(this, this, fileno, 6, false,
693  QString(" '%1'")
694  .arg(sf->function()->object()->prettyName()));
695  }
696  }
697  else {
698  new SourceItem(this, this, fileno, 3, false,
699  tr("This is because its source file cannot be found:"));
700  new SourceItem(this, this, fileno, 4, false,
701  QString(" '%1'").arg(sf->file()->name()));
702  new SourceItem(this, this, fileno, 5, false,
703  tr("Add the folder of this file to the source folder list."));
704  new SourceItem(this, this, fileno, 6, false,
705  tr("The list can be found in the configuration dialog."));
706  }
707  return;
708  }
709 
710  // initialisation for arrow drawing
711  // create sorted list of jumps (for jump arrows)
712  TraceLineMap::Iterator it = lineIt, nextIt;
713  _lowList.clear();
714  _highList.clear();
715  while(1) {
716 
717  nextIt = it;
718  ++nextIt;
719  while(nextIt != lineItEnd) {
720  if (&(*nextIt) == sLine) break;
721  if ((*nextIt).hasCost(_eventType)) break;
722  if (_eventType2 && (*nextIt).hasCost(_eventType2)) break;
723  ++nextIt;
724  }
725 
726  TraceLineJumpList jlist = (*it).lineJumps();
727  foreach(TraceLineJump* lj, jlist) {
728  if (lj->executedCount()==0) continue;
729  // skip jumps to next source line with cost
730  //if (lj->lineTo() == &(*nextIt)) continue;
731 
732  _lowList.append(lj);
733  _highList.append(lj);
734  }
735  it = nextIt;
736  if (it == lineItEnd) break;
737  }
738  qSort(_lowList.begin(), _lowList.end(), lineJumpLowLessThan);
739  qSort(_highList.begin(), _highList.end(), lineJumpHighLessThan);
740  _lowListIter = _lowList.begin(); // iterators to list start
741  _highListIter = _highList.begin();
742  _jump.resize(0);
743 
744  char buf[160];
745  bool inside = false, skipLineWritten = true;
746  int readBytes;
747  int fileLineno = 0;
748  SubCost most = 0;
749 
750  QList<QTreeWidgetItem*> items;
751  TraceLine* currLine;
752  SourceItem *si, *si2, *item = 0, *first = 0, *selected = 0;
753  QFile file(filename);
754  bool fileEndReached = false;
755  if (!file.open(QIODevice::ReadOnly)) return;
756  while (1) {
757  readBytes=file.readLine(buf, sizeof( buf ));
758  if (readBytes<=0) {
759  // for nice empty 4 lines after function with EOF
760  buf[0] = 0;
761  if (readBytes<0) fileEndReached = true;
762  }
763 
764  if ((readBytes >0) && (buf[readBytes-1] != '\n')) {
765  /* Something was read but not ending in newline. I.e.
766  * - buffer was not big enough: discard rest of line, add "..."
767  * - this is last line of file, not ending in newline
768  * NB: checking for '\n' is enough for all systems.
769  */
770  int r;
771  char buf2[32];
772  bool somethingRead = false;
773  while(1) {
774  r = file.readLine(buf2, sizeof(buf2));
775  if ((r<=0) || (buf2[r-1] == '\n')) break;
776  somethingRead = true;
777  }
778  if (somethingRead) {
779  // add dots as sign that we truncated the line
780  Q_ASSERT(readBytes>3);
781  buf[readBytes-1] = buf[readBytes-2] = buf[readBytes-3] = '.';
782  }
783  }
784  else if ((readBytes>0) && (buf[readBytes-1] == '\n'))
785  buf[readBytes-1] = 0;
786 
787 
788  // keep fileLineno inside [lastCostLineno;nextCostLineno]
789  fileLineno++;
790  if (fileLineno == nextCostLineno) {
791  currLine = &(*lineIt);
792 
793  // get next line with cost of selected type
794  ++lineIt;
795  while(lineIt != lineItEnd) {
796  if (&(*lineIt) == sLine) break;
797  if ((*lineIt).hasCost(_eventType)) break;
798  if (_eventType2 && (*lineIt).hasCost(_eventType2)) break;
799  ++lineIt;
800  }
801 
802  lastCostLineno = nextCostLineno;
803  nextCostLineno = (lineIt == lineItEnd) ? 0 : (*lineIt).lineno();
804  }
805  else
806  currLine = 0;
807 
808  // update inside
809  if (!inside) {
810  if (currLine) inside = true;
811  }
812  else {
813  if ( (fileLineno > lastCostLineno) &&
814  ((nextCostLineno == 0) ||
815  (fileLineno < nextCostLineno - GlobalConfig::noCostInside()) ))
816  inside = false;
817  }
818 
819  int context = GlobalConfig::context();
820 
821  if ( ((lastCostLineno==0) || (fileLineno > lastCostLineno + context)) &&
822  ((nextCostLineno==0) || (fileLineno < nextCostLineno - context))) {
823  if ((lineIt == lineItEnd) || fileEndReached) break;
824 
825  if (!skipLineWritten) {
826  skipLineWritten = true;
827  // a "skipping" line: print "..." instead of a line number
828  strcpy(buf,"...");
829  }
830  else
831  continue;
832  }
833  else
834  skipLineWritten = false;
835 
836  QString s = QString(buf);
837  if(s.size() > 0 && s.at(s.length()-1) == '\r')
838  s = s.left(s.length()-1);
839  si = new SourceItem(this, 0,
840  fileno, fileLineno, inside, s,
841  currLine);
842  items.append(si);
843 
844  if (!currLine) continue;
845 
846  if (!selected && (currLine == sLine)) selected = si;
847  if (!first) first = si;
848 
849  if (currLine->subCost(_eventType) > most) {
850  item = si;
851  most = currLine->subCost(_eventType);
852  }
853 
854  si->setExpanded(true);
855  foreach(TraceLineCall* lc, currLine->lineCalls()) {
856  if ((lc->subCost(_eventType)==0) &&
857  (lc->subCost(_eventType2)==0)) continue;
858 
859  if (lc->subCost(_eventType) > most) {
860  item = si;
861  most = lc->subCost(_eventType);
862  }
863 
864  si2 = new SourceItem(this, si, fileno, fileLineno, currLine, lc);
865 
866  if (!selected && (lc->call()->called() == _selectedItem))
867  selected = si2;
868  }
869 
870  foreach(TraceLineJump* lj, currLine->lineJumps()) {
871  if (lj->executedCount()==0) continue;
872 
873  new SourceItem(this, si, fileno, fileLineno, currLine, lj);
874  }
875  }
876 
877  file.close();
878 
879  // Resize column 0 (line number) and 1/2 (cost) to contents
880 #if QT_VERSION >= 0x050000
881  header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
882  header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
883  header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
884 #else
885  header()->setResizeMode(0, QHeaderView::ResizeToContents);
886  header()->setResizeMode(1, QHeaderView::ResizeToContents);
887  header()->setResizeMode(2, QHeaderView::ResizeToContents);
888 #endif
889 
890  setSortingEnabled(false);
891  addTopLevelItems(items);
892  this->expandAll();
893  setSortingEnabled(true);
894  // always reset to line number sort
895  sortByColumn(0, Qt::AscendingOrder);
896  header()->setSortIndicatorShown(false);
897 
898  // Reallow interactive column size change after resizing to content
899 #if QT_VERSION >= 0x050000
900  header()->setSectionResizeMode(0, QHeaderView::Interactive);
901  header()->setSectionResizeMode(1, QHeaderView::Interactive);
902  header()->setSectionResizeMode(2, QHeaderView::Interactive);
903 #else
904  header()->setResizeMode(0, QHeaderView::Interactive);
905  header()->setResizeMode(1, QHeaderView::Interactive);
906  header()->setResizeMode(2, QHeaderView::Interactive);
907 #endif
908 
909  if (selected) item = selected;
910  if (item) first = item;
911  if (first) {
912  scrollToItem(first);
913  _inSelectionUpdate = true;
914  setCurrentItem(first);
915  _inSelectionUpdate = false;
916  }
917 
918  // for arrows: go down the list according to list sorting
919  QTreeWidgetItem *item1, *item2;
920  for (int i=0; i<topLevelItemCount(); i++) {
921  item1 = topLevelItem(i);
922  si = (SourceItem*)item1;
923  updateJumpArray(si->lineno(), si, true, false);
924 
925  for (int j=0; j<item1->childCount(); j++) {
926  item2 = item1->child(j);
927  si2 = (SourceItem*)item2;
928  if (si2->lineJump())
929  updateJumpArray(si->lineno(), si2, false, true);
930  else
931  si2->setJumpArray(_jump);
932  }
933  }
934 
935  if (arrowLevels())
936  //fix this: setColumnWidth(3, 10 + 6*arrowLevels() + itemMargin() * 2);
937  setColumnWidth(3, 10 + 6*arrowLevels() + 2);
938  else
939  setColumnWidth(3, 0);
940 }
941 
942 
943 void SourceView::headerClicked(int col)
944 {
945  if (col == 0) {
946  sortByColumn(col, Qt::AscendingOrder);
947  }
948  //All others but Source Text column Descending
949  else if (col !=4) {
950  sortByColumn(col, Qt::DescendingOrder);
951  }
952 }
953 
954 #include "sourceview.moc"
TraceLineJumpList
QList< TraceLineJump * > TraceLineJumpList
Definition: tracedata.h:181
TraceItemView::selectedItemChanged
Definition: traceitemview.h:86
TraceItemView::_selectedItem
CostItem * _selectedItem
Definition: traceitemview.h:211
TracePart::name
QString name() const
Definition: tracedata.h:667
ProfileCostArray::subCost
SubCost subCost(EventType *)
Returns a sub cost.
Definition: costitem.cpp:591
globalconfig.h
ProfileContext::Line
Definition: context.h:39
SourceView::selectedSlot
void selectedSlot(QTreeWidgetItem *, QTreeWidgetItem *)
Definition: sourceview.cpp:145
GlobalConfig::sourceDirs
static QStringList sourceDirs(TraceData *, TraceObject *o=0)
Definition: globalconfig.cpp:305
QTreeWidget
TraceLineMap
QMap< uint, TraceLine > TraceLineMap
Definition: tracedata.h:194
TraceObject::prettyName
QString prettyName() const
Similar to name, but prettyfied = more descriptive to humans.
Definition: tracedata.cpp:2959
TraceItemView::addEventTypeMenu
void addEventTypeMenu(QMenu *, bool withCost2=true)
Definition: traceitemview.cpp:456
TraceLineJump::lineTo
TraceLine * lineTo() const
Definition: tracedata.h:764
CostItem::type
ProfileContext::Type type() const
Definition: costitem.h:45
QWidget
TraceFunction
A traced function.
Definition: tracedata.h:1122
TraceItemView::_data
TraceData * _data
Definition: traceitemview.h:209
TraceJumpCost::executedCount
SubCost executedCount()
Definition: tracedata.cpp:55
TraceFile::setDirectory
void setDirectory(const QString &dir)
Definition: tracedata.cpp:2826
TraceFunctionSource::function
TraceFunction * function() const
Definition: tracedata.h:1041
TraceItemView::addGoMenu
void addGoMenu(QMenu *)
Definition: traceitemview.cpp:461
TraceFunction::object
TraceObject * object() const
Definition: tracedata.h:1164
SourceView::headerClicked
void headerClicked(int)
Definition: sourceview.cpp:943
CostItem
Base class for cost items.
Definition: costitem.h:37
SourceItem::lineno
uint lineno() const
Definition: sourceitem.h:52
TraceLineCall
A call from a line of one function to another function.
Definition: tracedata.h:808
ProfileContext::Instr
Definition: context.h:38
TraceFunctionSource::firstLineno
uint firstLineno()
Definition: tracedata.cpp:1532
SourceView::SourceItem
friend class SourceItem
Definition: sourceview.h:33
TraceLine::lineJumps
const TraceLineJumpList & lineJumps() const
Definition: tracedata.h:957
SourceView::activatedSlot
void activatedSlot(QTreeWidgetItem *, int)
Definition: sourceview.cpp:177
sourceview.h
SourceView::keyPressEvent
void keyPressEvent(QKeyEvent *event)
Definition: sourceview.cpp:198
TraceItemView::_eventType2
EventType * _eventType2
Definition: traceitemview.h:212
TraceItemView
Abstract Base Class for KCachegrind Views.
Definition: traceitemview.h:70
SourceItem::setJumpArray
void setJumpArray(const QVector< TraceLineJump * > &a)
Definition: sourceitem.cpp:288
TraceData::parts
TracePartList parts() const
Definition: tracedata.h:1397
TraceItemView::_eventType
EventType * _eventType
Definition: traceitemview.h:212
SourceView::context
void context(const QPoint &)
Definition: sourceview.cpp:107
TraceInstr
A code instruction address of the program.
Definition: tracedata.h:887
getJumpLines
void getJumpLines(const TraceLineJump *jump, uint &low, uint &high)
Definition: sourceview.cpp:546
CostItem::name
virtual QString name() const
Returns dynamic name info (without type)
Definition: costitem.cpp:53
TraceLine::lineCalls
const TraceLineCallList & lineCalls() const
Definition: tracedata.h:956
TraceLineCall::call
TraceCall * call() const
Definition: tracedata.h:817
TraceFile::prettyName
QString prettyName() const
Similar to name, but prettyfied = more descriptive to humans.
Definition: tracedata.cpp:2858
SourceView::arrowLevels
int arrowLevels()
Definition: sourceview.h:43
TraceFunctionSource
A container helper class for TraceFunction for source lines where a function is implemented in...
Definition: tracedata.h:1029
lineJumpHighLessThan
bool lineJumpHighLessThan(const TraceLineJump *jump1, const TraceLineJump *jump2)
Definition: sourceview.cpp:575
GlobalConfig::context
static int context()
Definition: globalconfig.cpp:412
TraceCostItem::name
virtual QString name() const
Returns dynamic name info (without type)
Definition: tracedata.h:986
TraceFunction::prettyName
QString prettyName() const
Similar to name, but prettyfied = more descriptive to humans.
Definition: tracedata.cpp:1889
SourceView::whatsThis
QString whatsThis() const
Definition: sourceview.cpp:92
TraceLine::lineno
uint lineno() const
Definition: tracedata.h:955
TraceItemView::_activeItem
CostItem * _activeItem
Definition: traceitemview.h:211
searchFileRecursive
static bool searchFileRecursive(QString &dir, const QString &name)
Definition: sourceview.cpp:382
TraceLine
A source line of the program.
Definition: tracedata.h:935
GlobalConfig::shortenSymbol
static QString shortenSymbol(const QString &)
Definition: globalconfig.cpp:395
TraceLine::name
virtual QString name() const
Returns dynamic name info (without type)
Definition: tracedata.cpp:1475
TraceItemView::selected
virtual void selected(TraceItemView *sender, CostItem *)
Notification from child views.
Definition: traceitemview.cpp:313
QTreeWidgetItem
TraceFunctionSource::file
TraceFile * file() const
Definition: tracedata.h:1040
TraceItemView::activated
virtual void activated(TraceItemView *sender, CostItem *)
Definition: traceitemview.cpp:342
lineJumpLowLessThan
bool lineJumpLowLessThan(const TraceLineJump *jump1, const TraceLineJump *jump2)
Definition: sourceview.cpp:559
SourceView::SourceView
SourceView(TraceItemView *parentView, QWidget *parent=0)
Definition: sourceview.cpp:45
TraceFunction::sourceFiles
const TraceFunctionSourceList & sourceFiles() const
Definition: tracedata.h:1168
SourceItem::lineCall
TraceLineCall * lineCall() const
Definition: sourceitem.h:56
TraceLineJump::lineFrom
TraceLine * lineFrom() const
Definition: tracedata.h:763
TracePart
A Trace Part: All data read from a trace file, containing all costs that happened in a specified time...
Definition: tracedata.h:655
ProfileContext::Type
Type
Definition: context.h:36
SubCost
Cost event counter, simple wrapper around a 64bit entity.
Definition: subcost.h:32
TraceFunction::sourceFile
TraceFunctionSource * sourceFile(TraceFile *file=0, bool createNew=false)
Definition: tracedata.cpp:2169
SourceItem::lineJump
TraceLineJump * lineJump() const
Definition: sourceitem.h:57
TraceCall::called
TraceFunction * called(bool skipCycle=false) const
Definition: tracedata.cpp:1235
sourceitem.h
TraceItemView::groupTypeChanged
Definition: traceitemview.h:83
TraceFunctionSource::lastLineno
uint lastLineno()
Definition: tracedata.cpp:1542
TraceFile::directory
QString directory()
Definition: tracedata.cpp:2834
TraceItemView::select
void select(CostItem *i)
Definition: traceitemview.cpp:79
GlobalConfig::noCostInside
static int noCostInside()
Definition: globalconfig.cpp:417
TraceFile::shortName
QString shortName() const
Definition: tracedata.cpp:2849
TraceLineJump
A jump from one line to another inside of a function.
Definition: tracedata.h:754
SourceItemDelegate
Definition: sourceitem.h:84
SourceItem
Definition: sourceitem.h:33
EventType::name
const QString & name()
Definition: eventtype.h:65
ProfileContext::Function
Definition: context.h:46
QList
ProfileContext::InvalidType
Definition: context.h:37
TraceFunctionSource::lineMap
TraceLineMap * lineMap()
Definition: tracedata.cpp:1618
SourceItem::line
TraceLine * line() const
Definition: sourceitem.h:55
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 23:03:27 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kcachegrind

Skip menu "kcachegrind"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members

kdesdk API Reference

Skip menu "kdesdk API Reference"
  • kapptemplate
  • kcachegrind
  • kompare
  • lokalize
  • okteta
  • umbrello
  •   umbrello

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal