Skip to content

Commit ea3c0c4

Browse files
authored
Updated diaghub support to match correct interface. (#14)
1 parent 1261c30 commit ea3c0c4

5 files changed

Lines changed: 121 additions & 14 deletions

File tree

_msbuild_test.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,14 @@
4848
CSourceFile('etwtrace/_tdhreader.cpp'),
4949
IncludeFile('etwtrace/_tdhreader.h'),
5050
),
51-
PydFile(
52-
'DiagnosticsHub.InstrumentationCollector',
53-
*PYD_OPTS,
54-
CSourceFile('etwtrace/_diaghubstub.c'),
55-
TargetExt='.dll',
56-
),
51+
# This package will be renamed in init_PACKAGE
52+
Package('arch',
53+
CProject(
54+
'DiagnosticsHubStub',
55+
*PYD_OPTS,
56+
CSourceFile('etwtrace/_diaghubstub.c'),
57+
),
58+
)
5759
),
5860
source='src',
5961
)
@@ -65,3 +67,14 @@ def init_METADATA():
6567
if sep and re.match(r"\d+(\.\d+)+((a|b|rc)\d+)?$", version):
6668
# Looks like a version tag
6769
METADATA["Version"] = version
70+
71+
72+
def init_PACKAGE(tag=None):
73+
if not tag:
74+
return
75+
if tag.endswith("-win32"):
76+
PACKAGE.find('test/arch').name = 'x86'
77+
elif tag.endswith("-win_amd64"):
78+
PACKAGE.find('test/arch').name = 'amd64'
79+
elif tag.endswith("-win_arm64"):
80+
PACKAGE.find('test/arch').name = 'arm64'

src/etwtrace/__init__.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,16 +101,28 @@ def __init__(self):
101101

102102
class DiagnosticsHubTracer(_TracingMixin):
103103
def __init__(self, stub=False):
104+
self._data = None
104105
if stub:
105106
from ctypes import PyDLL, py_object
106107
from pathlib import Path
108+
from os import environ
109+
from sys import winver
107110
self._data = []
108-
dll = Path(__file__).parent / "test" / "DiagnosticsHub.InstrumentationCollector.dll"
111+
root = Path(__file__).parent / "test"
112+
if winver.endswith("-32"):
113+
dll = root / "x86"
114+
elif winver.endswith("-arm64"):
115+
dll = root / "arm64"
116+
else:
117+
dll = root / "amd64"
118+
dll = dll / "DiagnosticsHubStub.dll"
109119
if not dll.is_file():
110120
raise RuntimeError("Diagnostics hub stub requires test files")
111121
self._stub = PyDLL(str(dll))
112122
self._stub.OnEvent.argtypes = [py_object]
113123
self._stub.OnEvent(lambda *a: self._on_event(*a))
124+
environ["DIAGHUB_INSTR_COLLECTOR_ROOT"] = str(root)
125+
environ["DIAGHUB_INSTR_RUNTIME_NAME"] = dll.name
114126
super().__init__()
115127
from . import _vsinstrument as mod
116128
self._module = mod
@@ -121,7 +133,8 @@ def _on_event(self, *args):
121133

122134
def disable(self):
123135
super().disable()
124-
print(*self._data, sep="\n")
136+
if self._data:
137+
print(*self._data, sep="\n")
125138

126139

127140
def enable_if(enable_var, type_var):

src/etwtrace/_diaghubstub.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,20 @@ EXPORT void PROBE_IMPL Cap_Define_Script_Function(_In_ void* pFunction, _In_ voi
5555
}
5656
}
5757

58+
EXPORT BOOL PROBE_IMPL ChildAttach()
59+
{
60+
if (_on_event) {
61+
PyObject *r = PyObject_CallFunction(_on_event, "s", "ChildAttach");
62+
if (!r) {
63+
PyErr_WriteUnraisable(NULL);
64+
return FALSE;
65+
} else {
66+
Py_DECREF(r);
67+
}
68+
}
69+
return TRUE;
70+
}
71+
5872
EXPORT void PROBE_IMPL Stub_Write_Mark(_In_ int opcode, _In_z_ LPCWSTR szMark)
5973
{
6074
if (_on_event) {

src/etwtrace/_vsinstrument.c

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -278,14 +278,52 @@ static int vsinstrument_exec(PyObject *m)
278278
return -1;
279279
}
280280

281-
// We ensure the DLL is loaded already before loading it again, but
282-
// use LoadLibraryW to increment the reference count to ensure it does not
283-
// get freed on us.
284-
if (!GetModuleHandleW(L"DiagnosticsHub.InstrumentationCollector.dll")) {
285-
PyErr_SetString(PyExc_RuntimeError, "VS tracing must be launched from Diagnostics Hub");
281+
#if defined(_M_IX86)
282+
const wchar_t * const subpath = L"\\x86\\";
283+
#elif defined(_M_AMD64)
284+
const wchar_t * const subpath = L"\\amd64\\";
285+
#elif defined(_M_ARM64)
286+
const wchar_t * const subpath = L"\\arm64\\";
287+
#else
288+
#error Unsupported architecture
289+
#endif
290+
291+
DWORD cchPath = GetEnvironmentVariableW(L"DIAGHUB_INSTR_COLLECTOR_ROOT", NULL, 0);
292+
if (!cchPath) {
293+
PyErr_SetFromWindowsErr(0);
294+
return -1;
295+
}
296+
DWORD cchName = GetEnvironmentVariableW(L"DIAGHUB_INSTR_RUNTIME_NAME", NULL, 0);
297+
if (!cchName) {
298+
PyErr_SetFromWindowsErr(0);
299+
return -1;
300+
}
301+
cchPath = cchPath + cchName + (DWORD)wcslen(subpath);
302+
wchar_t *path = (wchar_t *)PyMem_Malloc(cchPath * sizeof(wchar_t));
303+
if (!path) {
304+
PyErr_NoMemory();
305+
return -1;
306+
}
307+
308+
DWORD cch = GetEnvironmentVariable(L"DIAGHUB_INSTR_COLLECTOR_ROOT", path, cchPath);
309+
if (!cch) {
310+
PyErr_SetFromWindowsErr(0);
286311
return -1;
287312
}
288-
state->hModule = LoadLibraryW(L"DiagnosticsHub.InstrumentationCollector.dll");
313+
while (cch > 0 && path[cch - 1] == L'\\') {
314+
--cch;
315+
}
316+
wcscpy_s(&path[cch], cchPath - cch, subpath);
317+
cch += (DWORD)wcslen(subpath);
318+
319+
if (!GetEnvironmentVariable(L"DIAGHUB_INSTR_RUNTIME_NAME", &path[cch], cchPath - cch)) {
320+
PyMem_Free(path);
321+
PyErr_SetFromWindowsErr(0);
322+
return -1;
323+
}
324+
325+
state->hModule = LoadLibraryW(path);
326+
PyMem_Free(path);
289327
if (!state->hModule) {
290328
PyErr_SetFromWindowsErr(0);
291329
return -1;
@@ -314,6 +352,17 @@ static int vsinstrument_exec(PyObject *m)
314352
// Allowed to be absent
315353
state->WriteMark = (Stub_Write_Mark)GetProcAddress(state->hModule, "Stub_Write_Mark");
316354

355+
BOOL (*childAttach)() = (BOOL (*)())GetProcAddress(state->hModule, "ChildAttach");
356+
if (!childAttach) {
357+
PyErr_SetFromWindowsErr(0);
358+
return -1;
359+
}
360+
361+
if (!(*childAttach)()) {
362+
PyErr_SetString(PyExc_RuntimeError, "Failed to attach to profiler");
363+
return -1;
364+
}
365+
317366
return 0;
318367
}
319368

tests/test_diaghub.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,28 @@ def test_but_do_we_diaghub():
6565
with subprocess.Popen(
6666
[sys.executable, "-m", "etwtrace", "--diaghub", "--", SCRIPTS / "no_events.py"],
6767
cwd=SCRIPTS,
68+
env={
69+
**os.environ,
70+
"DIAGHUB_INSTR_COLLECTOR_ROOT": "",
71+
"DIAGHUB_INSTR_RUNTIME_NAME": "",
72+
},
6873
) as p:
6974
p.wait()
7075
assert p.returncode
7176

77+
# We should succeed, but can't tell what's happened
78+
with subprocess.Popen(
79+
[sys.executable, "-m", "etwtrace", "--diaghub", "--", SCRIPTS / "no_events.py"],
80+
cwd=SCRIPTS,
81+
env={
82+
**os.environ,
83+
"DIAGHUB_INSTR_COLLECTOR_ROOT": str(Path(etwtrace.__file__).parent / "test"),
84+
"DIAGHUB_INSTR_RUNTIME_NAME": "DiagnosticsHubStub.dll",
85+
},
86+
) as p:
87+
p.wait()
88+
assert not p.returncode
89+
7290

7391
def test_but_do_we_diaghubtest():
7492
subprocess.check_call(

0 commit comments

Comments
 (0)