Skip to content

Commit aad2b6e

Browse files
authored
Merge pull request swiftlang#66973 from hjyamauchi/dump-arrays
Improve the dump-arrays performance on Windows
2 parents 1f9502d + af890f3 commit aad2b6e

File tree

6 files changed

+659
-84
lines changed

6 files changed

+659
-84
lines changed

tools/swift-inspect/Package.swift

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
// swift-tools-version:5.2
1+
// swift-tools-version:5.3
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
55

66
let package = Package(
77
name: "swift-inspect",
8+
products: [
9+
.library(name: "SwiftInspectClient", type: .dynamic, targets: ["SwiftInspectClient"]),
10+
],
811
dependencies: [
912
.package(url: "https://github.com/apple/swift-argument-parser", from: "0.0.1"),
1013
],
@@ -16,12 +19,18 @@ let package = Package(
1619
dependencies: [
1720
"SymbolicationShims",
1821
.product(name: "ArgumentParser", package: "swift-argument-parser"),
22+
.target(name: "SwiftInspectClient", condition: .when(platforms: [.windows])),
23+
.target(name: "SwiftInspectClientInterface", condition: .when(platforms: [.windows])),
1924
],
2025
swiftSettings: [
2126
.unsafeFlags([
2227
"-parse-as-library",
2328
]),
2429
]),
30+
.target(
31+
name: "SwiftInspectClient"),
32+
.systemLibrary(
33+
name: "SwiftInspectClientInterface"),
2534
.testTarget(
2635
name: "swiftInspectTests",
2736
dependencies: ["swift-inspect"]),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#if defined(_WIN32)
14+
15+
#pragma comment(lib, "swiftCore.lib")
16+
17+
#include "../SwiftInspectClientInterface/SwiftInspectClientInterface.h"
18+
#include <assert.h>
19+
#include <memory>
20+
#include <stdio.h>
21+
#include <strsafe.h>
22+
#include <vector>
23+
#include <windows.h>
24+
25+
namespace {
26+
27+
struct ScopedHandle {
28+
HANDLE Handle;
29+
explicit ScopedHandle(HANDLE Handle) noexcept : Handle(Handle) {}
30+
~ScopedHandle() noexcept {
31+
if (Handle != NULL && Handle != INVALID_HANDLE_VALUE) {
32+
CloseHandle(Handle);
33+
}
34+
}
35+
operator HANDLE() const { return Handle; }
36+
};
37+
38+
struct ScopedViewOfFile {
39+
void *View;
40+
explicit ScopedViewOfFile(void *View) noexcept : View(View) {}
41+
~ScopedViewOfFile() noexcept {
42+
if (View != NULL) {
43+
UnmapViewOfFile(View);
44+
}
45+
}
46+
void *get() const { return View; }
47+
template <typename T> T *as() const { return reinterpret_cast<T *>(View); }
48+
};
49+
50+
struct ScopedHeapLock {
51+
HANDLE Heap;
52+
bool Failure = false;
53+
explicit ScopedHeapLock(HANDLE Heap) noexcept : Heap(Heap) {
54+
if (!HeapLock(Heap)) {
55+
OutputDebugStringA("Failed to lock heap\n");
56+
Failure = true;
57+
}
58+
}
59+
~ScopedHeapLock() noexcept {
60+
if (Heap != NULL && !Failure) {
61+
if (!HeapUnlock(Heap)) {
62+
OutputDebugStringA("Failed to lock heap\n");
63+
}
64+
}
65+
}
66+
};
67+
68+
} // anonymous namespace
69+
70+
#define BUF_NUM_ENTRIES (BUF_SIZE / sizeof(HeapEntry))
71+
72+
static int heapWalk() {
73+
// Format the shared mem and event object names
74+
DWORD Pid = GetCurrentProcessId();
75+
char SharedMemName[128];
76+
char ReadEventName[128];
77+
char WriteEventName[128];
78+
if (StringCbPrintfA(SharedMemName, sizeof(SharedMemName), "%hS-%lu",
79+
SHARED_MEM_NAME_PREFIX, Pid) != S_OK) {
80+
OutputDebugStringA("StringCbPrintfA for SharedMemName failed\n");
81+
return 1;
82+
}
83+
if (StringCbPrintfA(ReadEventName, sizeof(ReadEventName), "%hS-%lu",
84+
READ_EVENT_NAME_PREFIX, Pid) != S_OK) {
85+
OutputDebugStringA("StringCbPrintfA for ReadEventName failed\n");
86+
return 1;
87+
}
88+
if (StringCbPrintfA(WriteEventName, sizeof(WriteEventName), "%hS-%lu",
89+
WRITE_EVENT_NAME_PREFIX, Pid) != S_OK) {
90+
OutputDebugStringA("StringCbPrintfA for WriteEventName failed\n");
91+
return 1;
92+
}
93+
94+
ScopedHandle MapFile(
95+
OpenFileMappingA(FILE_MAP_ALL_ACCESS, false, SharedMemName));
96+
if (MapFile == NULL) {
97+
OutputDebugStringA("OpenFileMapping failed\n");
98+
return 1;
99+
}
100+
ScopedViewOfFile Buf(
101+
MapViewOfFile(MapFile.Handle, FILE_MAP_ALL_ACCESS, 0, 0, BUF_SIZE));
102+
if (Buf.get() == NULL) {
103+
OutputDebugStringA("MapViewOfFile failed\n");
104+
return 1;
105+
}
106+
std::memset(Buf.get(), 0, BUF_SIZE);
107+
ScopedHandle WriteEvent(OpenEventA(EVENT_ALL_ACCESS, false, WriteEventName));
108+
if (WriteEvent == NULL) {
109+
OutputDebugStringA("OpenEventA failed\n");
110+
return 1;
111+
}
112+
ScopedHandle ReadEvent(OpenEventA(EVENT_ALL_ACCESS, false, ReadEventName));
113+
if (ReadEvent == NULL) {
114+
OutputDebugStringA("OpenEventA failed\n");
115+
return 1;
116+
}
117+
118+
// Collect heaps. This is a loop because GetProcessHeaps requires
119+
// specifying the max number of heaps to get upfront.
120+
std::vector<HANDLE> Heaps;
121+
while (TRUE) {
122+
DWORD ActualHeapCount = GetProcessHeaps(Heaps.size(), Heaps.data());
123+
if (ActualHeapCount <= Heaps.size()) {
124+
Heaps.resize(ActualHeapCount);
125+
break;
126+
}
127+
Heaps.resize(ActualHeapCount);
128+
}
129+
130+
// Iterate heaps and heap entries
131+
size_t Count = 0;
132+
for (HANDLE Heap : Heaps) {
133+
PROCESS_HEAP_ENTRY Entry;
134+
135+
// NOTE: Be careful not to reenter the heap lock while holding the
136+
// heap lock or else it would hang.
137+
ScopedHeapLock HeapLock(Heap);
138+
if (HeapLock.Failure) {
139+
continue;
140+
}
141+
142+
Entry.lpData = NULL;
143+
while (HeapWalk(Heap, &Entry)) {
144+
if ((Entry.wFlags & PROCESS_HEAP_REGION) ||
145+
(Entry.wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) ||
146+
(!(Entry.wFlags & PROCESS_HEAP_ENTRY_BUSY))) {
147+
continue;
148+
}
149+
assert(Count < BUF_NUM_ENTRIES);
150+
Buf.as<HeapEntry>()[Count] = {
151+
reinterpret_cast<uintptr_t>(Entry.lpData),
152+
Entry.cbData + Entry.cbOverhead
153+
};
154+
if (++Count == BUF_NUM_ENTRIES) {
155+
if (!SetEvent(ReadEvent)) {
156+
OutputDebugStringA("SetEvent on ReadEvent failed\n");
157+
return 1;
158+
}
159+
DWORD Wait = WaitForSingleObject(WriteEvent, WAIT_TIMEOUT_MS);
160+
if (Wait != WAIT_OBJECT_0) {
161+
char Msg[128];
162+
if (StringCbPrintfA(Msg, sizeof(Msg),
163+
"WaitForSingleObject failed %lu\n",
164+
Wait) == S_OK) {
165+
OutputDebugStringA(Msg);
166+
}
167+
return 1;
168+
}
169+
std::memset(Buf.get(), 0, BUF_SIZE);
170+
Count = 0;
171+
}
172+
}
173+
174+
if (Count > 0) {
175+
// Write the remaining entries.
176+
if (!SetEvent(ReadEvent)) {
177+
OutputDebugStringA("SetEvent on ReadEvent failed\n");
178+
return 1;
179+
}
180+
DWORD Wait = WaitForSingleObject(WriteEvent, WAIT_TIMEOUT_MS);
181+
if (Wait != WAIT_OBJECT_0) {
182+
char Msg[128];
183+
if (StringCbPrintfA(Msg, sizeof(Msg),
184+
"WaitForSingleObject failed %lu\n", Wait) == S_OK) {
185+
OutputDebugStringA(Msg);
186+
}
187+
return 1;
188+
}
189+
std::memset(Buf.get(), 0, BUF_SIZE);
190+
Count = 0;
191+
}
192+
}
193+
194+
// Indicate the end of iteration with one last write.
195+
std::memset(Buf.get(), 0, BUF_SIZE);
196+
Buf.as<HeapEntry>()[0].Address = -1;
197+
if (!SetEvent(ReadEvent)) {
198+
OutputDebugStringA("SetEvent at the end of heap iteration failed\n");
199+
return 1;
200+
}
201+
DWORD Wait = WaitForSingleObject(WriteEvent, WAIT_TIMEOUT_MS);
202+
if (Wait != WAIT_OBJECT_0) {
203+
char Msg[128];
204+
if (StringCbPrintfA(Msg, sizeof(Msg), "WaitForSingleObject failed %lu\n",
205+
Wait) == S_OK) {
206+
OutputDebugStringA(Msg);
207+
}
208+
return 1;
209+
}
210+
211+
return 0;
212+
}
213+
214+
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call,
215+
LPVOID lpReserved) {
216+
if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
217+
heapWalk();
218+
}
219+
return TRUE;
220+
}
221+
222+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#if defined(_WIN32)
14+
15+
#include <stdint.h>
16+
17+
#define BUF_SIZE 512
18+
#define SHARED_MEM_NAME_PREFIX "Local\\SwiftInspectFileMapping"
19+
#define READ_EVENT_NAME_PREFIX "Local\\SwiftInspectReadEvent"
20+
#define WRITE_EVENT_NAME_PREFIX "Local\\SwiftInspectWriteEvent"
21+
#define WAIT_TIMEOUT_MS 30000
22+
23+
struct HeapEntry {
24+
uintptr_t Address;
25+
uintptr_t Size;
26+
};
27+
28+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module SwiftInspectClientInterface {
2+
header "SwiftInspectClientInterface.h"
3+
export *
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#if os(Windows)
14+
15+
import WinSDK
16+
17+
internal let FILE_MAP_ALL_ACCESS = DWORD(
18+
STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_WRITE | SECTION_MAP_READ
19+
| SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE)
20+
21+
#endif

0 commit comments

Comments
 (0)