From e27ee6f152cb6dd9d8a5d668ef2bb724d6cc8b5e Mon Sep 17 00:00:00 2001 From: Rom Walton Date: Thu, 15 Sep 2011 23:04:10 +0000 Subject: [PATCH] - VBOX: Add a way to track overall network utilization of a VM. samples/vboxwrapper/ vbox.cpp, .h svn path=/trunk/boinc/; revision=24223 --- checkin_notes | 6 ++ samples/vboxwrapper/vbox.cpp | 185 +++++++++++++++++++++++++++-------- samples/vboxwrapper/vbox.h | 7 +- win_build/wrapper.vcproj | 8 +- 4 files changed, 157 insertions(+), 49 deletions(-) diff --git a/checkin_notes b/checkin_notes index 4885111523..18adf12581 100644 --- a/checkin_notes +++ b/checkin_notes @@ -6114,3 +6114,9 @@ David 15 Sept 2011 client/ rr_sim.cpp + +Rom 15 Sept 2011 + - VBOX: Add a way to track overall network utilization of a VM. + + samples/vboxwrapper/ + vbox.cpp, .h diff --git a/samples/vboxwrapper/vbox.cpp b/samples/vboxwrapper/vbox.cpp index 5d22027ee3..3a5ecd89d8 100644 --- a/samples/vboxwrapper/vbox.cpp +++ b/samples/vboxwrapper/vbox.cpp @@ -140,7 +140,7 @@ int VBOX_VM::vbm_popen(string& arguments, string& output) { sa.lpSecurityDescriptor = &sd; - if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, 128*1024)) { + if (!CreatePipe(&hReadPipe, &hWritePipe, &sa, NULL)) { fprintf( stderr, "%s CreatePipe failed! (%d).\n", @@ -175,33 +175,28 @@ int VBOX_VM::vbm_popen(string& arguments, string& output) { // Wait until process has completed while(1) { GetExitCodeProcess(pi.hProcess, &ulExitCode); - if (ulExitCode != STILL_ACTIVE) break; - Sleep(250); - } + // Copy stdout/stderr to output buffer, handle in the loop so that we can + // copy the pipe as it is populated and prevent the child process from blocking + // in case the output is bigger than pipe buffer. + PeekNamedPipe(hReadPipe, NULL, NULL, NULL, &dwCount, NULL); + if (dwCount) { + pBuf = malloc(dwCount+1); + memset(pBuf, 0, dwCount+1); - // Copy stdout/stderr to output buffer - if (!PeekNamedPipe(hReadPipe, NULL, NULL, NULL, &dwCount, NULL)) { - fprintf( - stderr, - "%s PeekNamedPipe failed! (%d).\n", - boinc_msg_prefix(buf, sizeof(buf)), - GetLastError() - ); - } + if (ReadFile(hReadPipe, pBuf, dwCount, &dwCount, NULL)) { + output += (char*)pBuf; + } - if (dwCount) { - pBuf = malloc(dwCount+1); - memset(pBuf, 0, dwCount+1); - - if (ReadFile(hReadPipe, pBuf, dwCount, &dwCount, NULL)) { - output += (char*)pBuf; + free(pBuf); } - free(pBuf); + if (ulExitCode != STILL_ACTIVE) break; + Sleep(100); } + CLEANUP: if (pi.hThread) CloseHandle(pi.hThread); if (pi.hProcess) CloseHandle(pi.hProcess); @@ -302,18 +297,18 @@ bool VBOX_VM::is_running() { string command; string output; string vmstate; - size_t vmstate_location; - size_t vmstate_length; + size_t vmstate_start; + size_t vmstate_end; command = "showvminfo \"" + vm_name + "\" "; command += "--machinereadable "; if (vbm_popen(command, output) == 0) { - vmstate_location = output.find("VMState=\""); - if (vmstate_location != string::npos) { - vmstate_location += 9; - vmstate_length = output.find("\"", vmstate_location); - vmstate = output.substr(vmstate_location, vmstate_length - vmstate_location); + vmstate_start = output.find("VMState=\""); + if (vmstate_start != string::npos) { + vmstate_start += 9; + vmstate_end = output.find("\"", vmstate_start); + vmstate = output.substr(vmstate_start, vmstate_end - vmstate_start); // VirtualBox Documentation suggests that that a VM is running when its // machine state is between MachineState_FirstOnline and MachineState_LastOnline @@ -714,8 +709,8 @@ int VBOX_VM::deregister_stale_vm() { string command; string output; string virtual_machine_root_dir; - size_t uuid_location; - size_t uuid_length; + size_t uuid_start; + size_t uuid_end; char buf[256]; int retval; @@ -751,12 +746,12 @@ int VBOX_VM::deregister_stale_vm() { // In use by VMs: test2 (UUID: 000ab2be-1254-4c6a-9fdc-1536a478f601) // Location: C:\Users\romw\VirtualBox VMs\test2\test2.vdi // - uuid_location = output.find("(UUID: "); - if (uuid_location != string::npos) { + uuid_start = output.find("(UUID: "); + if (uuid_start != string::npos) { // We can parse the virtual machine ID from the output - uuid_location += 7; - uuid_length = output.find(")", uuid_location); - vm_name = output.substr(uuid_location, uuid_length - uuid_location); + uuid_start += 7; + uuid_end = output.find(")", uuid_start); + vm_name = output.substr(uuid_start, uuid_end - uuid_start); // Deregister stale VM by UUID return deregister_vm(); @@ -1034,8 +1029,8 @@ int VBOX_VM::get_vm_process_id(int& process_id) { string command; string output; string pid; - size_t pid_location; - size_t pid_length; + size_t pid_start; + size_t pid_end; char buf[256]; int retval; @@ -1068,20 +1063,126 @@ int VBOX_VM::get_vm_process_id(int& process_id) { // 00:00:06.015 Installed Extension Packs: // 00:00:06.015 None installed! // - pid_location = output.find("Process ID: "); - if (pid_location == string::npos) { + pid_start = output.find("Process ID: "); + if (pid_start == string::npos) { fprintf(stderr, "%s couldn't find 'Process ID: ' in %s\n", boinc_msg_prefix(buf, sizeof(buf)), output.c_str()); return ERR_NOT_FOUND; } - pid_location += 12; - pid_length = output.find("\n", pid_location); - pid = output.substr(pid_location, pid_length - pid_location); + pid_start += 12; + pid_end = output.find("\n", pid_start); + pid = output.substr(pid_start, pid_end - pid_start); if (pid.size() <= 0) { fprintf(stderr, "%s no PID: location %d length %d\n", - boinc_msg_prefix(buf, sizeof(buf)), (int)pid_location, (int)(pid_length - pid_location) + boinc_msg_prefix(buf, sizeof(buf)), (int)pid_start, (int)(pid_end - pid_start) ); return ERR_NOT_FOUND; } process_id = atol(pid.c_str()); + if (process_id) { + fprintf(stderr, "%s Virtual Machine PID Detected\n", + boinc_msg_prefix(buf, sizeof(buf)), process_id + ); + } + return 0; +} + +int VBOX_VM::get_vm_network_bytes_received(unsigned long long& received) { + string command; + string output; + string counter_value; + size_t counter_start; + size_t counter_end; + char buf[256]; + int retval; + + command = "debugvm \"" + vm_name + "\" "; + command += "statistics --pattern \"/Devices/*/ReceiveBytes\" "; + + retval = vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error getting network statistics for virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + + // Output should look like this: + // + // + // + // + // + + // Reset the return value, we'll end up summing any c="*" values returned. + received = 0; + + // Begin looking for the counter(s) + counter_start = output.find("c=\""); + while (counter_start != string::npos) { + counter_start += 3; + counter_end = output.find("\"", counter_start); + counter_value = output.substr(counter_start, counter_end - counter_start); + + received += boinc_strtoull(counter_value.c_str(), NULL, 10); + + counter_start = output.find("\n", counter_start); + } + + return 0; +} + +int VBOX_VM::get_vm_network_bytes_transmitted(unsigned long long& transmited) +{ + string command; + string output; + string counter_value; + size_t counter_start; + size_t counter_end; + char buf[256]; + int retval; + + command = "debugvm \"" + vm_name + "\" "; + command += "statistics --pattern \"/Devices/*/TransmitBytes\" "; + + retval = vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error getting network statistics for virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + + // Output should look like this: + // + // + // + // + // + + // Reset the return value, we'll end up summing any c="*" values returned. + transmited = 0; + + // Begin looking for the counter(s) + counter_start = output.find("c=\""); + while (counter_start != string::npos) { + counter_start += 3; + counter_end = output.find("\"", counter_start); + counter_value = output.substr(counter_start, counter_end - counter_start); + + transmited += boinc_strtoull(counter_value.c_str(), NULL, 10); + + counter_start = output.find("\n", counter_start); + } + return 0; } diff --git a/samples/vboxwrapper/vbox.h b/samples/vboxwrapper/vbox.h index d9dc48abb9..d89e652960 100644 --- a/samples/vboxwrapper/vbox.h +++ b/samples/vboxwrapper/vbox.h @@ -45,7 +45,6 @@ struct VBOX_VM { // useful for debugging VMs. bool register_only; - void poll(); int run(); int stop(); @@ -64,11 +63,13 @@ struct VBOX_VM { int set_cpu_usage_fraction(double); int set_network_max_bytes_sec(double); int get_vm_process_id(int& process_id); + int get_vm_network_bytes_received(unsigned long long& received); + int get_vm_network_bytes_transmitted(unsigned long long& transmited); static int initialize(); + static int get_install_directory(std::string& dir); static int generate_vm_root_dir(std::string& dir); - static int vbm_popen(std::string&, std::string&); - static int get_install_directory(std::string&); + static int vbm_popen(std::string& command, std::string& output); }; #endif diff --git a/win_build/wrapper.vcproj b/win_build/wrapper.vcproj index 694917a6a9..9e7a816b7f 100644 --- a/win_build/wrapper.vcproj +++ b/win_build/wrapper.vcproj @@ -81,13 +81,13 @@ @@ -182,13 +182,13 @@