From 5ba46f0692454103f5d3c86a2db561207a738a5a Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Tue, 19 Sep 2023 17:10:30 +0200 Subject: [PATCH] JIT: Initialize jitstdout lazily (#92123) Avoid duplicating a handle and doing several I/O operations on the startup path. Fixes #91856 as a side effect. --- src/coreclr/jit/codegencommon.cpp | 6 +- src/coreclr/jit/compiler.cpp | 342 +++++++++++++++--------------- src/coreclr/jit/compiler.h | 2 +- src/coreclr/jit/disasm.cpp | 6 +- src/coreclr/jit/ee_il_dll.cpp | 66 ++++-- src/coreclr/jit/emit.cpp | 4 +- src/coreclr/jit/error.cpp | 4 +- src/coreclr/jit/fgdiagnostic.cpp | 2 +- src/coreclr/jit/gentree.cpp | 4 +- src/coreclr/jit/gentree.h | 2 +- src/coreclr/jit/host.h | 5 +- src/coreclr/jit/inline.cpp | 2 +- src/coreclr/jit/lsra.cpp | 2 +- 13 files changed, 238 insertions(+), 209 deletions(-) diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 76c0212ceaba54..c364b5c3538528 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -2011,7 +2011,7 @@ void CodeGen::genEmitMachineCode() #if TRACK_LSRA_STATS if (JitConfig.DisplayLsraStats() == 3) { - compiler->m_pLinearScan->dumpLsraStatsSummary(jitstdout); + compiler->m_pLinearScan->dumpLsraStatsSummary(jitstdout()); } #endif // TRACK_LSRA_STATS @@ -2104,7 +2104,7 @@ void CodeGen::genEmitUnwindDebugGCandEH() genCreateAndStoreGCInfo(codeSize, prologSize, epilogSize DEBUGARG(codePtr)); #ifdef DEBUG - FILE* dmpf = jitstdout; + FILE* dmpf = jitstdout(); compiler->opts.dmpHex = false; if (!strcmp(compiler->info.compMethodName, "= 0.5) { - fprintf(fout, " GT_%-17s %7u (%4.1lf%%) %3u bytes each\n", GenTree::OpName(oper.Oper), count, - percentage, size); + jitprintf(" GT_%-17s %7u (%4.1lf%%) %3u bytes each\n", GenTree::OpName(oper.Oper), count, + percentage, size); remainingCount -= count; } else @@ -1483,14 +1481,14 @@ void Compiler::compShutdown() if (remainingCount > 0) { - fprintf(fout, " All other GT_xxx ... %7u (%4.1lf%%) ... %4.1lf%% small + %4.1lf%% large\n", - remainingCount, 100.0 * remainingCount / totalCount, 100.0 * remainingCountSmall / totalCount, - 100.0 * remainingCountLarge / totalCount); + jitprintf(" All other GT_xxx ... %7u (%4.1lf%%) ... %4.1lf%% small + %4.1lf%% large\n", remainingCount, + 100.0 * remainingCount / totalCount, 100.0 * remainingCountSmall / totalCount, + 100.0 * remainingCountLarge / totalCount); } - fprintf(fout, " -----------------------------------------------------\n"); - fprintf(fout, " Total ....... %11u --ALL-- ... %4.1lf%% small + %4.1lf%% large\n", totalCount, - 100.0 * countSmall / totalCount, 100.0 * countLarge / totalCount); - fprintf(fout, "\n"); + jitprintf(" -----------------------------------------------------\n"); + jitprintf(" Total ....... %11u --ALL-- ... %4.1lf%% small + %4.1lf%% large\n", totalCount, + 100.0 * countSmall / totalCount, 100.0 * countLarge / totalCount); + jitprintf("\n"); } #endif // COUNT_AST_OPERS @@ -1499,49 +1497,49 @@ void Compiler::compShutdown() if (grossVMsize && grossNCsize) { - fprintf(fout, "\n"); - fprintf(fout, "--------------------------------------\n"); - fprintf(fout, "Function and GC info size stats\n"); - fprintf(fout, "--------------------------------------\n"); + jitprintf("\n"); + jitprintf("--------------------------------------\n"); + jitprintf("Function and GC info size stats\n"); + jitprintf("--------------------------------------\n"); - fprintf(fout, "[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, grossNCsize, Target::g_tgtCPUName, - 100 * grossNCsize / grossVMsize, "Total (excluding GC info)"); + jitprintf("[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, grossNCsize, Target::g_tgtCPUName, + 100 * grossNCsize / grossVMsize, "Total (excluding GC info)"); - fprintf(fout, "[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, totalNCsize, Target::g_tgtCPUName, - 100 * totalNCsize / grossVMsize, "Total (including GC info)"); + jitprintf("[%7u VM, %8u %6s %4u%%] %s\n", grossVMsize, totalNCsize, Target::g_tgtCPUName, + 100 * totalNCsize / grossVMsize, "Total (including GC info)"); if (gcHeaderISize || gcHeaderNSize) { - fprintf(fout, "\n"); + jitprintf("\n"); - fprintf(fout, "GC tables : [%7uI,%7uN] %7u byt (%u%% of IL, %u%% of %s).\n", - gcHeaderISize + gcPtrMapISize, gcHeaderNSize + gcPtrMapNSize, totalNCsize - grossNCsize, - 100 * (totalNCsize - grossNCsize) / grossVMsize, 100 * (totalNCsize - grossNCsize) / grossNCsize, - Target::g_tgtCPUName); + jitprintf("GC tables : [%7uI,%7uN] %7u byt (%u%% of IL, %u%% of %s).\n", gcHeaderISize + gcPtrMapISize, + gcHeaderNSize + gcPtrMapNSize, totalNCsize - grossNCsize, + 100 * (totalNCsize - grossNCsize) / grossVMsize, 100 * (totalNCsize - grossNCsize) / grossNCsize, + Target::g_tgtCPUName); - fprintf(fout, "GC headers : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcHeaderISize, - gcHeaderNSize, gcHeaderISize + gcHeaderNSize, (float)gcHeaderISize / (genMethodICnt + 0.001), - (float)gcHeaderNSize / (genMethodNCnt + 0.001), - (float)(gcHeaderISize + gcHeaderNSize) / genMethodCnt); + jitprintf("GC headers : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcHeaderISize, + gcHeaderNSize, gcHeaderISize + gcHeaderNSize, (float)gcHeaderISize / (genMethodICnt + 0.001), + (float)gcHeaderNSize / (genMethodNCnt + 0.001), + (float)(gcHeaderISize + gcHeaderNSize) / genMethodCnt); - fprintf(fout, "GC ptr maps : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcPtrMapISize, - gcPtrMapNSize, gcPtrMapISize + gcPtrMapNSize, (float)gcPtrMapISize / (genMethodICnt + 0.001), - (float)gcPtrMapNSize / (genMethodNCnt + 0.001), - (float)(gcPtrMapISize + gcPtrMapNSize) / genMethodCnt); + jitprintf("GC ptr maps : [%7uI,%7uN] %7u byt, [%4.1fI,%4.1fN] %4.1f byt/meth\n", gcPtrMapISize, + gcPtrMapNSize, gcPtrMapISize + gcPtrMapNSize, (float)gcPtrMapISize / (genMethodICnt + 0.001), + (float)gcPtrMapNSize / (genMethodNCnt + 0.001), + (float)(gcPtrMapISize + gcPtrMapNSize) / genMethodCnt); } else { - fprintf(fout, "\n"); + jitprintf("\n"); - fprintf(fout, "GC tables take up %u bytes (%u%% of instr, %u%% of %6s code).\n", - totalNCsize - grossNCsize, 100 * (totalNCsize - grossNCsize) / grossVMsize, - 100 * (totalNCsize - grossNCsize) / grossNCsize, Target::g_tgtCPUName); + jitprintf("GC tables take up %u bytes (%u%% of instr, %u%% of %6s code).\n", totalNCsize - grossNCsize, + 100 * (totalNCsize - grossNCsize) / grossVMsize, 100 * (totalNCsize - grossNCsize) / grossNCsize, + Target::g_tgtCPUName); } #ifdef DEBUG #if DOUBLE_ALIGN - fprintf(fout, "%u out of %u methods generated with double-aligned stack\n", - Compiler::s_lvaDoubleAlignedProcsCount, genMethodCnt); + jitprintf("%u out of %u methods generated with double-aligned stack\n", Compiler::s_lvaDoubleAlignedProcsCount, + genMethodCnt); #endif #endif } @@ -1549,110 +1547,110 @@ void Compiler::compShutdown() #endif // DISPLAY_SIZES #if CALL_ARG_STATS - compDispCallArgStats(fout); + compDispCallArgStats(jitstdout()); #endif #if COUNT_BASIC_BLOCKS - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "Basic block count frequency table:\n"); - fprintf(fout, "--------------------------------------------------\n"); - bbCntTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); - - fprintf(fout, "\n"); - - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "IL method size frequency table for methods with a single basic block:\n"); - fprintf(fout, "--------------------------------------------------\n"); - bbOneBBSizeTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); - - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "fgComputeDoms `while (change)` iterations:\n"); - fprintf(fout, "--------------------------------------------------\n"); - domsChangedIterationTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); - - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "fgComputeReachabilitySets `while (change)` iterations:\n"); - fprintf(fout, "--------------------------------------------------\n"); - computeReachabilitySetsIterationTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); - - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "fgComputeReachability `while (change)` iterations:\n"); - fprintf(fout, "--------------------------------------------------\n"); - computeReachabilityIterationTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); + jitprintf("--------------------------------------------------\n"); + jitprintf("Basic block count frequency table:\n"); + jitprintf("--------------------------------------------------\n"); + bbCntTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); + + jitprintf("\n"); + + jitprintf("--------------------------------------------------\n"); + jitprintf("IL method size frequency table for methods with a single basic block:\n"); + jitprintf("--------------------------------------------------\n"); + bbOneBBSizeTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); + + jitprintf("--------------------------------------------------\n"); + jitprintf("fgComputeDoms `while (change)` iterations:\n"); + jitprintf("--------------------------------------------------\n"); + domsChangedIterationTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); + + jitprintf("--------------------------------------------------\n"); + jitprintf("fgComputeReachabilitySets `while (change)` iterations:\n"); + jitprintf("--------------------------------------------------\n"); + computeReachabilitySetsIterationTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); + + jitprintf("--------------------------------------------------\n"); + jitprintf("fgComputeReachability `while (change)` iterations:\n"); + jitprintf("--------------------------------------------------\n"); + computeReachabilityIterationTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); #endif // COUNT_BASIC_BLOCKS #if COUNT_LOOPS - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Loop stats\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Total number of methods with loops is %5u\n", totalLoopMethods); - fprintf(fout, "Total number of loops is %5u\n", totalLoopCount); - fprintf(fout, "Maximum number of loops per method is %5u\n", maxLoopsPerMethod); - fprintf(fout, "# of methods overflowing nat loop table is %5u\n", totalLoopOverflows); - fprintf(fout, "Total number of 'unnatural' loops is %5u\n", totalUnnatLoopCount); - fprintf(fout, "# of methods overflowing unnat loop limit is %5u\n", totalUnnatLoopOverflows); - fprintf(fout, "Total number of loops with an iterator is %5u\n", iterLoopCount); - fprintf(fout, "Total number of loops with a constant iterator is %5u\n", constIterLoopCount); - - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "Loop count frequency table:\n"); - fprintf(fout, "--------------------------------------------------\n"); - loopCountTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); - fprintf(fout, "Loop exit count frequency table:\n"); - fprintf(fout, "--------------------------------------------------\n"); - loopExitCountTable.dump(fout); - fprintf(fout, "--------------------------------------------------\n"); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Loop stats\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Total number of methods with loops is %5u\n", totalLoopMethods); + jitprintf("Total number of loops is %5u\n", totalLoopCount); + jitprintf("Maximum number of loops per method is %5u\n", maxLoopsPerMethod); + jitprintf("# of methods overflowing nat loop table is %5u\n", totalLoopOverflows); + jitprintf("Total number of 'unnatural' loops is %5u\n", totalUnnatLoopCount); + jitprintf("# of methods overflowing unnat loop limit is %5u\n", totalUnnatLoopOverflows); + jitprintf("Total number of loops with an iterator is %5u\n", iterLoopCount); + jitprintf("Total number of loops with a constant iterator is %5u\n", constIterLoopCount); + + jitprintf("--------------------------------------------------\n"); + jitprintf("Loop count frequency table:\n"); + jitprintf("--------------------------------------------------\n"); + loopCountTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); + jitprintf("Loop exit count frequency table:\n"); + jitprintf("--------------------------------------------------\n"); + loopExitCountTable.dump(jitstdout()); + jitprintf("--------------------------------------------------\n"); #endif // COUNT_LOOPS #if MEASURE_NODE_SIZE - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "GenTree node allocation stats\n"); - fprintf(fout, "---------------------------------------------------\n"); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("GenTree node allocation stats\n"); + jitprintf("---------------------------------------------------\n"); - fprintf(fout, "Allocated %6I64u tree nodes (%7I64u bytes total, avg %4I64u bytes per method)\n", - genNodeSizeStats.genTreeNodeCnt, genNodeSizeStats.genTreeNodeSize, - genNodeSizeStats.genTreeNodeSize / genMethodCnt); + jitprintf("Allocated %6I64u tree nodes (%7I64u bytes total, avg %4I64u bytes per method)\n", + genNodeSizeStats.genTreeNodeCnt, genNodeSizeStats.genTreeNodeSize, + genNodeSizeStats.genTreeNodeSize / genMethodCnt); - fprintf(fout, "Allocated %7I64u bytes of unused tree node space (%3.2f%%)\n", - genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize, - (float)(100 * (genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize)) / - genNodeSizeStats.genTreeNodeSize); + jitprintf("Allocated %7I64u bytes of unused tree node space (%3.2f%%)\n", + genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize, + (float)(100 * (genNodeSizeStats.genTreeNodeSize - genNodeSizeStats.genTreeNodeActualSize)) / + genNodeSizeStats.genTreeNodeSize); - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Distribution of per-method GenTree node counts:\n"); - genTreeNcntHist.dump(fout); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Distribution of per-method GenTree node counts:\n"); + genTreeNcntHist.dump(jitstdout()); - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Distribution of per-method GenTree node allocations (in bytes):\n"); - genTreeNsizHist.dump(fout); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Distribution of per-method GenTree node allocations (in bytes):\n"); + genTreeNsizHist.dump(jitstdout()); #endif // MEASURE_NODE_SIZE #if MEASURE_BLOCK_SIZE - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "BasicBlock and FlowEdge/BasicBlockList allocation stats\n"); - fprintf(fout, "---------------------------------------------------\n"); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("BasicBlock and FlowEdge/BasicBlockList allocation stats\n"); + jitprintf("---------------------------------------------------\n"); - fprintf(fout, "Allocated %6u basic blocks (%7u bytes total, avg %4u bytes per method)\n", BasicBlock::s_Count, - BasicBlock::s_Size, BasicBlock::s_Size / genMethodCnt); - fprintf(fout, "Allocated %6u flow nodes (%7u bytes total, avg %4u bytes per method)\n", genFlowNodeCnt, - genFlowNodeSize, genFlowNodeSize / genMethodCnt); + jitprintf("Allocated %6u basic blocks (%7u bytes total, avg %4u bytes per method)\n", BasicBlock::s_Count, + BasicBlock::s_Size, BasicBlock::s_Size / genMethodCnt); + jitprintf("Allocated %6u flow nodes (%7u bytes total, avg %4u bytes per method)\n", genFlowNodeCnt, genFlowNodeSize, + genFlowNodeSize / genMethodCnt); #endif // MEASURE_BLOCK_SIZE @@ -1660,21 +1658,21 @@ void Compiler::compShutdown() if (s_dspMemStats) { - fprintf(fout, "\nAll allocations:\n"); - ArenaAllocator::dumpAggregateMemStats(jitstdout); + jitprintf("\nAll allocations:\n"); + ArenaAllocator::dumpAggregateMemStats(jitstdout()); - fprintf(fout, "\nLargest method:\n"); - ArenaAllocator::dumpMaxMemStats(jitstdout); + jitprintf("\nLargest method:\n"); + ArenaAllocator::dumpMaxMemStats(jitstdout()); - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Distribution of total memory allocated per method (in KB):\n"); - memAllocHist.dump(fout); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Distribution of total memory allocated per method (in KB):\n"); + memAllocHist.dump(jitstdout()); - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Distribution of total memory used per method (in KB):\n"); - memUsedHist.dump(fout); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Distribution of total memory used per method (in KB):\n"); + memUsedHist.dump(jitstdout()); } #endif // MEASURE_MEM_ALLOC @@ -1684,29 +1682,29 @@ void Compiler::compShutdown() if (JitConfig.DisplayLoopHoistStats() != 0) #endif // DEBUG { - PrintAggregateLoopHoistStats(jitstdout); + PrintAggregateLoopHoistStats(jitstdout()); } #endif // LOOP_HOIST_STATS #if TRACK_ENREG_STATS if (JitConfig.JitEnregStats() != 0) { - s_enregisterStats.Dump(fout); + s_enregisterStats.Dump(jitstdout()); } #endif // TRACK_ENREG_STATS #if MEASURE_PTRTAB_SIZE - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "GC pointer table stats\n"); - fprintf(fout, "---------------------------------------------------\n"); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("GC pointer table stats\n"); + jitprintf("---------------------------------------------------\n"); - fprintf(fout, "Reg pointer descriptor size (internal): %8u (avg %4u per method)\n", GCInfo::s_gcRegPtrDscSize, - GCInfo::s_gcRegPtrDscSize / genMethodCnt); + jitprintf("Reg pointer descriptor size (internal): %8u (avg %4u per method)\n", GCInfo::s_gcRegPtrDscSize, + GCInfo::s_gcRegPtrDscSize / genMethodCnt); - fprintf(fout, "Total pointer table size: %8u (avg %4u per method)\n", GCInfo::s_gcTotalPtrTabSize, - GCInfo::s_gcTotalPtrTabSize / genMethodCnt); + jitprintf("Total pointer table size: %8u (avg %4u per method)\n", GCInfo::s_gcTotalPtrTabSize, + GCInfo::s_gcTotalPtrTabSize / genMethodCnt); #endif // MEASURE_PTRTAB_SIZE @@ -1714,37 +1712,37 @@ void Compiler::compShutdown() if (genMethodCnt != 0) { - fprintf(fout, "\n"); - fprintf(fout, "A total of %6u methods compiled", genMethodCnt); + jitprintf("\n"); + jitprintf("A total of %6u methods compiled", genMethodCnt); #if DISPLAY_SIZES if (genMethodICnt || genMethodNCnt) { - fprintf(fout, " (%u interruptible, %u non-interruptible)", genMethodICnt, genMethodNCnt); + jitprintf(" (%u interruptible, %u non-interruptible)", genMethodICnt, genMethodNCnt); } #endif // DISPLAY_SIZES - fprintf(fout, ".\n"); + jitprintf(".\n"); } #endif // MEASURE_NODE_SIZE || MEASURE_BLOCK_SIZE || MEASURE_PTRTAB_SIZE || DISPLAY_SIZES #if EMITTER_STATS - emitterStats(fout); + emitterStats(jitstdout()); #endif #if MEASURE_FATAL - fprintf(fout, "\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, "Fatal errors stats\n"); - fprintf(fout, "---------------------------------------------------\n"); - fprintf(fout, " badCode: %u\n", fatal_badCode); - fprintf(fout, " noWay: %u\n", fatal_noWay); - fprintf(fout, " implLimitation: %u\n", fatal_implLimitation); - fprintf(fout, " NOMEM: %u\n", fatal_NOMEM); - fprintf(fout, " noWayAssertBody: %u\n", fatal_noWayAssertBody); + jitprintf("\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf("Fatal errors stats\n"); + jitprintf("---------------------------------------------------\n"); + jitprintf(" badCode: %u\n", fatal_badCode); + jitprintf(" noWay: %u\n", fatal_noWay); + jitprintf(" implLimitation: %u\n", fatal_implLimitation); + jitprintf(" NOMEM: %u\n", fatal_NOMEM); + jitprintf(" noWayAssertBody: %u\n", fatal_noWayAssertBody); #ifdef DEBUG - fprintf(fout, " noWayAssertBodyArgs: %u\n", fatal_noWayAssertBodyArgs); + jitprintf(" noWayAssertBodyArgs: %u\n", fatal_noWayAssertBodyArgs); #endif // DEBUG - fprintf(fout, " NYI: %u\n", fatal_NYI); + jitprintf(" NYI: %u\n", fatal_NYI); #endif // MEASURE_FATAL } @@ -1753,14 +1751,14 @@ void Compiler::compShutdown() */ /* static */ -void Compiler::compDisplayStaticSizes(FILE* fout) +void Compiler::compDisplayStaticSizes() { #if MEASURE_NODE_SIZE - GenTree::DumpNodeSizes(fout); + GenTree::DumpNodeSizes(); #endif #if EMITTER_STATS - emitterStaticStats(fout); + emitterStaticStats(); #endif } @@ -5153,7 +5151,7 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl #if TRACK_LSRA_STATS if (JitConfig.DisplayLsraStats() == 2) { - m_pLinearScan->dumpLsraStatsCsv(jitstdout); + m_pLinearScan->dumpLsraStatsCsv(jitstdout()); } #endif // TRACK_LSRA_STATS @@ -5879,7 +5877,7 @@ int Compiler::compCompile(CORINFO_MODULE_HANDLE classPtr, } #endif // FUNC_INFO_LOGGING - // if (s_compMethodsCount==0) setvbuf(jitstdout, NULL, _IONBF, 0); + // if (s_compMethodsCount==0) setvbuf(jitstdout(), NULL, _IONBF, 0); if (compIsForInlining()) { @@ -6363,7 +6361,7 @@ void Compiler::compCompileFinish() if (s_dspMemStats || verbose) { printf("\nAllocations for %s (MethodHash=%08x)\n", info.compFullName, info.compMethodHash()); - compArenaAllocator->dumpMemStats(jitstdout); + compArenaAllocator->dumpMemStats(jitstdout()); } #endif // DEBUG #endif // MEASURE_MEM_ALLOC diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 3c4badb6088b4b..7d407d9643b41e 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -10351,7 +10351,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX InlineInfo* inlineInfo); void compDone(); - static void compDisplayStaticSizes(FILE* fout); + static void compDisplayStaticSizes(); //------------ Some utility functions -------------- diff --git a/src/coreclr/jit/disasm.cpp b/src/coreclr/jit/disasm.cpp index e1926a3f640b7b..fd5c98eb068810 100644 --- a/src/coreclr/jit/disasm.cpp +++ b/src/coreclr/jit/disasm.cpp @@ -1478,12 +1478,12 @@ void DisAssembler::disAsmCode(BYTE* hotCodePtr, size_t hotCodeSize, BYTE* coldCo } #else // !DEBUG // NOTE: non-DEBUG builds always use jitstdout currently! - disAsmFile = jitstdout; + disAsmFile = jitstdout(); #endif // !DEBUG if (disAsmFile == nullptr) { - disAsmFile = jitstdout; + disAsmFile = jitstdout(); } // As this writes to a common file, this is not reentrant. @@ -1519,7 +1519,7 @@ void DisAssembler::disAsmCode(BYTE* hotCodePtr, size_t hotCodeSize, BYTE* coldCo DisasmBuffer(disAsmFile, /* printIt */ true); fprintf(disAsmFile, "\n"); - if (disAsmFile != jitstdout) + if (disAsmFile != jitstdout()) { fclose(disAsmFile); } diff --git a/src/coreclr/jit/ee_il_dll.cpp b/src/coreclr/jit/ee_il_dll.cpp index 4e87fd52c55a6b..11c7f77ecc4a27 100644 --- a/src/coreclr/jit/ee_il_dll.cpp +++ b/src/coreclr/jit/ee_il_dll.cpp @@ -31,8 +31,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /*****************************************************************************/ -FILE* jitstdout = nullptr; - ICorJitHost* g_jitHost = nullptr; bool g_jitInitialized = false; @@ -71,16 +69,25 @@ extern "C" DLLEXPORT void jitStartup(ICorJitHost* jitHost) assert(!JitConfig.isInitialized()); JitConfig.initialize(jitHost); + Compiler::compStartup(); + + g_jitInitialized = true; +} + +static FILE* volatile s_jitstdout; +static FILE* jitstdoutInit() +{ const WCHAR* jitStdOutFile = JitConfig.JitStdOutFile(); + FILE* file = nullptr; if (jitStdOutFile != nullptr) { - jitstdout = _wfopen(jitStdOutFile, W("a")); - assert(jitstdout != nullptr); + file = _wfopen(jitStdOutFile, W("a")); + assert(file != nullptr); } #if !defined(HOST_UNIX) - if (jitstdout == nullptr) + if (file == nullptr) { int stdoutFd = _fileno(procstdout()); // Check fileno error output(s) -1 may overlap with errno result @@ -89,43 +96,61 @@ extern "C" DLLEXPORT void jitStartup(ICorJitHost* jitHost) // or bogus and avoid making further calls. if ((stdoutFd != -1) && (stdoutFd != -2) && (errno != EINVAL)) { - int jitstdoutFd = _dup(_fileno(procstdout())); + int jitstdoutFd = _dup(stdoutFd); // Check the error status returned by dup. if (jitstdoutFd != -1) { _setmode(jitstdoutFd, _O_TEXT); - jitstdout = _fdopen(jitstdoutFd, "w"); - assert(jitstdout != nullptr); + file = _fdopen(jitstdoutFd, "w"); + assert(file != nullptr); // Prevent the FILE* from buffering its output in order to avoid calls to // `fflush()` throughout the code. - setvbuf(jitstdout, nullptr, _IONBF, 0); + setvbuf(file, nullptr, _IONBF, 0); } } } #endif // !HOST_UNIX - // If jitstdout is still null, fallback to whatever procstdout() was - // initially set to. - if (jitstdout == nullptr) + if (file == nullptr) { - jitstdout = procstdout(); + file = procstdout(); } - Compiler::compStartup(); + FILE* observed = InterlockedCompareExchangeT(&s_jitstdout, file, nullptr); - g_jitInitialized = true; + if (observed != nullptr) + { + if (file != procstdout()) + { + fclose(file); + } + + return observed; + } + + return file; } -#ifndef DEBUG +FILE* jitstdout() +{ + FILE* file = s_jitstdout; + if (file != nullptr) + { + return file; + } + + return jitstdoutInit(); +} + +// Like printf/logf, but only outputs to jitstdout -- skips call back into EE. void jitprintf(const char* fmt, ...) { va_list vl; va_start(vl, fmt); - vfprintf(jitstdout, fmt, vl); + vfprintf(jitstdout(), fmt, vl); va_end(vl); } -#endif void jitShutdown(bool processIsTerminating) { @@ -136,14 +161,15 @@ void jitShutdown(bool processIsTerminating) Compiler::compShutdown(); - if (jitstdout != procstdout()) + FILE* file = s_jitstdout; + if ((file != nullptr) && (file != procstdout())) { // When the process is terminating, the fclose call is unnecessary and is also prone to // crashing since the UCRT itself often frees the backing memory earlier on in the // termination sequence. if (!processIsTerminating) { - fclose(jitstdout); + fclose(file); } } diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index 039e3395da00cc..d169504491818c 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -215,7 +215,7 @@ unsigned emitter::emitInt32CnsCnt; unsigned emitter::emitNegCnsCnt; unsigned emitter::emitPow2CnsCnt; -void emitterStaticStats(FILE* fout) +void emitterStaticStats() { // The IG buffer size depends on whether we are storing a debug info pointer or not. For our purposes // here, do not include that. @@ -227,6 +227,8 @@ void emitterStaticStats(FILE* fout) insGroup* igDummy = nullptr; + FILE* fout = jitstdout(); + fprintf(fout, "\n"); fprintf(fout, "insGroup:\n"); fprintf(fout, "Offset / size of igNext = %3zu / %2zu\n", offsetof(insGroup, igNext), diff --git a/src/coreclr/jit/error.cpp b/src/coreclr/jit/error.cpp index a4c2855dff83b2..a45ad7c7df0ef0 100644 --- a/src/coreclr/jit/error.cpp +++ b/src/coreclr/jit/error.cpp @@ -370,7 +370,7 @@ int logf(const char* fmt, ...) { // if the EE refuses to log it, we try to send it to stdout va_start(args, fmt); - written = vflogf(jitstdout, fmt, args); + written = vflogf(jitstdout(), fmt, args); va_end(args); } #if 0 // Enable this only when you need it @@ -431,7 +431,7 @@ void gcDump_logf(const char* fmt, ...) { // if the EE refuses to log it, we try to send it to stdout va_start(args, fmt); - vflogf(jitstdout, fmt, args); + vflogf(jitstdout(), fmt, args); va_end(args); } #if 0 // Enable this only when you need it diff --git a/src/coreclr/jit/fgdiagnostic.cpp b/src/coreclr/jit/fgdiagnostic.cpp index 168b2e6f7a96e2..afc1bbc1db73ed 100644 --- a/src/coreclr/jit/fgdiagnostic.cpp +++ b/src/coreclr/jit/fgdiagnostic.cpp @@ -674,7 +674,7 @@ FILE* Compiler::fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, PhasePositi } else if (strcmp(filename, "stdout") == 0) { - fgxFile = jitstdout; + fgxFile = jitstdout(); *wbDontClose = true; } else if (strcmp(filename, "stderr") == 0) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 874541864c037a..239ddfaff5b297 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -481,10 +481,12 @@ void GenTree::ReportOperBashing(FILE* f) #if MEASURE_NODE_SIZE -void GenTree::DumpNodeSizes(FILE* fp) +void GenTree::DumpNodeSizes() { // Dump the sizes of the various GenTree flavors + FILE* fp = jitstdout(); + fprintf(fp, "Small tree node size = %zu bytes\n", TREE_NODE_SZ_SMALL); fprintf(fp, "Large tree node size = %zu bytes\n", TREE_NODE_SZ_LARGE); fprintf(fp, "\n"); diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 1b20ba741f2816..b0f7536f261de5 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -2311,7 +2311,7 @@ struct GenTree void SetIndirExceptionFlags(Compiler* comp); #if MEASURE_NODE_SIZE - static void DumpNodeSizes(FILE* fp); + static void DumpNodeSizes(); #endif #ifdef DEBUG diff --git a/src/coreclr/jit/host.h b/src/coreclr/jit/host.h index c99a0601e499b0..0ccefae924e637 100644 --- a/src/coreclr/jit/host.h +++ b/src/coreclr/jit/host.h @@ -3,6 +3,8 @@ /*****************************************************************************/ +void jitprintf(const char* fmt, ...); + #ifdef DEBUG #undef printf @@ -44,7 +46,6 @@ extern "C" void ANALYZER_NORETURN __cdecl assertAbort(const char* why, const cha // Re-define printf in Release to use jitstdout (can be overwritten with DOTNET_JitStdOutFile=file) #undef printf #define printf jitprintf -void jitprintf(const char* fmt, ...); #undef assert #define assert(p) (void)0 @@ -55,7 +56,7 @@ void jitprintf(const char* fmt, ...); #define _HOST_H_ /*****************************************************************************/ -extern FILE* jitstdout; +FILE* jitstdout(); inline FILE* procstdout() { diff --git a/src/coreclr/jit/inline.cpp b/src/coreclr/jit/inline.cpp index bae5755707594d..0ded3ef3482a70 100644 --- a/src/coreclr/jit/inline.cpp +++ b/src/coreclr/jit/inline.cpp @@ -480,7 +480,7 @@ void InlineContext::DumpData(unsigned indent) { const char* inlineReason = InlGetObservationString(m_Observation); printf("%*s%u,\"%s\",\"%s\",", indent, "", GetOrdinal(), inlineReason, calleeName); - m_Policy->DumpData(jitstdout); + m_Policy->DumpData(jitstdout()); printf("\n"); } diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index 0b42a838004644..8c088ac3bc1bfa 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -1421,7 +1421,7 @@ PhaseStatus LinearScan::doLinearScan() #endif ) { - dumpLsraStats(jitstdout); + dumpLsraStats(jitstdout()); } #endif // TRACK_LSRA_STATS