53 #ifdef HAVE_TEUCHOS_ADD_TIME_MONITOR_TO_STACKED_TIMER
110 template<
class Ordinal,
class ScalarType,
class IndexType>
115 reduce (
const Ordinal count,
116 const std::pair<ScalarType, IndexType> inBuffer[],
117 std::pair<ScalarType, IndexType> inoutBuffer[])
const;
120 template<
class Ordinal>
126 const std::pair<double, int> inBuffer[],
127 std::pair<double, int> inoutBuffer[])
const
129 for (Ordinal ind = 0; ind < count; ++ind) {
130 const std::pair<double, int>& in = inBuffer[ind];
131 std::pair<double, int>& inout = inoutBuffer[ind];
133 if (in.first > inout.first) {
134 inout.first = in.first;
135 inout.second = in.second;
136 }
else if (in.first < inout.first) {
139 inout.first = in.first;
140 inout.second = std::min (in.second, inout.second);
172 template<
class Ordinal,
class ScalarType,
class IndexType>
177 reduce (
const Ordinal count,
178 const std::pair<ScalarType, IndexType> inBuffer[],
179 std::pair<ScalarType, IndexType> inoutBuffer[])
const;
182 template<
class Ordinal>
188 const std::pair<double, int> inBuffer[],
189 std::pair<double, int> inoutBuffer[])
const
191 for (Ordinal ind = 0; ind < count; ++ind) {
192 const std::pair<double, int>& in = inBuffer[ind];
193 std::pair<double, int>& inout = inoutBuffer[ind];
195 if (in.first < inout.first) {
196 inout.first = in.first;
197 inout.second = in.second;
198 }
else if (in.first > inout.first) {
201 inout.first = in.first;
202 inout.second = std::min (in.second, inout.second);
211 template<
class Ordinal,
class ScalarType,
class IndexType>
216 reduce (
const Ordinal count,
217 const std::pair<ScalarType, IndexType> inBuffer[],
218 std::pair<ScalarType, IndexType> inoutBuffer[])
const;
221 template<
class Ordinal>
227 const std::pair<double, int> inBuffer[],
228 std::pair<double, int> inoutBuffer[])
const
230 for (Ordinal ind = 0; ind < count; ++ind) {
231 const std::pair<double, int>& in = inBuffer[ind];
232 std::pair<double, int>& inout = inoutBuffer[ind];
234 if ( (in.first < inout.first && in.first != 0) || (inout.first == 0 && in.first != 0) ) {
235 inout.first = in.first;
236 inout.second = in.second;
237 }
else if (in.first > inout.first) {
240 inout.first = in.first;
241 inout.second = std::min (in.second, inout.second);
251 typedef std::map<std::string, std::pair<double, int> >
timer_map_t;
261 #ifdef HAVE_TEUCHOS_ADD_TIME_MONITOR_TO_STACKED_TIMER
271 #ifdef HAVE_TEUCHOS_ADD_TIME_MONITOR_TO_STACKED_TIMER
276 catch (std::runtime_error&) {
277 std::ostringstream warning;
279 "\n*********************************************************************\n"
280 "WARNING: Overlapping timers detected!\n"
281 "A TimeMonitor timer was stopped before a nested subtimer was\n"
282 "stopped. This is not allowed by the StackedTimer. This corner case\n"
283 "typically occurs if the TimeMonitor is stored in an RCP and the RCP is\n"
284 "assigned to a new timer. To disable this warning, either fix the\n"
285 "ordering of timer creation and destuction or disable the StackedTimer\n"
286 "support in the TimeMonitor by setting the StackedTimer to null\n"
288 "Teuchos::TimeMonitor::setStackedTimer(Teuchos::null)\n"
289 "*********************************************************************\n";
290 std::cout << warning.str() << std::endl;
302 timer ==
null, std::invalid_argument,
303 "TimeMonitor::disableTimer: Invalid timer \"" << name <<
"\"");
312 timer ==
null, std::invalid_argument,
313 "TimeMonitor::enableTimer: Invalid timer \"" << name <<
"\"");
320 typedef std::map<std::string, RCP<Time> > map_type;
321 typedef map_type::iterator iter_type;
329 for (iter_type it = ctrs.begin(); it != ctrs.end(); ++it) {
335 it->second->isRunning (), std::runtime_error,
336 "Timer \"" << it->second->name () <<
"\" is currently running. "
337 "You are not allowed to reset running timers.");
339 #endif // TEUCHOS_DEBUG
341 for (iter_type it = ctrs.begin(); it != ctrs.end(); ++it) {
342 it->second->reset ();
355 std::pair<std::string, std::pair<double, int> >
356 makeEmptyTimerDatum (
const std::string& name)
358 return std::make_pair (name, std::make_pair (
double(0),
int(0)));
380 const std::map<std::string, RCP<Time> >& localCounters,
381 const std::string& filter=
"")
383 using std::make_pair;
384 typedef timer_map_t::iterator iter_t;
387 for (std::map<std::string, RCP<Time> >::const_iterator it = localCounters.begin();
388 it != localCounters.end(); ++it) {
389 const std::string& name = it->second->name ();
393 const bool skipThisOne = (filter !=
"" && name.find (filter) != 0);
395 const double timing = it->second->totalElapsedTime ();
396 const int numCalls = it->second->numCalls ();
400 iter_t loc = theLocalData.find (name);
401 if (loc == theLocalData.end()) {
403 theLocalData.insert (loc, make_pair (name, make_pair (timing, numCalls)));
406 loc->second.first += timing;
407 loc->second.second += numCalls;
413 localData.swap (theLocalData);
425 for (timer_map_t::const_iterator it = timerData.begin();
426 it != timerData.end(); ++it) {
427 if (it->second.second > 0) {
428 newTimerData[it->first] = it->second;
431 timerData.swap (newTimerData);
456 collectLocalTimerDataAndNames (
timer_map_t& localTimerData,
457 Array<std::string>& localTimerNames,
458 const std::map<std::string, RCP<Time> >& localTimers,
459 const bool writeZeroTimers,
460 const std::string& filter=
"")
463 collectLocalTimerData (localTimerData, localTimers, filter);
469 if (! writeZeroTimers) {
470 filterZeroData (localTimerData);
475 localTimerNames.reserve (localTimerData.size());
476 for (timer_map_t::const_iterator it = localTimerData.begin();
477 it != localTimerData.end(); ++it) {
478 localTimerNames.push_back (it->first);
517 collectGlobalTimerData (
timer_map_t& globalTimerData,
518 Array<std::string>& globalTimerNames,
520 Array<std::string>& localTimerNames,
521 Ptr<
const Comm<int> > comm,
522 const bool alwaysWriteLocal,
551 const timer_map_t::size_type myNumGlobalNames = globalTimerNames.size();
552 timer_map_t::size_type minNumGlobalNames = 0;
553 timer_map_t::size_type maxNumGlobalNames = 0;
555 outArg (minNumGlobalNames));
557 outArg (maxNumGlobalNames));
559 std::logic_error,
"Min # global timer names = " << minNumGlobalNames
560 <<
" != max # global timer names = " << maxNumGlobalNames
561 <<
". Please report this bug to the Teuchos developers.");
563 std::logic_error,
"My # global timer names = " << myNumGlobalNames
564 <<
" != min # global timer names = " << minNumGlobalNames
565 <<
". Please report this bug to the Teuchos developers.");
567 #endif // TEUCHOS_DEBUG
584 timer_map_t::iterator globalMapIter = globalTimerData.begin();
585 timer_map_t::iterator localMapIter;
587 it != globalTimerNames.end(); ++it) {
588 const std::string& globalName = *it;
589 localMapIter = localTimerData.find (globalName);
591 if (localMapIter == localTimerData.end()) {
592 if (alwaysWriteLocal) {
608 localMapIter = localTimerData.insert (localMapIter, makeEmptyTimerDatum (globalName));
613 localTimerNames.push_back (globalName);
618 globalMapIter = globalTimerData.insert (globalMapIter, makeEmptyTimerDatum (globalName));
624 globalMapIter = globalTimerData.insert (globalMapIter, std::make_pair (globalName, localMapIter->second));
628 if (alwaysWriteLocal) {
631 std::sort (localTimerNames.begin(), localTimerNames.end());
638 const timer_map_t::size_type myNumGlobalTimers = globalTimerData.size();
639 timer_map_t::size_type minNumGlobalTimers = 0;
640 timer_map_t::size_type maxNumGlobalTimers = 0;
642 outArg (minNumGlobalTimers));
644 outArg (maxNumGlobalTimers));
646 std::logic_error,
"Min # global timers = " << minNumGlobalTimers
647 <<
" != max # global timers = " << maxNumGlobalTimers
648 <<
". Please report this bug to the Teuchos developers.");
650 std::logic_error,
"My # global timers = " << myNumGlobalTimers
651 <<
" != min # global timers = " << minNumGlobalTimers
652 <<
". Please report this bug to the Teuchos developers.");
654 #endif // TEUCHOS_DEBUG
705 std::vector<std::string>& statNames,
706 Ptr<
const Comm<int> > comm,
708 const bool ignoreZeroTimers)
712 const int numTimers = static_cast<int> (globalTimerData.size());
713 const int numProcs = comm->getSize();
718 Array<std::pair<double, int> > timingsAndCallCounts;
719 timingsAndCallCounts.reserve (numTimers);
720 for (timer_map_t::const_iterator it = globalTimerData.begin();
721 it != globalTimerData.end(); ++it) {
722 timingsAndCallCounts.push_back (it->second);
729 Array<std::pair<double, int> > minTimingsAndCallCounts (numTimers);
731 if (ignoreZeroTimers)
732 reduceAll (*comm, MinLocNonzero<int, double, int>(), numTimers,
733 &timingsAndCallCounts[0], &minTimingsAndCallCounts[0]);
735 reduceAll (*comm, MinLoc<int, double, int>(), numTimers,
736 &timingsAndCallCounts[0], &minTimingsAndCallCounts[0]);
743 Array<std::pair<double, int> > maxTimingsAndCallCounts (numTimers);
745 reduceAll (*comm, MaxLoc<int, double, int>(), numTimers,
746 &timingsAndCallCounts[0], &maxTimingsAndCallCounts[0]);
760 Array<double> meanOverCallCountsTimings (numTimers);
761 Array<double> meanOverProcsTimings (numTimers);
762 Array<double> meanCallCounts (numTimers);
763 Array<int> ICallThisTimer (numTimers);
764 Array<int> numProcsCallingEachTimer (numTimers);
767 if (ignoreZeroTimers) {
768 for (
int k = 0; k < numTimers; ++k) {
769 const double callCount = static_cast<double> (timingsAndCallCounts[k].second);
770 if (callCount > 0) ICallThisTimer[k] = 1;
771 else ICallThisTimer[k] = 0;
775 &numProcsCallingEachTimer[0]);
782 Array<double> scaledTimings (numTimers);
783 Array<double> scaledCallCounts (numTimers);
784 const double P = static_cast<double> (numProcs);
786 if (ignoreZeroTimers) {
787 for (
int k = 0; k < numTimers; ++k) {
788 const double timing = timingsAndCallCounts[k].first;
789 const double callCount = static_cast<double> (timingsAndCallCounts[k].second);
791 scaledTimings[k] = timing / numProcsCallingEachTimer[k];
792 scaledCallCounts[k] = callCount / numProcsCallingEachTimer[k];
796 for (
int k = 0; k < numTimers; ++k) {
797 const double timing = timingsAndCallCounts[k].first;
798 const double callCount = static_cast<double> (timingsAndCallCounts[k].second);
800 scaledTimings[k] = timing / P;
801 scaledCallCounts[k] = callCount / P;
807 &meanOverProcsTimings[0]);
813 for (
int k = 0; k < numTimers; ++k) {
815 meanOverCallCountsTimings[k] = meanOverProcsTimings[k] / meanCallCounts[k];
827 statNames.resize (4);
828 statNames[0] =
"MinOverProcs";
829 statNames[1] =
"MeanOverProcs";
830 statNames[2] =
"MaxOverProcs";
831 statNames[3] =
"MeanOverCallCounts";
833 stat_map_type::iterator statIter = statData.end();
834 timer_map_t::const_iterator it = globalTimerData.begin();
835 for (
int k = 0; it != globalTimerData.end(); ++k, ++it) {
836 std::vector<std::pair<double, double> > curData (4);
837 curData[0] = minTimingsAndCallCounts[k];
838 curData[1] = std::make_pair (meanOverProcsTimings[k], meanCallCounts[k]);
839 curData[2] = maxTimingsAndCallCounts[k];
840 curData[3] = std::make_pair (meanOverCallCountsTimings[k], meanCallCounts[k]);
845 statIter = statData.insert (statIter, std::make_pair (it->first, curData));
866 RCP<const Comm<int> >
878 int mpiHasBeenStarted = 0;
879 MPI_Initialized (&mpiHasBeenStarted);
880 if (! mpiHasBeenStarted) {
882 comm = rcp_implicit_cast<
const Comm<int> > (
rcp (
new SerialComm<int> ()));
894 std::vector<std::string>& statNames,
897 const std::string& filter)
905 const bool writeZeroTimers =
false;
906 collectLocalTimerDataAndNames (localTimerData, localTimerNames,
907 counters(), writeZeroTimers, filter);
912 const bool alwaysWriteLocal =
false;
913 collectGlobalTimerData (globalTimerData, globalTimerNames,
914 localTimerData, localTimerNames,
915 comm, alwaysWriteLocal, setOp);
917 computeGlobalTimerStats (statData, statNames, comm, globalTimerData,
false);
924 const bool alwaysWriteLocal,
925 const bool writeGlobalStats,
926 const bool writeZeroTimers,
928 const std::string& filter,
929 const bool ignoreZeroTimers)
936 const int numProcs = comm->getSize();
937 const int myRank = comm->getRank();
945 collectLocalTimerDataAndNames (localTimerData, localTimerNames,
946 counters(), writeZeroTimers, filter);
955 std::vector<std::string> statNames;
956 if (writeGlobalStats) {
957 collectGlobalTimerData (globalTimerData, globalTimerNames,
958 localTimerData, localTimerNames,
959 comm, alwaysWriteLocal, setOp);
964 computeGlobalTimerStats (statData, statNames, comm, globalTimerData, ignoreZeroTimers);
970 const std::ios_base::fmtflags& flags = out.flags();
988 titles.
append (
"Timer Name");
991 TableColumn nameCol (writeGlobalStats ? globalTimerNames : localTimerNames);
992 tableColumns.
append (nameCol);
997 columnWidths.
append (
format().computeRequiredColumnWidth (titles.
back(), nameCol));
1007 if (alwaysWriteLocal && numProcs > 1 && myRank == 0) {
1008 titles.
append (
"Local time (num calls)");
1014 for (timer_map_t::const_iterator it = localTimerData.begin();
1015 it != localTimerData.end(); ++it) {
1016 localTimings.
push_back (it->second.first);
1017 localNumCalls.
push_back (static_cast<double> (it->second.second));
1019 TableColumn timeAndCalls (localTimings, localNumCalls, precision, flags,
true);
1020 tableColumns.
append (timeAndCalls);
1021 columnWidths.
append (
format().computeRequiredColumnWidth (titles.
back(), timeAndCalls));
1024 if (writeGlobalStats) {
1029 if (numProcs == 1) {
1033 for (timer_map_t::const_iterator it = globalTimerData.begin();
1034 it != globalTimerData.end(); ++it) {
1035 globalTimings.
push_back (it->second.first);
1036 globalNumCalls.
push_back (static_cast<double> (it->second.second));
1039 titles.
append (
"Global time (num calls)");
1040 TableColumn timeAndCalls (globalTimings, globalNumCalls, precision, flags,
true);
1041 tableColumns.
append (timeAndCalls);
1042 columnWidths.
append (
format().computeRequiredColumnWidth (titles.
back(), timeAndCalls));
1049 const timer_map_t::size_type numGlobalTimers = globalTimerData.
size();
1050 for (std::vector<std::string>::size_type statInd = 0; statInd < statNames.size(); ++statInd) {
1055 stat_map_type::const_iterator it = statData.begin();
1056 for (
int k = 0; it != statData.end(); ++it, ++k) {
1057 statTimings[k] = (it->second[statInd]).first;
1058 statCallCounts[k] = (it->second[statInd]).second;
1061 const std::string& statisticName = statNames[statInd];
1062 const std::string titleString = statisticName;
1063 titles.
append (titleString);
1064 TableColumn timeAndCalls (statTimings, statCallCounts, precision, flags,
true);
1065 tableColumns.
append (timeAndCalls);
1066 columnWidths.
append (
format().computeRequiredColumnWidth (titles.
back(), timeAndCalls));
1074 std::ostringstream theTitle;
1075 theTitle <<
"TimeMonitor results over " << numProcs <<
" processor"
1076 << (numProcs > 1 ?
"s" :
"");
1083 const bool alwaysWriteLocal,
1084 const bool writeGlobalStats,
1085 const bool writeZeroTimers,
1087 const std::string& filter,
1088 const bool ignoreZeroTimers)
1096 writeGlobalStats, writeZeroTimers, setOp, filter, ignoreZeroTimers);
1101 std::vector<std::string>& statNames,
1103 const std::string& filter)
1139 quoteLabelForYaml (
const std::string& label)
1144 if (label.empty ()) {
1151 const bool alreadyQuoted = label.size () >= 2 &&
1152 label[0] ==
'"' && label[label.size() - 1] ==
'"';
1157 bool needToQuote =
false;
1160 out.reserve (label.size ());
1162 const size_t startPos = alreadyQuoted ? 1 : 0;
1163 const size_t endPos = alreadyQuoted ? label.size () - 1 : label.size ();
1164 for (
size_t i = startPos; i < endPos; ++i) {
1165 const char c = label[i];
1166 if (c ==
'"' || c ==
'\\') {
1167 out.push_back (
'\\');
1170 else if (c ==
':') {
1176 if (needToQuote || alreadyQuoted) {
1179 return "\"" + out +
"\"";
1193 const std::string& filter)
1196 using Teuchos::fancyOStream;
1197 using Teuchos::getFancyOStream;
1200 using Teuchos::rcpFromRef;
1202 typedef std::vector<std::string>::size_type size_type;
1212 std::vector<std::string> statNames;
1215 const int numProcs = comm->getSize();
1229 pfout->setTabIndentStr (
" ");
1232 fout <<
"# Teuchos::TimeMonitor report" << endl
1244 fout <<
"Output mode: " << (compact ?
"compact" :
"spacious") << endl
1245 <<
"Number of processes: " << numProcs << endl
1246 <<
"Time unit: s" << endl;
1250 fout <<
"Statistics collected: ";
1254 for (size_type i = 0; i < statNames.size (); ++i) {
1255 fout << quoteLabelForYaml (statNames[i]);
1256 if (i + 1 < statNames.size ()) {
1260 fout <<
"]" << endl;
1265 for (size_type i = 0; i < statNames.size (); ++i) {
1266 fout <<
"- " << quoteLabelForYaml (statNames[i]) << endl;
1275 fout <<
"Timer names: ";
1279 for (stat_map_type::const_iterator it = statData.begin();
1280 it != statData.end(); ++it, ++ind) {
1281 fout << quoteLabelForYaml (it->first);
1282 if (ind + 1 < statData.size ()) {
1286 fout <<
"]" << endl;
1291 for (stat_map_type::const_iterator it = statData.begin();
1292 it != statData.end(); ++it) {
1293 fout <<
"- " << quoteLabelForYaml (it->first) << endl;
1298 fout <<
"Total times: ";
1301 size_type outerInd = 0;
1302 for (stat_map_type::const_iterator outerIter = statData.begin();
1303 outerIter != statData.end(); ++outerIter, ++outerInd) {
1305 fout << quoteLabelForYaml (outerIter->first) <<
": ";
1307 const std::vector<std::pair<double, double> >& curData = outerIter->second;
1309 for (size_type innerInd = 0; innerInd < curData.size (); ++innerInd) {
1310 fout << quoteLabelForYaml (statNames[innerInd]) <<
": "
1311 << curData[innerInd].first;
1312 if (innerInd + 1 < curData.size ()) {
1317 if (outerInd + 1 < statData.size ()) {
1321 fout <<
"}" << endl;
1326 size_type outerInd = 0;
1327 for (stat_map_type::const_iterator outerIter = statData.begin();
1328 outerIter != statData.end(); ++outerIter, ++outerInd) {
1330 fout << quoteLabelForYaml (outerIter->first) <<
": " << endl;
1333 const std::vector<std::pair<double, double> >& curData = outerIter->second;
1334 for (size_type innerInd = 0; innerInd < curData.size (); ++innerInd) {
1335 fout << quoteLabelForYaml (statNames[innerInd]) <<
": "
1336 << curData[innerInd].first << endl;
1342 fout <<
"Call counts:";
1345 size_type outerInd = 0;
1346 for (stat_map_type::const_iterator outerIter = statData.begin();
1347 outerIter != statData.end(); ++outerIter, ++outerInd) {
1349 fout << quoteLabelForYaml (outerIter->first) <<
": ";
1351 const std::vector<std::pair<double, double> >& curData = outerIter->second;
1353 for (size_type innerInd = 0; innerInd < curData.size (); ++innerInd) {
1354 fout << quoteLabelForYaml (statNames[innerInd]) <<
": "
1355 << curData[innerInd].second;
1356 if (innerInd + 1 < curData.size ()) {
1361 if (outerInd + 1 < statData.size ()) {
1365 fout <<
"}" << endl;
1370 size_type outerInd = 0;
1371 for (stat_map_type::const_iterator outerIter = statData.begin();
1372 outerIter != statData.end(); ++outerIter, ++outerInd) {
1374 fout << quoteLabelForYaml (outerIter->first) <<
": " << endl;
1377 const std::vector<std::pair<double, double> >& curData = outerIter->second;
1378 for (size_type innerInd = 0; innerInd < curData.size (); ++innerInd) {
1379 fout << quoteLabelForYaml (statNames[innerInd]) <<
": "
1380 << curData[innerInd].second << endl;
1389 const std::string& filter)
1414 const std::string name (
"Report format");
1415 const std::string defaultValue (
"Table");
1416 const std::string docString (
"Output format for report of timer statistics");
1422 docs.
push_back (
"YAML (see yaml.org) format");
1425 docs.
push_back (
"Tabular format via Teuchos::TableFormat");
1428 setStringToIntegralParameter<ETimeMonitorReportFormat> (name, defaultValue,
1430 strings (), docs (),
1437 const std::string name (
"YAML style");
1438 const std::string defaultValue (
"spacious");
1439 const std::string docString (
"YAML-specific output format");
1445 docs.
push_back (
"Compact format: use \"flow style\" (see YAML 1.2 spec at "
1446 "yaml.org) for most sequences except the outermost sequence");
1450 docs.
push_back (
"Spacious format: avoid flow style");
1453 setStringToIntegralParameter<ETimeMonitorYamlFormat> (name, defaultValue,
1455 strings (), docs (),
1462 const std::string name (
"How to merge timer sets");
1463 const std::string defaultValue (
"Intersection");
1464 const std::string docString (
"How to merge differing sets of timers "
1465 "across processes");
1471 docs.
push_back (
"Compute intersection of timer sets over processes");
1474 docs.
push_back (
"Compute union of timer sets over processes");
1477 setStringToIntegralParameter<ECounterSetOp> (name, defaultValue, docString,
1478 strings (), docs (), values (),
1502 const bool alwaysWriteLocal =
false;
1503 const bool writeGlobalStats =
true;
1504 const bool writeZeroTimers =
true;
1509 plist->set (
"alwaysWriteLocal", alwaysWriteLocal,
1510 "Always output local timers' values on Proc 0");
1511 plist->set (
"writeGlobalStats", writeGlobalStats,
"Always output global "
1512 "statistics, even if there is only one process in the "
1514 plist->set (
"writeZeroTimers", writeZeroTimers,
"Generate output for "
1515 "timers that have never been called");
1517 return rcp_const_cast<const ParameterList> (plist);
1526 bool alwaysWriteLocal =
false;
1527 bool writeGlobalStats =
true;
1528 bool writeZeroTimers =
true;
1540 reportFormat = getIntegralValue<ETimeMonitorReportFormat> (*params,
"Report format");
1541 yamlStyle = getIntegralValue<ETimeMonitorYamlFormat> (*params,
"YAML style");
1542 setOp = getIntegralValue<ECounterSetOp> (*params,
"How to merge timer sets");
1543 alwaysWriteLocal = params->
get<
bool> (
"alwaysWriteLocal");
1544 writeGlobalStats = params->
get<
bool> (
"writeGlobalStats");
1545 writeZeroTimers = params->
get<
bool> (
"writeZeroTimers");
1563 const std::string& filter,
1577 "Invalid report format. This should never happen; ParameterList "
1578 "validation should have caught this. Please report this bug to the "
1579 "Teuchos developers.");
1588 report (comm, out,
"", params);
1593 const std::string& filter,
1597 report (comm.
ptr (), out, filter, params);