To monitor the host or a virtual machine performance on a periodic basis, an event handler (callback function) is required. Within the event handler, first check the type of event. Events of type
PET_DSP_EVT_HOST_STATISTICS_UPDATED
indicate an event containing statistics data. To access the statistics handle (a handle of type
PHT_SYSTEM_STATISTICS
), first extract the event parameter using
PrlEvent_GetParam
, then convert the result (which will be a handle to an object of type
PHT_EVENT_PARAMETER
) to a handle using
PrlEvtPrm_ToHandle
. The functions that operate on
PHT_SYSTEM_STATISTICS
references can then be used to obtain statistics data.
For the event handler to be called, it is necessary to register it with
PrlSrv_RegEventHandler
. Before the event handler will receive statistics events, the application must subscribe to statistics events using
PrlSrv_SubscribeToHostStatistics
. When statistics data is no longer required, unsubscribe from statistics events using
PrlSrv_UnsubscribeFromHostStatistics
. When events are no longer required, unregister the event event handler using
PrlSrv_UnregEventHandler
.
The following is a complete example that demonstrates how to obtain statistics data asynchronously using
PrlSrv_SubscribeToHostStatistics
. Note that the same code could be used to receive statistics data for a virtual machine, instead of the host computer, by using
PrlVm_SubscribeToGuestStatistics
instead of
PrlSrv_SubscribeToHostStatistics
, and passing it a handle to a virtual machine that is running. This would also require using
PrlVm_UnsubscribeFromGuestStatistics
to stop receiving statistics data for the virtual machine.
#include "Parallels.h"
#include "Wrappers/SdkWrap/SdkWrap.h"
#include <stdio.h>
#ifdef _WIN_
#include <windows.h>
#else
#include <unistd.h>
#endif
const char *szServer = "123.123.123.123";
const char *szUsername = "Your Username";
const char *szPassword = "Your Password";
// -------------------------------------------------------------------------
// Event handler.
// -------------------------------------------------------------------------
// 1. Check for events of type PET_DSP_EVT_HOST_STATISTICS_UPDATES.
// 2. Display a header if first call to this event handler.
// 3. Get the event param (PHT_EVENT_PARAMETER) from the PHT_EVENT handle.
// 4. Convert event param to a handle (will be type PHT_SYSTEM_STATISTICS).
// 5. Use PHT_SYSTEM_STATISTICS handle to obtain CPU usage, memory usage,
// and disk usage data.
// -------------------------------------------------------------------------
static PRL_RESULT OurCallback(PRL_HANDLE handle, void *pData)
{
PRL_HANDLE_TYPE nHandleType;
PRL_RESULT ret = PrlHandle_GetType(handle, &nHandleType);
// Check for PrlHandle_GetType error here.
if (nHandleType == PHT_EVENT)
{
PRL_EVENT_TYPE EventType;
PrlEvent_GetType(handle, &EventType);
// Check if the event type is a statistics update.
if (EventType == PET_DSP_EVT_HOST_STATISTICS_UPDATED)
{
// Output a header if first call to this function.
static PRL_BOOL bHeaderHasBeenPrinted = PRL_FALSE;
if (!bHeaderHasBeenPrinted)
{
bHeaderHasBeenPrinted = PRL_TRUE;
printf("CPU (%%) Used RAM (MB) Free RAM (MB) Used Disk Space (MB)"
" Free Disk Space (MB)\n");
printf("---------------------------------------------------------"
"--------------------\n");
}
PRL_HANDLE hEventParameters;
PRL_HANDLE hServerStatistics;
// Get the event parameter (PHT_EVENT_PARAMETER) from the event handle.
PrlEvent_GetParam(handle, 0, &hEventParameters);
// Convert the event parameter to a handle (PHT_SYSTEM_STATISTICS).
PrlEvtPrm_ToHandle(hEventParameters, &hServerStatistics);
// Get CPU statistics (usage in %).
PRL_HANDLE hCpuStatistics;
ret = PrlStat_GetCpuStat(hServerStatistics, 0, &hCpuStatistics);
PRL_UINT32 nCpuUsage = 0;
ret = PrlStatCpu_GetCpuUsage(hCpuStatistics, &nCpuUsage);
// Get RAM statistics.
PRL_UINT64 nUsedRam, nFreeRam;
PrlStat_GetFreeRamSize(hServerStatistics, &nFreeRam);
PrlStat_GetUsageRamSize(hServerStatistics, &nUsedRam);
nUsedRam /= (1024 * 1024);
nFreeRam /= (1024 * 1024);
// Get disk space statistics.
PRL_UINT64 nFreeDiskSpace, nUsedDiskSpace;
PRL_HANDLE hDiskStatistics;
PrlStat_GetDiskStat(hServerStatistics, 0, &hDiskStatistics);
PrlStatDisk_GetFreeDiskSpace(hDiskStatistics, &nFreeDiskSpace);
PrlStatDisk_GetUsageDiskSpace(hDiskStatistics, &nUsedDiskSpace);
nUsedDiskSpace /= (1024 * 1024);
nFreeDiskSpace /= (1024 * 1024);
printf("%7d %10lld %13lld %20lld %20lld\n",
nCpuUsage, nUsedRam, nFreeRam, nUsedDiskSpace, nFreeDiskSpace);
PrlHandle_Free(hDiskStatistics);
PrlHandle_Free(hCpuStatistics);
PrlHandle_Free(hServerStatistics);
PrlHandle_Free(hEventParameters);
}
}
PrlHandle_Free(handle);
return PRL_ERR_SUCCESS;
}
// --------------------------------------------------------------------------
// Program entry point.
// --------------------------------------------------------------------------
// 1. Call SdkWrap_Load(SDK_LIB_NAME).
// 2. Call PrlApi_Init(PARALLELS_API_VER).
// 3. Create a PRL_SERVER handle using PrlSrv_Create.
// 4. Log in using PrlSrv_Login.
// 5. Register our event handler (OurCallback function).
// 6. Subscribe to host statistics events.
// 7. Keep receiving events until user presses <enter> key.
// 8. Unsubscribe from host statistics events.
// 9. Un-register our event handler.
// 10. Logoff using PrlSrv_Logoff.
// 11. Call PrlApi_Uninit.
// 12. Call SdkWrap_Unload.
// --------------------------------------------------------------------------
int main(int argc, char* argv[])
{
PRL_HANDLE hServer;
PRL_RESULT ret;
// Use the correct dynamic library depending on the platform.
#ifdef _WIN_
#define SDK_LIB_NAME "prl_sdk.dll"
#elif defined(_LIN_)
#define SDK_LIB_NAME "libprl_sdk.so"
#elif defined(_MAC_)
#define SDK_LIB_NAME "libprl_sdk.dylib"
#endif
// Try to load the SDK library, terminate on failure to do so.
if (PRL_FAILED(SdkWrap_Load(SDK_LIB_NAME)) &&
PRL_FAILED(SdkWrap_Load("./" SDK_LIB_NAME)))
{
fprintf(stderr, "Failed to load " SDK_LIB_NAME "\n");
return -1;
}
// Initialize the Parallels API.
ret = PrlApi_Init(PARALLELS_API_VER);
if (PRL_FAILED(ret))
{
fprintf(stderr, "PrlApi_Init returned with error: %s.\n",
prl_result_to_string(ret));
PrlApi_Deinit();
SdkWrap_Unload();
return ret;
}
// Create a PHP_SERVER handle.
ret = PrlSrv_Create(&hServer);
if (PRL_FAILED(ret))
{
fprintf(stderr, "PrlSvr_Create failed, error: %s",
prl_result_to_string(ret));
PrlHandle_Free(hServer);
PrlApi_Deinit();
SdkWrap_Unload();
return -1;
}
// Log in (PrlSrv is asynchronous).
PRL_HANDLE hJob = PrlSrv_Login(
hServer, // PRL_HANDLE of type PHT_SERVER.
szServer, // Host name or IP address.
szUsername, // Username.
szPassword, // Password.
0, // Deprecated - UUID of previous session.
0, // Optional - port number (0 for default).
0, // Optional - timeout value (0 for default).
PSL_LOW_SECURITY); // Security level (can be PSL_LOW_SECURITY,
PSL_NORMAL_SECURITY, or PSL_HIGH_SECURITY).
// Wait for a maximum of 10 seconds for
// asynchronous function PrlSrv_Login to complete.
ret = PrlJob_Wait(hJob, 1000);
if (PRL_FAILED(ret))
{
fprintf(stderr, "PrlJob_Wait for PrlSrv_Login returned with error: %s\n",
prl_result_to_string(ret));
PrlHandle_Free(hJob);
PrlHandle_Free(hServer);
PrlApi_Deinit();
SdkWrap_Unload();
return -1;
}
// Analyze the result of PrlSrv_Login.
PRL_RESULT nJobResult;
ret = PrlJob_GetRetCode(hJob, &nJobResult);
if (PRL_FAILED(nJobResult))
{
printf("Login job returned with error: %s\n",
prl_result_to_string(nJobResult));
PrlHandle_Free(hJob);
PrlHandle_Free(hServer);
PrlApi_Deinit();
SdkWrap_Unload();
return -1;
}
else
printf("Login was successful.\n");
// ----------------------------------------------------------------------------
// 1. Register our event handler (OurCallback function).
// 2. Subscribe to host statistics events.
// 3. Keep receiving events until user presses <enter> key.
// 4. Unsubscribe from host statistics events.
// 5. Un-register out event handler.
// ----------------------------------------------------------------------------
PrlSrv_RegEventHandler(hServer, OurCallback, NULL);
PrlSrv_SubscribeToHostStatistics(hServer);
char c;
scanf(&c, 1);
PrlSrv_UnsubscribeFromHostStatistics(hServer);
PrlSrv_UnregEventHandler(hServer, OurCallback, NULL);
// ----------------------------------------------------------------------------
// Log off.
hJob = PrlSrv_Logoff(hServer);
ret = PrlJob_Wait(hJob, 1000);
if (PRL_FAILED(ret))
{
fprintf(stderr, "PrlJob_Wait for PrlSrv_Logoff returned error: %s\n",
prl_result_to_string(ret));
PrlHandle_Free(hJob);
PrlHandle_Free(hServer);
PrlApi_Deinit();
SdkWrap_Unload();
return -1;
}
ret = PrlJob_GetRetCode(hJob, &nJobResult);
if (PRL_FAILED(ret))
{
fprintf(stderr, "PrlJob_GetRetCode failed for PrlSrv_Logoff with error: %s\n",
prl_result_to_string(ret));
PrlHandle_Free(hJob);
PrlHandle_Free(hServer);
PrlApi_Deinit();
SdkWrap_Unload();
return -1;
}
// Report success or failure of PrlSrv_Logoff.
if (PRL_FAILED(nJobResult))
{
fprintf(stderr, "PrlSrv_Logoff failed with error: %s\n",
prl_result_to_string(nJobResult));
PrlHandle_Free(hJob);
PrlHandle_Free(hServer);
PrlApi_Deinit();
SdkWrap_Unload();
return -1;
}
else
printf("Logoff was successful.\n");
// Free handles that are no longer required.
PrlHandle_Free(hJob);
PrlHandle_Free(hServer);
// De-initialize the Parallels API, and unload the SDK.
PrlApi_Deinit();
SdkWrap_Unload();
return 0;
}