Dryad/xcompute_native/property.cpp

424 lines
14 KiB
C++

/*
Copyright (c) Microsoft Corporation
All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License
at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions and
limitations under the License.
*/
/*++
Module Name:
property.cpp
Abstract:
This module contains the public interface and support routines for
process properties for xcompute on the HPC scheduler
--*/
#include "stdafx.h"
//#include <scoped_any.h>
using namespace System;
using namespace System::Threading;
using namespace System::Runtime::InteropServices;
//
// Prototypes for functions internal to this module
//
HRESULT
SetGetProps(
XCPROCESSHANDLE hProcessHandle,
long cPropCount,
PXC_PROCESSPROPERTY_INFO setProp[],
LPCSTR blockOnLabel,
UINT64 blockOnVersion,
XCTIMEINTERVAL maxBlockTime,
LPCSTR getPropLabel,
DWORD fetchOptions,
PXC_SETANDGETPROCESSINFO_REQRESULTS *presults,
PCXC_ASYNC_INFO pAsyncInfo
);
static void ConvertManagedProcessInfoToNative(ProcessInfo ^managedInfo, PXC_PROCESS_INFO &pNativeInfo)
{
char *strTemp = NULL;
pNativeInfo = (PXC_PROCESS_INFO)::LocalAlloc(LMEM_FIXED, sizeof(XC_PROCESS_INFO));
ZeroMemory(pNativeInfo, sizeof(XC_PROCESS_INFO));
pNativeInfo->Size = sizeof(XC_PROCESS_INFO);
pNativeInfo->Flags = managedInfo->flags;
pNativeInfo->ProcessState = TranslateProcessState(managedInfo->processState);
pNativeInfo->ProcessStatus = managedInfo->processStatus;
pNativeInfo->ExitCode = managedInfo->exitCode;
if (managedInfo->propertyInfos != nullptr)
{
pNativeInfo->ppProperties = (PXC_PROCESSPROPERTY_INFO*)LocalAlloc(LMEM_FIXED, sizeof(PXC_PROCESSPROPERTY_INFO) * managedInfo->propertyInfos->Length);
pNativeInfo->NumberofProcessProperties = managedInfo->propertyInfos->Length;
for (int i = 0; i < managedInfo->propertyInfos->Length; i ++)
{
PXC_PROCESSPROPERTY_INFO processProp = (XC_PROCESSPROPERTY_INFO*)LocalAlloc(LMEM_FIXED, sizeof(XC_PROCESSPROPERTY_INFO));
ZeroMemory(processProp, sizeof(XC_PROCESSPROPERTY_INFO));
processProp->Size = sizeof(XC_PROCESSPROPERTY_INFO);
size_t len = managedInfo->propertyInfos[i]->propertyLabel->Length + 1;
strTemp = (char*)(void*)Marshal::StringToHGlobalAnsi(managedInfo->propertyInfos[i]->propertyLabel);
processProp->pPropertyLabel = (char*)LocalAlloc(LMEM_FIXED, sizeof(char) * len);
strncpy(processProp->pPropertyLabel, strTemp, len);
Marshal::FreeHGlobal((IntPtr)strTemp);
strTemp = NULL;
len = managedInfo->propertyInfos[i]->propertyString->Length + 1;
strTemp = (char*)(void*)Marshal::StringToHGlobalAnsi(managedInfo->propertyInfos[i]->propertyString);
processProp->pPropertyString = (char*)LocalAlloc(LMEM_FIXED, sizeof(char) * len);
strncpy(processProp->pPropertyString, strTemp, len);
Marshal::FreeHGlobal((IntPtr)strTemp);
strTemp = NULL;
processProp->PropertyVersion = managedInfo->propertyInfos[i]->propertyVersion;
if (managedInfo->propertyInfos[i]->propertyBlock != nullptr && managedInfo->propertyInfos[i]->propertyBlock->Length > 0)
{
processProp->PropertyBlockSize = managedInfo->propertyInfos[i]->propertyBlock->Length;
processProp->pPropertyBlock = (char*)LocalAlloc(LMEM_FIXED, sizeof(char) * processProp->PropertyBlockSize);
Marshal::Copy(managedInfo->propertyInfos[i]->propertyBlock,
0,
(IntPtr)processProp->pPropertyBlock,
processProp->PropertyBlockSize);
}
pNativeInfo->ppProperties[i] = processProp;
}
}
if (managedInfo->processStatistics != nullptr)
{
PXC_PROCESS_STATISTICS stats = (XC_PROCESS_STATISTICS*)LocalAlloc(LMEM_FIXED, sizeof(XC_PROCESS_STATISTICS));
ZeroMemory(stats, sizeof(XC_PROCESS_STATISTICS));
stats->Size = sizeof(XC_PROCESS_STATISTICS);
stats->Flags = managedInfo->processStatistics->flags;
stats->ProcessUserTime = managedInfo->processStatistics->processUserTime;
stats->ProcessKernelTime = managedInfo->processStatistics->processKernelTime;
stats->PageFaults = managedInfo->processStatistics->pageFaults;
stats->TotalProcessesCreated = managedInfo->processStatistics->totalProcessesCreated;
stats->PeakVMUsage = managedInfo->processStatistics->peakVMUsage;
stats->PeakMemUsage = managedInfo->processStatistics->peakMemUsage;
stats->MemUsageSeconds = managedInfo->processStatistics->memUsageSeconds;
stats->TotalIo = managedInfo->processStatistics->totalIo;
pNativeInfo->pProcessStatistics = stats;
}
if (strTemp != NULL)
{
Marshal::FreeHGlobal((IntPtr)strTemp);
strTemp = NULL;
}
}
ref class AsyncPropWrapper
{
public:
ASYNC *m_pASYNC;
ManualResetEvent ^m_event;
XCPROCESSHANDLE m_process;
PXC_SETANDGETPROCESSINFO_REQRESULTS *m_ppResults;
HRESULT m_hResult;
AsyncPropWrapper(ASYNC *pAsync, XCPROCESSHANDLE hProc, PXC_SETANDGETPROCESSINFO_REQRESULTS *ppResults)
{
m_pASYNC = pAsync;
m_event = nullptr;
if (m_pASYNC == NULL)
{
m_event = gcnew ManualResetEvent(false);
}
m_process = hProc;
m_ppResults = ppResults;
m_hResult = HRESULT_FROM_WIN32(ERROR_IO_PENDING);
}
~AsyncPropWrapper()
{
if (m_pASYNC)
{
delete m_pASYNC;
}
}
void GetSetPropertyHandler(System::Object ^sender, Microsoft::Research::Dryad::XComputeProcessGetSetPropertyEventArgs ^e)
{
if (m_ppResults != NULL)
{
PXC_SETANDGETPROCESSINFO_REQRESULTS pResults = (PXC_SETANDGETPROCESSINFO_REQRESULTS)::LocalAlloc(LMEM_FIXED, sizeof(XC_SETANDGETPROCESSINFO_REQRESULTS));
if (pResults == NULL )
{
m_hResult = E_OUTOFMEMORY;
goto Exit;
}
ZeroMemory(pResults, sizeof(XC_SETANDGETPROCESSINFO_REQRESULTS));
try
{
if (e->ProcessInfo != nullptr)
{
ConvertManagedProcessInfoToNative(e->ProcessInfo, pResults->pProcessInfo);
}
if (e->PropertyVersions != nullptr && e->PropertyVersions->Length > 0)
{
pResults->NumberOfPropertyVersions = e->PropertyVersions->Length;
pResults->pPropertyVersions = (UINT64 *)LocalAlloc(LMEM_FIXED, sizeof(UINT64) * e->PropertyVersions->Length);
for (UINT32 i = 0; i < pResults->NumberOfPropertyVersions; i++)
{
pResults->pPropertyVersions[i] = e->PropertyVersions[i];
}
}
}
catch(Exception ^e)
{
m_hResult = Marshal::GetHRForException(e);
Console::WriteLine("[XComputeNative.GetSetPropertyHandler] Exception: {0}", e->Message);
goto Exit;
}
*m_ppResults = pResults;
}
m_hResult = S_OK;
Exit:
if (m_pASYNC)
{
m_pASYNC->Complete(m_hResult);
}
else
{
m_event->Set();
}
}
};
HRESULT
SetAppProcessConstraints(
IN XCPROCESSHANDLE hProcess,
IN PCXC_PROCESS_CONSTRAINTS Constraints
)
{
// TODO implement this! (return success for now because Dryad tries to dink with the runtime
return S_OK;
}
// #pragma unmanaged
// push managed state on to stack and set unmanaged state
#pragma managed(push, off)
/*++
XcSetAndGetProcessInfo API
Description:
Gets the process related information from the Process Node.
JobManager (e.g. Dryad Job manager), will use this API to get
information about a given XCompute process, of a job.
Various bit flags (explained below) control the amount of data
retreived for a given process
It also provides the user with the ability to block on a
particular property, for maxBlockTime amount of time, before the
API finishes (synchronously or asynchronously). Dryad uses this
to extend the lease period for a given process
Arguments:
hProcessHandle
Handle to the process.
Use the XcCreateNewProcessHandle () API
to get obtain the handle to the process
pXcRequestInputs
Pointer to the
XC_SETANDGETPROCESSINFO_REQINPUT struct.
It contains the various inputs to the API
clubbed together. This structure needs to
be preserverd by the user till the Async
call is completed
ppXcRequestResults
The results structure.The user should use
the XcFreeMemory(ppXcPnProcessInfo) to free
the memory after the results have been
consumed.
See PXC_SETANDGETPROCESSINFO_REQRESULTS for
more info.
pAsyncInfo
The async info structure. Its an alias to
the CS_ASYNC_INFO defined in Cosmos.h. If
this parameter is NULL, then function
completes in synchronous manner and error
code is returned as return value.
If parameter is not NULL then operation is
carried on in asynchronous manner. If
asynchronous operation has been successfully
started then function terminates
immediately with
HRESULT_FROM_WIN32(ERROR_IO_PENDING) return
value.
Any other return value indicates that it was
impossible to start asynchronous operation.
Return Value:
if pAsyncInfo is NULL
XCERROR_OK indicates call succeeded
Any other error code, indicates the failure reason.
if pAsyncInfo != NULL
HRESULT_FROM_WIN32(ERROR_IO_PENDING) indicates the async
operation was successfully started
Any other return value indicates it was impossible to start
asynchronous operation
--*/
XCOMPUTEAPI_EXT
XCERROR
XCOMPUTEAPI
XcSetAndGetProcessInfo(
IN XCPROCESSHANDLE hProcessHandle,
IN PXC_SETANDGETPROCESSINFO_REQINPUT pXcRequestInputs,
OUT PXC_SETANDGETPROCESSINFO_REQRESULTS* ppXcRequestResults,
IN PCXC_ASYNC_INFO pAsyncInfo
)
{
HRESULT hr;
printf("In native XcSetAndGetProcessInfo\n");
// check for malformed input
if (pXcRequestInputs->Size < sizeof(XC_SETANDGETPROCESSINFO_REQINPUT))
{
return E_NOTIMPL;
}
// no support for process constraints
if (pXcRequestInputs->pAppProcessConstraints != NULL)
{
hr = SetAppProcessConstraints(hProcessHandle, pXcRequestInputs->pAppProcessConstraints);
if (FAILED(hr))
{
return hr;
}
}
*ppXcRequestResults = NULL;
if (hProcessHandle == CURRENT_PROCESS_ID)
{
// We need to use the real dryad process id so the vertex service host can find it
CStringA procId;
procId.GetEnvironmentVariable("CCP_DRYADPROCID");
hProcessHandle = (XCPROCESSHANDLE)atoi((LPCSTR)procId);
}
hr = SetGetProps(
hProcessHandle,
pXcRequestInputs->NumberOfProcessPropertiesToSet,
pXcRequestInputs->ppPropertiesToSet,
pXcRequestInputs->pBlockOnPropertyLabel,
pXcRequestInputs->BlockOnPropertyversionLastSeen,
pXcRequestInputs->MaxBlockTime,
pXcRequestInputs->pPropertyFetchTemplate,
pXcRequestInputs->ProcessInfoFetchOptions,
ppXcRequestResults,
pAsyncInfo);
return hr;
}
// #pragma managed
#pragma managed(pop)
HRESULT
SetGetProps(
XCPROCESSHANDLE hProcessHandle,
long cPropCount,
PXC_PROCESSPROPERTY_INFO setProp[],
LPCSTR blockOnLabel,
UINT64 blockOnVersion,
XCTIMEINTERVAL maxBlockTime,
LPCSTR getPropLabel,
DWORD fetchOptions,
PXC_SETANDGETPROCESSINFO_REQRESULTS *ppResults,
PCXC_ASYNC_INFO pAsyncInfo
)
{
PASYNC async;
CAPTURE_ASYNC(async);
HRESULT hr = S_OK;
// Build a managed ProcessPropertyInfo array from the setProp[] array
array<ProcessPropertyInfo ^> ^infos = gcnew array<ProcessPropertyInfo ^>(cPropCount);
for (int i = 0; i < cPropCount; i++)
{
ProcessPropertyInfo ^info = gcnew ProcessPropertyInfo();
info->propertyLabel = gcnew String(setProp[i]->pPropertyLabel);
info->propertyVersion = setProp[i]->PropertyVersion;
info->propertyString = gcnew String(setProp[i]->pPropertyString);
if (setProp[i]->PropertyBlockSize > 0)
{
info->propertyBlock = gcnew array<byte>(setProp[i]->PropertyBlockSize);
Marshal::Copy((IntPtr)setProp[i]->pPropertyBlock, info->propertyBlock, 0, setProp[i]->PropertyBlockSize);
}
infos[i] = info;
}
AsyncPropWrapper ^wrapper = gcnew AsyncPropWrapper(async, hProcessHandle, ppResults);
GetSetPropertyEventHandler ^handler = gcnew GetSetPropertyEventHandler(wrapper, &AsyncPropWrapper::GetSetPropertyHandler);
VertexScheduler ^vs = VertexScheduler::GetInstance();
bool bRetVal = vs->SetGetProps(
(int)hProcessHandle,
infos,
gcnew String(blockOnLabel),
blockOnVersion,
maxBlockTime,
gcnew String(getPropLabel),
(fetchOptions & XCPROCESSINFOOPTION_PROCESSSTAT) != 0,
handler);
if (pAsyncInfo == NULL)
{
wrapper->m_event->WaitOne();
return wrapper->m_hResult;
}
else
{
return HRESULT_FROM_WIN32(ERROR_IO_PENDING);
}
}