void
MM_VerboseHandlerOutputStandard::handleCompactEnd(J9HookInterface** hook, uintptr_t eventNum, void* eventData)
{
	MM_CompactEndEvent* event = (MM_CompactEndEvent*)eventData;
	MM_EnvironmentBase* env = MM_EnvironmentBase::getEnvironment(event->omrVMThread);
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();
	MM_CompactStats *compactStats = &MM_GCExtensionsBase::getExtensions(env->getOmrVM())->globalGCStats.compactStats;
	uint64_t duration = 0;
	bool deltaTimeSuccess = getTimeDeltaInMicroSeconds(&duration, compactStats->_startTime, compactStats->_endTime);

	enterAtomicReportingBlock();
	handleGCOPOuterStanzaStart(env, "compact", env->_cycleState->_verboseContextID, duration, deltaTimeSuccess);

	if(COMPACT_PREVENTED_NONE == compactStats->_compactPreventedReason) {
		writer->formatAndOutput(env, 1, "<compact-info movecount=\"%zu\" movebytes=\"%zu\" reason=\"%s\" />",
				compactStats->_movedObjects, compactStats->_movedBytes, getCompactionReasonAsString(compactStats->_compactReason));
	} else {
		writer->formatAndOutput(env, 1, "<compact-info reason=\"%s\" />", getCompactionReasonAsString(compactStats->_compactReason));
		writer->formatAndOutput(env, 1, "<warning details=\"compaction prevented due to %s\" />", getCompactionPreventedReasonAsString(compactStats->_compactPreventedReason));
	}

	handleCompactEndInternal(env, eventData);

	handleGCOPOuterStanzaEnd(env);
	writer->flush(env);
	exitAtomicReportingBlock();
}
void
MM_VerboseHandlerOutputStandard::handleGCOPOuterStanzaEnd(MM_EnvironmentBase* env)
{
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();
	writer->formatAndOutput(env, 0, "</gc-op>");
}
Example #3
0
void
MM_VerboseHandlerOutput::handleInitialized(J9HookInterface** hook, uintptr_t eventNum, void* eventData)
{
	MM_InitializedEvent* event = (MM_InitializedEvent*)eventData;
	MM_VerboseWriterChain* writer = _manager->getWriterChain();
	MM_EnvironmentBase* env = MM_EnvironmentBase::getEnvironment(event->currentThread);
	OMRPORT_ACCESS_FROM_ENVIRONMENT(env);

	char tagTemplate[200];

	_manager->setInitializedTime(event->timestamp);

	getTagTemplate(tagTemplate, sizeof(tagTemplate), _manager->getIdAndIncrement(), omrtime_current_time_millis());
	enterAtomicReportingBlock();
	writer->formatAndOutput(env, 0, "<initialized %s>", tagTemplate);
	writer->formatAndOutput(env, 1, "<attribute name=\"gcPolicy\" value=\"%s\" />", event->gcPolicy);
#if defined(OMR_GC_CONCURRENT_SCAVENGER)
	if (_extensions->isConcurrentScavengerEnabled()) {
		writer->formatAndOutput(env, 1, "<attribute name=\"concurrentScavenger\" value=\"%s\" />",
#if defined(S390)
				_extensions->concurrentScavengerHWSupport ?
				"enabled, with H/W assistance" :
				"enabled, without H/W assistance");
#else /* defined(S390) */
				"enabled");
#endif /* defined(S390) */
	}
Example #4
0
void
MM_VerboseHandlerOutput::writeVmArgs(MM_EnvironmentBase* env)
{
	/* TODO (stefanbu) OMR does not support argument parsing yet, but we should repsect schema.*/
	MM_VerboseWriterChain* writer = _manager->getWriterChain();
	writer->formatAndOutput(env, 1, "<vmargs>");
	writer->formatAndOutput(env, 1, "</vmargs>");
}
void
MM_VerboseHandlerOutputStandard::outputMemType(MM_EnvironmentBase* env, uintptr_t indent, const char* type, uintptr_t free, uintptr_t total)
{
	MM_VerboseWriterChain* writer = _manager->getWriterChain();

	writer->formatAndOutput(
			env,
			indent,
			"<mem type=\"%s\" free=\"%zu\" total=\"%zu\" percent=\"%zu\" />",
			type, free, total,
			((total == 0) ? 0 : ((uintptr_t)(((uint64_t)free*100) / (uint64_t)total))));
}
void
MM_VerboseHandlerOutputStandard::handleConcurrentHaltedInternal(MM_EnvironmentBase *env, void* eventData)
{
	MM_ConcurrentHaltedEvent* event = (MM_ConcurrentHaltedEvent*)eventData;
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();
	const char* statusString = getConcurrentStatusString((ConcurrentStatus)event->executionMode);
	const char* stateString = "Complete";
	if (0 == event->isTracingExhausted) {
		stateString = "Tracing incomplete";
	}

	writer->formatAndOutput(env, 1, "<halted state=\"%s\" status=\"%s\" />", stateString, statusString);
}
void
MM_VerboseHandlerOutputStandard::handleGCOPOuterStanzaStart(MM_EnvironmentBase* env, const char *type, uintptr_t contextID, uint64_t duration, bool deltaTimeSuccess)
{
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();
	OMRPORT_ACCESS_FROM_OMRPORT(env->getPortLibrary());

	if (!deltaTimeSuccess) {
		writer->formatAndOutput(env, 0, "<warning details=\"clock error detected, following timing may be inaccurate\" />");
	}

	char tagTemplate[200];
	getTagTemplate(tagTemplate, sizeof(tagTemplate), manager->getIdAndIncrement(), type ,contextID, duration, omrtime_current_time_millis());
	writer->formatAndOutput(env, 0, "<gc-op %s>", tagTemplate);
}
void
MM_VerboseHandlerOutputStandard::handleCompactStart(J9HookInterface** hook, uintptr_t eventNum, void* eventData)
{
	MM_CompactEndEvent* event = (MM_CompactEndEvent*)eventData;
	MM_EnvironmentBase* env = MM_EnvironmentBase::getEnvironment(event->omrVMThread);
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();

	MM_CollectionStatisticsStandard *stats = (MM_CollectionStatisticsStandard *)env->_cycleState->_collectionStatistics;
	if (stats->_tenureFragmentation) {
		stats->collectCollectionStatistics(env, stats);
		enterAtomicReportingBlock();
		outputMemoryInfo(env, manager->getIndentLevel(), stats);
		writer->flush(env);
		exitAtomicReportingBlock();
		stats->resetFragmentionStats(env);
	}
}
void
MM_VerboseHandlerOutputStandard::handleConcurrentCollectionEnd(J9HookInterface** hook, uintptr_t eventNum, void* eventData)
{
	MM_ConcurrentCollectionEndEvent* event = (MM_ConcurrentCollectionEndEvent*)eventData;
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();
	MM_EnvironmentBase* env = MM_EnvironmentBase::getEnvironment(event->currentThread);
	OMRPORT_ACCESS_FROM_ENVIRONMENT(env);
	char tagTemplate[200];
	enterAtomicReportingBlock();
	getTagTemplate(tagTemplate, sizeof(tagTemplate), manager->getIdAndIncrement(), omrtime_current_time_millis());
	writer->formatAndOutput(env, 0, "<concurrent-collection-end %s />", tagTemplate);
	writer->flush(env);

	handleConcurrentCollectionEndInternal(env, eventData);

	exitAtomicReportingBlock();
}
void
MM_VerboseHandlerOutputStandard::handleScavengePercolate(J9HookInterface** hook, uintptr_t eventNum, void* eventData)
{
	MM_PercolateCollectEvent *event = (MM_PercolateCollectEvent *)eventData;
	MM_EnvironmentBase* env = MM_EnvironmentBase::getEnvironment(event->currentThread);
	OMRPORT_ACCESS_FROM_OMRPORT(env->getPortLibrary());
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();

	char tagTemplate[200];
	getTagTemplate(tagTemplate, sizeof(tagTemplate), omrtime_current_time_millis());
	enterAtomicReportingBlock();
	writer->formatAndOutput(env, 0, "<percolate-collect id=\"%zu\" from=\"%s\" to=\"%s\" reason=\"%s\" %s/>", manager->getIdAndIncrement(), "nursery", "global", getPercolateReasonAsString((PercolateReason)event->reason), tagTemplate);
	writer->flush(env);

	handleScavengePercolateInternal(env, eventData);

	exitAtomicReportingBlock();
}
void
MM_VerboseHandlerOutputStandard::handleConcurrentCollectionStart(J9HookInterface** hook, uintptr_t eventNum, void* eventData)
{
	MM_ConcurrentCollectionStartEvent* event = (MM_ConcurrentCollectionStartEvent*)eventData;
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();
	MM_EnvironmentBase* env = MM_EnvironmentBase::getEnvironment(event->currentThread);
	OMRPORT_ACCESS_FROM_ENVIRONMENT(env);
	uint64_t currentTime = event->timestamp;
	uint64_t previousTime = manager->getLastConcurrentGCTime();
	manager->setLastConcurrentGCTime(currentTime);
	if (0 == previousTime) {
		previousTime = manager->getInitializedTime();
	}
	uint64_t deltaTime = omrtime_hires_delta(previousTime, currentTime, OMRPORT_TIME_DELTA_IN_MICROSECONDS);
	const char* cardCleaningReasonString = "unknown";

	switch (event->cardCleaningReason) {
	case TRACING_COMPLETED:
		cardCleaningReasonString = "tracing completed";
		break;
	case CARD_CLEANING_THRESHOLD_REACHED:
		cardCleaningReasonString = "card cleaning threshold reached";
		break;
	}

	char tagTemplate[200];
	enterAtomicReportingBlock();
	getTagTemplate(tagTemplate, sizeof(tagTemplate), manager->getIdAndIncrement(), omrtime_current_time_millis());
	writer->formatAndOutput(env, 0, "<concurrent-collection-start %s intervalms=\"%llu.%03llu\" >",
		tagTemplate, deltaTime / 1000, deltaTime % 1000);
	writer->formatAndOutput(env, 1, "<concurrent-trace-info reason=\"%s\" tracedByMutators=\"%zu\" tracedByHelpers=\"%zu\" cardsCleaned=\"%zu\" workStackOverflowCount=\"%zu\" />",
		cardCleaningReasonString, event->tracedByMutators, event->tracedByHelpers, event->cardsCleaned, event->workStackOverflowCount);
  	writer->formatAndOutput(env, 0, "</concurrent-collection-start>");

	writer->flush(env);

	handleConcurrentCollectionStartInternal(env, eventData);

	exitAtomicReportingBlock();
}
void
MM_VerboseHandlerOutputStandard::handleConcurrentTracingEnd(J9HookInterface** hook, uintptr_t eventNum, void* eventData)
{
	MM_ConcurrentCompleteTracingEndEvent* event = (MM_ConcurrentCompleteTracingEndEvent*)eventData;
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();
	MM_EnvironmentBase* env = MM_EnvironmentBase::getEnvironment(event->currentThread);
	OMRPORT_ACCESS_FROM_ENVIRONMENT(env);
	uint64_t durationUs = omrtime_hires_delta(0, event->duration, OMRPORT_TIME_DELTA_IN_MICROSECONDS);

	enterAtomicReportingBlock();
	handleGCOPOuterStanzaStart(env, "tracing", env->_cycleState->_verboseContextID, durationUs, true);

	writer->formatAndOutput(env, 1, "<trace bytesTraced=\"%zu\" workStackOverflowCount=\"%zu\" />", event->bytesTraced, event->workStackOverflowCount);

	handleConcurrentTracingEndInternal(env, eventData);

	handleGCOPOuterStanzaEnd(env);
	writer->flush(env);
	exitAtomicReportingBlock();
}
void
MM_VerboseHandlerOutputStandard::handleConcurrentHalted(J9HookInterface** hook, uintptr_t eventNum, void* eventData)
{
	MM_ConcurrentHaltedEvent* event = (MM_ConcurrentHaltedEvent*)eventData;
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();
	MM_EnvironmentBase* env = MM_EnvironmentBase::getEnvironment(event->currentThread);
	OMRPORT_ACCESS_FROM_ENVIRONMENT(env);

	char tagTemplate[200];
	enterAtomicReportingBlock();
	getTagTemplate(tagTemplate, sizeof(tagTemplate), manager->getIdAndIncrement(), omrtime_current_time_millis());
	writer->formatAndOutput(env, 0, "<concurrent-halted %s>", tagTemplate);

	handleConcurrentHaltedInternal(env, eventData);

	writer->formatAndOutput(env, 1,
			"<traced "
			"bytesTarget=\"%zu\" bytesTotal=\"%zu\" "
			"bytesByMutator=\"%zu\" bytesByHelper=\"%zu\" "
			"percent=\"%zu\" />",
			event->traceTarget, event->tracedTotal,
			event->tracedByMutators, event->tracedByHelpers,
			event->traceTarget == 0 ? 0 : (uintptr_t)(((uint64_t)event->tracedTotal * 100) / (uint64_t)event->traceTarget));
	writer->formatAndOutput(env, 1, "<cards cleaned=\"%zu\" thresholdBytes=\"%zu\" />", event->cardsCleaned, event->cardCleaningThreshold);
	writer->formatAndOutput(env, 0, "</concurrent-halted>");
	writer->flush(env);

	exitAtomicReportingBlock();
}
void
MM_VerboseHandlerOutputStandard::handleConcurrentAborted(J9HookInterface** hook, uintptr_t eventNum, void* eventData)
{
	MM_ConcurrentAbortedEvent* event = (MM_ConcurrentAbortedEvent*)eventData;
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();
	MM_EnvironmentBase* env = MM_EnvironmentBase::getEnvironment(event->currentThread);
	OMRPORT_ACCESS_FROM_ENVIRONMENT(env);
	char tagTemplate[100];
	enterAtomicReportingBlock();
	getTagTemplate(tagTemplate, sizeof(tagTemplate), manager->getIdAndIncrement(), omrtime_current_time_millis());
	writer->formatAndOutput(env, 0, "<concurrent-aborted %s>", tagTemplate);

	const char* reason;
	switch((CollectionAbortReason)event->reason) {
	case ABORT_COLLECTION_INSUFFICENT_PROGRESS:
		reason = "insufficient progress made";
		break;
	case ABORT_COLLECTION_REMEMBERSET_OVERFLOW:
		reason = "remembered set overflow";
		break;
	case ABORT_COLLECTION_SCAVENGE_REMEMBEREDSET_OVERFLOW:
		reason = "scavenge remembered set overflow";
		break;
	case ABORT_COLLECTION_PREPARE_HEAP_FOR_WALK:
		reason = "prepare heap for walk";
		break;
	default:
		reason = "unknown";
		break;
	}

	writer->formatAndOutput(env, 1, "<reason value=\"%s\" />", reason);
	writer->formatAndOutput(env, 0, "</concurrent-aborted>");
	writer->flush(env);

	handleConcurrentAbortedInternal(env, eventData);

	exitAtomicReportingBlock();
}
void
MM_VerboseHandlerOutputStandard::handleConcurrentKickoff(J9HookInterface** hook, uintptr_t eventNum, void* eventData)
{
	MM_ConcurrentKickoffEvent* event = (MM_ConcurrentKickoffEvent*)eventData;
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();
	MM_EnvironmentBase* env = MM_EnvironmentBase::getEnvironment(event->currentThread);
	MM_GCExtensionsBase* extensions = MM_GCExtensionsBase::getExtensions(env->getOmrVM());
	OMRPORT_ACCESS_FROM_ENVIRONMENT(env);
	char tagTemplate[200];
	enterAtomicReportingBlock();
	getTagTemplate(tagTemplate, sizeof(tagTemplate), manager->getIdAndIncrement(), omrtime_current_time_millis());
	writer->formatAndOutput(env, 0, "<concurrent-kickoff %s>", tagTemplate);

	const char* reasonString = getConcurrentKickoffReason(eventData);

	if (extensions->scavengerEnabled) {
		writer->formatAndOutput(
				env, 1, "<kickoff reason=\"%s\" targetBytes=\"%zu\" thresholdFreeBytes=\"%zu\"  remainingFree=\"%zu\" tenureFreeBytes=\"%zu\" nurseryFreeBytes=\"%zu\" />",
				reasonString, event->traceTarget, event->kickOffThreshold, event->remainingFree, event->commonData->tenureFreeBytes, event->commonData->nurseryFreeBytes);
	} else {
		writer->formatAndOutput(
				env, 1, "<kickoff reason=\"%s\" targetBytes=\"%zu\" thresholdFreeBytes=\"%zu\" remainingFree=\"%zu\" tenureFreeBytes=\"%zu\" />",
				reasonString, event->traceTarget, event->kickOffThreshold, event->remainingFree, event->commonData->tenureFreeBytes);
	}
	writer->formatAndOutput(env, 0, "</concurrent-kickoff>");
	writer->flush(env);

	handleConcurrentKickoffInternal(env, eventData);

	exitAtomicReportingBlock();
}
void
MM_VerboseHandlerOutputStandard::handleMarkEnd(J9HookInterface** hook, uintptr_t eventNum, void* eventData)
{
	MM_MarkEndEvent* event = (MM_MarkEndEvent*)eventData;
	MM_EnvironmentBase* env = MM_EnvironmentBase::getEnvironment(event->currentThread);
	MM_GCExtensionsBase *extensions = MM_GCExtensionsBase::getExtensions(env->getOmrVM());
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();
	MM_MarkStats *markStats = &extensions->globalGCStats.markStats;
	uint64_t duration = 0;
	bool deltaTimeSuccess = getTimeDeltaInMicroSeconds(&duration, markStats->_startTime, markStats->_endTime);

	enterAtomicReportingBlock();
	handleGCOPOuterStanzaStart(env, "mark", env->_cycleState->_verboseContextID, duration, deltaTimeSuccess);

	writer->formatAndOutput(env, 1, "<trace-info objectcount=\"%zu\" scancount=\"%zu\" scanbytes=\"%zu\" />",
			markStats->_objectsMarked, markStats->_objectsScanned, markStats->_bytesScanned);

	handleMarkEndInternal(env, eventData);

	handleGCOPOuterStanzaEnd(env);
	writer->flush(env);
	exitAtomicReportingBlock();
}
void
MM_VerboseHandlerOutputStandard::outputMemoryInfoInnerStanza(MM_EnvironmentBase *env, uintptr_t indent, MM_CollectionStatistics *statsBase)
{
	MM_VerboseWriterChain* writer = _manager->getWriterChain();
	MM_CollectionStatisticsStandard *stats = MM_CollectionStatisticsStandard::getCollectionStatistics(statsBase);

	if (stats->_scavengerEnabled) {
		writer->formatAndOutput(env, indent, "<mem type=\"nursery\" free=\"%zu\" total=\"%zu\" percent=\"%zu\">",
				stats->_totalFreeNurseryHeapSize, stats->_totalNurseryHeapSize,
				((stats->_totalNurseryHeapSize == 0) ? 0 : ((uintptr_t)(((uint64_t)stats->_totalFreeNurseryHeapSize*100) / (uint64_t)stats->_totalNurseryHeapSize))));

		outputMemType(env, indent + 1, "allocate", stats->_totalFreeNurseryHeapSize - stats->_totalFreeSurvivorHeapSize, stats->_totalNurseryHeapSize - stats->_totalSurvivorHeapSize);
		outputMemType(env, indent + 1, "survivor",  stats->_totalFreeSurvivorHeapSize,  stats->_totalSurvivorHeapSize);
		writer->formatAndOutput(env, indent, "</mem>");
	}

	if (stats->_loaEnabled) {
		if (stats->_tenureFragmentation) {
			writer->formatAndOutput(env, indent, "<mem type=\"tenure\" free=\"%zu\" total=\"%zu\" percent=\"%zu\" micro-fragmented=\"%zu\" macro-fragmented=\"%zu\">",
				stats->_totalFreeTenureHeapSize, stats->_totalTenureHeapSize,
				((stats->_totalTenureHeapSize == 0) ? 0 : ((uintptr_t)(((uint64_t)stats->_totalFreeTenureHeapSize*100) / (uint64_t)stats->_totalTenureHeapSize))),
				stats->_microFragmentedSize, stats->_macroFragmentedSize);
		} else {
			writer->formatAndOutput(env, indent, "<mem type=\"tenure\" free=\"%zu\" total=\"%zu\" percent=\"%zu\">",
				stats->_totalFreeTenureHeapSize, stats->_totalTenureHeapSize,
				((stats->_totalTenureHeapSize == 0) ? 0 : ((uintptr_t)(((uint64_t)stats->_totalFreeTenureHeapSize*100) / (uint64_t)stats->_totalTenureHeapSize))));
		}

		outputMemType(env, indent + 1, "soa", (stats->_totalFreeTenureHeapSize - stats->_totalFreeLOAHeapSize), (stats->_totalTenureHeapSize - stats->_totalLOAHeapSize));
		outputMemType(env, indent + 1, "loa", stats->_totalFreeLOAHeapSize, stats->_totalLOAHeapSize);
		writer->formatAndOutput(env, indent, "</mem>");
	} else {
		if (stats->_tenureFragmentation) {
			outputMemType(env, indent, "tenure", stats->_totalFreeTenureHeapSize, stats->_totalTenureHeapSize, stats->_microFragmentedSize, stats->_macroFragmentedSize);
		} else {
			outputMemType(env, indent, "tenure", stats->_totalFreeTenureHeapSize, stats->_totalTenureHeapSize);
		}
	}

	outputMemoryInfoInnerStanzaInternal(env, indent, statsBase);

	if (stats->_scavengerEnabled) {
		writer->formatAndOutput(env, indent, "<remembered-set count=\"%zu\" />", stats->_rememberedSetCount);
	}

	stats->_tenureFragmentation = false;
}
Example #18
0
void
MM_VerboseHandlerOutput::handleInitializedRegion(J9HookInterface** hook, uintptr_t eventNum, void* eventData)
{
	MM_InitializedEvent* event = (MM_InitializedEvent*)eventData;
	MM_VerboseWriterChain* writer = _manager->getWriterChain();
	MM_EnvironmentBase* env = MM_EnvironmentBase::getEnvironment(event->currentThread);

	writer->formatAndOutput(env, 1, "<region>");
	writer->formatAndOutput(env, 2, "<attribute name=\"regionSize\" value=\"%zu\" />", event->regionSize);
	writer->formatAndOutput(env, 2, "<attribute name=\"regionCount\" value=\"%zu\" />", event->regionCount);
#if defined(OMR_GC_ARRAYLETS)
	writer->formatAndOutput(env, 2, "<attribute name=\"arrayletLeafSize\" value=\"%zu\" />", event->arrayletLeafSize);
#endif	
	writer->formatAndOutput(env, 1, "</region>");
}
void
MM_VerboseHandlerOutputStandard::handleScavengeEnd(J9HookInterface** hook, uintptr_t eventNum, void* eventData)
{
	MM_ScavengeEndEvent* event = (MM_ScavengeEndEvent*)eventData;
	MM_EnvironmentBase* env = MM_EnvironmentBase::getEnvironment(event->currentThread);
	MM_GCExtensionsBase *extensions = MM_GCExtensionsBase::getExtensions(env->getOmrVM());
	MM_VerboseManager* manager = getManager();
	MM_VerboseWriterChain* writer = manager->getWriterChain();
	MM_ScavengerStats *scavengerStats = &extensions->scavengerStats;
	OMRPORT_ACCESS_FROM_OMRPORT(env->getPortLibrary());
	uint64_t duration = 0;
	bool deltaTimeSuccess = getTimeDeltaInMicroSeconds(&duration, scavengerStats->_startTime, scavengerStats->_endTime);

	enterAtomicReportingBlock();
	handleGCOPOuterStanzaStart(env, "scavenge", env->_cycleState->_verboseContextID, duration, deltaTimeSuccess);

	writer->formatAndOutput(env, 1, "<scavenger-info tenureage=\"%zu\" tenuremask=\"%4zx\" tiltratio=\"%zu\" />", scavengerStats->_tenureAge, scavengerStats->getFlipHistory(0)->_tenureMask, scavengerStats->_tiltRatio);

	if (0 != scavengerStats->_flipCount) {
		writer->formatAndOutput(env, 1, "<memory-copied type=\"nursery\" objects=\"%zu\" bytes=\"%zu\" bytesdiscarded=\"%zu\" />",
				scavengerStats->_flipCount, scavengerStats->_flipBytes, scavengerStats->_flipDiscardBytes);
	}
	if (0 != scavengerStats->_tenureAggregateCount) {
		writer->formatAndOutput(env, 1, "<memory-copied type=\"tenure\" objects=\"%zu\" bytes=\"%zu\" bytesdiscarded=\"%zu\" />",
				scavengerStats->_tenureAggregateCount, scavengerStats->_tenureAggregateBytes, scavengerStats->_tenureDiscardBytes);
	}
	if (0 != scavengerStats->_failedFlipCount) {
		writer->formatAndOutput(env, 1, "<copy-failed type=\"nursery\" objects=\"%zu\" bytes=\"%zu\" />",
				scavengerStats->_failedFlipCount, scavengerStats->_failedFlipBytes);
	}
	if (0 != scavengerStats->_failedTenureCount) {
		writer->formatAndOutput(env, 1, "<copy-failed type=\"tenure\" objects=\"%zu\" bytes=\"%zu\" />",
				scavengerStats->_failedTenureCount, scavengerStats->_failedTenureBytes);
	}

	handleScavengeEndInternal(env, eventData);
	
	if(0 != scavengerStats->_tenureExpandedCount) {
		uint64_t expansionMicros = omrtime_hires_delta(0, scavengerStats->_tenureExpandedTime, OMRPORT_TIME_DELTA_IN_MICROSECONDS);
		outputCollectorHeapResizeInfo(env, 1, HEAP_EXPAND, scavengerStats->_tenureExpandedBytes, scavengerStats->_tenureExpandedCount, MEMORY_TYPE_OLD, SATISFY_COLLECTOR, expansionMicros);
	}

	if(scavengerStats->_rememberedSetOverflow) {
		writer->formatAndOutput(env, 1, "<warning details=\"remembered set overflow detected\" />");
		if(scavengerStats->_causedRememberedSetOverflow) {
			writer->formatAndOutput(env, 1, "<warning details=\"remembered set overflow triggered\" />");
		}
	}
	if(scavengerStats->_scanCacheOverflow) {
		writer->formatAndOutput(env, 1, "<warning details=\"scan cache overflow (storage acquired from heap)\" />");
	}
	if(scavengerStats->_backout) {
		writer->formatAndOutput(env, 1, "<warning details=\"aborted collection due to insufficient free space\" />");
	}

	handleGCOPOuterStanzaEnd(env);
	writer->flush(env);
	exitAtomicReportingBlock();
}