I am trying to make a judge system on Windows using C++ (please don't tell me anything about Linux). Thus, I have to run the precompiled code and measure its CPU time and memory consumption. At first I used the CreateProcess to run the precompiled code, WaitForSingleObject to wait the end of the process and measured the time using getMillisecondsNow() and the memory using std::async(). It didn't work, the application terminated almost immediately before it get exit code from precompiled code. I read on forums that this is due to the fact that the tested code creates a process, but there were just for loop with random integers output. After that I read The Old New Thing and started use GetQueuedCompletionStatus to wait the end of the process. It is now waiting for the program to terminate. Always. I cannot make time limits.
First attempt
void myJudger(std::wstring aName, std::wstring aInputFilePath, std::wstring aOutputFilePath)
{
long long timeUsage = 1000;
long long reservedTime = 200;
long long memoryLimit = 200;
PROCESS_INFORMATION processInfo;
ZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION));
STARTUPINFOW startupInfo = { 0 };
IORedirection(startupInfo, aInputFilePath, aOutputFilePath);
wchar_t* cmd = const_cast<wchar_t*>(aName.c_str());
auto feature = std::async(std::launch::async, getMaxMemoryUsage, std::ref(processInfo), memoryLimit);
if (CreateProcess(NULL, cmd,
NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED | CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo) == FALSE)
{
std::cout << "ERROR #2: can't start process" << std::endl;
}
long long startTime = getMillisecondsNow();
ResumeThread(processInfo.hThread);
//DWORD waitResult =
DWORD waitResult;
while ((waitResult = WaitForSingleObject(processInfo.hProcess, INFINITE)) == STILL_ACTIVE)
{
std::cout << "working...\n";
}
if (waitResult == WAIT_FAILED)
{
std::cout << "ERROR #3: WAIT_FAILED" << std::endl;
}
if (waitResult == WAIT_OBJECT_0)
{
std::cout << "Code complite\n" << std::endl;
}
if (waitResult == WAIT_TIMEOUT)
{
std::cout << "Time out\n" << std::endl;
}
if (getExitCode(processInfo.hProcess) == STILL_ACTIVE) {
std::cout << "Alive" << std::endl;
killProcess(processInfo);
}
long long endTime = getMillisecondsNow();
long long memoryUsage = feature.get();
std::cout << "time usage: " << endTime - startTime << std::endl;
std::cout << "memory usage: " << memoryUsage << std::endl;
}
Second attempt
void myJudger3(std::wstring aName, std::wstring aInputFilePath, std::wstring aOutputFilePath)
{
CHandle Job(CreateJobObject(nullptr, nullptr));
if (!Job) ERRORCOUT(1, "create job object");
CHandle IOPort(CreateIoCompletionPort(INVALID_HANDLE_VALUE,
nullptr, 0, 1));
if (!IOPort) ERRORCOUT(2,"create IO completion port");
JOBOBJECT_ASSOCIATE_COMPLETION_PORT Port;
Port.CompletionKey = Job;
Port.CompletionPort = IOPort;
if (!SetInformationJobObject(Job,
JobObjectAssociateCompletionPortInformation,
&Port, sizeof(Port))) ERRORCOUT(3, "set information");
PROCESS_INFORMATION ProcessInformation;
STARTUPINFO StartupInfo = { sizeof(StartupInfo) };
IORedirection(StartupInfo, aInputFilePath, aOutputFilePath);
wchar_t* cmd = const_cast<wchar_t*>(aName.c_str());
long long memoryLimit = 2e6;
auto feature = std::async(std::launch::async, getMaxMemoryUsage, std::ref(ProcessInformation), memoryLimit);
if (!CreateProcess(nullptr, cmd, nullptr, nullptr,
TRUE, CREATE_UNICODE_ENVIRONMENT | CREATE_SUSPENDED | CREATE_NO_WINDOW, nullptr, nullptr,
&StartupInfo, &ProcessInformation))
ERRORCOUT(4, "create process");
if (!AssignProcessToJobObject(Job,
ProcessInformation.hProcess)) ERRORCOUT(4, "assign process");
long long startTime = getMillisecondsNow();
ResumeThread(ProcessInformation.hThread);
uint_64 memoryUsage = feature.get();
CloseHandle(ProcessInformation.hThread);
CloseHandle(ProcessInformation.hProcess);
DWORD CompletionCode;
ULONG_PTR CompletionKey;
LPOVERLAPPED Overlapped;
GetQueuedCompletionStatus(IOPort, &CompletionCode,
&CompletionKey, &Overlapped, 1000);
std::cout << getMillisecondsNow() - startTime << std::endl;
long long endTime = getMillisecondsNow();
std::cout << "\n\ntime usage: " << endTime - startTime << std::endl;
std::cout << "\n\nmemory usage: " << memoryUsage << std::endl;
}
Code to test
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; ++i)
{
cout << rand() << "\n";
}
}