Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable FEATURE_PERFMAP on OSX, and update perfjitdump.cpp to work on OSX #99986

Merged
merged 15 commits into from
Apr 3, 2024
Merged
3 changes: 3 additions & 0 deletions src/coreclr/clrdefinitions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ endif(CLR_CMAKE_TARGET_LINUX AND CLR_CMAKE_HOST_LINUX)
if(CLR_CMAKE_TARGET_FREEBSD)
add_compile_definitions(FEATURE_PERFMAP)
endif(CLR_CMAKE_TARGET_FREEBSD)
if(CLR_CMAKE_TARGET_APPLE)
add_compile_definitions(FEATURE_PERFMAP)
endif(CLR_CMAKE_TARGET_APPLE)

if(FEATURE_COMWRAPPERS)
add_compile_definitions(FEATURE_COMWRAPPERS)
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/inc/clrconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ RETAIL_CONFIG_STRING_INFO(UNSUPPORTED_ETW_ObjectAllocationEventsPerTypePerSec, W
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_ProfAPI_ValidateNGENInstrumentation, W("ProfAPI_ValidateNGENInstrumentation"), 0, "This flag enables additional validations when using the IMetaDataEmit APIs for NGEN'ed images to ensure only supported edits are made.")

#ifdef FEATURE_PERFMAP
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_PerfMapEnabled, W("PerfMapEnabled"), 0, "This flag is used on Linux to enable writing /tmp/perf-$pid.map. It is disabled by default")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_PerfMapEnabled, W("PerfMapEnabled"), 0, "This flag is used on Linux and macOS to enable writing /tmp/perf-$pid.map. It is disabled by default")
RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_PerfMapJitDumpPath, W("PerfMapJitDumpPath"), "Specifies a path to write the perf jitdump file. Defaults to /tmp", CLRConfig::LookupOptions::TrimWhiteSpaceFromStringValue)
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_PerfMapIgnoreSignal, W("PerfMapIgnoreSignal"), 0, "When perf map is enabled, this option will configure the specified signal to be accepted and ignored as a marker in the perf logs. It is disabled by default")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_PerfMapShowOptimizationTiers, W("PerfMapShowOptimizationTiers"), 1, "Shows optimization tiers in the perf map for methods, as part of the symbol name. Useful for seeing separate stack frames for different optimization tiers of each method.")
Expand Down
61 changes: 35 additions & 26 deletions src/coreclr/pal/src/misc/perfjitdump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
// The .NET Foundation licenses this file to you under the MIT license.
// ===========================================================================

#if defined(__linux__)
#define JITDUMP_SUPPORTED
#endif

#include "pal/palinternal.h"
#include "pal/dbgmsg.h"

#include <cstddef>

#if defined(__linux__) || defined(__APPLE__)
#define JITDUMP_SUPPORTED
#endif

#ifdef JITDUMP_SUPPORTED

#include <fcntl.h>
Expand Down Expand Up @@ -61,24 +61,11 @@ namespace
JIT_CODE_LOAD = 0,
};

uint64_t GetTimeStampNS()
static uint64_t GetTimeStampNS()
{
#if HAVE_CLOCK_MONOTONIC
struct timespec ts;
int result = clock_gettime(CLOCK_MONOTONIC, &ts);

if (result != 0)
{
ASSERT("clock_gettime(CLOCK_MONOTONIC) failed: %d\n", result);
return 0;
}
else
{
return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
}
#else
#error "The PAL jitdump requires clock_gettime(CLOCK_MONOTONIC) to be supported."
#endif
LARGE_INTEGER result;
QueryPerformanceCounter(&result);
return result.QuadPart;
}

struct FileHeader
Expand Down Expand Up @@ -115,7 +102,7 @@ namespace
{
JitCodeLoadRecord() :
pid(getpid()),
tid(syscall(SYS_gettid))
tid((uint32_t)PlatformGetCurrentThreadId())
{
header.id = JIT_CODE_LOAD;
header.timestamp = GetTimeStampNS();
Expand Down Expand Up @@ -170,6 +157,19 @@ struct PerfJitDumpState
{
int result = 0;

// On platforms where JITDUMP is used, the PAL QueryPerformanceFrequency
// returns tccSecondsToNanoSeconds, meaning QueryPerformanceCounter
// will return a direct nanosecond value. If this isn't true,
// then some other method will need to be used to implement GetTimeStampNS.
// Validate this is true once in Start here.
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
if (freq.QuadPart != tccSecondsToNanoSeconds)
{
_ASSERTE(!"QueryPerformanceFrequency does not return tccSecondsToNanoSeconds. Implement JITDUMP GetTimeStampNS directly for this platform.\n");
FatalError();
}

// Write file header
FileHeader header;

Expand Down Expand Up @@ -203,12 +203,18 @@ struct PerfJitDumpState
if (result == -1)
return FatalError();

#if !defined(__APPLE__)
// mmap jitdump file
// this is a marker for perf inject to find the jitdumpfile
// this is a marker for perf inject to find the jitdumpfile on linux.
// On OSX, samply and others hook open and mmap is not needed. It also fails on OSX,
// likely because of PROT_EXEC and hardened runtime
mmapAddr = mmap(nullptr, sizeof(FileHeader), PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);

if (mmapAddr == MAP_FAILED)
return FatalError();
#else
mmapAddr = NULL;
#endif

enabled = true;

Expand Down Expand Up @@ -314,10 +320,13 @@ struct PerfJitDumpState
if (!enabled)
goto exit;

result = munmap(mmapAddr, sizeof(FileHeader));
if (mmapAddr != NULL)
jkotas marked this conversation as resolved.
Show resolved Hide resolved
{
result = munmap(mmapAddr, sizeof(FileHeader));

if (result == -1)
return FatalError();
if (result == -1)
return FatalError();
}

mmapAddr = MAP_FAILED;

Expand Down
Loading