Skip to content

Commit 8998235

Browse files
Jason Mittertreinerjrose-apple
authored andcommitted
Enable Child Memory Usage Tracking on Windows (#23686)
Windows requires a handle to get memory usage, so do a slight refactor to collect the child's memory usage as it exits instead of as the parent is cleaning up.
1 parent 0235ba7 commit 8998235

File tree

5 files changed

+69
-22
lines changed

5 files changed

+69
-22
lines changed

include/swift/Basic/Statistic.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ class UnifiedStatsReporter {
140140
private:
141141
bool currentProcessExitStatusSet;
142142
int currentProcessExitStatus;
143+
long maxChildRSS = 0;
143144
SmallString<128> StatsFilename;
144145
SmallString<128> TraceFilename;
145146
SmallString<128> ProfileDirname;
@@ -192,6 +193,8 @@ class UnifiedStatsReporter {
192193
void flushTracesAndProfiles();
193194
void noteCurrentProcessExitStatus(int);
194195
void saveAnyFrontendStatsEvents(FrontendStatsTracer const &T, bool IsEntry);
196+
void recordJobMaxRSS(long rss);
197+
int64_t getChildrenMaxResidentSetSize();
195198
};
196199

197200
// This is a non-nested type just to make it less work to write at call sites.

include/swift/Basic/TaskQueue.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ struct TaskProcessInformation {
9696
#if defined(HAVE_GETRUSAGE) && !defined(__HAIKU__)
9797
TaskProcessInformation(ProcessId Pid, struct rusage Usage);
9898
#endif // defined(HAVE_GETRUSAGE) && !defined(__HAIKU__)
99+
Optional<ResourceUsage> getResourceUsage() { return ProcessUsage; }
99100
virtual ~TaskProcessInformation() = default;
100101
virtual void provideMapping(json::Output &out);
101102
};

lib/Basic/Default/TaskQueue.inc

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@
2929
#include "llvm/Support/MemoryBuffer.h"
3030
#include "llvm/Support/Signals.h"
3131

32+
#if defined(_WIN32)
33+
#define NOMINMAX
34+
#include <Windows.h>
35+
#include <psapi.h>
36+
#endif
37+
3238
using namespace llvm::sys;
3339

3440
namespace swift {
@@ -150,15 +156,35 @@ bool TaskQueue::execute(TaskBeganCallback Began, TaskFinishedCallback Finished,
150156
// This isn't a true signal on Windows, but we'll treat it as such so that
151157
// we clean up after it properly
152158
bool crashed = ReturnCode & 0xC0000000;
159+
160+
FILETIME creationTime;
161+
FILETIME exitTime;
162+
FILETIME utimeTicks;
163+
FILETIME stimeTicks;
164+
PROCESS_MEMORY_COUNTERS counters = {};
165+
GetProcessTimes(PI.Process, &creationTime, &exitTime, &stimeTicks,
166+
&utimeTicks);
167+
// Each tick is 100ns
168+
uint64_t utime =
169+
((uint64_t)utimeTicks.dwHighDateTime << 32 | utimeTicks.dwLowDateTime) /
170+
10;
171+
uint64_t stime =
172+
((uint64_t)stimeTicks.dwHighDateTime << 32 | stimeTicks.dwLowDateTime) /
173+
10;
174+
GetProcessMemoryInfo(PI.Process, &counters, sizeof(counters));
175+
176+
TaskProcessInformation tpi(PI.Pid, utime, stime,
177+
counters.PeakWorkingSetSize);
153178
#else
154179
// Wait() returning a return code of -2 indicates the process received
155180
// a signal during execution.
156181
bool crashed = ReturnCode == -2;
182+
TaskProcessInformation tpi(PI.Pid);
157183
#endif
158184
if (crashed) {
159185
if (Signalled) {
160186
TaskFinishedResponse Response =
161-
Signalled(PI.Pid, ErrMsg, stdoutContents, stderrContents, T->Context, ReturnCode, TaskProcessInformation(PI.Pid));
187+
Signalled(PI.Pid, ErrMsg, stdoutContents, stderrContents, T->Context, ReturnCode, tpi);
162188
ContinueExecution = Response != TaskFinishedResponse::StopExecution;
163189
} else {
164190
// If we don't have a Signalled callback, unconditionally stop.
@@ -169,7 +195,7 @@ bool TaskQueue::execute(TaskBeganCallback Began, TaskFinishedCallback Finished,
169195
// finished.
170196
if (Finished) {
171197
TaskFinishedResponse Response = Finished(PI.Pid, PI.ReturnCode,
172-
stdoutContents, stderrContents, TaskProcessInformation(PI.Pid), T->Context);
198+
stdoutContents, stderrContents, tpi, T->Context);
173199
ContinueExecution = Response != TaskFinishedResponse::StopExecution;
174200
} else if (PI.ReturnCode != 0) {
175201
ContinueExecution = false;

lib/Basic/Statistic.cpp

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
#ifdef HAVE_MALLOC_MALLOC_H
4646
#include <malloc/malloc.h>
4747
#endif
48+
#if defined(_WIN32)
49+
#define NOMINMAX
50+
#include "Windows.h"
51+
#include "psapi.h"
52+
#endif
4853

4954
namespace swift {
5055
using namespace llvm;
@@ -56,26 +61,6 @@ bool environmentVariableRequestedMaximumDeterminism() {
5661
return false;
5762
}
5863

59-
static int64_t
60-
getChildrenMaxResidentSetSize() {
61-
#if defined(HAVE_GETRUSAGE) && !defined(__HAIKU__)
62-
struct rusage RU;
63-
::getrusage(RUSAGE_CHILDREN, &RU);
64-
int64_t M = static_cast<int64_t>(RU.ru_maxrss);
65-
if (M < 0) {
66-
M = std::numeric_limits<int64_t>::max();
67-
} else {
68-
#ifndef __APPLE__
69-
// Apple systems report bytes; everything else appears to report KB.
70-
M <<= 10;
71-
#endif
72-
}
73-
return M;
74-
#else
75-
return 0;
76-
#endif
77-
}
78-
7964
static std::string
8065
makeFileName(StringRef Prefix,
8166
StringRef ProgramName,
@@ -380,6 +365,29 @@ UnifiedStatsReporter::UnifiedStatsReporter(StringRef ProgramName,
380365
EntityProfilers = make_unique<StatsProfilers>();
381366
}
382367

368+
void UnifiedStatsReporter::recordJobMaxRSS(long rss) {
369+
maxChildRSS = std::max(maxChildRSS, rss);
370+
}
371+
372+
int64_t UnifiedStatsReporter::getChildrenMaxResidentSetSize() {
373+
#if defined(HAVE_GETRUSAGE) && !defined(__HAIKU__)
374+
struct rusage RU;
375+
::getrusage(RUSAGE_CHILDREN, &RU);
376+
int64_t M = static_cast<int64_t>(RU.ru_maxrss);
377+
if (M < 0) {
378+
M = std::numeric_limits<int64_t>::max();
379+
} else {
380+
#ifndef __APPLE__
381+
// Apple systems report bytes; everything else appears to report KB.
382+
M <<= 10;
383+
#endif
384+
}
385+
return M;
386+
#else
387+
return maxChildRSS;
388+
#endif
389+
}
390+
383391
UnifiedStatsReporter::AlwaysOnDriverCounters &
384392
UnifiedStatsReporter::getDriverCounters()
385393
{

lib/Driver/Compilation.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,10 @@ namespace driver {
603603
}
604604
}
605605

606+
if (Comp.getStatsReporter() && ProcInfo.getResourceUsage().hasValue())
607+
Comp.getStatsReporter()->recordJobMaxRSS(
608+
ProcInfo.getResourceUsage()->Maxrss);
609+
606610
if (isBatchJob(FinishedCmd)) {
607611
return unpackAndFinishBatch(ReturnCode, Output, Errors,
608612
static_cast<const BatchJob *>(FinishedCmd));
@@ -684,6 +688,11 @@ namespace driver {
684688
if (TaskQueue::supportsBufferingOutput())
685689
llvm::errs() << Output;
686690
}
691+
692+
if (Comp.getStatsReporter() && ProcInfo.getResourceUsage().hasValue())
693+
Comp.getStatsReporter()->recordJobMaxRSS(
694+
ProcInfo.getResourceUsage()->Maxrss);
695+
687696
if (!ErrorMsg.empty())
688697
Comp.getDiags().diagnose(SourceLoc(),
689698
diag::error_unable_to_execute_command,

0 commit comments

Comments
 (0)